267 lines
16 KiB
Plaintext
267 lines
16 KiB
Plaintext
// parser.rs 编译时引入,生成 syntax 的 Token 解析规则;source 是这些 Token 对应的原始 UTF-8 文本。
|
||
// 规则只构造拥有文本及原文跨度的 AST,不解析名称/类型,也不执行函数或操作 VM。
|
||
peg::parser! {
|
||
// parse/parse_expression/parse_ast 的交互分支调用相应公开根,默认要求完整消费 Token 输入。
|
||
grammar syntax(source: &str) for [Token] {
|
||
// 各语法上下文按原文精确匹配 Name;词法器不把这些词全局保留为独立关键字种类。
|
||
rule keyword(word: &str) -> Span
|
||
= [Token { kind: TokenKind::Name, span } if &source[span.start..span.end] == word] { span }
|
||
|
||
// function 规则的开头;quiet 隐藏内部 Token 细节,失败期望显示可读的 function。
|
||
rule function_keyword() -> Span
|
||
= quiet!{keyword("function")} / expected!("'function'")
|
||
// binding 的开头,同样提供稳定可读的期望项。
|
||
rule let_keyword() -> Span
|
||
= quiet!{keyword("let")} / expected!("'let'")
|
||
// return_statement 的开头及 local_statement 的负向前瞻,避免 return 被普通表达式语句消费。
|
||
rule return_keyword() -> Span
|
||
= quiet!{keyword("return")} / expected!("'return'")
|
||
|
||
// 声明、类型名及表达式引用共用;从 Token 范围复制名称文本,AST 不借用原源码缓冲。
|
||
rule name() -> Name
|
||
= span:quiet!{[Token { kind: TokenKind::Name, span }] { span }} {
|
||
Name { text: source[span.start..span.end].into(), span }
|
||
}
|
||
/ expected!("identifier")
|
||
|
||
// 函数参数、调用及括号表达式复用左括号匹配,返回范围供组合节点使用。
|
||
rule lparen() -> Span
|
||
= quiet!{[Token { kind: TokenKind::LeftParen, span }] { span }} / expected!("'('")
|
||
// 参数/调用/括号表达式复用右括号匹配,其终点可成为完整表达式终点。
|
||
rule rparen() -> Span
|
||
= quiet!{[Token { kind: TokenKind::RightParen, span }] { span }} / expected!("')'")
|
||
// 类和 block 的左边界,缺失时报告可读的左花括号期望项。
|
||
rule lbrace() -> Span
|
||
= quiet!{[Token { kind: TokenKind::LeftBrace, span }] { span }} / expected!("'{'")
|
||
// 类和 block 的右边界,节点跨度包含这个闭合括号。
|
||
rule rbrace() -> Span
|
||
= quiet!{[Token { kind: TokenKind::RightBrace, span }] { span }} / expected!("'}'")
|
||
// 类型注解和类继承共用冒号,不额外构造 AST 节点。
|
||
rule colon()
|
||
= quiet!{[Token { kind: TokenKind::Colon, .. }]} / expected!("':'")
|
||
// 参数/实参列表分隔;列表组合器决定空列表及分隔规则。
|
||
rule comma()
|
||
= quiet!{[Token { kind: TokenKind::Comma, .. }]} / expected!("','")
|
||
// 绑定和赋值共用单等号 Token,不接受相等比较 Token。
|
||
rule equal()
|
||
= quiet!{[Token { kind: TokenKind::Equal, .. }]} / expected!("'='")
|
||
// 成员后缀和符号字面量共用点,返回其范围以保留符号起点。
|
||
rule dot() -> Span
|
||
= quiet!{[Token { kind: TokenKind::Dot, span }] { span }} / expected!("'.'")
|
||
// 加法优先级层消费 Plus Token。
|
||
rule plus()
|
||
= [Token { kind: TokenKind::Plus, .. }]
|
||
// 减法及一元取负共用 Minus,前缀负号需要它的跨度作为节点起点。
|
||
rule minus() -> Span
|
||
= [Token { kind: TokenKind::Minus, span }] { span }
|
||
// 乘法优先级层消费 Star Token。
|
||
rule star()
|
||
= [Token { kind: TokenKind::Star, .. }]
|
||
// 除法优先级层消费 Slash,注释已在词法 trivia 中跳过。
|
||
rule slash()
|
||
= [Token { kind: TokenKind::Slash, .. }]
|
||
|
||
// parse 的模块入口;至少一个顶层函数或类声明,默认拒绝剩余 Token。
|
||
pub rule program() -> Program
|
||
= declarations:declaration()+ {
|
||
// 声明列表由 + 保证非空,根范围从首声明起点延伸到末声明终点。
|
||
let span = declarations[0].span.through(declarations.last().unwrap().span);
|
||
Program { declarations, span }
|
||
}
|
||
|
||
// program/interactive_statement 的声明分支;函数直接包装,类则收集基类及成员。
|
||
rule declaration() -> Decl
|
||
= function:function() {
|
||
Decl { span: function.span, kind: DeclKind::Function(function) }
|
||
}
|
||
/ start:keyword("class") name:name() base:(colon() base:name() { base })?
|
||
lbrace() members:class_member()* end:rbrace() {
|
||
// 按字段出现顺序收集字段参数结构,类的布局稍后由编译器及 VM 解释。
|
||
let mut fields = Vec::new();
|
||
// 按方法出现顺序收集函数结构,与字段分开存储但不改变各自顺序。
|
||
let mut methods = Vec::new();
|
||
// 解析阶段先统一取得成员,再按中间分类分发到两份 AST 列表。
|
||
for member in members {
|
||
// 字段和方法保留各自原节点及跨度,不在这里检查成员重名或 self。
|
||
match member {
|
||
ClassMember::Field(field) => fields.push(field),
|
||
ClassMember::Method(method) => methods.push(method),
|
||
}
|
||
}
|
||
// 类范围包括 class 开头与闭合花括号,中间空白/注释仍属于原文范围。
|
||
let span = start.through(end);
|
||
Decl { span, kind: DeclKind::Class(Class { name, base, fields, methods, span }) }
|
||
}
|
||
|
||
// declaration 的类体调用,先尝试完整方法,再尝试名称加类型的字段。
|
||
rule class_member() -> ClassMember
|
||
= function:function() { ClassMember::Method(function) }
|
||
/ field:parameter() { ClassMember::Field(field) }
|
||
|
||
// parse_ast 的交互入口;恰好一个完整语句包装为列表,不管理多次提交的环境。
|
||
pub rule interactive() -> InteractiveInput
|
||
= statement:interactive_statement() {
|
||
InteractiveInput { span: statement.span, statements: vec![statement] }
|
||
}
|
||
|
||
// 交互允许声明、控制流、let、属性/普通赋值及表达式,不提供根级 return。
|
||
rule interactive_statement() -> Stmt
|
||
= declaration:declaration() {
|
||
Stmt { span: declaration.span, kind: StmtKind::Declaration(declaration) }
|
||
}
|
||
/ control:control_statement() { control }
|
||
/ binding:binding() { binding_statement(binding) }
|
||
/ assignment:member_assignment() { assignment }
|
||
/ assignment:assignment() { assignment }
|
||
/ expression:expression() {
|
||
Stmt { span: expression.span, kind: StmtKind::Expression(expression) }
|
||
}
|
||
|
||
// 顶层和类方法共用函数语法,显式参数类型、返回类型及函数体;self 合法性留给分析。
|
||
rule function() -> Function
|
||
= start:function_keyword() name:name() lparen()
|
||
parameters:(parameter() ** comma()) rparen() colon() return_type:name() body:block() {
|
||
Function { span: start.through(body.span), name, parameters, return_type, body }
|
||
}
|
||
|
||
// 函数参数或类字段共用名称/类型名节点,语法只保留注解文本而不解析类型身份。
|
||
rule parameter() -> Parameter
|
||
= name:name() colon() type_name:name() {
|
||
Parameter { span: name.span.through(type_name.span), name, type_name }
|
||
}
|
||
|
||
// function 和控制流共用块语法,普通语句后可接一个末尾 return;return 当前要求表达式。
|
||
rule block() -> Block
|
||
= start:lbrace() locals:local_statement()* returned:return_statement()? end:rbrace() {
|
||
// 先保留普通语句序列,下面仅在存在末尾 return 时追加,保持源码顺序。
|
||
let mut statements = locals;
|
||
// 可选 return 不会被当作普通表达式消费,也不能后接其他块内语句。
|
||
if let Some(returned) = returned { statements.push(returned); }
|
||
Block { statements, span: start.through(end) }
|
||
}
|
||
|
||
// 块内语句分派;成员赋值先于普通赋值,最后表达式分支显式排除 return 前缀。
|
||
rule local_statement() -> Stmt
|
||
= control:control_statement() { control }
|
||
/ binding:binding() { binding_statement(binding) }
|
||
/ assignment:member_assignment() { assignment }
|
||
/ assignment:assignment() { assignment }
|
||
/ !return_keyword() expression:expression() {
|
||
Stmt { span: expression.span, kind: StmtKind::Expression(expression) }
|
||
}
|
||
|
||
// 交互或块内解析 if/else、while,条件和嵌套 block 都保留为语法树,尚不推断初始化。
|
||
rule control_statement() -> Stmt
|
||
= start:keyword("if") condition:expression() body:block()
|
||
otherwise:(keyword("else") body:block() { body })? {
|
||
// if 范围有 else 时延伸到 else 块末尾,否则只延伸到 then 块末尾。
|
||
let span=start.through(otherwise.as_ref().map_or(body.span,|b|b.span));
|
||
Stmt {span,kind:StmtKind::If(IfStatement {condition,body,otherwise,span})}
|
||
}
|
||
/ start:keyword("while") condition:expression() body:block() {
|
||
// while 范围覆盖关键字、条件及整个循环体。
|
||
let span=start.through(body.span);
|
||
Stmt {span,kind:StmtKind::While(WhileStatement {condition,body,span})}
|
||
}
|
||
|
||
// 交互或局部普通赋值;允许语法上未声明目标,具体全局/局部规则由 compiler::analyze 决定。
|
||
rule assignment() -> Stmt
|
||
= name:name() equal() value:expression() {
|
||
// 赋值语句的原文范围从目标名延伸到右值末尾。
|
||
let span = name.span.through(value.span);
|
||
Stmt { span, kind: StmtKind::Assignment(Assignment { name, value, span }) }
|
||
}
|
||
|
||
// 先解析后缀目标再检查其最外层确为 Member;错误目标使本规则失败,不执行对象写入。
|
||
rule member_assignment() -> Stmt
|
||
= target:postfix_expression() equal() value:expression() {?
|
||
// 属性赋值保留整个接收对象/属性链及右值的原文范围。
|
||
let span = target.span.through(value.span);
|
||
// 只有成员访问可拆成接收对象与字段名,裸名字留给普通赋值分支识别。
|
||
match target.kind {
|
||
ExprKind::Member { object, name } => Ok(Stmt {
|
||
span, kind: StmtKind::MemberAssignment(MemberAssignment { object: *object, name, value, span }),
|
||
}),
|
||
_ => Err("member assignment target"),
|
||
}
|
||
}
|
||
|
||
// 交互/局部 let 绑定,范围包括 let 关键字;重复名和右值初始化检查在后续语义分析。
|
||
rule binding() -> Binding
|
||
= start:let_keyword() name:name() equal() value:expression() {
|
||
Binding { span: start.through(value.span), name, value }
|
||
}
|
||
|
||
// block 的可选末尾返回,语法要求一个表达式,构造 ReturnStatement 的 Some 值。
|
||
rule return_statement() -> Stmt
|
||
= start:return_keyword() value:expression() {
|
||
// return 范围从关键字到返回表达式末尾,包括其间空白。
|
||
let span = start.through(value.span);
|
||
Stmt { span, kind: StmtKind::Return(ReturnStatement { value: Some(value), span }) }
|
||
}
|
||
|
||
// parse_expression 公开入口及各子表达式共用;precedence 层由低到高组织,二元操作在同层左结合。
|
||
pub rule expression() -> Expr = precedence! {
|
||
// 比较层优先级最低;六种比较均复用 binary 包装左右节点和范围。
|
||
left:(@) [Token {kind:TokenKind::EqualEqual,..}] right:@ {binary(left,BinaryOp::Equal,right)}
|
||
left:(@) [Token {kind:TokenKind::NotEqual,..}] right:@ {binary(left,BinaryOp::NotEqual,right)}
|
||
left:(@) [Token {kind:TokenKind::Less,..}] right:@ {binary(left,BinaryOp::Less,right)}
|
||
left:(@) [Token {kind:TokenKind::LessEqual,..}] right:@ {binary(left,BinaryOp::LessEqual,right)}
|
||
left:(@) [Token {kind:TokenKind::Greater,..}] right:@ {binary(left,BinaryOp::Greater,right)}
|
||
left:(@) [Token {kind:TokenKind::GreaterEqual,..}] right:@ {binary(left,BinaryOp::GreaterEqual,right)}
|
||
--
|
||
// 加减层高于比较、低于乘除,同层按左结合嵌套。
|
||
left:(@) plus() right:@ { binary(left, BinaryOp::Add, right) }
|
||
left:(@) minus() right:@ { binary(left, BinaryOp::Subtract, right) }
|
||
--
|
||
// 乘除层先构造节点,再交给外围的加减/比较层。
|
||
left:(@) star() right:@ { binary(left, BinaryOp::Multiply, right) }
|
||
left:(@) slash() right:@ { binary(left, BinaryOp::Divide, right) }
|
||
--
|
||
// 前缀 await 构造等待节点,是否允许停放由执行上下文决定。
|
||
start:keyword("await") operand:@ {
|
||
Expr { span: start.through(operand.span), kind: ExprKind::Await(Box::new(operand)) }
|
||
}
|
||
// 前缀取负包住当前高优先级操作数,不在语法阶段计算数值。
|
||
start:minus() operand:@ {
|
||
Expr { span: start.through(operand.span), kind: ExprKind::Unary { operation: UnaryOp::Negate, operand: Box::new(operand) } }
|
||
}
|
||
--
|
||
// 后缀表达式位于最高优先级层,先形成调用/成员链,再被一元或二元节点包裹。
|
||
expression:postfix_expression() { expression }
|
||
}
|
||
|
||
// 优先级最高的 primary 后接零或多个成员/调用后缀,从左到右 fold 保持链式求值结构。
|
||
rule postfix_expression() -> Expr
|
||
= expression:primary() suffixes:suffix()* {
|
||
// parser::postfix 每次把先前结果作为接收对象或被调用表达式,构造 a.b(c).d 一类链。
|
||
suffixes.into_iter().fold(expression, postfix)
|
||
}
|
||
|
||
// postfix_expression 共用后缀;点后取 Name,调用保存参数列表及右括号范围。
|
||
rule suffix() -> Suffix
|
||
= dot() name:name() { Suffix::Member(name) }
|
||
/ lparen() arguments:(expression() ** comma()) end:rparen() { Suffix::Call(arguments, end) }
|
||
|
||
// 原子表达式:括号、符号、数字、字符串或名称;AST 文本均从匹配 Token 原文复制/解码。
|
||
rule primary() -> Expr
|
||
= start:lparen() expression:expression() end:rparen() {
|
||
// 括号不新增语义节点种类,只把子表达式范围扩大到两侧括号。
|
||
Expr { span: start.through(end), ..expression }
|
||
}
|
||
/ start:dot() name:name() {
|
||
// 点开头的符号与成员后缀不同;前端保留它,编译器当前尚不支持生成该运行时值。
|
||
Expr { span: start.through(name.span), kind: ExprKind::Symbol(name) }
|
||
}
|
||
/ [Token { kind: TokenKind::Number, span }] {
|
||
// 数值保存原始十进制拼写,精确解析与负号处理留给 codegen。
|
||
Expr { span, kind: ExprKind::Number(source[span.start..span.end].into()) }
|
||
}
|
||
/ [Token { kind: TokenKind::String, span }] {
|
||
// Token 跨度含引号,去掉引号后调用已验证转义的 decode_string,AST 保存解码结果。
|
||
Expr { span, kind: ExprKind::String(decode_string(&source[span.start + 1..span.end - 1])) }
|
||
}
|
||
/ name:name() { Expr { span: name.span, kind: ExprKind::Name(name.text) } }
|
||
}
|
||
}
|