如何自己设计一个DSL

📅 2026/8/3 19:05:16
如何自己设计一个DSL
设计DSL并没有想象中那么高深它分为三个层级难度从易到难。从最简单的开始逐步深入到原理层。第一层用通用语言“伪装”DSL内部DSL这是最简单、最安全的方式不需要自己写解析器直接利用现有语言的特性。方法使用方法链Fluent API或Builder模式让代码读起来像英语句子。Java示例模拟一个条件查询ListUser result Query.select(name, age) .from(users) .where(age).greaterThan(18) .and(city).equals(Beijing) .execute();虽然它是Java代码但读起来已经像一门专门查数据的DSL了。这招在构建测试框架如Mockito和配置工具时极其常用。优点不用学新语法IDE自动补全安全可靠。缺点受限于宿主语言的语法规则比如括号、分号去不掉无法做到极致的简洁。第二层解析结构化配置外部DSL的轻量版如果你希望DSL不是代码而是存成纯文本的配置文件比如.txt或.yaml方便非开发人员修改那就需要写一个解释器Interpreter。场景设计一个“简单规则引擎”比如电商促销规则IF 订单金额 500 THEN 打9折。做法不用复杂工具直接用字符串匹配或词法分析库如ANTLR。极简手写示例Pythonrule price 100 AND brand Apple # 你写代码把这条字符串拆成 # {left: price, op: , right: 100, logic: AND, ...} # 然后判断当前商品是否满足条件。这就是DSL解析的最朴素形态。进阶工具当规则变复杂时建议用ANTLRJava、Peg.jsJavaScript或ParsecHaskell这类解析器生成器你只需定义语法规则类似正则的增强版它们能自动生成解析代码。第三层完整的外部DSL设计一门“小语言”这是最高阶玩法你需要定义完整的语法Syntax和语义Semantics甚至自己写词法分析器Lexer和语法分析器Parser。经典案例Elasticsearch的查询DSL基于JSON和PromQLPrometheus的监控查询语言。核心流程这就是编译原理的简化版词法分析把(age 18)拆成一堆Token左括号、标识符age、操作符、数字18、右括号。语法分析根据你定义的语法规则比如比较表达式 - 标识符 操作符 数字把这堆Token组装成一棵树——抽象语法树ASTAbstract Syntax Tree。执行/编译遍历这棵树执行具体的逻辑比如调用数据库查询。这里的核心产出就是AST。你看下面这段DSLfilter: { range: { age: { gte: 18 } } }解析后生成的AST大致是有了这棵树计算机就知道“需要比较年龄字段条件是大于等于18”。进阶实战在Spring Boot里实现一个极简DSL思路假设你要实现一个权限校验DSLPermission(user:delete OR admin:all)。定义语法支持AND、OR、括号。写解析器用Java的Pattern先分词再通过递归下降解析一种手写解析方式构建AST。执行校验当前用户权限列表是否满足这棵树的逻辑。你会发现整个过程中最难的不是执行而是“优雅地处理语法错误”比如少个括号时给出友好的报错这是工业级DSL最考验功底的地方。给你一个“该不该造DSL”的判断标准虽然造DSL很酷但别为了炫技而造。记住这条铁律如果某类配置或规则需要非程序员如运营、测试、运维频繁修改且修改频率远高于代码发布频率那么DSL就是最佳方案。否则直接用代码写死或使用现有工具即可。