Cirru 是一個使用語法樹編輯器來編寫代碼, 以此繞開語法限制的方案.
目前成熟的編輯器方案有 Stack Editor 和 Cumulo Editor,
其中 Cumulo Editor 是我目前開發當中正在持續維護的, 用於開發 ClojureScript.git
Cirru Editor 首先會用 Vector 和 String 的遞歸結構來表示代碼.
更進一步, 基於 Clojure 的 Namespace 設計, 對文件的組織方式進行了拆分,
好比下面是 Cirru Editor 存儲格式的例子, 每一個文件被拆分紅 ns
defs
proc
三部分:github
{"app.comp.container" {:ns ["ns" "app.comp.container" [":require" ["[]" "respo.comp.space" ":refer" ["[]" "=<"]]]], :defs {"comp-container" ["defcomp" "comp-container" ["store"]], "on-click" ["defn" "on-click" ["e" "dispatch!"] ["dispatch!" ":inc" "nil"]]}, :procs []}, "app.main" {:ns ["ns" "app.main" [":require" ["[]" "app.schema" ":as" "schema"]]], :defs {"dispatch!" ["defn" "dispatch!" ["op" "op-data"]], "*store" ["defonce" "*store" ["atom" "schema/store"]], "ssr?" ["def" "ssr?" ["some?" ["js/document.querySelector" "|meta.respo-ssr"]]], "main!" ["defn" "main!" [] ["println" "|App started."]], "mount-target" ["def" "mount-target" [".querySelector" "js/document" "|.app"]]}, :procs [["set!" [".-onload" "js/window"] "main!"]]}, "app.updater.core" {:ns ["ns" "app.updater.core"], :defs {"updater" ["defn" "updater" ["store" "op" "op-data"] ["case" "op" [":inc" ["update" "store" ":data" "inc"]] "store"]]}, :procs []}, "app.schema" {:ns ["ns" "app.schema"], :defs {"store" ["def" "store" ["{}" [":states" ["{}"]] [":data" "0"]]]}, :procs []}}
完整的例子, 好比 Stack Editor 使用的存儲格式, 在 namespace 稍微有區別:
https://github.com/mvc-works/...
而 Cumulo Editor 使用的格式存儲了更多的信息(於是沒有作格式化):
https://github.com/mvc-works/...mvc
整體上使用的格式仍是統一的, 依據如下規則:app
ns
defs
proc
拆分, 用 Map 存儲ns
存儲命名空間的定義defs
存儲變量的定義, 用 Map 存儲proc
存儲腳本代碼序列, 大多數爲空的 Vector這個格式是爲了編輯器操做的便利而設計, 並非最終代碼,
於是也就須要編譯出代碼, 從而能夠被其餘編譯器或解釋器解析.
Cirru 格式的編譯器須要作的事情有:編輯器
ns
defs
proc
進行組合拼接defs
存在依賴關係, 須要進行簡單依賴分析和排序Cirru 目前對應的是動態類型的腳本語言, 好比 Clojure.
因爲使用了語法樹做爲存儲格式, 必定程度上會給代碼分析帶來方便,
但也因爲動態語言缺乏類型提示, 實際上可供分析的信息有限,
從而難以提供模仿 VS Code 提供的代碼提示功能和重構功能.佈局
這個格式的好處是整個項目容易被放進 Cirru 的網頁編輯器當中.
而後藉助 Cirru Editor 的實現, 提供佈局管理和實時同步.ui