元计算是我设计的太极语言中一个重要的特征。这里元计算指的是在编译时间运行从源语言代码编译后获得的目标语言代码。受到C语言中的预处理指令前缀#(#define, #if-#else等)的启发,我选用#开头的一组符号作为各种元运算的算符。比如##expression 是编译时间运行expression, # if ..., # let ..., # while ..., # try ... 等将先对后续代码进行某种类似lisp的宏转换,然后在编译时间进行计算,通过这种转换,# if 会有C语言下的条件编译的效果,# let 等等也都具有各自的功能,因此某种程度上#是C语言的预处理指令通用化以后的一个算符,如果#后面不是这些特殊语句,而是一个普通的表达式,那么其效果与##相同。元算符#.的作用是让#.expression同时在编译时间和运行时间有效。
元计算可以有很大的威力,可以想象到很多应用的可能。以下例子,只是很多用途中的一种。
在下面的例子中,text是解析器正在解析的整个文本,cursor是当前全局解析位置,parserLineno和parserRow分别是全局行号和列号。
考虑到处理换行符号,匹配任意文字的解析函数可以这样写
literal = (string) ->
start = cursor; lineno = parserLineno; row = parserRow
for c in string
if c==text[cur++]
if c=='
' then parserLineno++; parserRow = 0
else if c=='
' then parserRow = 0; continue
else parserRow++
else cursor = start; parserLineno = lineno; parserRow = row; return
true
但是在实际应用中,绝大多数情况下我们都不需要考虑换行符号,因此使用如下的函数就可以了。
literal2 = (string) ->
start = cursor; row = parserRow
for c in string
if c==text[cursor++] then parserRow++
else cursor = start; parserRow = row; return
true
或者更快捷的实现
literal2 = (string) -> if text[cursor...cursor+length]==string then cursor += length; parserRow += length-1; true
下面是解析while语句的函数,作为例子,做了一些简化:
whileStatement = >
if literl('while') and (test = parser.clause())? and literal('then') and (body=parser.block() or parser.line())
return ['while', test, body]
出于速度的原因,我们应该将上面whileStatement实现代码中的literal替换成literal2。
对于这样一个功能简单的小问题引入两个函数,无疑会增加API的数量,从文档提供和库用户的学习使用的角度来讲都是一种负担。另外仔细分析,上面的通用文字处理函数literal还有优化的空间,由此引出了下面第二种方案。
第二种方案
literal = (string) ->
i = 0; lineNumber = 0; length = string.length
while c = string[i++]
if c=='
' then lineNumber++; row = 0
else if c=='
' then _r = true; continue
else row++
if lineNumber==0
if _r then -> if text[cursor...cursor+length]==string then cursor += length; parserRow += length-1; true
else -> if text[cursor...cursor+length]==string then cursor += length; parserRow += length; true
else -> if text[cursor...cursor+length]==string then cursor += length; parserLineno += lineNumber; parserRow += row; true
在此实现下,whileStatement的代码如下:
whileStatement = >
if literal('while')() and (test = parser.clause())? and literal('then')() and (body=parser.block() or parser.line())
return ['while', test, body]
然而,这样写并不能提升速度,反而会有性能损失,因为每次都必须要计算函数闭包。为了达到性能提升的目的,我们应该把对于的闭包计算提到函数之外:
因此应该这样写
while_ = literal('while'); then_ = literal('then')
whileStatement = >
if while_() and (test = parser.clause())? and then_() and (body=parser.block() or parser.line())
return ['while', test, body]
元计算派上用场:
这种情况正好是我设计的新语言的元计算能力的用武之地。
whileStatement = >
if #(literal('while'))() and (test = parser.clause())? and #(literal('then'))() and (body=parser.block() or parser.line())
return ['while', test, body]
元计算让我们鱼和熊掌兼得:同时拥有运行效率和编程效率。