老赵写字的地方

XLang:可逆计算的编译期语言族

可逆计算公式中有一个关键操作:变换。DSL 定义完后,需要经过结构变换才能得到最终的可运行产物。这个变换由 XLang 完成。

XLang 不是一门语言,而是一整套面向 DSL 变换的语言族,包含 XScript、Xpl、XTransform 三个核心成员。它们共享同一个类型系统和运行时,各自负责不同的变换任务。

为什么需要一门新语言

通用的编程语言(Java、Python)操作 XML/JSON 时,通常需要经过“解析 → 对象 → 遍历 → 修改 → 序列化”的冗长流程。对于 DSL 的编译期变换来说,这个流程太重了。

XLang 的设计目标是在 DSL 的结构层次上直接操作,而不是把 DSL 转成内存对象再处理。这类似于 SQL 直接在表上操作,而不需要把表转成对象再遍历。

用 XLang 表达“删除实体中的 password 字段”:

for (entity in /orm/entities) {
    entity.removeColumn("password")
}

对比 Java 实现同样的逻辑:

  1. 解析 XML → 20 行
  2. 遍历实体 → 5 行
  3. 查找并删除字段 → 5 行
  4. 序列化回 XML → 5 行
  5. 总共约 35 行

XLang 直接在内建的 XNode 结构上操作,没有解析和序列化开销。

XScript:脚本语言

XScript 是一门类似 JavaScript 的动态脚本语言,语法上兼容 JavaScript 的基础表达式,但针对树结构操作做了专门扩展。

let entity = xpl.loadXml("/nop/auth/orm/app.orm.xml");
let columns = entity.$children("columns").$children("column");
for (let col in columns) {
    if (col.$attr("name") == "password") {
        col.$remove();
    }
}
xpl.saveXml("/nop/auth/orm/app.orm.xml", entity);

XScript 中的 $ 前缀方法($children、$attr、$remove)是操作树结构的专用 API,直接在 XML 节点上执行,不需要经过 Java 对象映射。

使用场景:

  • 编译期的模型变换和修正
  • 动态生成 DSL 片段
  • 条件化处理(根据环境变量选择不同的模型)

Xpl:模板语言

Xpl 是类似 FreeMarker 的模板语言,但它的输出是结构化数据(XML 节点),而非字符串。这避免了字符串拼接导致的 XML 格式错误。

<c:unit xpl:outputMode="xml">
  <entity name="MyEntity" table="my_entity">
    <columns>
      <c:for var="col" items="${extFields}">
        <column name="${col.name}" code="${col.type}">
          <comment text="${col.desc}" />
        </column>
      </c:for>
    </columns>
  </entity>
</c:unit>

Xpl 在服务端渲染时直接输出 XNode 树,不会产生无效的 XML 字符串。这意味着它可以安全地与 x-extends 合并引擎配合——合并引擎在结构树层面操作,不需要解析字符串。

使用场景:

  • 代码生成器的模板文件
  • 报表模板
  • 前端页面描述

XTransform:树结构变换语言

XTransform 是专门为“一棵树变成另一棵树”设计的声明式变换语言。你描述“输出结构”,框架自动推导出从输入到输出的映射关系。

<xt:transform xpl:outputMode="xml">
  <!-- 输入:一个扁平列表 -->
  <xt:source from="/app/entities" />
 
  <!-- 输出:按模块分组后的树 -->
  <modules>
    <c:for var="entity" items="${entities}">
      <c:if test="${entity.module != lastModule}">
        <module name="${entity.module}">
          <entities>
            <entity name="${entity.name}" />
          </entities>
        </module>
      </c:if>
    </c:for>
  </modules>
</xt:transform>

XTransform 是可逆计算中“Generator”的具体实现载体——它定义了如何将一种 DSL 结构变换为另一种 DSL 结构。

使用场景:

  • ORM 模型 → GraphQL Schema
  • 数据模型 → 前端表单描述
  • API 模型 → gRPC Proto 定义

共享基础设施

三个语言共享同一套基础设施:

  • 类型系统:统一的数据类型,与 XDef 类型系统一致
  • 函数库:内置 200+ 标准函数,涵盖字符串、日期、集合、XML 操作
  • 调试器:nop-idea-plugin 支持断点调试所有 XLang 语言
  • IDE 支持:语法高亮、代码补全、文件跳转

与通用语言的对比

对比维度 Java/Python XLang
操作对象 内存对象 结构树(XNode)
解析序列化 每次都要 不需要
类型系统 静态/动态 面向 DSL 的类型
IDE 支持 成熟 基于 XDef 自动生成
适用范围 通用 DSL 变换

XLang 的设计哲学是:在 DSL 的结构层次上思考,而不是在通用语言的抽象层次上思考。这正是面向语言编程(LOP)在工具层面的体现。

进一步阅读

zh/nop/reversible_computing_implementation/xlang_intro.txt · 最后更改: 由 127.0.0.1