文章內容所描述的方案, 已經實現了一個原型, 有時間我繼續改進
https://github.com/Cirru/CirruSepal.jlgit
昨天晚上不知怎麼想起來 Julia, 翻了翻文檔, 又有發現,
就是 Julia 有出色的元編程能力, 能夠在執行過程當中拼接 AST 而後執行
http://julia.readthedocs.org/en/latest/manual/metaprogramming/
好比說文檔裏給出了這樣一些例子:github
textjulia> ex2 = Expr(:call, :+, 1, 1) :(1 + 1)
大體梳理一下, 我如今瞭解到的就是幾個方面,編程
Symbol 是和 String 不同的數據類型, 二者共同點是數據不可修改
二者差異須要看網上的說明, 可是 Symbol 是能夠用於生成 AST 的:
http://stackoverflow.com/questions/23480722/what-is-a-symbol-in-julia/...
或者說 Symbol 能夠用於表示程序自身, 好比說這樣的代碼:數組
textjulia> a = 1 1 julia> eval(a) 1 julia> eval(:a) 1
Quote 能夠獲得表達式的 expr
對象, 對應表達式的 AST.
這些跟 Lisp 當中的 Quote 跟 Symbol 大概很是類似吧
只不過在 Julia 同時又有語法糖, 因此看起來怪怪的函數
textjulia> a = Expr(:call, :+, 1, 2) :(1 + 2) julia> b = :(1 + 2) :(1 + 2) julia> a == b true julia> eval(a) 3 julia> eval(b) 3
parse
函數parse
能夠將一段字符串解析成 AST, 或者也能看出了就是 Quote:性能
textjulia> a = :(1 + 2) :(1 + 2) julia> c = parse("1 + 2") :(1 + 2) julia> a == c true
而後能夠打印具體的結構, 用文檔例子裏的 dump
函數:優化
julia> dump(c) Expr head: Symbol call args: Array(Any,(3,)) 1: Symbol + 2: Int64 1 3: Int64 2 typ: Any
以及經過 eval
能夠將上邊獲得的 AST 執行:
http://julia.readthedocs.org/en/latest/stdlib/base/#Base.evalui
julia> eval(c) 3
把上述幾個流程連接到一塊兒, 就也辦法在 Julia 當中本身生成 AST 去執行code
先查看正常的代碼如何編寫, 瞭解 AST 的結構:orm
julia> a = parse("1 + 2") :(1 + 2) julia> b = dump(a) Expr head: Symbol call args: Array(Any,(3,)) 1: Symbol + 2: Int64 1 3: Int64 2 typ: Any
而後用 Expr
本身構造一份 AST, 執行一下:
julia> c = Expr(:call, :+, 1, 2) :(1 + 2) julia> d = eval(c) 3
並且能夠下有個 Julia 自身實現的 parser, 其中有很多 AST 的例子
https://github.com/jakebolewski/JuliaParser.jl/blob/master/src/parser....
另外按照元編程文檔開頭講的, Julia 的 AST 跟 Lisp 很像, 都是表達式:
Like Lisp, Julia represents its own code as a data structure of the language itself. Since code is represented by objects that can be created and manipulated from within the language, it is possible for a program to transform and generate its own code. This allows sophisticated code generation without extra build steps, and also allows true Lisp-style macros operating at the level of abstract syntax trees.
就是說不像是 JavaScript AST 存在 Statement 那樣奇葩的結構,
而是在一層包裹下, 一切都是表達式, 可以實現自由組合, 看看分號分隔的語句:
julia> a = parse("1 + 2; 2 + 3") :($(Expr(:toplevel, :(1 + 2), :(2 + 3)))) julia> dump(a) Expr head: Symbol toplevel args: Array(Any,(2,)) 1: Expr head: Symbol call args: Array(Any,(3,)) 1: Symbol + 2: Int64 1 3: Int64 2 typ: Any 2: Expr head: Symbol call args: Array(Any,(3,)) 1: Symbol + 2: Int64 2 3: Int64 3 typ: Any typ: Any
整體上是一個嵌套表達式的結構, 也就是 Cirru 所模仿的 Lisp 的形態
所以 Cirru 的語法是個 Julia 的 AST 結構對應的,
就有可能達到編寫 Cirru 腳本, 直接替換爲 Julia AST 執行
前面已經說過, Julia 能夠在運行過程當中生成 LLVM IR 的
就是說實現的話, Cirru 的解釋器就算跑在 LLVM IR 上邊了
不知道性能如何, 可是有 Julia 作中間層優化, 效果呢應該不會太差
以前 Sepal 項目直接放棄了, 這個地方卻是有一線但願
另外一個之後須要考慮的是多個文件組成模塊系統的問題,
如今能夠先不考慮的吧..
Cirru 在 JavaScript 當中是先轉化成 JSON 對象, 而後操做的
Julia 固然少不了操做 JSON 的庫, 我最初的思路是從 JSON 開始
https://github.com/JuliaLang/JSON.jl
不過這地方有棘手的問題, Cirru 的 JSON 結構是嵌套的數組,
而 Jualia 當中, 分紅了不一樣的 Array 跟 Tuple 兩種結構,
http://en.wikibooks.org/wiki/Introducing_Julia/Arrays_and_tuples
Array 限定了元素類型一致, 能夠不斷增加, 而 Tuple 容許多種類型, 但不能增加
這個相似 Haskell, Haskell 的 Cirru Parser 用代數類型系統解決了,
由於就是說 Haskell 定義類型系統支持遞歸, 就能表示 Cirru 的樹
可是 Julia 我彷佛沒找到遞歸類型.. 那麼 JSON 還能用麼?
極端畢竟注重性能的語言, 很難像 JavaScript 跟 Haskell 這麼瀟灑...
另外我也嘗試考慮直接解析 Cirru 代碼生成 Quote 的可能,
目前 Cirru 解析分紅兩步,
$
和 ,
造成的轉換$
和 ,
對樹進行 desuger 的轉換原來 parser 的實現極大地藉助了 JSON 自由的結構,
這裏直接生成 Quote 彷佛也是不可行的, 中間過程仍是受到 Array 和 Tuple 限制.
其餘的考慮, 還有其餘一些 Lisp LLVM 實現, 我在 Google 隨手找到的:
https://github.com/drmeister/clasp
https://github.com/artagnon/rhine-ml
https://github.com/mylesmegyesi/lisp-compiler-llvm
https://github.com/eudoxia0/corvus
通常 Lisp 會有直接操做 AST 的功能, 也就是 Quote
至少從原理上, Cirru 轉化成 Quote, 而後 eval
, 這是行得通的
但考慮到我對 Lisp 自己不夠深刻, 短期是無法看了
不過, 從成熟度上, 我想要 Cirru 生成 LLVM IR 玩, 仍是 Julia 吧..
總之就是還沒找到具體實現的辦法.
看了份中文的筆記, 發現能夠定義任意類型的數組... 得研究下
http://www.justinablog.com/archives/1604
julia> {"1", {"2", "3", {"4"}}} 2-element Array{Any,1}: "1" {"2","3",{"4"}}