Hotdry.
compilers

Pharo BPatterns:使用块级联的声明式重写引擎

在 Pharo Smalltalk 中,通过块级联实现 AST 模式匹配、统配与术语重写,提供最小样板的重构与弃用迁移实践。

Pharo Smalltalk 的重写引擎(Rewrite Engine)是强大的 AST 变换工具,由 John Brant 和 Don Roberts 于 1997 年引入,用于 Refactoring Browser。它支持精确的模式匹配与替换,但传统语法依赖字符串如 ``@rcv 或`@arg,难以记忆且不利于 IDE 支持:无代码补全、无重构、无浏览器导航。这导致开发者常需复制示例,增加 boilerplate。

BPatterns 库解决了这些痛点,提供声明式 API:直接用普通 Smalltalk 块(block cascades)描述模式与替换,变量以 any 开头自动作为 wildcard(统配任意子树)。核心消息 #bpattern 将块转为 BPattern,支持 #browseUsers 搜索匹配方法;[[matchBlock -> replaceBlock]] brewrite 创建重写规则,支持 #preview 显示变更、#apply 执行。

例如,替换 isNil ifTrue: 为 ifNil::

[ anyRcv isNil ifTrue: anyBlock ] bpattern browseUsers.
[[ anyRcv isNil ifTrue: anyBlock ] -> [ anyRcv ifNil: anyBlock ]] brewrite preview.

这在 DoIt 中即用,无需特殊工具。BPatterns 底层构建 rewrite engine 的 pattern AST,保留原生威力。

为细化模式,用 #with: 级联配置:

[ anyVar isNil ifTrue: anyBlock ] bpattern
  with: [ anyVar ] -> [:pat | pat beVariable];
  with: [ anyBlock ] -> [:pat | pat beInstVar where: [:var | var name beginsWith: 'temp']].

#with: 参数为块(引用变量)、关联(配置)或符号(选择器)。可用 beInstVar/beLocalVar/beGlobalVar/beUndeclared/beLiteral 等限定变量;beKeyword/beBinary/beUnary 限定消息;where: 添加谓词如 selector beginsWith: 'prim'。

选择器模式天然支持部分匹配:

[ anyRcv anyKeywordPart: anyArg1 staticPart: anyArg2 ]  "匹配 at:xxxPart: 等"
[ any anyMessage: anyArg ] bpattern with: #anyMessage: -> [:pat | pat beBinary].  "任意二元运算"

单目 anyMessage 匹配任意消息链(包括关键字 / 二元)。

字面量与全局:

[ any new: anySize ] bpattern
  with: [ any ] -> [:pat | pat beGlobalVarWithAny: {Array. OrderedCollection}];
  with: [ anySize ] -> [:pat | pat beLiteral].

精确过滤如 beLiteralWithAny: #(nil true false)。

方法级用 #bmethod:

[[ self anyMethod: anyArg ] -> [ anyArg ifNil: [self default]]] bmethod brewrite preview.

匹配整个方法头与体,支持 super anyMessage 等高级场景。

落地参数与清单

  1. 安装(Pharo 13/14):Metacello new baseline: 'BPatterns'; repository: 'github://dionisiydk/BPatterns:main'; load. 测试:运行上述示例,确认 #bpattern 在。
  2. 安全阈值
    • 始终先 #preview,检查变更数 <100,避免大范围。
    • 作用域:#browseUsersInClass: Class / #inPackage: 'MyPkg-*',从小包测试。
    • 备份:重写前 Iceberg commit;回滚用原规则反向 brewrite。
  3. 监控点
    步骤 命令 预期 风险阈值
    搜索 bpattern browseUsers <500 方法 >1000 缩小 with:
    预览 brewrite preview 变更预览无语法错 手动审阅 >10%
    执行 brewrite apply 编译成功率 100% 失败 <5% 逐审
    测试 跑 suite 通过率 >95% 隔离变更测试
  4. 常见规则清单
    • 弃用迁移:[[ self deprecatedSel: arg ] -> [ self newSel: arg ]] brewrite.
    • 风格统一:[[ rcv ifTrue: [blk] ] -> [ rcv then: blk ]] brewrite.(ifTrue: → then:)
    • 性能:[[ Array new: n ] -> [ Array streamContents: [:s \| s nextPutAll: coll]](避免大 new)。
    • 安全:[ any at: idx ] bpattern with: [idx] -> [:pat \| pat bePositiveIntegerLiteral] 查潜在越界。

在弃用场景,BPatterns 简化 Pharo deprecated: transformWith:,如 Object>>confirm: 可直接用块推导 sender 重写,无字符串重复。

此单一技术点使重写从 “魔法字符串” 转为 “声明式块”,最小 boilerplate,提升团队协作。扩展:集成 Calypso/GToolkit 浏览器,或自定义 where: 谓词。

资料来源

(正文 1256 字)

查看归档