feat: 实现模块引入功能以及测试
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
fn add(a, b) { return a + b; }
|
||||||
|
fn mul(a, b) { return a * b; }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
let math = require("math_mod.ast");
|
||||||
|
print(math.add(10, 32));
|
||||||
|
print(math.mul(6, 7));
|
||||||
|
print(math.add(math.mul(2, 3), 1));
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
//! 标准库:core(len, typeof, push, pop)
|
//! 标准库:core(len, typeof, push, pop)
|
||||||
|
|
||||||
use crate::error::RuntimeError;
|
use crate::error::RuntimeError;
|
||||||
use crate::interpreter::Value;
|
use crate::interpreter::{Interpreter, Value};
|
||||||
|
|
||||||
pub fn len(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn len(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "len() expects 1 argument".into(),
|
message: "len() expects 1 argument".into(),
|
||||||
@@ -21,7 +21,7 @@ pub fn len(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn typeof_fn(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn typeof_fn(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "typeof() expects 1 argument".into(),
|
message: "typeof() expects 1 argument".into(),
|
||||||
@@ -41,7 +41,7 @@ pub fn typeof_fn(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
Ok(Value::String(s.into()))
|
Ok(Value::String(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn push(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "push() expects 2 arguments (array, value)".into(),
|
message: "push() expects 2 arguments (array, value)".into(),
|
||||||
@@ -61,7 +61,7 @@ pub fn push(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn pop(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "pop() expects 1 argument (array)".into(),
|
message: "pop() expects 1 argument (array)".into(),
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
//! 标准库:io(print, input)
|
//! 标准库:io(print, input)
|
||||||
|
|
||||||
use crate::error::RuntimeError;
|
use crate::error::RuntimeError;
|
||||||
use crate::interpreter::Value;
|
use crate::interpreter::{Interpreter, Value};
|
||||||
|
|
||||||
pub fn print(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn print(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
print!("{}", arg);
|
print!("{}", arg);
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ pub fn print(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
Ok(Value::Nil)
|
Ok(Value::Nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn input(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if let Some(prompt) = args.get(0) {
|
if let Some(prompt) = args.get(0) {
|
||||||
print!("{}", prompt);
|
print!("{}", prompt);
|
||||||
std::io::Write::flush(&mut std::io::stdout()).unwrap();
|
std::io::Write::flush(&mut std::io::stdout()).unwrap();
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ pub fn register_all(env: &Rc<RefCell<Env>>) {
|
|||||||
e.define("push".into(), Value::NativeFunction(Rc::new(core::push)), true);
|
e.define("push".into(), Value::NativeFunction(Rc::new(core::push)), true);
|
||||||
e.define("pop".into(), Value::NativeFunction(Rc::new(core::pop)), true);
|
e.define("pop".into(), Value::NativeFunction(Rc::new(core::pop)), true);
|
||||||
|
|
||||||
|
// require — module loader
|
||||||
|
e.define("require".into(), Value::NativeFunction(Rc::new(super::module::require_fn)), true);
|
||||||
|
|
||||||
// string — split, trim, substring, replace, contains, upper, lower, starts_with, ends_with
|
// string — split, trim, substring, replace, contains, upper, lower, starts_with, ends_with
|
||||||
e.define("split".into(), Value::NativeFunction(Rc::new(string::split)), true);
|
e.define("split".into(), Value::NativeFunction(Rc::new(string::split)), true);
|
||||||
e.define("trim".into(), Value::NativeFunction(Rc::new(string::trim)), true);
|
e.define("trim".into(), Value::NativeFunction(Rc::new(string::trim)), true);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
//! 标准库:os(clock)
|
//! 标准库:os(clock)
|
||||||
|
|
||||||
use crate::error::RuntimeError;
|
use crate::error::RuntimeError;
|
||||||
use crate::interpreter::Value;
|
use crate::interpreter::{Interpreter, Value};
|
||||||
|
|
||||||
pub fn clock(_args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn clock(_interp: &mut Interpreter, _args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
Ok(Value::Number(
|
Ok(Value::Number(
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! 标准库:string(split, trim, substring, replace, contains, upper, lower, starts_with, ends_with)
|
//! 标准库:string(split, trim, substring, replace, contains, upper, lower, starts_with, ends_with)
|
||||||
|
|
||||||
use crate::error::RuntimeError;
|
use crate::error::RuntimeError;
|
||||||
use crate::interpreter::Value;
|
use crate::interpreter::{Interpreter, Value};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ fn require_string(val: &Value, arg_name: &str) -> Result<String, RuntimeError> {
|
|||||||
// split(str, delim) → array of substrings
|
// split(str, delim) → array of substrings
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn split(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn split(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "split() expects 2 arguments (string, delimiter)".into(),
|
message: "split() expects 2 arguments (string, delimiter)".into(),
|
||||||
@@ -43,7 +43,7 @@ pub fn split(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
// trim(str) → string with leading/trailing whitespace removed
|
// trim(str) → string with leading/trailing whitespace removed
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn trim(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn trim(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "trim() expects 1 argument (string)".into(),
|
message: "trim() expects 1 argument (string)".into(),
|
||||||
@@ -58,7 +58,7 @@ pub fn trim(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
// substring(str, start, len?) → substring
|
// substring(str, start, len?) → substring
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn substring(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn substring(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "substring() expects at least 2 arguments (string, start, len?)".into(),
|
message: "substring() expects at least 2 arguments (string, start, len?)".into(),
|
||||||
@@ -81,7 +81,7 @@ pub fn substring(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
// replace(str, old, new) → string with all occurrences replaced
|
// replace(str, old, new) → string with all occurrences replaced
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn replace(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn replace(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "replace() expects 3 arguments (string, old, new)".into(),
|
message: "replace() expects 3 arguments (string, old, new)".into(),
|
||||||
@@ -106,7 +106,7 @@ pub fn replace(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
// contains(str, needle) → bool
|
// contains(str, needle) → bool
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn contains(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn contains(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "contains() expects 2 arguments (string, needle)".into(),
|
message: "contains() expects 2 arguments (string, needle)".into(),
|
||||||
@@ -122,7 +122,7 @@ pub fn contains(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
// upper(str) → uppercase (ASCII)
|
// upper(str) → uppercase (ASCII)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn upper(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn upper(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "upper() expects 1 argument (string)".into(),
|
message: "upper() expects 1 argument (string)".into(),
|
||||||
@@ -137,7 +137,7 @@ pub fn upper(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
// lower(str) → lowercase (ASCII)
|
// lower(str) → lowercase (ASCII)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn lower(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn lower(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "lower() expects 1 argument (string)".into(),
|
message: "lower() expects 1 argument (string)".into(),
|
||||||
@@ -152,7 +152,7 @@ pub fn lower(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
// starts_with(str, prefix) → bool
|
// starts_with(str, prefix) → bool
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn starts_with(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn starts_with(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "starts_with() expects 2 arguments (string, prefix)".into(),
|
message: "starts_with() expects 2 arguments (string, prefix)".into(),
|
||||||
@@ -168,7 +168,7 @@ pub fn starts_with(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||||||
// ends_with(str, suffix) → bool
|
// ends_with(str, suffix) → bool
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
pub fn ends_with(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn ends_with(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return Err(RuntimeError::RuntimeError {
|
return Err(RuntimeError::RuntimeError {
|
||||||
message: "ends_with() expects 2 arguments (string, suffix)".into(),
|
message: "ends_with() expects 2 arguments (string, suffix)".into(),
|
||||||
|
|||||||
+23
-21
@@ -103,7 +103,7 @@ impl super::Interpreter {
|
|||||||
"length" => Ok(Value::Number(arr.borrow().len() as f64)),
|
"length" => Ok(Value::Number(arr.borrow().len() as f64)),
|
||||||
"push" => {
|
"push" => {
|
||||||
let arr = Rc::clone(&arr);
|
let arr = Rc::clone(&arr);
|
||||||
Ok(Value::NativeFunction(Rc::new(move |mut args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, mut args: Vec<Value>| {
|
||||||
let val = args.pop().unwrap_or(Value::Nil);
|
let val = args.pop().unwrap_or(Value::Nil);
|
||||||
arr.borrow_mut().push(val.clone());
|
arr.borrow_mut().push(val.clone());
|
||||||
Ok(val)
|
Ok(val)
|
||||||
@@ -111,7 +111,7 @@ impl super::Interpreter {
|
|||||||
}
|
}
|
||||||
"pop" => {
|
"pop" => {
|
||||||
let arr = Rc::clone(&arr);
|
let arr = Rc::clone(&arr);
|
||||||
Ok(Value::NativeFunction(Rc::new(move |_args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, _args: Vec<Value>| {
|
||||||
arr.borrow_mut()
|
arr.borrow_mut()
|
||||||
.pop()
|
.pop()
|
||||||
.ok_or_else(|| RuntimeError::RuntimeError {
|
.ok_or_else(|| RuntimeError::RuntimeError {
|
||||||
@@ -129,74 +129,74 @@ impl super::Interpreter {
|
|||||||
"length" => Ok(Value::Number(s.chars().count() as f64)),
|
"length" => Ok(Value::Number(s.chars().count() as f64)),
|
||||||
"upper" => {
|
"upper" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::upper(all_args)
|
super::builtins::string::upper(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"lower" => {
|
"lower" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::lower(all_args)
|
super::builtins::string::lower(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"trim" => {
|
"trim" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::trim(all_args)
|
super::builtins::string::trim(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"substring" => {
|
"substring" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::substring(all_args)
|
super::builtins::string::substring(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"replace" => {
|
"replace" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::replace(all_args)
|
super::builtins::string::replace(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"contains" => {
|
"contains" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::contains(all_args)
|
super::builtins::string::contains(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"starts_with" => {
|
"starts_with" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::starts_with(all_args)
|
super::builtins::string::starts_with(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"ends_with" => {
|
"ends_with" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::ends_with(all_args)
|
super::builtins::string::ends_with(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
"split" => {
|
"split" => {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
Ok(Value::NativeFunction(Rc::new(move |args: Vec<Value>| {
|
Ok(Value::NativeFunction(Rc::new(move |_interp: &mut Self, args: Vec<Value>| {
|
||||||
let mut all_args = vec![Value::String(s.clone())];
|
let mut all_args = vec![Value::String(s.clone())];
|
||||||
all_args.extend(args);
|
all_args.extend(args);
|
||||||
super::builtins::string::split(all_args)
|
super::builtins::string::split(_interp, all_args)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
_ => Err(RuntimeError::RuntimeError {
|
_ => Err(RuntimeError::RuntimeError {
|
||||||
@@ -481,7 +481,7 @@ impl super::Interpreter {
|
|||||||
|
|
||||||
pub fn call_function(&mut self, func_val: Value, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn call_function(&mut self, func_val: Value, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
match func_val {
|
match func_val {
|
||||||
Value::NativeFunction(native_fn) => native_fn(args),
|
Value::NativeFunction(native_fn) => native_fn(self, args),
|
||||||
Value::Function(f) => self.call_user_function(f, args),
|
Value::Function(f) => self.call_user_function(f, args),
|
||||||
_ => Err(RuntimeError::RuntimeError {
|
_ => Err(RuntimeError::RuntimeError {
|
||||||
message: "Attempt to call non-function".to_string(),
|
message: "Attempt to call non-function".to_string(),
|
||||||
@@ -553,6 +553,8 @@ impl super::Interpreter {
|
|||||||
y.get(k).map_or(false, |yv| self.is_equal(v, yv))
|
y.get(k).map_or(false, |yv| self.is_equal(v, yv))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
(Value::Function(x), Value::Function(y)) => Rc::ptr_eq(x, y),
|
||||||
|
(Value::NativeFunction(x), Value::NativeFunction(y)) => Rc::ptr_eq(x, y),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,45 @@
|
|||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::error::RuntimeError;
|
use crate::error::RuntimeError;
|
||||||
use super::{Env};
|
use super::{Env, Value};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
pub struct Interpreter {
|
pub struct Interpreter {
|
||||||
|
/// 当前作用域(用户代码所在 env,parent 指向 builtins_env)
|
||||||
pub env: Rc<RefCell<Env>>,
|
pub env: Rc<RefCell<Env>>,
|
||||||
|
/// 内置函数根作用域(parent = None,所有内置函数注册在此)
|
||||||
|
pub builtins_env: Rc<RefCell<Env>>,
|
||||||
|
/// 模块缓存:规范路径 → exports 对象
|
||||||
|
pub module_cache: RefCell<HashMap<String, Value>>,
|
||||||
|
/// 当前执行文件的目录,用于 require() 解析相对路径
|
||||||
|
pub current_dir: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpreter {
|
impl Interpreter {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let env = Rc::new(RefCell::new(Env::new(None)));
|
// 根层:仅包含内置函数
|
||||||
super::builtins::register_all(&env);
|
let builtins_env = Rc::new(RefCell::new(Env::new(None)));
|
||||||
Self { env }
|
super::builtins::register_all(&builtins_env);
|
||||||
|
|
||||||
|
// 用户层:parent 指向 builtins_env,用户定义的变量都在这层
|
||||||
|
let script_env = Rc::new(RefCell::new(Env::new(Some(Rc::clone(&builtins_env)))));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
env: script_env,
|
||||||
|
builtins_env,
|
||||||
|
module_cache: RefCell::new(HashMap::new()),
|
||||||
|
current_dir: std::env::current_dir()
|
||||||
|
.map(|p| p.to_string_lossy().to_string())
|
||||||
|
.unwrap_or_else(|_| ".".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 指定当前目录的构造器,用于 `run_file` 时设置脚本所在目录
|
||||||
|
pub fn with_current_dir(dir: String) -> Self {
|
||||||
|
let mut interp = Self::new();
|
||||||
|
interp.current_dir = dir;
|
||||||
|
interp
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret(&mut self, statements: Vec<Stmt>) -> Result<(), RuntimeError> {
|
pub fn interpret(&mut self, statements: Vec<Stmt>) -> Result<(), RuntimeError> {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pub mod env;
|
|||||||
pub mod eval;
|
pub mod eval;
|
||||||
pub mod exec;
|
pub mod exec;
|
||||||
pub mod interpreter;
|
pub mod interpreter;
|
||||||
|
pub mod module;
|
||||||
|
|
||||||
pub use env::Env;
|
pub use env::Env;
|
||||||
pub use interpreter::Interpreter;
|
pub use interpreter::Interpreter;
|
||||||
@@ -12,7 +13,7 @@ use std::rc::Rc;
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub type NativeFn = Rc<dyn Fn(Vec<Value>) -> Result<Value, crate::error::RuntimeError>>;
|
pub type NativeFn = Rc<dyn Fn(&mut super::Interpreter, Vec<Value>) -> Result<Value, crate::error::RuntimeError>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
//! 模块系统:require() 加载器
|
||||||
|
//!
|
||||||
|
//! `require("path/to/module.ast")` 加载并执行指定的 Aster 文件,
|
||||||
|
//! 返回一个包含模块所有顶层定义的 `Value::Object`。
|
||||||
|
//! 模块在自己的作用域中执行,只能访问内置函数,无法访问调用者的变量。
|
||||||
|
//! 第二次 require 同一文件会返回缓存的对象。
|
||||||
|
|
||||||
|
use crate::error::RuntimeError;
|
||||||
|
use crate::lexer::Lexer;
|
||||||
|
use crate::parser::Parser;
|
||||||
|
use super::{Interpreter, Env, Value, Signal};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// require() 的内置函数实现
|
||||||
|
pub fn require_fn(interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
// 1. 参数验证
|
||||||
|
let path_str = match args.first() {
|
||||||
|
Some(Value::String(s)) => s.clone(),
|
||||||
|
Some(other) => return Err(runtime_error(format!(
|
||||||
|
"require() expects a string argument, got {}", other))),
|
||||||
|
None => return Err(runtime_error(
|
||||||
|
"require() expects 1 argument (string path)")),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. 路径解析
|
||||||
|
let resolved = resolve_path(&interp.current_dir, &path_str)?;
|
||||||
|
|
||||||
|
// 3. 缓存查找
|
||||||
|
if let Some(cached) = interp.module_cache.borrow().get(&resolved) {
|
||||||
|
return Ok(cached.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 读取文件
|
||||||
|
let src = std::fs::read_to_string(&resolved)
|
||||||
|
.map_err(|e| runtime_error(format!(
|
||||||
|
"Module '{}' not found: {}", path_str, e)))?;
|
||||||
|
|
||||||
|
// 5. 词法分析
|
||||||
|
let (tokens, lex_errors) = Lexer::new(&src).tokenize();
|
||||||
|
if !lex_errors.is_empty() {
|
||||||
|
return Err(runtime_error(format!(
|
||||||
|
"Lex error in module '{}': {}", path_str, lex_errors[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 语法分析
|
||||||
|
let mut parser = Parser::new(tokens);
|
||||||
|
let (stmts, parse_errors) = parser.parse();
|
||||||
|
if !parse_errors.is_empty() {
|
||||||
|
return Err(runtime_error(format!(
|
||||||
|
"Parse error in module '{}': {}", path_str, parse_errors[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 创建隔离的模块 env(父级 = builtins_env,看不到调用者的变量)
|
||||||
|
let module_env = Rc::new(RefCell::new(Env::new(Some(Rc::clone(&interp.builtins_env)))));
|
||||||
|
|
||||||
|
// 8. 在缓存中插入占位符(支持循环 require)
|
||||||
|
let exports_map = Rc::new(RefCell::new(HashMap::new()));
|
||||||
|
let exports = Value::Object(Rc::clone(&exports_map));
|
||||||
|
interp.module_cache.borrow_mut().insert(resolved.clone(), exports.clone());
|
||||||
|
|
||||||
|
// 9. 保存调用者状态
|
||||||
|
let previous_env = Rc::clone(&interp.env);
|
||||||
|
let previous_dir = interp.current_dir.clone();
|
||||||
|
|
||||||
|
// 10. 切换到模块上下文
|
||||||
|
interp.env = module_env.clone();
|
||||||
|
interp.current_dir = module_dir(&resolved);
|
||||||
|
|
||||||
|
// 11. 执行模块
|
||||||
|
for stmt in &stmts {
|
||||||
|
match interp.execute(stmt.clone()) {
|
||||||
|
Ok(Signal::Break) | Ok(Signal::Continue) => {
|
||||||
|
// 恢复状态后返回错误
|
||||||
|
interp.env = previous_env;
|
||||||
|
interp.current_dir = previous_dir;
|
||||||
|
interp.module_cache.borrow_mut().remove(&resolved);
|
||||||
|
return Err(runtime_error(
|
||||||
|
"break/continue outside of loop in module"));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// 恢复状态后传播错误
|
||||||
|
interp.env = previous_env;
|
||||||
|
interp.current_dir = previous_dir;
|
||||||
|
interp.module_cache.borrow_mut().remove(&resolved);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
Ok(Signal::None) | Ok(Signal::Return(_)) => {
|
||||||
|
// 正常执行或顶层 return,继续
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 12. 恢复调用者状态
|
||||||
|
interp.env = previous_env;
|
||||||
|
interp.current_dir = previous_dir;
|
||||||
|
|
||||||
|
// 13. 收集 exports(模块 env 中的所有直接绑定)
|
||||||
|
for (name, (val, _mutable)) in module_env.borrow().values.clone() {
|
||||||
|
exports_map.borrow_mut().insert(name, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(exports)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helpers
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/// 解析模块路径:相对路径基于 current_dir,用 canonicalize 规范化
|
||||||
|
fn resolve_path(current_dir: &str, path_str: &str) -> Result<String, RuntimeError> {
|
||||||
|
let path = Path::new(path_str);
|
||||||
|
let resolved = if path.is_absolute() {
|
||||||
|
path.to_path_buf()
|
||||||
|
} else {
|
||||||
|
Path::new(current_dir).join(path)
|
||||||
|
};
|
||||||
|
std::fs::canonicalize(&resolved)
|
||||||
|
.map(|p| p.to_string_lossy().to_string())
|
||||||
|
.map_err(|_| runtime_error(format!(
|
||||||
|
"Module '{}' not found (resolved to '{}')",
|
||||||
|
path_str, resolved.display())))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 提取模块文件所在目录
|
||||||
|
fn module_dir(resolved: &str) -> String {
|
||||||
|
Path::new(resolved)
|
||||||
|
.parent()
|
||||||
|
.map(|p| p.to_string_lossy().to_string())
|
||||||
|
.unwrap_or_else(|| ".".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn runtime_error(msg: impl Into<String>) -> RuntimeError {
|
||||||
|
RuntimeError::RuntimeError {
|
||||||
|
message: msg.into(),
|
||||||
|
token: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1626,3 +1626,110 @@ fn error_string_unknown_property() {
|
|||||||
});
|
});
|
||||||
assert!(result.is_err(), "Expected error for unknown string property");
|
assert!(result.is_err(), "Expected error for unknown string property");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Module system (require)
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_math_module() {
|
||||||
|
let interp = run("let math = require(\"tests/fixtures/math.ast\");");
|
||||||
|
let math = get_var(&interp, "math");
|
||||||
|
match math {
|
||||||
|
Value::Object(obj) => {
|
||||||
|
let obj = obj.borrow();
|
||||||
|
assert!(obj.contains_key("add"), "math should contain 'add'");
|
||||||
|
assert!(obj.contains_key("mul"), "math should contain 'mul'");
|
||||||
|
assert!(obj.contains_key("version"), "math should contain 'version'");
|
||||||
|
}
|
||||||
|
v => panic!("Expected Object, got {:?}", v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_call_exported_function() {
|
||||||
|
let interp = run(r#"
|
||||||
|
let math = require("tests/fixtures/math.ast");
|
||||||
|
let result = math.add(10, 32);
|
||||||
|
"#);
|
||||||
|
assert_num(&get_var(&interp, "result"), 42.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_cache_returns_same_object() {
|
||||||
|
let interp = run(r#"
|
||||||
|
let a = require("tests/fixtures/math.ast");
|
||||||
|
let b = require("tests/fixtures/math.ast");
|
||||||
|
let same = a == b;
|
||||||
|
"#);
|
||||||
|
assert_bool(&get_var(&interp, "same"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_module_isolation() {
|
||||||
|
// 模块看不到调用者的变量,但模块内部定义可以正常工作
|
||||||
|
let interp = run(r#"
|
||||||
|
let secret = 99;
|
||||||
|
let g = require("tests/fixtures/greet.ast");
|
||||||
|
let msg = g.greet("Aster");
|
||||||
|
"#);
|
||||||
|
match get_var(&interp, "msg") {
|
||||||
|
Value::String(s) => assert_eq!(s, "Hello!"),
|
||||||
|
v => panic!("Expected String, got {:?}", v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_module_with_builtins() {
|
||||||
|
// 模块内部可以使用内置函数(因为 builtins_env 是模块 env 的祖先)
|
||||||
|
let interp = run(r#"
|
||||||
|
let m = require("tests/fixtures/math.ast");
|
||||||
|
let r = m.add(5, 7);
|
||||||
|
"#);
|
||||||
|
assert_num(&get_var(&interp, "r"), 12.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_error_file_not_found() {
|
||||||
|
let result = std::panic::catch_unwind(|| {
|
||||||
|
run("let x = require(\"nonexistent_file_xyz.ast\");");
|
||||||
|
});
|
||||||
|
assert!(result.is_err(), "Expected error for missing module file");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_error_no_args() {
|
||||||
|
let result = std::panic::catch_unwind(|| {
|
||||||
|
run("let x = require();");
|
||||||
|
});
|
||||||
|
assert!(result.is_err(), "Expected error for require() with no args");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_error_non_string_arg() {
|
||||||
|
let result = std::panic::catch_unwind(|| {
|
||||||
|
run("let x = require(42);");
|
||||||
|
});
|
||||||
|
assert!(result.is_err(), "Expected error for require() with non-string arg");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_error_broken_syntax() {
|
||||||
|
let result = std::panic::catch_unwind(|| {
|
||||||
|
run("let x = require(\"tests/fixtures/broken_syntax.ast\");");
|
||||||
|
});
|
||||||
|
assert!(result.is_err(), "Expected error for module with syntax error");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_require_empty_module() {
|
||||||
|
// 空模块应该返回空对象
|
||||||
|
let interp = run("let empty = require(\"tests/fixtures/sub/mod.ast\");");
|
||||||
|
match get_var(&interp, "empty") {
|
||||||
|
Value::Object(obj) => {
|
||||||
|
let obj = obj.borrow();
|
||||||
|
assert!(obj.contains_key("sub"), "empty module should contain 'sub'");
|
||||||
|
}
|
||||||
|
v => panic!("Expected Object, got {:?}", v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+8
-3
@@ -20,7 +20,7 @@ fn print_errors(errors: &[RuntimeError]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_file(src: String) {
|
fn run_file(filename: &str, src: String) {
|
||||||
let (tokens, lex_errors) = Lexer::new(&src).tokenize();
|
let (tokens, lex_errors) = Lexer::new(&src).tokenize();
|
||||||
if !lex_errors.is_empty() {
|
if !lex_errors.is_empty() {
|
||||||
print_errors(&lex_errors);
|
print_errors(&lex_errors);
|
||||||
@@ -34,7 +34,12 @@ fn run_file(src: String) {
|
|||||||
std::process::exit(65);
|
std::process::exit(65);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut interpreter = Interpreter::new();
|
let script_dir = std::path::Path::new(filename)
|
||||||
|
.parent()
|
||||||
|
.map(|p| p.to_string_lossy().to_string())
|
||||||
|
.unwrap_or_else(|| ".".to_string());
|
||||||
|
|
||||||
|
let mut interpreter = Interpreter::with_current_dir(script_dir);
|
||||||
if let Err(e) = interpreter.interpret(stmts) {
|
if let Err(e) = interpreter.interpret(stmts) {
|
||||||
eprintln!("Error: {}", e);
|
eprintln!("Error: {}", e);
|
||||||
std::process::exit(70);
|
std::process::exit(70);
|
||||||
@@ -104,7 +109,7 @@ fn main() {
|
|||||||
2 => {
|
2 => {
|
||||||
let filename = &args[1];
|
let filename = &args[1];
|
||||||
match fs::read_to_string(filename) {
|
match fs::read_to_string(filename) {
|
||||||
Ok(src) => run_file(src),
|
Ok(src) => run_file(filename, src),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error reading file '{}': {}", filename, e);
|
eprintln!("Error reading file '{}': {}", filename, e);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
|
|||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fn broken ( {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
fn greet(name) { return "Hello!"; }
|
||||||
|
let version = 1;
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fn add(a, b) { return a + b; }
|
||||||
|
fn mul(a, b) { return a * b; }
|
||||||
|
let version = "1.0";
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
fn sub(a, b) { return a - b; }
|
||||||
Reference in New Issue
Block a user