关于 Cirru Vector 语法以及近期回顾

Cirru Vector 语法

上周给 Cirru 增长了一个简单的向量语法, 基于 EDN 弄的.
以前 Cirru 已经有 .cirru 格式的缩进写法, 可是不合适,
缘由是个人代码广泛用 Cirru Editor 生成的, 结构比较复杂,
而 Cirru 缩进语法经过程序生成的代码, 老是不够可靠,
因而我改用了 JSON 存储, 但 JSON 的问题是查看 git diff 不方便,
因而基于 Clojure EDN 语法定制了一个版本, 用于存储源码:git

repo https://github.com/Cirru/vect...github

大体的样子是这样的, 注意中间故意加上的一些空格:算法

[
[ "a" "b" "c d" ]
[ "e" [ "f" [ "g" ] "h" ] ]
[ "i" ]
]

我实际在使用当中生成的代码会成不少, 好比下面这样,
因为 git diff --word-diff 依据空格来分割, 其实会有点用处:编程

https://github.com/mvc-works/...json

[
[ "ns" "boot-workflow.core" [ ":require" [ "[]" "respo.core" ":refer" [ "[]" "render!" "clear-cache!" ] ] [ "[]" "boot-workflow.component.container" ":refer" [ "[]" "comp-container" ] ] [ "[]" "cljs.reader" ":refer" [ "[]" "read-string" ] ] ] ]
[ "defonce" "store-ref" [ "atom" [ "{}" ] ] ]
[ "defonce" "states-ref" [ "atom" [ "{}" ] ] ]
[ "defn" "dispatch!" [ "op" "op-data" ] ]
[ "defn" "render-app!" [  ] [ "let" [ [ "target" [ ".querySelector" "js/document" "|#app" ] ] ] [ "render!" [ "comp-container" "@store-ref" ] "target" "dispatch!" "states-ref" ] ] ]
[ "defn" "-main" [  ] [ "enable-console-print!" ] [ "render-app!" ] [ "add-watch" "store-ref" ":changes" "render-app!" ] [ "add-watch" "states-ref" ":changes" "render-app!" ] [ "println" "|app started!" ] [ "let" [ [ "configEl" [ ".querySelector" "js/document" "|#config" ] ] [ "config" [ "read-string" [ ".-innerHTML" "configEl" ] ] ] ] [ "if" [ "and" [ "some?" "navigator.serviceWorker" ] [ ":build?" "config" ] ] [ "->" "navigator.serviceWorker" [ ".register" "|./sw.js" ] [ ".then" [ "fn" [ "registration" ] [ "println" "|resigtered:" "registration.scope" ] ] ] [ ".catch" [ "fn" [ "error" ] [ "println" "|failed:" "error" ] ] ] ] ] ] ]
[ "set!" "js/window.onload" "-main" ]
[ "defn" "on-jsload" [  ] [ "clear-cache!" ] [ "render-app!" ] [ "println" "|code updated." ] ]
]

解析过程

固然做为一个图形编辑器生成出来文件, 其实没有多大看的必要.
可能中间惟一有意思的就是解析语法的过程, 稍微有点意思:
https://github.com/Cirru/vect...
这段代码大体用了我以前学习 Parser Combinator 的套路,
也就是用高阶函数不可变数据作的一个 parser, 能够解析简单的文本.后端

好比怎样解析一个字符串, 能够看到我第一步判断引号,
第二步判断内部的内容, 第三步判断结尾的引号, 完成一个字符串,
若是解析成功, 将返回一个 ok: yes 的对象, rest 字段是剩下的文本,
若是解析失败, 将返回一个 ok: no 的对象, rest 字段是原先的文本不变,
data 字段这存放和解析到的内容有关的信息:mvc

parseString = (text) ->
  quote1 = parseDoubleQuote text
  if quote1.ok
    inside = parseStringInside quote1.rest
    if inside.ok
      quote2 = parseDoubleQuote inside.rest
      if quote2.ok
        ok: yes, data: inside.data, rest: quote2.rest
      else ok: no, data: 'no close quote', rest: text
    else ok: no, data: 'failed to parse string inside', rest: text
  else ok: no, data: 'no open quote', rest: text

而字符串内容, 一样进行分解, 多是普通的字符, 多是转义字符,
注意 data 字段有时候须要对内容作一些拼接, 以便最后返回:app

parseStringInside = (text) ->
  tryChar = parseCharInString text
  if tryChar.ok
    tryInside = parseStringInside tryChar.rest
    if tryInside.ok
      ok: yes, data: "#{tryChar.data}#{tryInside.data}", rest: tryInside.rest
    else ok: yes, data: tryChar.data, rest: tryChar.rest
  else
    tryEscape = parseEscape text
    if tryEscape.ok
      tryInside = parseStringInside tryEscape.rest
      if tryInside.ok
        ok: yes, data: "#{tryEscape.data}#{tryInside.data}", rest: tryInside.rest
      else ok: yes, data: tryEscape.data, rest: tryEscape.rest
    else ok: yes, data: '', rest: text

我以前学的版本里, 高阶函数还能作 or 或者 sequence 这样的抽象,
用了高阶的抽象, 代码还能够更精简, 肯定是查找 bug 会困难很多,
大致上我语法解析还不够深刻, 这个 case 足够简单, 因此意外地很快搞定了.
这个例子大概对于新手来讲比较直观, 做为参考应该能够吧,,
深层的 Parser Combinator 仍是须要找更深刻的资料去学习.编程语言

Cirru 发展回顾

Cirru Editor 在微博贴了不少图, 细节不重复了, 已经用了而三个多月,
然后端存储的语法支持了 .cirru .json .edn 三种格式,
其中 .edn 会触发 boot-reload 的 bug, 我通常用 .ir 后缀,
另外 .cirru 在处理 cond 那样复杂的表达式, 生成的代码有 bug, 不建议用.
未来 Cirru 主要会是以图形编辑器的形式存在.
考虑到这个节点已经稳定, 能够思考一下所处的发展方向.编辑器

固然 Cirru Editor 自己若是有更多人用, 其实应该增长一些高级功能,
好比基于树的 token 替换, 好比编辑颜色的控件, 好比自动 watch 文件夹,
文本编辑器发展了不少年, 有至关多实用的技巧, 有时间能够跟进,
不过考虑如今的状况, 我大概要放弃 React 转而 Respo 重写一遍,
其中的反作用好比光标跳动其实很差处理, 还得想一想办法.

另外一个是 Clouditor 展开的方向, 就是在 Cirru 基础上, 把文件也抽象掉,
那样话其实能获得一个更有意思的开发环境, 减小依赖管理的成本,
不过以前也想了, 干掉文件的话, 跟编程语言自己就很差交互了,
好比我还要编译到 Clojure 的话, 那么改写语法树是少不了的,
并且为了过程更容易排查错误, 我还得加入强大的静态分析,
我还真没有能力把那么牛逼的东西作出来... 好多细节还得想一想.

Cirru 的一个目标是抹掉平常开发中的某些语法痛点,另一个目标确实有装逼的成分, 否则写代码也太无趣了.有机会的话我也许应该在 Quamolit 上实现一套 Cirru Editor,那样就不是 DOM layout 而是自动写算法来布局了...想一想都以为很装逼. 我以为张泉灵说得有道理, 泡沫有其存在的价值,轻微的泡沫能够帮助增加, 随后须要将泡沫夯实,而后在可靠的基础之上继续泡沫跟夯实, 从而加快进度. 值得试一试.

相关文章
相关标签/搜索