feat: support bare name assignments in interactive and function scopes

This commit is contained in:
2026-10-20 18:16:54 +08:00
parent 6281e58647
commit df1b77fc1a
17 changed files with 259 additions and 37 deletions
+15 -1
View File
@@ -3,7 +3,7 @@
use super::Spanned;
use crate::Span;
pub const AST_SCHEMA_ID: &str =
"urn:endor:ast:sha256:c0da1a2640ad85f2c8e8159a10756e649d3aab179823a7cd890d9ebbb7f5d46e";
"urn:endor:ast:sha256:8c89fde6c029357a0809751c41cb46d59972b987bbe1b25c0cced4bfcdbe2a7b";
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AstDocument {
@@ -123,6 +123,7 @@ impl Spanned for Stmt {
#[serde(tag = "kind", content = "data", deny_unknown_fields)]
pub enum StmtKind {
Binding(Binding),
Assignment(Assignment),
Return(ReturnStatement),
Expression(Expr),
Declaration(Decl),
@@ -131,6 +132,7 @@ impl Spanned for StmtKind {
fn span(&self) -> Span {
match self {
Self::Binding(node) => node.span(),
Self::Assignment(node) => node.span(),
Self::Return(node) => node.span(),
Self::Expression(node) => node.span(),
Self::Declaration(node) => node.span(),
@@ -151,6 +153,18 @@ impl Spanned for Binding {
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Assignment {
pub name: Name,
pub value: Expr,
pub span: Span,
}
impl Spanned for Assignment {
fn span(&self) -> Span {
self.span
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ReturnStatement {
pub value: Option<Expr>,
pub span: Span,
+21 -2
View File
@@ -1,8 +1,9 @@
// Generated by scripts/generate_ast.py from Endor.asdl. Do not edit.
use super::{
AstDocument, AstRoot, BinaryOp, Binding, Block, Decl, DeclKind, Expr, ExprKind, Function,
InteractiveInput, Name, Parameter, Program, ReturnStatement, Spanned, Stmt, StmtKind, UnaryOp,
Assignment, AstDocument, AstRoot, BinaryOp, Binding, Block, Decl, DeclKind, Expr, ExprKind,
Function, InteractiveInput, Name, Parameter, Program, ReturnStatement, Spanned, Stmt, StmtKind,
UnaryOp,
};
use crate::Span;
pub trait Visitor {
@@ -83,6 +84,12 @@ pub trait Visitor {
self.leave_node();
result
}
fn visit_assignment(&mut self, node: &Assignment) -> Result<(), Self::Error> {
self.enter_node(node.span())?;
let result = walk_assignment(self, node);
self.leave_node();
result
}
fn visit_return_statement(&mut self, node: &ReturnStatement) -> Result<(), Self::Error> {
self.enter_node(node.span())?;
let result = walk_return_statement(self, node);
@@ -201,6 +208,9 @@ pub fn walk_stmt_kind<V: Visitor + ?Sized>(
StmtKind::Binding(value) => {
visitor.visit_binding(value)?;
}
StmtKind::Assignment(value) => {
visitor.visit_assignment(value)?;
}
StmtKind::Return(value) => {
visitor.visit_return_statement(value)?;
}
@@ -219,6 +229,15 @@ pub fn walk_binding<V: Visitor + ?Sized>(visitor: &mut V, node: &Binding) -> Res
visitor.visit_span(&node.span)?;
Ok(())
}
pub fn walk_assignment<V: Visitor + ?Sized>(
visitor: &mut V,
node: &Assignment,
) -> Result<(), V::Error> {
visitor.visit_name(&node.name)?;
visitor.visit_expr(&node.value)?;
visitor.visit_span(&node.span)?;
Ok(())
}
pub fn walk_return_statement<V: Visitor + ?Sized>(
visitor: &mut V,
node: &ReturnStatement,
+13 -2
View File
@@ -62,6 +62,7 @@ peg::parser! {
Stmt { span: declaration.span, kind: StmtKind::Declaration(declaration) }
}
/ binding:binding() { binding_statement(binding) }
/ assignment:assignment() { assignment }
/ expression:expression() {
Stmt { span: expression.span, kind: StmtKind::Expression(expression) }
}
@@ -78,12 +79,22 @@ peg::parser! {
}
rule block() -> Block
= start:lbrace() bindings:binding()* returned:return_statement() end:rbrace() {
let mut statements: Vec<Stmt> = bindings.into_iter().map(binding_statement).collect();
= start:lbrace() locals:local_statement()* returned:return_statement() end:rbrace() {
let mut statements = locals;
statements.push(returned);
Block { statements, span: start.through(end) }
}
rule local_statement() -> Stmt
= binding:binding() { binding_statement(binding) }
/ assignment:assignment() { assignment }
rule assignment() -> Stmt
= name:name() equal() value:expression() {
let span = name.span.through(value.span);
Stmt { span, kind: StmtKind::Assignment(Assignment { name, value, span }) }
}
rule binding() -> Binding
= start:let_keyword() name:name() equal() value:expression() {
Binding { span: start.through(value.span), name, value }
+2 -2
View File
@@ -1,6 +1,6 @@
use crate::ast::{
AstRoot, BinaryOp, Binding, Block, Decl, DeclKind, Expr, ExprKind, Function, InteractiveInput,
Name, Parameter, Program, ReturnStatement, Stmt, StmtKind, UnaryOp,
Assignment, AstRoot, BinaryOp, Binding, Block, Decl, DeclKind, Expr, ExprKind, Function,
InteractiveInput, Name, Parameter, Program, ReturnStatement, Stmt, StmtKind, UnaryOp,
};
use crate::lexer::decode_string;
use crate::{Diagnostic, DiagnosticKind, Span, Token, TokenKind, lex};