Add token-based PEG frontend and CLI source parsing
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 7m30s
Verify databases and deploy Aster VM / verify-and-deploy (push) Successful in 7m30s
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# 源码词法与 PEG 语法前端
|
||||
|
||||
frontend 包提供手写 Rust lexer 和 rust-peg 生成的 token parser。当前入口为 lex、parse、parse_expression,CLI 提供 parse 文件命令;结果是 AST,还没有 AST 到字节码的编译器、类型检查、名称解析或源码执行。Core 不依赖 frontend 或 peg,仍保持零外部依赖。
|
||||
|
||||
首版以 Endorphin-Language 设计稿的基础词法、表达式与函数章节为起点,语法可以继续修改;设计稿中的未完成部分不作为阻塞前端实现的前置条件,也不被整体视作已经实现的语言能力。这里维护当前解析契约;源码位置见 [frontend](../../crates/frontend/README.md)。
|
||||
|
||||
## 入口和所有权
|
||||
|
||||
| API | 输入与结果 |
|
||||
| --- | --- |
|
||||
| lex(&str) | 产生 Vec<Token>;每个 token 只有种类和原始源码的字节范围,不复制文本 |
|
||||
| parse(&str) | 解析一个或多个完整函数定义,返回 Program;空输入和未消费的尾部内容报错 |
|
||||
| parse_expression(&str) | 解析一个完整表达式,不能忽略尾部 token |
|
||||
|
||||
AST 的名称、数字原文和解码后的字符串均由 AST 自己持有,可以在释放输入后继续使用。Token/AST 的 Span 均为原始 UTF-8 源码的半开字节区间 start..end;节点跨度包含首尾 token 之间的空白及注释,不包含外侧 trivia。分组表达式的范围包括括号,Program 范围从第一个函数到最后一个函数。
|
||||
|
||||
语法动作只构造 AST,不做 I/O、VM 分配或其他外部写入。PEG 回溯不会执行语言函数或产生宿主业务副作用。
|
||||
|
||||
## 词法规则
|
||||
|
||||
- 输入是有效 UTF-8 的 &str。CLI 使用严格的 read_to_string 读文件;其他编码由宿主先显式解码,不修改全局 locale。
|
||||
- 名称首字符为下划线或 Rust char::is_alphabetic,后续为下划线或 char::is_alphanumeric。这是当前明确采用的分类,不承诺 XID/NFKC 规则;没有自动规范化。中文、日文可用于名称,emoji 可以用于字符串。
|
||||
- 名称统一产生 Name token。function、let、return 只在相应语法位置按拼写识别,不预先固定全局保留字表;class、agent 等也仍可作为名称。
|
||||
- 数字为 ASCII 十进制数字,可带两边都有数字的小数部分;原文保留,不转换为 f64。负号单独分词;科学计数法、数字后缀、下划线分隔、前导正号、.5 和 1. 形式不在当前表达式语法中。
|
||||
- 双引号字符串允许 Unicode 文本,支持 `\n`、`\t`、`\"`、`\\`。token 范围包含引号,构造 AST 时解码转义。未闭合字符串、未知转义、裸换行和 NUL 报错;没有单引号、多行或插值字符串。
|
||||
- 空格、Tab、LF、CR 和 CRLF 分隔 token;缩进和换行不形成语句或代码块。`//` 到行末为注释,字符串内的 `//` 保持文本。没有块注释。
|
||||
- 支持 `(`、`)`、`{`、`}`、`:`、`,`、`.`、`=`、`+`、`-`、`*`、`/`;不接受分号和其他未支持字符。
|
||||
|
||||
## 当前语法
|
||||
|
||||
```text
|
||||
program = function+
|
||||
function = "function" name "(" parameters? ")" ":" name block
|
||||
parameter = name ":" name
|
||||
block = "{" binding* "return" expression "}"
|
||||
binding = "let" name "=" expression
|
||||
```
|
||||
|
||||
parameters 和调用参数列表使用逗号分隔,不接受尾随逗号。函数体要求一个末尾 return;不支持独立表达式语句、重赋值、嵌套函数声明或默认参数源码写法。参数和返回类型目前只是名称节点;并不据此创建语言 type 对象或检查类型。
|
||||
|
||||
表达式包括名称、数字、字符串、`.name` 符号、括号分组、成员访问与位置参数调用、一元负号以及四则运算。优先级从高到低为:
|
||||
|
||||
1. 成员访问与调用,可任意连续组合,例如 factory(1).build(.title)("日文")。
|
||||
2. 一元负号,可嵌套。
|
||||
3. 乘除,从左到右结合。
|
||||
4. 加减,从左到右结合。
|
||||
|
||||
符号字面量、名称与成员分别保留为独立 AST 结构。true、false、Nil 等词目前只是普通名称,没有额外的源码字面量或内建值绑定。
|
||||
|
||||
use、namespace、class、agent、完整类型语法、条件/循环、比较/布尔运算和闭包声明等尚未加入首版。当前语法可修改;扩展时同步 AST、PEG 规则、样例和测试,不将旧草案视作不可修改的 ABI。
|
||||
|
||||
## 诊断和命令
|
||||
|
||||
词法和语法错误分别标记为 Lexical/Syntax。语法错误将 PEG 的 token 下标转换成原始源码 Span,保留期望项目列表;EOF 错误使用 source.len() 处的空区间。Diagnostic::location 返回一基行列,列按 Unicode 标量计数,CRLF 只算一次换行,不按字节列或字形簇计数。
|
||||
|
||||
`cli parse <file>` 成功时输出 Rust Debug 格式的 AST,失败时在 stderr 输出文件/行/列和诊断并返回非零退出码。AST Debug 文本不是稳定的序列化协议。命令不执行源码、不初始化 VM、不连接数据库;具体运行与本地禁测约定见 [运行](../operations/README.md) 和 [验证](../operations/validation.md)。
|
||||
|
||||
后续编译器应将 AST 经名称/闭包分析转换为现有字节码,不另设 AST 求值器;解析成功不表示表达式已有运行语义。VM 虽已支持 MakeFunction,但从源码创建函数仍需要编译器接入。解析器也不是不可信代码沙箱,当前没有通用输入大小或解析递归深度限额。
|
||||
Reference in New Issue
Block a user