zh CN 自定义语法 - chiba233/yumeDSL GitHub Wiki

自定义语法

API 参考 | 自定义标签名字符

默认语法是 $$tag(content)$$。想换成 @@tag(content)@@<<tag[content]>>?改 syntax 选项就行。


语法符号全景

Inline:   $$tag(content)$$
          ↑↑   ↑       ↑↑
      tagPrefix tagOpen endTag

          $$tag(arg | content)$$
                    ↑
               tagDivider

Raw:      $$tag(arg)%
                   ↑   raw 内容(不解析)
              rawOpen
          %end$$
          ↑
          rawClose

Block:    $$tag(arg)*
                   ↑   block 内容(递归解析)
             blockOpen
          *end$$
          ↑
          blockClose

转义:      \)  \\  \|
          ↑
          escapeChar

两种改法

想改语法?
    │
    ├─ 大多数情况 → createEasySyntax(推荐)
    │              改基础 token,复合 token 自动跟着变
    │
    └─ 完全手控 → createSyntax
                  纯浅合并,什么都要自己管

createEasySyntax(推荐)

function createEasySyntax(
  overrides?: Partial<SyntaxInput> & { closeMiddle?: string }
): SyntaxConfig

你只需要改 easy 层的基础输入,复合 token 会自动派生:

基础 token 默认值 你能改的
tagPrefix $$ 标签前缀
tagOpen ( 参数开头
tagClose ) 参数结尾
tagDivider | 管道分隔符
escapeChar \ 转义字符
closeMiddle end rawClose / blockClose 中间共享字面

escapeChar 易混淆点: 默认值在 JavaScript 源码里写作 "\\"——但它实际上是单个 \ 字符。 字符串的长度决定了用户在 DSL 文本里要打几个字符才能触发转义。 escapeChar: "\\" → 用户输入 \| 得到字面 |(一个按键)。 escapeChar: "~~" → 用户输入 ~~| 得到字面 |(两个按键)。 如果设置了多字符转义前缀,用户每次转义都要打完整序列。

复合 token 自动派生规则 默认结果
endTag tagClose + tagPrefix )$$
rawOpen tagClose + % )%
blockOpen tagClose + * )*
rawClose % + end + tagPrefix %end$$
blockClose * + end + tagPrefix *end$$

示例

改前缀——复合 token 跟着变:

createEasySyntax({tagPrefix: "@@"});
// endTag → ")@@"    rawClose → "%end@@"    blockClose → "*end@@"

改前缀 + 闭合符:

createEasySyntax({tagPrefix: "@@", tagClose: "]"});
// endTag → "]@@"    rawOpen → "]%"    blockOpen → "]*"

改共享闭合字面:

createEasySyntax({tagPrefix: "@@", closeMiddle: "fin"});
// rawClose → "%fin@@"    blockClose → "*fin@@"

只改分隔符:

createEasySyntax({tagDivider: ";"});
// $$tag(arg1;arg2)$$

显式覆盖优先于派生:

createEasySyntax({
    tagPrefix: "@@",
    rawClose: "<<ENDRAW>>",  // 显式覆盖,跳过派生
});
// endTag → ")@@"(派生)  rawClose → "<<ENDRAW>>"(你说了算)

createSyntax(底层)

function createSyntax(overrides?: Partial<SyntaxInput>): SyntaxConfig

DEFAULT_SYNTAX 的简单浅合并。不自动派生,不验证。 适合完全不规则的协议。

const syntax = createSyntax({
    tagPrefix: "<<",
    tagOpen: "[",
    tagClose: "]",
    tagDivider: ";",
    endTag: "]>>",
    rawOpen: "]#",
    blockOpen: "]*",
    rawClose: "#end>>",
    blockClose: "*end>>",
    escapeChar: "~",
});
// <<bold[hello]>>   <<code[ts]#\nconst x = 1;\n#end>>

注意: 如果你只改了 tagPrefix 但没改 endTag,inline 标签会关不上——endTag 还是 )$$ 但标签以新前缀开头。


Token 依赖关系

这是解析器的硬性约束,违反了标签会失效:

核心规则:endTagrawOpenblockOpen 必须以 tagClose 开头。

为什么?解析器在参数区域里平衡 tagOpen/tagClose 的嵌套之后,停在 tagClose 位置,然后向前看确定标签形式。如果复合 token 不以 tagClose 开头,就永远匹配不上。

Token 约束
endTag 必须以 tagClose 开头
rawOpen 必须以 tagClose 开头
blockOpen 必须以 tagClose 开头
tagOpen/tagClose 必须成对
其他 独立,随便改

createEasySyntax 就不用操心这些——它自动保证约束。closeMiddle 只影响 easy 派生,不改变这些依赖关系本身。


DEFAULT_SYNTAX 速查

DEFAULT_SYNTAX.tagPrefix === "$$"
DEFAULT_SYNTAX.tagOpen === "("
DEFAULT_SYNTAX.tagClose === ")"
DEFAULT_SYNTAX.tagDivider === "|"
DEFAULT_SYNTAX.endTag === ")$$"
DEFAULT_SYNTAX.rawOpen === ")%"
DEFAULT_SYNTAX.blockOpen === ")*"
DEFAULT_SYNTAX.rawClose === "%end$$"
DEFAULT_SYNTAX.blockClose === "*end$$"
DEFAULT_SYNTAX.escapeChar === "\\"
⚠️ **GitHub.com Fallback** ⚠️