用我的 Toy Language 裸写 AST 感觉挺好玩的.. 编程语言到底写的还是 AST, 只是 AST 通常太难看了,Cirru 还算好...
之前已经实现 ES6 的版本,CirruScript 用来生成 JavaScript https://github.com/Cirru/cirru-script 看到 Julia 可以编译 LLVM 就弄了个 Julia AST 的版本,原型而已.. https://github.com/Cirru/CirruSepal.jl
这周看到有文章描述了 Ruby 可以元编程可以 eval
..
https://www.igvita.com/2008/12/11/ruby-ast-for-fun-and-profit/
用到了 ruby2ruby
生成 AST, 用 ruby_parser
来查看 AST
那我想,用 Cirru 语法照着生成 Ruby 代码没啥问题了
然后就先把 CoffeeScript 写的 parser 直接转成 Ruby:
https://github.com/Cirru/parser.rb
然后改了先逻辑,把解析到的 JSON 转换成 ruby2ruby
用的表达式:
https://github.com/Cirru/sepal.rb
cirru-sepal
这个包暴露了基本的接口可以对代码进行编译,
另外提供了命令行,直接把一个 .cirru
的文件转化成 Ruby 执行 (eval
).
注意 :demo
实际上是生成 "demo"
, 算是 Cirru 特征的奇葩写法..(": a"
表示 " a"
)
最终效果是这样一个 demo.cirru
文件,
数字,字符串,nil
三者做了特殊处理。其他的都内容转化为 Symbol:
lasgn a :1
lasgn b 1
call nil p (lvar a)
defn p2 (args x)
call nil p (lvar x)
call nil p2 :demo
call nil p
call (call 1 + 2) + 3
实际上被编译成这样的 Ruby 代码然后 eval
:
a = "1"
b = 1
p(a)
def p2(x)
p(x)
end
p2("demo")
p(((1 + 2) + 3))
对应的 AST:
s(:block, s(:lasgn, :a, s(:str, "1")), s(:lasgn, :b, s(:lit, 1)), s(:call, nil, :p, s(:lvar, :a)), s(:defn, :p2, s(:args, :x), s(:call, nil, :p, s(:lvar, :x))), s(:call, nil, :p2, s(:str, "demo")), s(:call, nil, :p, s(:call, s(:call, s(:lit, 1), :+, s(:lit, 2)), :+, s(:lit, 3))))
没有进一步设计语法糖,命令行工具也没去完善... 感兴趣的同学看着玩一下 :P