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:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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>,
|
||||
}
|
||||
Reference in New Issue
Block a user