You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Cirru 的核心是一个数据结构:
这个结构可以用 JSON 的 String 和 Array 表达出来. 但是这个数据本身用文本展示不大方便.
Cirru 的文本语法, 早期的目标是提供一套精简便于书写和阅读的文本结构, 在树形编辑器不成熟的情况下提供一个实用的方案. 随着树形编辑器成熟, Cirru 的文本语法, 逐渐过渡为 Cirru EDN 数据结构使用的格式, 并且大量通过代码格式化工具 Cirru Writer 生成.
关于 Cirru 文本语法设计, 可以参考 calcit-lang/calcit-runner.nim#123 中的案例.
当前 Cirru 文本语法的解析过程, 可以参照 https://github.com/Cirru/parser.rs/blob/main/src/parser.rs 作为最新的实现方式. 其中包含 3 个处理过程:
LexItem:Open
和LexItem:Close
的组合, 并且使用LexItem:EOF
处理文件结束的特殊情况(后续案例中略过),(
和)
也会转化为LexItem:Open
和LexItem:Close
, 然后以 Lisp 的方式解析,$
用于简化尾部的缩进, 一个是,
用于处理 literals 需要被展开的特殊情况.缩进处理
最简单的情况, 比如两个行
处理之后得到:
这里有一个规则是每一行默认是一个表达式, 因而顶层的符号会被包括
OPEN
和CLOSE
.注意这里的
OPEN
和CLOSE
跟圆括号(
)
的语义是统一的. 例如预处理得到的是:
然后我们开始引入缩进规则, Cirru 使用严格的两个空格作为缩进, 因而奇数空格, 或者 Tab(具体实现可能未抛出错误), 对应的是解析出错.
两格缩进以后, 增加的缩进, 表示缩进的内容为之前的表达式的附属内容, 例如:
预处理之后得到:
而四个空格的缩进, 对应就会得到重复的嵌套层级, 例如
预处理之后得到:
稍复杂的情况其实是这样的, 先出现 4 个空格的缩进, 再出现 2 个空格的缩进, 这样的情况:
预处理得到:
使用 Lisp 的方式展示, 可以表示为:
这种支持其实是有现实意义的, 一个类似 Clojure
let
的语法, 在 Calcit 当中可以写为:对应 Lisp 风格的写法为:
相对应的, 在 Cirru Writer 生成代码的时候, 也存在该场景.
类 Lisp 基础语法解析
特殊符号是
(
)
"
以及各种空格. 即便\
也是允许的. 而"
用于标记字符串, 字符串内特殊.字符串格式,
""
"a"
以及支持用\
完成的一些特殊字符的转义, 目前只支持很少的转义字符,\n
\\
\"
\t
.但注意这里字符串的表示:
预处理其实得到:
这可能会让人很困惑为什么那么古怪的设计. 原因还是前面说的, Cirru 的核心是一个树形编辑器的数据结构,
["a b"]
["ab"]
这个结构当中空格也只是普通的字符串的一部分, 而空格到了文本语法中, 就需要被区分了.
基于 PEG.js的示例:
表达式折叠
$
和展开,
注意这里
$
和,
在解析过程当中不被作为特殊字符, 或者说, 最初解析时可以有这样的结构:首先可以被解析为
类似的,
,
一开始也作为一个普通的符号被解析:得到:
解析完成之后, 会加一个步骤对语法树做两次转换, 一次是识别
$
对当前分组的$
后的节点进行折叠, 这里用 Lisp 风格展示:会被转化为:
主要用于处理 Lisp 语法深度嵌套的情况, 经常最后一个节点是深度嵌套的, 而处在结尾的嵌套表达式, 是可以通过一些手段简化写法的.
另一次是处理
,
. 对应到一些特殊的位置主要展开, 还是以 Lisp 风格的写法演示:会被转换为:
这种设计其实是为了弥补缩进语法导致的一些表达上的不足, 比如基于缩进的写法, 当我们想要表达
(+ (+ 1 2) 3)
的结构时,会得到
(+ (+ 1 2) (3))
的结果, 而出现(3)
被强制作为函数被调用的情况. 但实际上我们需要的是:其中
(, 3)
会被展开成为父节点当中的3
从而满足需求.演示
可以从已有的例子作对照 https://repo.cirru.org/parser.coffee/
Beta Was this translation helpful? Give feedback.
All reactions