Hanjst 汉吉斯特: 正则驱动容错型拼接式模板引擎

2026新年伊始,由于 UfqiFina 有福金融 ( https://ufqi.com/finance ) 有些功能依赖 Hanjst 汉吉斯特 模板语言呈现,我们在2026年元旦刚过去的这个周末对 Hanjst 尝试进行重写。
在这个尝试重写/重构的过程中,我们使用 OpenAI 的 ChatGPT 进行协助。

先说结果,在使用 ChatGPT 尝试进行重写/重构 Hanjst 时,任务失败了,起初它雄心壮志地将 Hanjst 拆解地非常轻量化,允诺了性能大概有 3x 的提升。
可以随着新代码的实现及落地测试,ChatGPT 在多轮测试仍无法通过的情况下,也是在深入理解了 Hanjst 的深层逻辑之后,它对我提出的是否放弃重写/重构建议,深表赞同,并对 Hanjst 进行了确切地定义:

Hanjst 是“正则驱动 + 容错型拼接引擎”, 而不是 AST ( Abstract Syntax Tree, 抽象语法树 ) / 编译器。

于是,我请 ChatGPT 按照能跑能用/工程级的设计思路,从零重新规划设计 Hanjst 会是怎样的? 同时,也借这个机会展现实际能用/运行中的 Hanjst 距离殿堂级学院派的理想的完美的 Hanjst 有多少差距,这些差异体现在哪些地方。同样地,我们也是先说结论:

如果按 AST / 编译器思路设计,Hanjst 会变成:

  • 一个 “模板语言 → AST → JS 函数” 的编译器,
  • {} 不再靠正则,而是靠词法 + 语法规则

但代价是:实现复杂度 ×5,代码量 ×3,调试成本 ×10

A1. 原版 Hanjst 的本质是:

HTML
 └─ 正则扫描
     └─ 字符串拼接 JS
         └─ new Function()

它的设计哲学是:“能跑就行,JS 自己兜底”, 这在 2015 年左右是完全正确的设计

原版 Hanjst 在重构/重写过程中必然遇到的问题,不可回避且无法妥善解决:

1️⃣ {} 单分隔符是“语法层灾难”

  • HTML / CSS / JS 都天然用 { ,原版靠 “关键词前缀 + 宽松匹配” 苟活。

2️⃣ tpl2js ≠ AST

  • 它是 字符串启发式翻译 ,任何“语义化重构”都会破坏隐含假设。

3️⃣ Hanjst 的稳定性来自:Bug × 时间 × 兼容性,

Hanjst 的能用能跑,依靠的内核不是来自设计。
下面,我们将对 Hanjst 按 抽象语法树 编译器 的标准从零开始进行重构。尽管付出的代价是它将变得体积更大更臃肿结构更复杂运行更慢,但是,新版的 Hanjst 将是 殿堂级学院派的水平!

B2. 抽象语法树 AST 版本的 Hanjst:整体架构图

Template String
   │
   ▼
[ Lexer ]
   │  Token
   ▼
[ Parser ]
   │  AST
   ▼
[ Code Generator ]
   │  JS Source
   ▼
new Function(data) → HTML

1️⃣ Lexer(词法分析器)

目标:把模板拆成最小语义单元,Token 类型(示例)

TEXT            "<div>"
OPEN_TAG        "{"
CLOSE_TAG       "}"
IDENTIFIER      "if"
VARIABLE        "$user"
STRING          "'abc'"
NUMBER          123
OPERATOR        ">", "=="
KEYWORD         if / else / for / foreach / while

2️⃣ Parser(语法分析器)

Parser 不再关心字符串,而是语法结构,AST 节点示例

IfNode {
  test: BinaryExpression,
  consequent: BlockNode,
  alternate: BlockNode
}

{if} 的 AST 表达

{if $user.age > 18}
  adult
{else}
  child
{/if}

➡ AST:

{
  "type": "If",
  "test": {
    "type": "Binary",
    "left": "$user.age",
    "op": ">",
    "right": 18
  },
  "then": [...],
  "else": [...]
}

3️⃣ HTML 是 AST 的一等公民(关键点)

在 AST 模式下:

<span class="{if $x>1}big{else}small{/if}">

会变成:

AttributeNode {
  name: "class",
  value: [
    Text(""),
    IfNode(...),
    Text("")
  ]
}

👉 原版 Hanjst 最高级也是最痛苦的 embedded attribute,在 AST 世界是“天然支持”的

4️⃣ Code Generator(生成 JS)

AST → JS 的核心规则:

AST 节点JS 输出
TextNodeout.push("xxx")
ExprNodeout.push(expr)
IfNodeif(...) { ... }
ForEachNodefor(...) { ... }
Hanjst 抽象语法树 表达式 与 JS对应输出

示例

function render(ctx){
  let out = [];
  if(ctx.user.age > 18){
    out.push("adult");
  } else {
    out.push("child");
  }
  return out.join("");
}

C3. 一句非常重要的工程判断:

Hanjst 能跑到今天,本身就说明它的设计在当年是成功的。

你( 重构/重写者 )现在遇到的“痛苦”,恰恰说明:
你在把一个 “脚本拼接器”,升级成一个 “语言编译器”

👉 这不是重构,这是换物种


Hanjst, Han JavaScript Template Engine 汉吉斯特 模板语言及引擎
https://ufqi.com/dev/hanjst/Hanjst.demo.html

Hanjst 汉吉斯特

此条目发表在-Hanjst/-汉吉斯特, 编程技术, 计算机技术分类目录,贴了, , , , , , , 标签。将固定链接加入收藏夹。

Hanjst 汉吉斯特: 正则驱动容错型拼接式模板引擎》有1条回应

Wadelau进行回复 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

Captcha Code