贺拉
我唱的是Rhea赤裸的金色的Hera. 永生之后是她,在美丽中超越了一切:她是大声的宙斯的姐妹和妻子,是整个奥林波斯高地所祝福的光荣之人,即使像在雷霆中喜悦的宙斯一样荣耀.
——霍梅克·海姆12到赫拉 (转写:Evelyn-White)(希腊史诗C7到公元前4期)
诸释迦之母.
快速启动
npm install @danielx/hera
将“ a” 数与“ b” 数相接的示例语法 然后返回差数.
# parser.hera
Program
A:a B:b ->
return a.length - b.length
A
"a"*
B
"b"*
将解析器导入您的 JS/ TS 文件 :
// index.mjs
import { parse } from "./parser.hera"
console.log(parse("aaaa"), parse("bbb"), parse("aabb")) // 4 -3 0
parse("c") // throws error
在命令行上运行 :
node --import '@danielx/hera/register' index.mjs
您语法中的处理器块也可以被写入 类型脚本 或者说 密码 语法. 在这种情况下,使用适当的装载器:
node --import '@danielx/hera/register/tsc' index.mjs
# or
node --import '@danielx/hera/register/civet' index.mjs
使用 Hera 构建插件来捆绑 :
import esbuild from "esbuild"
import heraPlugin from "@danielx/hera/esbuild"
await esbuild.build({
entryPoints: ['index.mjs'],
bundle: true,
outfile: 'out.js',
plugins: [heraPlugin()],
})
如果您的处理器块使用 TypeScript 或 Civet 语法,
通过 language: "typescript" 或者说 language: "civet" 输入 heraPlugin(...)。 。 。 .
概览
Hera 使用解析表达式语法为程序创建解析器 语言.
赫拉语法以缩入为主,每个规则由一个名字组成, 缩进的选择,名称可以扩展至,以及 用于每个选项的可选再缩进代码块( handler):
RuleName
Choice1
Choice2 ->
...code...
解析大量使用内置正则表达式能力 Java脚本. 终端要么是字面字符串,要么是正则表达式. 规则由其他规则和终端的选择或顺序组成.
文法中列出的第一条规则是起步点. 每一个选项 规则按顺序检查,然后返回第一次匹配.
定义
规则:一种取名出品. 名称由自己用一行未缩入的行来书写,选择(可能的扩展)则用相通的缩入来书写. 例如:
RuleName
Choice1
Choice2
选择按顺序进行尝试,第一个成功者获胜. 注意此属性具有递归性,因此可能涉及回溯. 每种选择都可以是下文定义的任何表达式,同时包括: 可选处理器.
表达式:一个表达式可以是一个序列,选择表达式,或者重复终端,规则名称,或者表达式(重复序列,选择表达式,或者重复). 在混合序列,选择表达式,和重复时,用括号将其分出. 譬如说, Part ( "," Part )* 是一个规则名称的序列和一个终端和一个规则名称的重复,代表一个或多个 Part以逗号分隔.
选择表达式 (单位:千美元)/:一个简短的内置方式来指定两个或多个子选择之间的选择. 譬如说, This / That / Other 匹配 This 或者说 That 或者说 Other,以先成功为准。 这相当于 AnonymousRule 地点
AnonymousRule
This
That
Other
选择表达式返回匹配的( 第1)表达式 .
顺序 (单位:千美元) :一个接一个,由空格分隔.
譬如说, "(" Expr ")" 匹配字符 "(" 接下来是
匹配数 Expr 接下来是字符 ")"。 。 。 .
多个部分的序列返回多个部分的数组.
譬如说, "(" Expr ")" 返回由三个项目组成的数组:
字符串 "(",返回值为 Expr字符串 ")"。 。 。 .
值得注意的是,如果一个表达是仅一个项目的"序列",
它不会被长到1个阵列包裹.
终端字符串 (单位:千美元)"...":
字符串正文(以双引号相绕).
整个字符串必须在准确的位置匹配.
终端字符串匹配时返回匹配的字符串 .
终端正则表达式 (单位:千美元)/.../:
正则表达式,通常被前向鞭打所包围.
由 Just . 或字符类
喜欢 [A-Z][a-z]* 不需要周围的鞭打.
整个正则表达式必须在准确位置匹配
(好像正则表达式开始于 ^
它被应用到弦的其余部分.
终端正则表达式返回
match
数组: 索引上的匹配字符串 [0],然后是任何匹配的组合
指数 [1], (中文(简体) ), [2],, , , , , , , , .
(字符串或 undefined 用于未匹配的可选组.
例如,以下规则通过 $1
然后通过 $1[0]数字 :
Name
/[A-Za-z][A-Za-z0-9]*/ "=" /\d+/ -> $1[0]
作为一种特殊的情况,如果整个表达式是一个正则表达式,
然后返回值是匹配的字符串而不是匹配数组,
和处理器变量取自匹配数组 :
$0 是匹配的字符串(默认返回值),
财务报告和审定财务报表 $1, (中文(简体) ), $2被俘虏的团体 例如:
Name
# Returns matched string:
/([A-Za-z])[A-Za-z0-9]*/
# Returns matched string:
/([A-Za-z])[A-Za-z0-9]*/ -> $0
# Returns matched first letter:
/([A-Za-z])[A-Za-z0-9]*/ -> $1
三斜正则表达式 (单位:千美元)///...///:
白空间不敏感正则表达式,类似于
Civet 格氏语法。 。 。 .
空白空间和 // 身体内部的评论被忽略,如此之大
表达式可以分行:
Identifier
///
[A-Za-z_] // first character
[A-Za-z0-9_]*
///
三斜正则表达式也支持插入. ${expr} 实值
动态: 生成的剖析器重新评价 expr 当规则运行时,重建
页:1 RegExp 当生成源字符串时,并重用缓存
解析器,直到源代码更改.
Close
/// ${closingPattern} ///
使用 ${const expr} 用于插值应被捕获一次的插值.
如果每个插入部分都是 const,生成解析器计算
正则表达式一次再使用和普通正则相同的解析器
表达式。 在混合静态/动力表达式中,复杂 const 表达式
被缓存一次,而仅使用标识符 const 表达式是直接发射的.
Open
/// ${const openingPattern} /// ->
closingPattern = $0 === "(" ? "\\)" : "\\]"
return $0
Close
# Returns matched string:
/// ${closingPattern} ///
取决于分析状态的动态内插需要与 处理器的突变解析器状态。 如果启用结果缓存, 该状态 必须是缓存密钥/状态的一部分,而规则更改它不应是 已缓存 .
重复 (单位:千美元)*, (中文(简体) ), +: ...* 表示零或以上 ..." ,和 ...+ 表示一次或多次重复 Choice。 。 。 .
重复返回匹配的数组 .
特别是,数组的长度正是匹配的数量.
可选 (单位:千美元)?: ...? 表示零或一次扩张 ..." . 如果 ... 匹配时, ...? 直接返回该值。 否则它成功而不消耗输入和返回 undefined不同 * 财务报告和审定财务报表 +, (中文(简体) ), ? 不将其结果包成数组.
寻找上游 (单位:千美元)&, (中文(简体) ), !: &... 财务报告和审定财务报表 !... 分别声称存在或不存在与 ...,不推进位置或消耗任何投入。 譬如说, &/\s/ 就像正则表情 /(?=\s)/。 。 。 .
两者 & 财务报告和审定财务报表 ! 上游回归 true,这样匹配 vs 在标记为可选时无法区分 ? (例如:. (&Pattern)?) (中文(简体) ).
字符串 (单位:千美元)$: $... 匹配 ... 但返回的只是匹配的输入的字符串,而不是匹配过程中的计算返回值(来自处理器和序列和重复的数组).
譬如说, $/\d+/ 返回比对数字的字符串,而不是匹配数组,当表达式不仅仅是一个正则表达式时,该数组是有用的.
返回类型: 选择的返回类型(或更确切地说,其处理者)
可明确使用 ::type 选择之后和之前
处理器( 如果有—— 否则它返回默认值) .
此返回类型在生成 TypeScript 或 Civet 输出时会被释放 .
您也可以写 RuleName ::type 在规则标题上使用该类型作为
默认规则中的每个选项.
处理器:从匹配的选择到语言原始的映射.
处理器附加到规则选择上 -> 选择之后.
最普通的处理器是 JavaScript, TypeScript, 或者 Civet 代码缩进
在选择之下 returns 匹配选择的理想值.
或者,单一表达式可以在与 ->并会隐含 return编.
处理器代码可以指代默认值
(终端字符串的字符串,序列或重复的数组)通过 $0, (中文(简体) ),
如果不提供处理器,选择会得到回报.
这个 n最顶端序列中的 sth 匹配项目可以通过 $n· ;
最高序列中的每个项目也可以通过一个 :name 后缀
(例如, Block:name),然后代码也可以称为 name。 。 。 .
作为一种特殊的情况,如果扩张是单一的正则表达,
$0 指匹配的字符串(而不是匹配数组)和
$n 提及 n(原始内容存档于2018-03-21). th group in the regex.
处理器代码可以返回特殊值 $skip
以显示失败的匹配.
注释 (单位:千美元)#...:
处理器之外,线路从 # (在可能缩进之后)作为评论处理.
内部处理器,使用处理器语言的评论,例如,, // 或者说 /*...*/。 。 。 .
代码块
您可以使用三个回击创建直接插入的代码块 输入编译文件,使用与处理器相同的语言. 这对于创建公用功能或增加出口都是有益的.
```
function toInt(n) {
return parseInt(n)
}
```
Number
[0-9]+ ->
return toInt($0)
演示文稿
如果这些演示不能交互, 请查看此页面 https://danielx.net/hera/docs/README.html (中文(简体) )
URL 解析器 https://tools.itf.org/html/rfc3986 (中文(简体) )
#! hera url
数学实例.
#! hera math
赫拉是自我生成的:
#! hera hera
脚本位置示例
#! hera Grammar Punctuation? A+ Punctuation? -> return [$1, ...$2, $3].filter((token) => token !== undefined) A ("a" / "A") -> return {type: "A", loc: $loc, value: $1} Punctuation "!" / "." / "?" -> return {type: "Punctuation", loc: $loc, value: $1}
Regex 组
#! hera Phone /1-(\d{3})-(\d{3})-(\d{4})/ -> [$1, $2, $3]
#! hera Grammar NamedMapping NamedMapping NamedMapping Punctuation -> ["P", $0] Punctuation "."
实验
编译解析器到 TypeScript .
词汇表
EOS - 发言结束
EOF - 文件/输入结束
V2 构想
从匹配序列的一部分输出字符串的简单方式 。 也许添加 护理/选择前缀操作员.
优化选项、顺序和regexes(合并)的重复 减少调用.
平面图和其他平面图.
为处理者命名参数 .
减少常见子序列的回溯:
RuleBody
Indent Sequence EOS (Indent ^Sequence EOS)+ -> ["/", [2, 4...]]
Indent Sequence EOS -> 2
上述规则应该能够高效(不需要回溯) 因为它有一个共同的子序列 它应该 能够重新使用已经完成的工作.
一种选择是把它变成一条带可选部分的规则,并添加 逻辑进入处理器, 但似乎粗糙.
#! setup require("./interactive")(register)
CJS/ESM装载机
实现直接 import 或者说 require 联 合 国 .hera 文档,
在操作语言中使用适当的加载器:
--import/--require @danielx/hera/register
装入编译到 JavaScript 的.hera 文件 .
--import/--require @danielx/hera/register/tsc
装入编译到 TypeScript 的.hera 文件.
试图装入 typescript npm 模块将生成的 TypeScript 转换为 JavaScript .
--import/--require @danielx/hera/register/civet
装入编译到 Civet 的.hera 文件 .
试图装入 @danielx/civet npm 模块将生成的 Civet 转换为 JavaScript .
指定 Hera 编译器选项
见 loader-examples/hera-custom
用于将选项传递到赫拉编译器的示例.
支持的 Hera 编译器选项在 选项。 。 。 .
无害环境管理
而不是使用 --import @danielx/hera/register,登记 @danielx/hera/register/esm 钩并传递编译器选项.
举个例子.
// loader.js
const heraOptions = { ... }
register("@danielx/hera/register/esm", pathToFileURL(__filename), { data: heraOptions })
node --import ./loader.js my-script.mjs
司法理事会
而不是使用 --require @danielx/hera/register,要求和设置选项 @danielx/hera/register/cjs 模块.
举个例子.
require("@danielx/hera/register/cjs").options.hera = { inlineMap: false }
const { parse } = require("./my-typed-grammar.hera")
见 loader-examples/hera-custom/register.js
例如,同时登记无害环境管理和CJS两种选择.
设置类型脚本或 Civet 编译器选项
见 loader-examples/tsc-custom
或者说 loader-examples/civet-custom
用于将选项传递到 TypeScript 或 Civet 编译器.
无害环境管理
而不是使用 --import @danielx/hera/register/tsc 或者说 --import @danielx/hera/register/civet,登记 register/esm 财务报告和审定财务报表 register/tsc/esm 或者说 register/civet/esm 模块并传递您想要的选项.
(注意您还需要注册基地) register/esm 模块,因为无害环境管理装载器连锁在一起。 )
举个例子.
// custom-loader.js
const { register } = require("node:module")
const { pathToFileURL } = require("node:url")
register("@danielx/hera/register/esm", pathToFileURL(__filename), {
data: heraOptions
})
register("@danielx/hera/register/tsc/esm", pathToFileURL(__filename), {
data: tscCompilerOptions,
})
// OR
register("@danielx/hera/register/civet/esm", pathToFileURL(__filename), {
data: civetCompilerOptions,
})
node --import ./custom-loader.js ./my-script.mjs
司法理事会
而不是使用 --require @danielx/hera/register/tsc 或者说 --require @danielx/hera/register/civet,要求和设置选项 @danielx/hera/register/tsc/cjs 或者说 @danielx/hera/register/civet/cjs 模块.
举个例子.
const loader = require("@danielx/hera/register/tsc/cjs")
loader.options.hera = heraOptions
loader.options.tsc = tscCompilerOptions
const { parse } = require("./typed-grammar.hera")
const loader = require("@danielx/hera/register/civet/cjs")
loader.options.hera = heraOptions
loader.options.civet = civetCompilerOptions
const { parse } = require("./civet-grammar.hera")
见 loader-examples/tsc-custom/register.js
财务报告和审定财务报表 loader-examples/civet-custom/register.js
以实例说明同时登记无害环境管理和CJS的选项.
新建插件
使用 heraPlugin() 要导入 .hera 正在构建的文件.
如果处理器机构或代码块使用 TypeScript 或 Civet, 请设置插件 明确语言:
heraPlugin({ language: "typescript" })
heraPlugin({ language: "civet" })
插件自动选择合适的 esbuild 加载器,
虽然你可以用 loader 选项.
编辑器工具
VS 代码扩展和语言服务器支持 hera.language 用于控制
如何解释处理者的尸体.
在 VS 代码设置中 :
{
"hera.language": "civet"
}
在你的工作空间 package.json数字 :
{
"hera": {
"language": "civet"
}
}
见 lsp/README.md。 。 。 .
API 密码
无害环境管理:
import { compile } from "@danielx/hera"
CJS: 贾克:
const { compile } = require("@danielx/hera")
compile(grammar, options?)
将一个赫拉语法编译为解析源代码.
- 以原始语法源为字符串通过.
- 默认返回代码字符串 .
- 回返
{ code, sourceMap }何时options.sourceMap实值true。 。 。 .
选项
compile() 接受这些选项:
language?: "javascript" | "typescript" | "civet": 处理器体和代码块所使用的语言. 默认 :"javascript"。 。 。 .types?: boolean: 生成 TypeScript-flavored 剖析器输出. 默认 :false何时language未说明或"javascript",以及true何时language实值"typescript"或者说"civet"。 。 。 .module?: boolean: 消除无害环境管理,而不是CJS产出。 默认 :false。 。 。 .filename?: string: 生成源地图中使用的文件名. 默认 :"anonymous"。 。 。 .source?: string:原始语法源文本. 需要时间inlineMap或者说sourceMap已启用.inlineMap?: boolean: 在生成的输出中添加内置源代码注释。 默认 :false。 。 。 .sourceMap?: boolean编号: 返回{ code, sourceMap }而不是代码串。 默认 :false。 。 。 .libPath?: string: 导入生成解析器所使用的 Hera 运行时库的路径 。 默认 :"@danielx/hera/lib"。 。 。 .