XR Syntax
xr-syntax 是 XRobot / LibXR Python 工具使用的结构化源码解析、修改与代码生成基础库。
它解决的是源码层问题:
- 读取已有 C++ / CMake;
- 保留原始空白、换行、注释和用户代码;
- 按函数、类、调用、变量、命令等结构查询;
- 对指定结构进行不可变编辑;
- 用同一套模型生成新的 C++ / CMake;
- 给 XRobot、LibXR_CppCodeGenerator 提供统一 backend。
它不是 C++ 编译器,不会自己做 name lookup、overload resolution、template instantiation 或 type inference。
最基本的不变量是:
document = CppDocument.parse(source)
assert document.render_bytes() == source
即使 parser 对某段源码只能保守地表示,原始源码也不能因为解析而丢失。
安装
支持 Python 3.8–3.13,与 XRobot 和 LibXR_CppCodeGenerator 的 Python 包保持一致。
pip install xr-syntax
从源码安装:
git clone https://github.com/xrobot-org/xr-syntax.git
cd xr-syntax
pip install .
开发环境:
pip install -e ".[dev]"
当前基础包没有第三方 runtime dependency;C++ 与 CMake parser 都包含在包内。
包结构
src/xr_syntax/
├── core/ # 通用不可变 syntax tree、span、grammar、rewrite
├── cpp/ # C++ lexer/parser/query/view/factory/builder
├── cmake/ # CMake parser/query/view/factory/builder
└── format/ # 新生成源码使用的 layout IR
第一轮 code review 建议先看:
docs/REVIEW_GUIDE.md
C++:读取已有源码
解析
from xr_syntax.cpp import CppDocument
source = b"""
#include "device.hpp"
static Device device;
void app_main() {
XR_REGISTER(device, Base);
}
""".lstrip()
document = CppDocument.parse(source)
assert document.render_bytes() == source
CppDocument 是一个不可变源码 snapshot。
查询 include
includes = document.include_views()
assert includes[0].header == "device.hpp"
assert includes[0].system is False
对于:
#include <vector>
对应:
include.header == "vector"
include.system is True
查询函数
function = document.function_views("app_main")[0]
print(function.name)
print(function.parameters)
print(function.body)
如果需要底层 syntax node:
document.functions("app_main")
查询函数调用
例如:
XR_REGISTER(device, LibXR::GPIO);
可以直接查询:
calls = document.call_views("XR_REGISTER")
for call in calls:
print(call.callee)
print([argument.text for argument in call.arguments])
输出参数仍然保持源码层表示:
device
LibXR::GPIO
查询变量
all_variables = document.variable_views()
globals_ = document.variable_views(
global_scope=True,
)
locals_ = document.variable_views(
global_scope=False,
)
每个 variable view 可以读取:
variable.name
variable.base_type
variable.storage
variable.qualifiers
variable.initializer
variable.global_scope
这里提供的是源码结构信息,不是编译器语义。
它不会判断:
- typedef 展开后的最终类型;
- 某个 constructor call 选择哪个 overload;
- template 实例化结果。
查询 class / constructor
clazz = document.class_views("CameraBase")[0]
constructors = clazz.constructors(
public_only=True,
callable_only=True,
)
for constructor in constructors:
print(constructor.name)
print(constructor.parameters)
例如:
CameraBase(const CameraBase&) = delete;
仍然会被 syntax tree 表示,但 callable_only=True 会把它从“可调用构造函数”列表中过滤掉。
析构函数和 operator= 不会被误识别成 constructor。
C++:修改已有源码
CppDocument 不原地修改。
所有 edit 都返回新 document:
from xr_syntax.cpp import CppDocument, CppFactory
document = CppDocument.parse(
'#include "a.hpp"\n'
'void app_main() {}\n'
)
factory = CppFactory()
changed = document.insert_after(
document.includes()[0],
factory.include("b.hpp"),
)
assert document.render() == (
'#include "a.hpp"\n'
'void app_main() {}\n'
)
assert changed.render() == (
'#include "a.hpp"\n'
'#include "b.hpp"\n'
'void app_main() {}\n'
)
高层 edit 完成后会重新 parse,保证 field、diagnostic 和 error-recovery 结构与新源码一致。
User Code / format / lint 区域
STM32 常见区域:
/* User Code Begin 3 */
custom_code();
/* User Code End 3 */
不再需要自己写 regex:
region = document.user_regions()[0]
print(region.name)
print(region.body_text)
只替换区域内部:
changed = document.replace_region_body(
region,
"\ncustom_code();\nother_code();\n",
)
同样支持:
// clang-format off
...
// clang-format on
以及:
// NOLINTBEGIN
...
// NOLINTEND
对应:
document.format_regions()
document.lint_regions()
C++:生成源码
读取和生成使用同一个 syntax model。
FileBuilder
from xr_syntax.cpp import CppFileBuilder
builder = CppFileBuilder()
builder.include("device.hpp")
builder.raw("\nstatic Device device;\n")
document = builder.build()
print(document.render())
Function / block builder
builder = CppFileBuilder()
entry = builder.function(
"void",
"XRobotMain",
prefix=["[[noreturn]]"],
)
entry.parameter(
"LibXR::GPIO&",
"led",
)
entry.body.variable(
"BlinkLED",
"blink",
initializer="BlinkLED(led, 250)",
storage=["static"],
)
entry.body.call(
"Run",
["blink"],
)
document = builder.build()
builder 最终返回的仍然是 parser-backed CppDocument,不会产生第二套“生成器 AST”。
CMake
CMake frontend 与 C++ 共用同一套 core:
- immutable document;
- source span;
- grammar contract;
- rewrite;
- builder;
- layout。
读取
from xr_syntax.cmake import CMakeDocument
source = b"""
project(Demo)
add_library(foo STATIC foo.cpp)
""".lstrip()
document = CMakeDocument.parse(source)
assert document.render_bytes() == source
library = document.command_views(
"add_library"
)[0]
assert library.name == "add_library"
assert [
argument.text
for argument in library.arguments
] == [
"foo",
"STATIC",
"foo.cpp",
]
生成
from xr_syntax.cmake import CMakeFileBuilder
builder = CMakeFileBuilder()
builder.command(
"project",
["Demo", "LANGUAGES", "CXX"],
)
builder.command(
"add_library",
["foo", "STATIC", "foo.cpp"],
)
document = builder.build()
print(document.render())
Green / Red syntax tree
Green
Green tree 只保存结构:
- kind;
- text;
- trivia;
- children;
- field。
它不保存:
- parent;
- absolute offset;
- owning document。
这样未修改 subtree 可以在多个 immutable snapshot 之间复用。
Red
Red view 为某个具体 snapshot 增加:
- parent;
- child index;
- field;
- byte span;
- structural path。
因此:
Green = 可共享的不可变结构
Red = 某个 snapshot 中的位置视图
无损表示
parser 不一定会把所有字节都作为结构节点。
例如:
- 空白;
- 某些注释;
- parser 保守保留的未知片段;
- 不完整源码。
xr-syntax 会把无法安全细分的内容继续作为 source-preserving element 保留下来。
最终必须满足:
document.render_bytes() == input_bytes
diagnostic 可以存在,静默丢源码不允许存在。
排版
已有源码的 render() 与新源码的 formatting 是两件事。
render()
→ 保留已有 syntax / trivia
layout IR
→ 决定新生成源码如何缩进和折行
layout IR 包含:
Text
Concat
Group
Indent
Line
SoftLine
HardLine
IfBreak
这样 XRobot / LibXR_CppCodeGenerator 不需要再在业务逻辑里写行宽判断。
明确不做什么
xr-syntax 负责源码结构,不负责 C++ compiler semantics。
它不会自己实现:
- name lookup;
- overload resolution;
- template instantiation;
- type inference;
- constant evaluation;
- ABI;
- XRobot Module 依赖绑定;
XR_REGISTER的业务语义。
例如:
“某个 Module constructor 应该绑定哪个 LibXR view?”
仍然属于 XRobot 的 domain logic。
Python 支持
与 XRobot、LibXR_CppCodeGenerator 保持一致:
Python 3.8
Python 3.9
Python 3.10
Python 3.11
Python 3.12
Python 3.13
CI 在 Linux 和 Windows 上覆盖以上版本。
注释规范
项目要求:
- 每个 Python 文件都有模块说明;
- 每个 class 都有说明;
- 每个函数 / 方法(包含私有函数)都有中文说明;
- 关键 parser / rewrite 算法使用行内注释解释“为什么”,而不是逐行复述代码。
CI 中的:
tools/check_bilingual_docs.py
会自动检查源码、测试和工具脚本的文档覆盖。
验证
当前验证包括:
- Linux / Windows;
- Python 3.8–3.13;
- pytest;
- ruff;
- mypy strict;
- build / wheel / sdist;
- twine check;
- standalone wheel smoke;
- C++ corpus round-trip;
- CMake corpus round-trip;
- XRobot constructor parity;
- XR_REGISTER corpus probe。
详细数据见:
docs/VALIDATION.md
开发
pip install -e ".[dev]"
常用检查:
python -m pytest
python tools/check_bilingual_docs.py
python -m ruff check src tests tools
python -m mypy src
python -m build
Review
第一轮 review 请先看:
docs/REVIEW_GUIDE.md
它会告诉你哪些文件决定整体架构,哪些 grammar/test/tool 文件可以后看。
Metadata
Release files for xr-syntax 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| xr_syntax-0.1.0.tar.gz | 115.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| xr_syntax-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 220.2 kB
Release files / xr_syntax-0.1.0.tar.gz
| Download URL | xr_syntax-0.1.0.tar.gz |
|---|---|
| Size | 115.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f865ec66910511e3712b7544bc742ecdd4df7fda1769947003f562268c53ac69
|
|
BLAKE2b-256 checksum How to use checksums |
0724d59b6f8badc8e39e92312bb6ba566984cead642004ed2ecbff7de4902f8b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency logRelease files / xr_syntax-0.1.0-py3-none-any.whl
| Download URL | xr_syntax-0.1.0-py3-none-any.whl |
|---|---|
| Size | 104.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9c7495325f76f1051087fd5bcc301e797683142a306e7096ef7ed2fbaea6fd8f
|
|
BLAKE2b-256 checksum How to use checksums |
cdd822a95e1beff6b280eac9e8633a3084683d8ba476bcf3056f4a2fa1920915
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency log