Initialize Aster project with basic structure, including Cargo configuration, lexer, parser, interpreter, and AST definitions. Add a sample script and README documentation. Implement basic error handling and environment management for variable storage.
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aster"
|
||||
version = "0.1.0"
|
||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "aster"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
90
README.md
Normal file
90
README.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Aster
|
||||
|
||||
用 Rust 实现的脚本语言解释器。
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
aster/
|
||||
├── src/
|
||||
│ ├── lexer/ # 词法分析器
|
||||
│ ├── ast/ # 抽象语法树
|
||||
│ ├── parser/ # 语法分析器
|
||||
│ ├── interpreter/# 解释器
|
||||
│ ├── error/ # 错误处理
|
||||
│ └── main.rs
|
||||
├── script.ast # 示例脚本
|
||||
└── Cargo.toml
|
||||
```
|
||||
|
||||
## 运行方式
|
||||
|
||||
```bash
|
||||
# 运行脚本文件
|
||||
cargo run -- script.ast
|
||||
|
||||
# 从标准输入读取
|
||||
cargo run
|
||||
```
|
||||
|
||||
## 语言特性
|
||||
|
||||
### 数据类型
|
||||
|
||||
- 数字(`Number`)
|
||||
- 字符串(`String`)
|
||||
- 布尔值(`true` / `false`)
|
||||
- 空值(`nil`)
|
||||
|
||||
### 变量与赋值
|
||||
|
||||
```rust
|
||||
let x = 42;
|
||||
let name = "aster";
|
||||
```
|
||||
|
||||
### 控制流
|
||||
|
||||
- **条件分支**:`if` / `else`
|
||||
- **循环**:`while`
|
||||
|
||||
### 函数
|
||||
|
||||
```rust
|
||||
fn fib(n) {
|
||||
if (n <= 1) {
|
||||
return n
|
||||
}
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
}
|
||||
|
||||
print(fib(10))
|
||||
```
|
||||
|
||||
### 运算符
|
||||
|
||||
- 算术:`+` `-` `*` `/`
|
||||
- 比较:`<` `<=` `>` `>=` `==` `!=`
|
||||
- 逻辑:`&&` `||`
|
||||
- 一元:`!` `-`
|
||||
|
||||
### 内置函数
|
||||
|
||||
- `print(value)`:打印值
|
||||
- `clock()`:返回当前时间戳(秒)
|
||||
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
构建产物位于 `target/release/aster`,可直接执行:
|
||||
|
||||
```bash
|
||||
./target/release/aster script.ast
|
||||
```
|
||||
|
||||
## 依赖
|
||||
|
||||
无外部依赖,仅使用 Rust 标准库。
|
||||
40
script.ast
Normal file
40
script.ast
Normal file
@@ -0,0 +1,40 @@
|
||||
// 压测:循环、递归、闭包
|
||||
|
||||
fn fib(n) {
|
||||
if (n <= 1) {
|
||||
return n
|
||||
}
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
}
|
||||
|
||||
fn make_adder(x) {
|
||||
return fn(y) { return x + y }
|
||||
}
|
||||
|
||||
let t0 = clock()
|
||||
|
||||
// 1. 循环压测:100万次算术
|
||||
let sum = 0
|
||||
let i = 0
|
||||
while (i < 1000000) {
|
||||
sum = sum + i
|
||||
i = i + 1
|
||||
}
|
||||
print("loop 1M:", sum)
|
||||
|
||||
// 2. 递归压测:fib(25)
|
||||
let f = fib(25)
|
||||
print("fib(25):", f)
|
||||
|
||||
// 3. 闭包压测:100万次调用
|
||||
let add10 = make_adder(10)
|
||||
let j = 0
|
||||
let total = 0
|
||||
while (j < 1000000) {
|
||||
total = add10(j)
|
||||
j = j + 1
|
||||
}
|
||||
print("closure 1M calls:", total)
|
||||
|
||||
let t1 = clock()
|
||||
print("total time (s):", t1 - t0)
|
||||
84
src/ast/expr.rs
Normal file
84
src/ast/expr.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use crate::ast::stmt::Stmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Expr {
|
||||
/// 字面量:number / string / bool / nil
|
||||
Literal(Literal),
|
||||
|
||||
/// 变量引用
|
||||
Variable(String),
|
||||
|
||||
/// 赋值表达式:a = b
|
||||
Assign {
|
||||
name: String,
|
||||
value: Box<Expr>,
|
||||
},
|
||||
|
||||
/// 一元运算:!expr / -expr
|
||||
Unary {
|
||||
op: UnaryOp,
|
||||
right: Box<Expr>,
|
||||
},
|
||||
|
||||
/// 二元运算:a + b
|
||||
Binary {
|
||||
left: Box<Expr>,
|
||||
op: BinaryOp,
|
||||
right: Box<Expr>,
|
||||
},
|
||||
|
||||
/// 逻辑运算:&& ||
|
||||
Logical {
|
||||
left: Box<Expr>,
|
||||
op: LogicalOp,
|
||||
right: Box<Expr>,
|
||||
},
|
||||
|
||||
/// 函数调用
|
||||
Call {
|
||||
callee: Box<Expr>,
|
||||
arguments: Vec<Expr>,
|
||||
},
|
||||
|
||||
/// 匿名函数(为闭包预留)
|
||||
Lambda {
|
||||
params: Vec<String>,
|
||||
body: Vec<Stmt>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Literal {
|
||||
Number(f64),
|
||||
String(String),
|
||||
Bool(bool),
|
||||
Nil,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum UnaryOp {
|
||||
Negate, // -
|
||||
Not, // !
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum BinaryOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
Less,
|
||||
LessEqual,
|
||||
|
||||
Equal,
|
||||
NotEqual,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum LogicalOp {
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
5
src/ast/mod.rs
Normal file
5
src/ast/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
pub mod expr;
|
||||
pub mod stmt;
|
||||
|
||||
pub use expr::*;
|
||||
pub use stmt::*;
|
||||
39
src/ast/stmt.rs
Normal file
39
src/ast/stmt.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use crate::ast::expr::Expr;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Stmt {
|
||||
/// let x = expr;
|
||||
Let {
|
||||
name: String,
|
||||
initializer: Expr,
|
||||
},
|
||||
|
||||
/// 表达式语句:expr;
|
||||
ExprStmt(Expr),
|
||||
|
||||
/// 代码块:{ ... }
|
||||
Block(Vec<Stmt>),
|
||||
|
||||
/// if 语句
|
||||
If {
|
||||
condition: Expr,
|
||||
then_branch: Box<Stmt>,
|
||||
else_branch: Option<Box<Stmt>>,
|
||||
},
|
||||
|
||||
/// while 循环
|
||||
While {
|
||||
condition: Expr,
|
||||
body: Box<Stmt>,
|
||||
},
|
||||
|
||||
/// 函数声明
|
||||
Function {
|
||||
name: String,
|
||||
params: Vec<String>,
|
||||
body: Vec<Stmt>,
|
||||
},
|
||||
|
||||
/// return expr?;
|
||||
Return(Option<Expr>),
|
||||
}
|
||||
26
src/error/error.rs
Normal file
26
src/error/error.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::lexer::Token;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimeError {
|
||||
ParseError { message: String, token: Token },
|
||||
RuntimeError { message: String, token: Option<Token> },
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RuntimeError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
RuntimeError::ParseError { message, token } => {
|
||||
write!(f, "[Parse Error] {} at line {}, column {}", message, token.line, token.column)
|
||||
}
|
||||
RuntimeError::RuntimeError { message, token } => {
|
||||
if let Some(tok) = token {
|
||||
write!(f, "[Runtime Error] {} at line {}, column {}", message, tok.line, tok.column)
|
||||
} else {
|
||||
write!(f, "[Runtime Error] {}", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for RuntimeError {}
|
||||
3
src/error/mod.rs
Normal file
3
src/error/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod error;
|
||||
|
||||
pub use error::*;
|
||||
44
src/interpreter/env.rs
Normal file
44
src/interpreter/env.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use super::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Env {
|
||||
pub values: HashMap<String, Value>,
|
||||
pub parent: Option<Rc<RefCell<Env>>>,
|
||||
}
|
||||
|
||||
impl Env {
|
||||
pub fn new(parent: Option<Rc<RefCell<Env>>>) -> Self {
|
||||
Self {
|
||||
values: HashMap::new(),
|
||||
parent,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define(&mut self, name: String, val: Value) {
|
||||
self.values.insert(name, val);
|
||||
}
|
||||
|
||||
pub fn assign(&mut self, name: &str, val: Value) -> bool {
|
||||
if self.values.contains_key(name) {
|
||||
self.values.insert(name.to_string(), val);
|
||||
true
|
||||
} else if let Some(parent) = &self.parent {
|
||||
parent.borrow_mut().assign(name, val)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Option<Value> {
|
||||
if let Some(val) = self.values.get(name) {
|
||||
Some(val.clone())
|
||||
} else if let Some(parent) = &self.parent {
|
||||
parent.borrow().get(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
289
src/interpreter/interpreter.rs
Normal file
289
src/interpreter/interpreter.rs
Normal file
@@ -0,0 +1,289 @@
|
||||
use crate::ast::*;
|
||||
use crate::error::RuntimeError;
|
||||
use super::{Value, Env, Function};
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct Interpreter {
|
||||
pub env: Rc<RefCell<Env>>,
|
||||
}
|
||||
|
||||
impl Interpreter {
|
||||
pub fn new() -> Self {
|
||||
let env = Rc::new(RefCell::new(Env::new(None)));
|
||||
|
||||
// 注册内置函数
|
||||
env.borrow_mut().define("print".to_string(), Value::NativeFunction(native_print));
|
||||
env.borrow_mut().define("clock".to_string(), Value::NativeFunction(native_clock));
|
||||
|
||||
Self { env }
|
||||
}
|
||||
|
||||
pub fn interpret(&mut self, statements: Vec<Stmt>) -> Result<(), RuntimeError> {
|
||||
for stmt in statements {
|
||||
if let Some(val) = self.execute(stmt.clone())? {
|
||||
// 如果是表达式语句且结果不是 Nil,打印结果
|
||||
if matches!(stmt, Stmt::ExprStmt(_)) && !matches!(val, Value::Nil) {
|
||||
println!("{}", val);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute(&mut self, stmt: Stmt) -> Result<Option<Value>, RuntimeError> {
|
||||
match stmt {
|
||||
Stmt::Let { name, initializer } => {
|
||||
let val = self.evaluate(initializer)?;
|
||||
self.env.borrow_mut().define(name, val);
|
||||
Ok(None)
|
||||
}
|
||||
Stmt::ExprStmt(expr) => {
|
||||
Ok(Some(self.evaluate(expr)?))
|
||||
}
|
||||
Stmt::Block(stmts) => {
|
||||
let previous = Rc::clone(&self.env);
|
||||
self.env = Rc::new(RefCell::new(Env::new(Some(previous))));
|
||||
let mut result = None;
|
||||
for s in stmts {
|
||||
result = self.execute(s)?;
|
||||
}
|
||||
let parent = self.env.borrow().parent.as_ref().unwrap().clone();
|
||||
self.env = parent;
|
||||
Ok(result)
|
||||
}
|
||||
Stmt::If { condition, then_branch, else_branch } => {
|
||||
let cond_val = self.evaluate(condition)?;
|
||||
if self.is_truthy(&cond_val) {
|
||||
self.execute(*then_branch)
|
||||
} else if let Some(else_branch) = else_branch {
|
||||
self.execute(*else_branch)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
Stmt::While { condition, body } => {
|
||||
loop {
|
||||
let cond_val = self.evaluate(condition.clone())?;
|
||||
if !self.is_truthy(&cond_val) {
|
||||
break;
|
||||
}
|
||||
self.execute(*body.clone())?;
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
Stmt::Function { name, params, body } => {
|
||||
let func = Value::Function(Rc::new(Function {
|
||||
params,
|
||||
body,
|
||||
env: Rc::clone(&self.env),
|
||||
name: Some(name.clone()),
|
||||
}));
|
||||
self.env.borrow_mut().define(name, func);
|
||||
Ok(None)
|
||||
}
|
||||
Stmt::Return(expr_opt) => {
|
||||
if let Some(expr) = expr_opt {
|
||||
Ok(Some(self.evaluate(expr)?))
|
||||
} else {
|
||||
Ok(Some(Value::Nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate(&mut self, expr: Expr) -> Result<Value, RuntimeError> {
|
||||
match expr {
|
||||
Expr::Literal(lit) => Ok(match lit {
|
||||
crate::ast::expr::Literal::Number(n) => Value::Number(n),
|
||||
crate::ast::expr::Literal::String(s) => Value::String(s),
|
||||
crate::ast::expr::Literal::Bool(b) => Value::Bool(b),
|
||||
crate::ast::expr::Literal::Nil => Value::Nil,
|
||||
}),
|
||||
Expr::Variable(name) => {
|
||||
match self.env.borrow().get(&name) {
|
||||
Some(val) => Ok(val),
|
||||
None => Err(RuntimeError::RuntimeError {
|
||||
message: format!("Undefined variable '{}'", name),
|
||||
token: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
Expr::Assign { name, value } => {
|
||||
let val = self.evaluate(*value)?;
|
||||
if !self.env.borrow_mut().assign(&name, val.clone()) {
|
||||
return Err(RuntimeError::RuntimeError {
|
||||
message: format!("Undefined variable '{}'", name),
|
||||
token: None,
|
||||
});
|
||||
}
|
||||
Ok(val)
|
||||
}
|
||||
Expr::Unary { op, right } => {
|
||||
let val = self.evaluate(*right)?;
|
||||
match op {
|
||||
crate::ast::expr::UnaryOp::Negate => match val {
|
||||
Value::Number(n) => Ok(Value::Number(-n)),
|
||||
_ => Err(RuntimeError::RuntimeError {
|
||||
message: "Unary '-' on non-number".to_string(),
|
||||
token: None,
|
||||
}),
|
||||
},
|
||||
crate::ast::expr::UnaryOp::Not => Ok(Value::Bool(!self.is_truthy(&val))),
|
||||
}
|
||||
}
|
||||
Expr::Binary { left, op, right } => {
|
||||
let l = self.evaluate(*left)?;
|
||||
let r = self.evaluate(*right)?;
|
||||
match op {
|
||||
crate::ast::expr::BinaryOp::Add => match (l, r) {
|
||||
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a+b)),
|
||||
(Value::String(a), Value::String(b)) => Ok(Value::String(a+&b)),
|
||||
_ => Err(RuntimeError::RuntimeError {
|
||||
message: "Invalid '+' operands".to_string(),
|
||||
token: None,
|
||||
}),
|
||||
},
|
||||
crate::ast::expr::BinaryOp::Sub => match (l,r) {
|
||||
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a-b)),
|
||||
_ => Err(RuntimeError::RuntimeError {
|
||||
message: "Invalid '-' operands".to_string(),
|
||||
token: None,
|
||||
}),
|
||||
},
|
||||
crate::ast::expr::BinaryOp::Mul => match (l,r) {
|
||||
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a*b)),
|
||||
_ => Err(RuntimeError::RuntimeError {
|
||||
message: "Invalid '*' operands".to_string(),
|
||||
token: None,
|
||||
}),
|
||||
},
|
||||
crate::ast::expr::BinaryOp::Div => match (l,r) {
|
||||
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a/b)),
|
||||
_ => Err(RuntimeError::RuntimeError {
|
||||
message: "Invalid '/' operands".to_string(),
|
||||
token: None,
|
||||
}),
|
||||
},
|
||||
crate::ast::expr::BinaryOp::Greater => Ok(Value::Bool(self.as_number(&l)? > self.as_number(&r)?)),
|
||||
crate::ast::expr::BinaryOp::GreaterEqual => Ok(Value::Bool(self.as_number(&l)? >= self.as_number(&r)?)),
|
||||
crate::ast::expr::BinaryOp::Less => Ok(Value::Bool(self.as_number(&l)? < self.as_number(&r)?)),
|
||||
crate::ast::expr::BinaryOp::LessEqual => Ok(Value::Bool(self.as_number(&l)? <= self.as_number(&r)?)),
|
||||
crate::ast::expr::BinaryOp::Equal => Ok(Value::Bool(self.is_equal(&l,&r))),
|
||||
crate::ast::expr::BinaryOp::NotEqual => Ok(Value::Bool(!self.is_equal(&l,&r))),
|
||||
}
|
||||
}
|
||||
Expr::Logical { left, op, right } => {
|
||||
let l = self.evaluate(*left)?;
|
||||
match op {
|
||||
crate::ast::expr::LogicalOp::And => {
|
||||
Ok(if !self.is_truthy(&l) { l } else { self.evaluate(*right)? })
|
||||
}
|
||||
crate::ast::expr::LogicalOp::Or => {
|
||||
Ok(if self.is_truthy(&l) { l } else { self.evaluate(*right)? })
|
||||
}
|
||||
}
|
||||
}
|
||||
Expr::Call { callee, arguments } => {
|
||||
let func = self.evaluate(*callee)?;
|
||||
let mut args = Vec::new();
|
||||
for e in arguments {
|
||||
args.push(self.evaluate(e)?);
|
||||
}
|
||||
self.call_function(func, args)
|
||||
}
|
||||
Expr::Lambda { params, body } => {
|
||||
Ok(Value::Function(Rc::new(Function {
|
||||
params,
|
||||
body,
|
||||
env: Rc::clone(&self.env),
|
||||
name: None,
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn call_function(&mut self, func_val: Value, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
match func_val {
|
||||
Value::NativeFunction(native_fn) => {
|
||||
Ok(native_fn(args))
|
||||
}
|
||||
Value::Function(f) => {
|
||||
let env = Rc::new(RefCell::new(Env::new(Some(Rc::clone(&f.env)))));
|
||||
|
||||
if let Some(name) = &f.name {
|
||||
env.borrow_mut().define(name.clone(), Value::Function(Rc::clone(&f)));
|
||||
}
|
||||
|
||||
for (i,param) in f.params.iter().enumerate() {
|
||||
let val = args.get(i).cloned().unwrap_or(Value::Nil);
|
||||
env.borrow_mut().define(param.clone(), val);
|
||||
}
|
||||
|
||||
let previous = Rc::clone(&self.env);
|
||||
self.env = env;
|
||||
let mut ret = Value::Nil;
|
||||
for stmt in &f.body {
|
||||
if let Some(val) = self.execute(stmt.clone())? {
|
||||
ret = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.env = previous;
|
||||
Ok(ret)
|
||||
}
|
||||
_ => {
|
||||
Err(RuntimeError::RuntimeError {
|
||||
message: "Attempt to call non-function".to_string(),
|
||||
token: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_truthy(&self, val: &Value) -> bool {
|
||||
match val {
|
||||
Value::Nil => false,
|
||||
Value::Bool(b) => *b,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_equal(&self, a: &Value, b: &Value) -> bool {
|
||||
match (a,b) {
|
||||
(Value::Nil, Value::Nil) => true,
|
||||
(Value::Bool(x), Value::Bool(y)) => x==y,
|
||||
(Value::Number(x), Value::Number(y)) => x==y,
|
||||
(Value::String(x), Value::String(y)) => x==y,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_number(&self, val: &Value) -> Result<f64, RuntimeError> {
|
||||
if let Value::Number(n) = val {
|
||||
Ok(*n)
|
||||
} else {
|
||||
Err(RuntimeError::RuntimeError {
|
||||
message: "Expected number".to_string(),
|
||||
token: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 内置函数实现
|
||||
fn native_print(args: Vec<Value>) -> Value {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if i > 0 {
|
||||
print!(" ");
|
||||
}
|
||||
print!("{}", arg);
|
||||
}
|
||||
println!();
|
||||
Value::Nil
|
||||
}
|
||||
|
||||
// 获取当前时间
|
||||
fn native_clock(_args: Vec<Value>) -> Value {
|
||||
Value::Number(std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs_f64())
|
||||
}
|
||||
55
src/interpreter/mod.rs
Normal file
55
src/interpreter/mod.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
pub mod env;
|
||||
pub mod interpreter;
|
||||
|
||||
pub use env::Env;
|
||||
pub use interpreter::Interpreter;
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
|
||||
pub type NativeFn = fn(Vec<Value>) -> Value;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Value {
|
||||
Number(f64),
|
||||
String(String),
|
||||
Bool(bool),
|
||||
Nil,
|
||||
Function(Rc<Function>),
|
||||
NativeFunction(NativeFn),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Value {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Value::Number(n) => write!(f, "Number({:?})", n),
|
||||
Value::String(s) => write!(f, "String({:?})", s),
|
||||
Value::Bool(b) => write!(f, "Bool({:?})", b),
|
||||
Value::Nil => write!(f, "Nil"),
|
||||
Value::Function(_) => write!(f, "Function(...)"),
|
||||
Value::NativeFunction(_) => write!(f, "NativeFunction(...)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Value {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Value::Number(n) => write!(f, "{}", n),
|
||||
Value::String(s) => write!(f, "{}", s),
|
||||
Value::Bool(b) => write!(f, "{}", b),
|
||||
Value::Nil => write!(f, "nil"),
|
||||
Value::Function(_) => write!(f, "<function>"),
|
||||
Value::NativeFunction(_) => write!(f, "<native function>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
pub params: Vec<String>,
|
||||
pub body: Vec<crate::ast::Stmt>,
|
||||
pub env: Rc<RefCell<Env>>, // 闭包捕获环境
|
||||
pub name: Option<String>,
|
||||
}
|
||||
261
src/lexer/lexer.rs
Normal file
261
src/lexer/lexer.rs
Normal file
@@ -0,0 +1,261 @@
|
||||
// src/lexer/lexer.rs
|
||||
|
||||
use super::{Token, TokenKind};
|
||||
|
||||
pub struct Lexer {
|
||||
src: Vec<char>,
|
||||
current: usize,
|
||||
line: usize,
|
||||
column: usize,
|
||||
}
|
||||
|
||||
impl Lexer {
|
||||
pub fn new(input: &str) -> Self {
|
||||
Self {
|
||||
src: input.chars().collect(),
|
||||
current: 0,
|
||||
line: 1,
|
||||
column: 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tokenize(mut self) -> Vec<Token> {
|
||||
let mut tokens = Vec::new();
|
||||
|
||||
while !self.is_at_end() {
|
||||
if let Some(token) = self.next_token() {
|
||||
tokens.push(token);
|
||||
}
|
||||
}
|
||||
|
||||
tokens.push(Token {
|
||||
kind: TokenKind::EOF,
|
||||
line: self.line,
|
||||
column: self.column,
|
||||
});
|
||||
|
||||
tokens
|
||||
}
|
||||
|
||||
fn next_token(&mut self) -> Option<Token> {
|
||||
self.skip_whitespace();
|
||||
|
||||
if self.is_at_end() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let line = self.line;
|
||||
let column = self.column;
|
||||
let c = self.advance();
|
||||
|
||||
let kind = match c {
|
||||
'(' => TokenKind::LeftParen,
|
||||
')' => TokenKind::RightParen,
|
||||
'{' => TokenKind::LeftBrace,
|
||||
'}' => TokenKind::RightBrace,
|
||||
',' => TokenKind::Comma,
|
||||
';' => TokenKind::Semicolon,
|
||||
|
||||
'+' => TokenKind::Plus,
|
||||
'-' => TokenKind::Minus,
|
||||
'*' => TokenKind::Star,
|
||||
|
||||
'/' => {
|
||||
if self.match_char('/') {
|
||||
// 单行注释
|
||||
while !self.is_at_end() && self.peek() != '\n' {
|
||||
self.advance();
|
||||
}
|
||||
return None;
|
||||
} else {
|
||||
TokenKind::Slash
|
||||
}
|
||||
}
|
||||
|
||||
'!' => {
|
||||
if self.match_char('=') {
|
||||
TokenKind::BangEqual
|
||||
} else {
|
||||
TokenKind::Bang
|
||||
}
|
||||
}
|
||||
|
||||
'=' => {
|
||||
if self.match_char('=') {
|
||||
TokenKind::EqualEqual
|
||||
} else {
|
||||
TokenKind::Equal
|
||||
}
|
||||
}
|
||||
|
||||
'>' => {
|
||||
if self.match_char('=') {
|
||||
TokenKind::GreaterEqual
|
||||
} else {
|
||||
TokenKind::Greater
|
||||
}
|
||||
}
|
||||
|
||||
'<' => {
|
||||
if self.match_char('=') {
|
||||
TokenKind::LessEqual
|
||||
} else {
|
||||
TokenKind::Less
|
||||
}
|
||||
}
|
||||
|
||||
'&' => {
|
||||
if self.match_char('&') {
|
||||
TokenKind::AndAnd
|
||||
} else {
|
||||
panic!("Unexpected '&' at {}:{}", line, column);
|
||||
}
|
||||
}
|
||||
|
||||
'|' => {
|
||||
if self.match_char('|') {
|
||||
TokenKind::OrOr
|
||||
} else {
|
||||
panic!("Unexpected '|' at {}:{}", line, column);
|
||||
}
|
||||
}
|
||||
|
||||
'"' => return Some(self.string_literal(line, column)),
|
||||
|
||||
c if c.is_ascii_digit() => {
|
||||
return Some(self.number_literal(c, line, column));
|
||||
}
|
||||
|
||||
c if is_ident_start(c) => {
|
||||
return Some(self.identifier(c, line, column));
|
||||
}
|
||||
|
||||
_ => {
|
||||
panic!("Unexpected character '{}' at {}:{}", c, line, column);
|
||||
}
|
||||
};
|
||||
|
||||
Some(Token { kind, line, column })
|
||||
}
|
||||
|
||||
// ---------------- helpers ----------------
|
||||
|
||||
fn skip_whitespace(&mut self) {
|
||||
loop {
|
||||
if self.is_at_end() {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.peek() {
|
||||
' ' | '\t' | '\r' => {
|
||||
self.advance();
|
||||
}
|
||||
'\n' => {
|
||||
self.advance();
|
||||
self.line += 1;
|
||||
self.column = 1;
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn advance(&mut self) -> char {
|
||||
let c = self.src[self.current];
|
||||
self.current += 1;
|
||||
self.column += 1;
|
||||
c
|
||||
}
|
||||
|
||||
fn match_char(&mut self, expected: char) -> bool {
|
||||
if self.is_at_end() || self.peek() != expected {
|
||||
return false;
|
||||
}
|
||||
self.advance();
|
||||
true
|
||||
}
|
||||
|
||||
fn peek(&self) -> char {
|
||||
self.src[self.current]
|
||||
}
|
||||
|
||||
fn is_at_end(&self) -> bool {
|
||||
self.current >= self.src.len()
|
||||
}
|
||||
|
||||
fn string_literal(&mut self, line: usize, column: usize) -> Token {
|
||||
let mut value = String::new();
|
||||
|
||||
while !self.is_at_end() && self.peek() != '"' {
|
||||
value.push(self.advance());
|
||||
}
|
||||
|
||||
if self.is_at_end() {
|
||||
panic!("Unterminated string at {}:{}", line, column);
|
||||
}
|
||||
|
||||
self.advance(); // consume closing "
|
||||
|
||||
Token {
|
||||
kind: TokenKind::String(value),
|
||||
line,
|
||||
column,
|
||||
}
|
||||
}
|
||||
|
||||
fn number_literal(&mut self, first: char, line: usize, column: usize) -> Token {
|
||||
let mut s = String::new();
|
||||
s.push(first);
|
||||
|
||||
while !self.is_at_end() && self.peek().is_ascii_digit() {
|
||||
s.push(self.advance());
|
||||
}
|
||||
|
||||
if !self.is_at_end() && self.peek() == '.' {
|
||||
s.push(self.advance());
|
||||
while !self.is_at_end() && self.peek().is_ascii_digit() {
|
||||
s.push(self.advance());
|
||||
}
|
||||
}
|
||||
|
||||
let value = s.parse::<f64>().unwrap();
|
||||
|
||||
Token {
|
||||
kind: TokenKind::Number(value),
|
||||
line,
|
||||
column,
|
||||
}
|
||||
}
|
||||
|
||||
fn identifier(&mut self, first: char, line: usize, column: usize) -> Token {
|
||||
let mut s = String::new();
|
||||
s.push(first);
|
||||
|
||||
while !self.is_at_end() && is_ident_part(self.peek()) {
|
||||
s.push(self.advance());
|
||||
}
|
||||
|
||||
let kind = match s.as_str() {
|
||||
"let" => TokenKind::Let,
|
||||
"fn" => TokenKind::Fn,
|
||||
"if" => TokenKind::If,
|
||||
"else" => TokenKind::Else,
|
||||
"while" => TokenKind::While,
|
||||
"return" => TokenKind::Return,
|
||||
"true" => TokenKind::True,
|
||||
"false" => TokenKind::False,
|
||||
"nil" => TokenKind::Nil,
|
||||
_ => TokenKind::Identifier(s),
|
||||
};
|
||||
|
||||
Token { kind, line, column }
|
||||
}
|
||||
}
|
||||
|
||||
fn is_ident_start(c: char) -> bool {
|
||||
c.is_ascii_alphabetic() || c == '_'
|
||||
}
|
||||
|
||||
fn is_ident_part(c: char) -> bool {
|
||||
is_ident_start(c) || c.is_ascii_digit()
|
||||
}
|
||||
5
src/lexer/mod.rs
Normal file
5
src/lexer/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
pub mod token;
|
||||
pub mod lexer;
|
||||
|
||||
pub use token::{Token, TokenKind};
|
||||
pub use lexer::Lexer;
|
||||
42
src/lexer/token.rs
Normal file
42
src/lexer/token.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
// lexer/token.rs
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TokenKind {
|
||||
// 单字符
|
||||
LeftParen, RightParen,
|
||||
LeftBrace, RightBrace,
|
||||
Comma, Semicolon,
|
||||
|
||||
// 运算符
|
||||
Plus, Minus, Star, Slash,
|
||||
Bang,
|
||||
Equal,
|
||||
Greater, GreaterEqual,
|
||||
Less, LessEqual,
|
||||
EqualEqual, BangEqual,
|
||||
AndAnd, OrOr,
|
||||
|
||||
// 字面量
|
||||
Identifier(String),
|
||||
Number(f64),
|
||||
String(String),
|
||||
|
||||
// 关键字
|
||||
Let,
|
||||
Fn,
|
||||
If,
|
||||
Else,
|
||||
While,
|
||||
Return,
|
||||
True,
|
||||
False,
|
||||
Nil,
|
||||
|
||||
EOF,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Token {
|
||||
pub kind: TokenKind,
|
||||
pub line: usize,
|
||||
pub column: usize,
|
||||
}
|
||||
53
src/main.rs
Normal file
53
src/main.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
mod lexer;
|
||||
mod ast;
|
||||
mod parser;
|
||||
mod interpreter;
|
||||
mod error;
|
||||
|
||||
use lexer::Lexer;
|
||||
use parser::Parser;
|
||||
use interpreter::Interpreter;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
|
||||
fn main() {
|
||||
let src = match env::args().len() {
|
||||
1 => {
|
||||
// 无参数:从 stdin 读取
|
||||
let mut buf = String::new();
|
||||
if let Err(e) = io::stdin().read_to_string(&mut buf) {
|
||||
eprintln!("Failed to read stdin: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
buf
|
||||
}
|
||||
2 => {
|
||||
// 一个参数:作为文件路径
|
||||
let path = env::args().nth(1).unwrap();
|
||||
match fs::read_to_string(&path) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Failed to read file '{}': {}", path, e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
eprintln!("Usage: aster [script_file]");
|
||||
eprintln!(" aster - run from stdin");
|
||||
eprintln!(" aster <file> - run script file");
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let tokens = Lexer::new(&src).tokenize();
|
||||
let mut parser = Parser::new(tokens);
|
||||
let stmts = parser.parse();
|
||||
|
||||
let mut interpreter = Interpreter::new();
|
||||
if let Err(e) = interpreter.interpret(stmts) {
|
||||
eprintln!("{}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
3
src/parser/mod.rs
Normal file
3
src/parser/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod parser;
|
||||
|
||||
pub use parser::Parser;
|
||||
431
src/parser/parser.rs
Normal file
431
src/parser/parser.rs
Normal file
@@ -0,0 +1,431 @@
|
||||
use crate::ast::*;
|
||||
use crate::lexer::{Token, TokenKind};
|
||||
use crate::error::RuntimeError;
|
||||
|
||||
pub struct Parser {
|
||||
tokens: Vec<Token>,
|
||||
current: usize,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(tokens: Vec<Token>) -> Self {
|
||||
Self { tokens, current: 0 }
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> Vec<Stmt> {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
while !self.is_at_end() {
|
||||
statements.push(self.declaration());
|
||||
}
|
||||
|
||||
statements
|
||||
}
|
||||
|
||||
fn declaration(&mut self) -> Stmt {
|
||||
if self.match_kind(&[TokenKind::Let]) {
|
||||
self.let_declaration()
|
||||
} else if self.match_kind(&[TokenKind::Fn]) {
|
||||
self.fn_declaration()
|
||||
} else {
|
||||
self.statement()
|
||||
}
|
||||
}
|
||||
|
||||
fn statement(&mut self) -> Stmt {
|
||||
if self.match_kind(&[TokenKind::If]) {
|
||||
self.if_statement()
|
||||
} else if self.match_kind(&[TokenKind::While]) {
|
||||
self.while_statement()
|
||||
} else if self.match_kind(&[TokenKind::Return]) {
|
||||
self.return_statement()
|
||||
} else if self.match_kind(&[TokenKind::LeftBrace]) {
|
||||
Stmt::Block(self.block())
|
||||
} else {
|
||||
self.expression_statement()
|
||||
}
|
||||
}
|
||||
|
||||
fn let_declaration(&mut self) -> Stmt {
|
||||
let name = self.consume_ident("Expected variable name.").unwrap();
|
||||
self.consume(TokenKind::Equal, "Expected '=' after variable name.").unwrap();
|
||||
let initializer = self.expression();
|
||||
self.match_kind(&[TokenKind::Semicolon]); // 分号可选
|
||||
|
||||
Stmt::Let { name, initializer }
|
||||
}
|
||||
|
||||
fn fn_declaration(&mut self) -> Stmt {
|
||||
let name = self.consume_ident("Expected function name.").unwrap();
|
||||
self.consume(TokenKind::LeftParen, "Expected '(' after function name.").unwrap();
|
||||
|
||||
let mut params = Vec::new();
|
||||
if !self.check(&TokenKind::RightParen) {
|
||||
loop {
|
||||
params.push(self.consume_ident("Expected parameter name.").unwrap());
|
||||
if !self.match_kind(&[TokenKind::Comma]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.consume(TokenKind::RightParen, "Expected ')' after parameters.").unwrap();
|
||||
self.consume(TokenKind::LeftBrace, "Expected '{' before function body.").unwrap();
|
||||
let body = self.block();
|
||||
|
||||
Stmt::Function { name, params, body }
|
||||
}
|
||||
|
||||
fn lambda_expr(&mut self) -> Expr {
|
||||
self.consume(TokenKind::LeftParen, "Expected '(' after 'fn'.").unwrap();
|
||||
let mut params = Vec::new();
|
||||
if !self.check(&TokenKind::RightParen) {
|
||||
loop {
|
||||
params.push(self.consume_ident("Expected parameter name.").unwrap());
|
||||
if !self.match_kind(&[TokenKind::Comma]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.consume(TokenKind::RightParen, "Expected ')' after parameters.").unwrap();
|
||||
self.consume(TokenKind::LeftBrace, "Expected '{' before function body.").unwrap();
|
||||
let body = self.block();
|
||||
Expr::Lambda { params, body }
|
||||
}
|
||||
|
||||
fn if_statement(&mut self) -> Stmt {
|
||||
self.consume(TokenKind::LeftParen, "Expected '(' after 'if'.").unwrap();
|
||||
let condition = self.expression();
|
||||
self.consume(TokenKind::RightParen, "Expected ')' after condition.").unwrap();
|
||||
|
||||
let then_branch = Box::new(self.statement());
|
||||
let else_branch = if self.match_kind(&[TokenKind::Else]) {
|
||||
Some(Box::new(self.statement()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Stmt::If { condition, then_branch, else_branch }
|
||||
}
|
||||
|
||||
fn while_statement(&mut self) -> Stmt {
|
||||
self.consume(TokenKind::LeftParen, "Expected '(' after 'while'.").unwrap();
|
||||
let condition = self.expression();
|
||||
self.consume(TokenKind::RightParen, "Expected ')' after condition.").unwrap();
|
||||
|
||||
let body = Box::new(self.statement());
|
||||
Stmt::While { condition, body }
|
||||
}
|
||||
|
||||
fn return_statement(&mut self) -> Stmt {
|
||||
let value = if !self.check(&TokenKind::Semicolon) && !self.check(&TokenKind::RightBrace) {
|
||||
Some(self.expression())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.match_kind(&[TokenKind::Semicolon]); // 分号可选
|
||||
Stmt::Return(value)
|
||||
}
|
||||
|
||||
fn block(&mut self) -> Vec<Stmt> {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
while !self.check(&TokenKind::RightBrace) && !self.is_at_end() {
|
||||
statements.push(self.declaration());
|
||||
}
|
||||
|
||||
self.consume(TokenKind::RightBrace, "Expected '}' after block.").unwrap();
|
||||
statements
|
||||
}
|
||||
|
||||
fn expression_statement(&mut self) -> Stmt {
|
||||
let expr = self.expression();
|
||||
self.match_kind(&[TokenKind::Semicolon]); // 分号可选
|
||||
Stmt::ExprStmt(expr)
|
||||
}
|
||||
|
||||
fn expression(&mut self) -> Expr {
|
||||
self.assignment()
|
||||
}
|
||||
|
||||
fn assignment(&mut self) -> Expr {
|
||||
let expr = self.logical_or();
|
||||
|
||||
if self.match_kind(&[TokenKind::Equal]) {
|
||||
let value = self.assignment();
|
||||
if let Expr::Variable(name) = expr {
|
||||
return Expr::Assign {
|
||||
name,
|
||||
value: Box::new(value),
|
||||
};
|
||||
} else {
|
||||
panic!("Invalid assignment target.");
|
||||
}
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn logical_or(&mut self) -> Expr {
|
||||
let mut expr = self.logical_and();
|
||||
|
||||
while self.match_kind(&[TokenKind::OrOr]) {
|
||||
let right = self.logical_and();
|
||||
expr = Expr::Logical {
|
||||
left: Box::new(expr),
|
||||
op: LogicalOp::Or,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn logical_and(&mut self) -> Expr {
|
||||
let mut expr = self.equality();
|
||||
|
||||
while self.match_kind(&[TokenKind::AndAnd]) {
|
||||
let right = self.equality();
|
||||
expr = Expr::Logical {
|
||||
left: Box::new(expr),
|
||||
op: LogicalOp::And,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn equality(&mut self) -> Expr {
|
||||
let mut expr = self.comparison();
|
||||
|
||||
while self.match_kind(&[TokenKind::EqualEqual, TokenKind::BangEqual]) {
|
||||
let op = match self.previous().kind {
|
||||
TokenKind::EqualEqual => BinaryOp::Equal,
|
||||
TokenKind::BangEqual => BinaryOp::NotEqual,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let right = self.comparison();
|
||||
expr = Expr::Binary {
|
||||
left: Box::new(expr),
|
||||
op,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn comparison(&mut self) -> Expr {
|
||||
let mut expr = self.term();
|
||||
|
||||
while self.match_kind(&[TokenKind::Greater, TokenKind::GreaterEqual, TokenKind::Less, TokenKind::LessEqual]) {
|
||||
let op = match self.previous().kind {
|
||||
TokenKind::Greater => BinaryOp::Greater,
|
||||
TokenKind::GreaterEqual => BinaryOp::GreaterEqual,
|
||||
TokenKind::Less => BinaryOp::Less,
|
||||
TokenKind::LessEqual => BinaryOp::LessEqual,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let right = self.term();
|
||||
expr = Expr::Binary {
|
||||
left: Box::new(expr),
|
||||
op,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn term(&mut self) -> Expr {
|
||||
let mut expr = self.factor();
|
||||
|
||||
while self.match_kind(&[TokenKind::Plus, TokenKind::Minus]) {
|
||||
let op = match self.previous().kind {
|
||||
TokenKind::Plus => BinaryOp::Add,
|
||||
TokenKind::Minus => BinaryOp::Sub,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let right = self.factor();
|
||||
expr = Expr::Binary {
|
||||
left: Box::new(expr),
|
||||
op,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn factor(&mut self) -> Expr {
|
||||
let mut expr = self.unary();
|
||||
|
||||
while self.match_kind(&[TokenKind::Star, TokenKind::Slash]) {
|
||||
let op = match self.previous().kind {
|
||||
TokenKind::Star => BinaryOp::Mul,
|
||||
TokenKind::Slash => BinaryOp::Div,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let right = self.unary();
|
||||
expr = Expr::Binary {
|
||||
left: Box::new(expr),
|
||||
op,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn unary(&mut self) -> Expr {
|
||||
if self.match_kind(&[TokenKind::Bang, TokenKind::Minus]) {
|
||||
let op = match self.previous().kind {
|
||||
TokenKind::Bang => UnaryOp::Not,
|
||||
TokenKind::Minus => UnaryOp::Negate,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let right = self.unary();
|
||||
return Expr::Unary {
|
||||
op,
|
||||
right: Box::new(right),
|
||||
};
|
||||
}
|
||||
|
||||
self.call()
|
||||
}
|
||||
|
||||
fn call(&mut self) -> Expr {
|
||||
let mut expr = self.primary();
|
||||
|
||||
while self.match_kind(&[TokenKind::LeftParen]) {
|
||||
let mut arguments = Vec::new();
|
||||
if !self.check(&TokenKind::RightParen) {
|
||||
loop {
|
||||
arguments.push(self.expression());
|
||||
if !self.match_kind(&[TokenKind::Comma]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.consume(TokenKind::RightParen, "Expected ')' after arguments.").unwrap();
|
||||
expr = Expr::Call {
|
||||
callee: Box::new(expr),
|
||||
arguments,
|
||||
};
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
||||
fn primary(&mut self) -> Expr {
|
||||
// 布尔值
|
||||
if self.match_kind(&[TokenKind::True]) {
|
||||
return Expr::Literal(Literal::Bool(true));
|
||||
}
|
||||
if self.match_kind(&[TokenKind::False]) {
|
||||
return Expr::Literal(Literal::Bool(false));
|
||||
}
|
||||
if self.match_kind(&[TokenKind::Nil]) {
|
||||
return Expr::Literal(Literal::Nil);
|
||||
}
|
||||
|
||||
// 数字
|
||||
if let TokenKind::Number(n) = self.peek().kind {
|
||||
self.advance();
|
||||
return Expr::Literal(Literal::Number(n));
|
||||
}
|
||||
|
||||
// 字符串
|
||||
if let TokenKind::String(s) = &self.peek().kind {
|
||||
let s = s.clone();
|
||||
self.advance();
|
||||
return Expr::Literal(Literal::String(s));
|
||||
}
|
||||
|
||||
// 标识符(变量)
|
||||
if let TokenKind::Identifier(name) = &self.peek().kind {
|
||||
let name = name.clone();
|
||||
self.advance();
|
||||
return Expr::Variable(name);
|
||||
}
|
||||
|
||||
// 匿名函数(闭包): fn(params) { body }
|
||||
if self.match_kind(&[TokenKind::Fn]) {
|
||||
return self.lambda_expr();
|
||||
}
|
||||
|
||||
// 括号表达式
|
||||
if self.match_kind(&[TokenKind::LeftParen]) {
|
||||
let expr = self.expression();
|
||||
self.consume(TokenKind::RightParen, "Expected ')' after expression.").unwrap();
|
||||
return expr;
|
||||
}
|
||||
|
||||
panic!("Expected expression at line {}", self.peek().line);
|
||||
}
|
||||
|
||||
fn match_kind(&mut self, kinds: &[TokenKind]) -> bool {
|
||||
for kind in kinds {
|
||||
if self.check(kind) {
|
||||
self.advance();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn consume(&mut self, kind: TokenKind, msg: &str) -> Result<(), RuntimeError> {
|
||||
if self.check(&kind) {
|
||||
self.advance();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RuntimeError::ParseError {
|
||||
message: msg.to_string(),
|
||||
token: self.peek().clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn consume_ident(&mut self, msg: &str) -> Result<String, RuntimeError> {
|
||||
match &self.peek().kind {
|
||||
TokenKind::Identifier(name) => {
|
||||
let name = name.clone();
|
||||
self.advance();
|
||||
Ok(name)
|
||||
}
|
||||
_ => Err(RuntimeError::ParseError {
|
||||
message: msg.to_string(),
|
||||
token: self.peek().clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&self, kind: &TokenKind) -> bool {
|
||||
if self.is_at_end() {
|
||||
return false;
|
||||
}
|
||||
std::mem::discriminant(&self.peek().kind)
|
||||
== std::mem::discriminant(kind)
|
||||
}
|
||||
|
||||
fn advance(&mut self) -> &Token {
|
||||
if !self.is_at_end() {
|
||||
self.current += 1;
|
||||
}
|
||||
self.previous()
|
||||
}
|
||||
|
||||
fn is_at_end(&self) -> bool {
|
||||
matches!(self.peek().kind, TokenKind::EOF)
|
||||
}
|
||||
|
||||
fn peek(&self) -> &Token {
|
||||
&self.tokens[self.current]
|
||||
}
|
||||
|
||||
fn previous(&self) -> &Token {
|
||||
&self.tokens[self.current - 1]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user