zh CN 自定义语法 - chiba233/yumeDSL GitHub Wiki
默认语法是 $$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
纯浅合并,什么都要自己管
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>>"(你说了算)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还是)$$但标签以新前缀开头。
这是解析器的硬性约束,违反了标签会失效:
核心规则:endTag、rawOpen、blockOpen 必须以 tagClose 开头。
为什么?解析器在参数区域里平衡 tagOpen/tagClose 的嵌套之后,停在 tagClose 位置,然后向前看确定标签形式。如果复合 token
不以 tagClose 开头,就永远匹配不上。
| Token | 约束 |
|---|---|
endTag |
必须以 tagClose 开头 |
rawOpen |
必须以 tagClose 开头 |
blockOpen |
必须以 tagClose 开头 |
tagOpen/tagClose
|
必须成对 |
| 其他 | 独立,随便改 |
用 createEasySyntax 就不用操心这些——它自动保证约束。closeMiddle 只影响 easy 派生,不改变这些依赖关系本身。
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 === "\\"