分享 做了个玩具, 用 Cirru Sepal 来裸写 Ruby AST

jiyinyiyong · 2015年04月24日 · 2279 次阅读

用我的 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

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号