目录
在众多的编程语言中,爷爷辈的Lisp语言一直是一个独特的存在,这种独特性有人把它总结为"Lisp是可编程的编程语言" 。这指的是Lisp具有强大的元编程能力,可以由程序员自主创造新的语法抽象。 编程通俗的说就是写代码, 而所谓的元编程指的是写生成代码的代码。 Lisp通过宏提供了元编程的能力,而Lisp宏本质上就是一种内嵌在语言中的代码生成器。除了Lisp语言之外,Scala和Rust这些比较现代的程序语言也提供了所谓的宏的设计,但是宏一般被看作是非常复杂的底层技术,很少进入普通程序员的工具箱。
Nop平台的XLang语言是实现可逆计算原理的核心技术之一,为了落实可逆计算理论所提出的 App = Biz x-extends Generator<DSL>
这样一种面向DSL和差量编程的新的编程范式, XLang定义了一整套系统化的、覆盖应用系统开发方方面面的Generator方案。Lisp的宏仅仅是提供了生成Lisp AST的元编程机制,而XLang除了引入宏函数用于生成XLang AST之外,还提供了面向代码生成的Xpl模板语法, 生成的范围从局部的函数实现体,到单个模型文件,再到整个模块目录。特别是Nop平台中定义的所有DSL语言都内置了x:gen-extends
这样的差量生成机制,可以在模型解析、加载的过程中动态生成模型差量再自动实现差量合并, 从而创造了一种新的软件结构复用手段,解决了很多在传统编程范式下难以处理的技术问题。在本文中,我将简单介绍一下Nop平台中所内置的这些元编程机制。
宏函数
XLang语言中也定义了类似Lisp宏的宏函数。所谓宏函数是在编译期执行,自动生成Expression抽象语法树节点的函数。
宏函数具有特殊的参数要求,并且需要增加@Macro
注解。具体示例可以参见GlobalFunctions。
EvalGlobalRegistry.instance().registerStaticFunctions(GlobalFunctions.class) 会将类中的所有静态函数注册为XScript脚本语言中可用的全局函数
@Macro
public static Expression xpl(@Name("scope") IXLangCompileScope scope, @Name("expr") CallExpression expr) {
return TemplateMacroImpls.xpl(scope, expr);
}
宏函数的第一个参数必须是IXLangCompileScope类型,第二个参数必须是CallExpression类型,返回值必须是Expression类型。
编译宏函数的时候,会把函数调用所对应的AST作为CallExpression传入。例如
let result = xpl `<c:if test="${x}">aaa</c:if>`
编译xpl宏函数的时候CallExpression的第一个参数是TemplateStringLiteral,也就是上面调用中的XML文本 <c:if test="${x}">aaa</c:if>
。 在宏函数中我们可以自行解析这个XML文本,然后构造出新的Expression对象返回。
利用宏函数机制,结合XScript语言中的TemplateStringLiteral,我们可以很容易的将不同语法格式的DSL嵌入到XScript语言中。例如,* *提供类似C# LinQ的SQL查询语法**。
let result = linq `select ff from myObject o where o.value > 3`
目前在Nop平台中,内置了如下宏函数
函数名 | 说明 |
---|---|
xml | 解析XML文本得到XNode节点,并包装为LiteralExpression |
xpl | 解析Xpl模板文本得到Expression |
sql | 解析Xpl模板文本得到生成SQL语句的Expression |
jpath | 解析json path得到JPath对象,并包装为LiteralExpression |
xpath | 解析 XSelector文本得到XSeletor对象,并包装为LiteralExpression |
selection | 解析类似GraphQL Query的对象属性选择文本得到 FieldSelection对象,并包装为LiteralExpression |
order_by | 解析 order by语句片段,得到List对象,并包装为LiteralExpression |
location | 返回调用函数所在的源码位置,并包装为LiteralExpress |