Cirru 是一个使用语法树编辑器来编写代码, 以此绕开语法限制的方案.
目前成熟的编辑器方案有 Stack Editor 和 Cumulo Editor,
其中 Cumulo Editor 是我目前开发当中正在持续维护的, 用于开发 ClojureScript.
Cirru Editor 首先会用 Vector 和 String 的递归结构来表示代码.
更进一步, 基于 Clojure 的 Namespace 设计, 对文件的组织方式进行了拆分,
比如下面是 Cirru Editor 存储格式的例子, 每个文件被拆分成 ns
defs
proc
三部分:
{"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/...
总体上使用的格式还是统一的, 依据以下规则:
- 文件结构按照 namespace 划分, 用 Map 存储
- 每个文件当中按照
ns
defs
proc
拆分, 用 Map 存储 -
ns
存储命名空间的定义
-
-
defs
存储变量的定义, 用 Map 存储
-
-
proc
存储脚本代码序列, 大多数为空的 Vector
-
- 代码对应 S-Expression, 语法强行拆减
这个格式是为了编辑器操作的便利而设计, 并不是最终代码,
因而也就需要编译出代码, 从而可以被其他编译器或解释器解析.
Cirru 格式的编译器需要做的事情有:
- 对 namespace 进行转换生成文件
- 单个文件内对
ns
defs
proc
进行组合拼接 - 其中
defs
存在依赖关系, 需要进行简单依赖分析和排序
- 其中
- 解释 S-Expression 生成目标语言源码
Cirru 目前对应的是动态类型的脚本语言, 比如 Clojure.
由于使用了语法树作为存储格式, 一定程度上会给代码分析带来方便,
但也由于动态语言缺少类型提示, 实际上可供分析的信息有限,
从而难以提供模仿 VS Code 提供的代码提示功能和重构功能.
这个格式的好处是整个项目容易被放进 Cirru 的网页编辑器当中.
然后借助 Cirru Editor 的实现, 提供布局管理和实时同步.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。