關於 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 而是自動寫算法來佈局了...想一想都以爲很裝逼. 我以爲張泉靈說得有道理, 泡沫有其存在的價值,輕微的泡沫能夠幫助增加, 隨後須要將泡沫夯實,而後在可靠的基礎之上繼續泡沫跟夯實, 從而加快進度. 值得試一試.

相關文章
相關標籤/搜索