diff --git a/Cargo.toml b/Cargo.toml index b7b2c07..97fde7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,18 +18,25 @@ keywords = ["interpreter", "scripting"] [features] default = ["async"] -async = ["futures", "tokio"] - +async = [ "futures", "parking_lot" ] [dependencies] futures = { version = "0.3", optional = true } log = "0.4" +parking_lot = { version = "0.12", optional = true } pest = "2" pest_derive = "2" petgraph = "0.8" -tokio = { version = "1", features = ["full"], optional = true } + [dev-dependencies] +criterion = "0.6" env_logger = "0.11" -reqwest = { version = "0.12", features = ["rustls-tls"] } +hyper = { version = "1", features = ["full"] } +hyper-util = { version = "0.1", features = ["full"] } tokio = { version = "1", features = ["full"] } + + +[[bench]] +name = "vm_benchmark" +harness = false diff --git a/README.md b/README.md index 36f4eac..5d8cf36 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,56 @@ float number, f64. string quote by `"` + +## variable + +variable name is a string, start with `_` or letter, and can contain letter, number, `_`. + +```rust +let a; +let a = 1; +``` + +## expression + +```rust +1 + 2 * 3; +``` + +### operator + + +| operator | description | +| -------- | ----------- | +| `+` | add | +| `-` | subtract | +| `*` | multiply | +| `/` | divide | +| `%` | remainder | +| `==` | equal | +| `!=` | not equal | +| `<` | less than | +| `<=` | less than or equal | +| `>` | greater than | +| `>=` | greater than or equal | +| `&&` | and | +| `\|\|` | or | +| `!` | not | +| `=` | assign | +| `+=` | add assign | +| `-=` | subtract assign | +| `*=` | multiply assign | +| `/=` | divide assign | +| `%=` | remainder assign | +| `[]` | index | +| `.` | member | +| `()` | call | +| `..` | range | + + ## control flow -### loop +### loop statement `loop` to repeat. @@ -73,15 +120,15 @@ string quote by `"` loop {} ``` -### while +### while statement -`while` to repeat. +`while` to conditional repeat. ```rust while condition {} ``` -### for +### for statement `for` to iterate. @@ -89,7 +136,7 @@ while condition {} for i in 0..=10 {} ``` -### if +### if statement `if` to choose branch. @@ -97,19 +144,19 @@ for i in 0..=10 {} if condition {} else {} ``` -### break +### break statement `break` to exist loop. -### continue +### continue statement `continue` to finish one iterate. -### return +### return statement `return` to return value. -## fn +## fn item ### user defined function diff --git a/benches/mod.rs b/benches/mod.rs new file mode 100644 index 0000000..ebacfd2 --- /dev/null +++ b/benches/mod.rs @@ -0,0 +1 @@ +pub mod vm_benchmark; diff --git a/benches/vm_benchmark.rs b/benches/vm_benchmark.rs new file mode 100644 index 0000000..d3fb889 --- /dev/null +++ b/benches/vm_benchmark.rs @@ -0,0 +1,114 @@ +use std::sync::Arc; + +use criterion::{Criterion, criterion_group, criterion_main}; +use evalit::{Environment, Interpreter, Module, Object, VM, compile}; + +fn run_script(code: &str) -> Result<(), String> { + Interpreter::eval(code, Environment::new()); + + Ok(()) +} + +fn run_vm(program: Arc, env: Environment) -> T { + let mut vm = VM::new(program, env); + + #[cfg(not(feature = "async"))] + return vm.run().unwrap().unwrap().take().into_inner().unwrap(); + + #[cfg(feature = "async")] + return futures::executor::block_on(async { + vm.run() + .await + .unwrap() + .unwrap() + .take() + .into_inner() + .unwrap() + }); +} + +fn bench_simple_math(c: &mut Criterion) { + c.bench_function("simple math", |b| { + b.iter(|| { + run_script("1 + 2 * 3 - 4 / 5;").unwrap(); + }) + }); +} + +fn bench_function_call(c: &mut Criterion) { + let script = r#" + fn inc(x) { x + 1; } + for i in 0..1000 { + inc(i); + } + "#; + + c.bench_function("function call", |b| { + b.iter(|| { + run_script(script).unwrap(); + }) + }); +} + +fn bench_array_index_access(c: &mut Criterion) { + let script = r#" + let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + for i in 0..1000 { + arr[i % 10] = arr[(i + 1) % 10]; + } + "#; + + c.bench_function("array index access", |b| { + b.iter(|| { + run_script(script).unwrap(); + }) + }); +} + +fn bench_fibonacci(c: &mut Criterion) { + let script = r#" + fn fib(n) { + if n <= 1 { + return n; + } + return fib(n - 1) + fib(n - 2); + } + return fib(10); + "#; + + let env = Environment::new(); + let module = compile(script, &env).map_err(|e| e.to_string()).unwrap(); + + c.bench_function("fibonacci", |b| { + b.iter(|| { + let ret = run_vm::(module.clone(), env.clone()); + assert_eq!(ret, 55); + }) + }); +} + +fn bench_native_fibonacci(c: &mut Criterion) { + fn fib(n: i64) -> i64 { + if n <= 1 { + return n; + } + return fib(n - 1) + fib(n - 2); + } + + c.bench_function("native fibonacci", |b| { + b.iter(|| { + fib(10); + }) + }); +} + +// 注册新的 benchmark 到 criterion_group! +criterion_group!( + benches, + bench_simple_math, + bench_function_call, + bench_array_index_access, + bench_fibonacci, + bench_native_fibonacci, +); +criterion_main!(benches); diff --git a/examples/eval.rs b/examples/eval.rs new file mode 100644 index 0000000..b1b90ca --- /dev/null +++ b/examples/eval.rs @@ -0,0 +1,34 @@ +use evalit::{Environment, ValueRef, eval}; + +fn main() { + let mut env = Environment::new(); + + env.define_function("println", println); + + let script = r#" + println("hello, world"); + + let sum = 0; + for i in 0..=10 { + sum += i; + } + + return sum; + "#; + + let retval = eval::(script, env).unwrap(); + + println!("ret: {retval:?}"); + + assert_eq!(retval, Some(55)); +} + +fn println(args: &[ValueRef]) { + let s = args + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(""); + + println!("{s}"); +} diff --git a/examples/hello.rs b/examples/hello.rs deleted file mode 100644 index c4fd11f..0000000 --- a/examples/hello.rs +++ /dev/null @@ -1,83 +0,0 @@ -use evalit::{Environment, Interpreter, ValueRef}; - -#[cfg(not(feature = "async"))] -fn main() { - let mut env = Environment::new(); - - env.define_function("println", println); - - let script = r#" - println("hello, world"); - - let sum = 0; - for i in 0..=10 { - sum += i; - } - - println(resp); - - - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap(); - - println!("ret: {retval:?}"); -} - -#[cfg(feature = "async")] -#[tokio::main] -async fn main() { - let mut env = Environment::new(); - - env.define_function("println", println); - env.define_function("http_get", http_get); - - let script = r#" - println("hello, world"); - - let sum = 0; - for i in 0..=10 { - sum += i; - } - - let resp = http_get("https://bing.com").await; - - - println(resp); - - - return sum; - "#; - - let retval = Interpreter::eval_script_async(script, env).await.unwrap(); - - println!("ret: {retval:?}"); -} - -#[cfg(feature = "async")] -use evalit::{Promise, Value}; - -#[cfg(feature = "async")] -fn http_get(url: String) -> Promise { - use evalit::Promise; - - Promise::new(async move { - println!("url: {url:?}"); - - let resp = reqwest::get(url).await.unwrap(); - let body = resp.text().await.unwrap(); - - Value::new(body) - }) -} - -fn println(args: &[ValueRef]) { - let s = args - .iter() - .map(|v| format!("{v}")) - .collect::>() - .join(""); - - println!("{s}"); -} diff --git a/examples/scripting.rs b/examples/scripting.rs new file mode 100644 index 0000000..8f1c642 --- /dev/null +++ b/examples/scripting.rs @@ -0,0 +1,305 @@ +#[cfg(feature = "async")] +#[tokio::main] +async fn main() { + scripting::run().await +} + +#[cfg(feature = "async")] +mod scripting { + + use std::{fmt, sync::Arc}; + + use evalit::{Environment, Module, Object, RuntimeError, VM, ValueRef, compile}; + use hyper::{ + body::Incoming, + header::{HeaderName, HeaderValue}, + }; + use hyper_util::rt::TokioExecutor; + use tokio::net::TcpListener; + + pub async fn run() { + use hyper::service::service_fn; + use hyper_util::rt::TokioIo; + + let listener = TcpListener::bind("127.0.0.1:5000").await.unwrap(); + + println!("Listening on http://{}", listener.local_addr().unwrap()); + + let script = script(); + + while let Ok((socket, remote_addr)) = listener.accept().await { + let server = hyper_util::server::conn::auto::Builder::new(TokioExecutor::new()); + + let script = script.clone(); + let remote_addr = remote_addr.to_string(); + + tokio::task::spawn(async move { + let ret = server.serve_connection_with_upgrades( + TokioIo::new(socket), + service_fn(|req| { + let script_cloned = script.clone(); + let remote_addr_cloned = remote_addr.clone(); + + async move { + let mut env = Environment::new(); + + env.insert("request", RequestWrapper::new(req, remote_addr_cloned)); + env.insert("response", ResponseWrapper::new()); + + let mut vm = VM::new(script_cloned, env.clone()); + + let result = vm.run().await; + assert!(result.is_ok()); + + let req = env.remove_as::("request").unwrap(); + let rsp = env.remove_as::("response").unwrap(); + + println!( + "Accepted request from: {:?}", + req.inner.headers().get("X-Real-Ip") + ); + + Ok::<_, String>(rsp.into_inner()) + } + }), + ); + + if let Err(e) = ret.await { + log::error!("serve_connection error: {:?}", e); + } + }); + } + } + + fn script() -> Arc { + let mut env = Environment::new(); + env.insert("request", ()); + + let script = r#" + request.set_header("X-Hello", "World"); + request.remove_header("X-Hello"); + let remote_addr = request.remote_addr(); + request.set_header("X-Real-Ip", remote_addr); + + $response.set_header("Content-Type", "application/json"); + $response.set_body("{\"message\": \"Hello, World!\"}"); + "#; + + compile(script, &env).unwrap() + } + + struct RequestWrapper { + inner: hyper::Request, + remote_addr: String, + } + + impl RequestWrapper { + fn new(inner: hyper::Request, remote_addr: String) -> Self { + Self { inner, remote_addr } + } + } + + impl fmt::Debug for RequestWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Request") + .field("inner", &self.inner) + .finish() + } + } + + impl Object for RequestWrapper { + fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } + + fn call_method( + &mut self, + method: &str, + args: &[evalit::ValueRef], + ) -> Result, evalit::RuntimeError> { + match method { + "get_header" => { + if args.len() != 1 { + return Err(evalit::RuntimeError::invalid_argument_count(1, 0)); + } + + match args[0].value().downcast_ref::() { + Some(header_name) => { + if let Some(header_value) = + self.inner.headers().get(header_name.as_str()) + { + return Ok(header_value + .to_str() + .ok() + .map(|header_value| ValueRef::new(header_value.to_string()))); + } + + return Ok(None); + } + None => { + return Err(evalit::RuntimeError::invalid_argument::( + 0, &args[0], + )); + } + } + } + + "set_header" => { + if args.len() != 2 { + return Err(evalit::RuntimeError::invalid_argument_count(2, 0)); + } + + match ( + args[0].value().downcast_ref::(), + args[1].value().downcast_ref::(), + ) { + (Some(header_name), Some(header_value)) => { + self.inner.headers_mut().insert( + HeaderName::from_bytes(header_name.as_str().as_bytes()).unwrap(), + HeaderValue::from_bytes(header_value.as_str().as_bytes()).unwrap(), + ); + + return Ok(None); + } + _ => { + return Err(evalit::RuntimeError::invalid_argument::( + 0, &args[0], + )); + } + } + } + + "remove_header" => { + if args.len() != 1 { + return Err(evalit::RuntimeError::invalid_argument_count(1, 0)); + } + + match args[0].value().downcast_ref::() { + Some(header_name) => { + self.inner.headers_mut().remove(header_name.as_str()); + + return Ok(None); + } + None => { + return Err(evalit::RuntimeError::invalid_argument::( + 0, &args[0], + )); + } + } + } + + "remote_addr" => { + if !args.is_empty() { + return Err(evalit::RuntimeError::invalid_argument_count(1, 0)); + } + return Ok(Some(ValueRef::new(self.remote_addr.clone()))); + } + + _ => { + return Err(evalit::RuntimeError::missing_method::(method)); + } + } + } + } + + struct ResponseWrapper { + inner: hyper::Response, + } + + impl ResponseWrapper { + fn new() -> Self { + Self { + inner: hyper::Response::new(String::new()), + } + } + + fn into_inner(self) -> hyper::Response { + self.inner + } + + // 新增: 设置响应状态码 + fn set_status(&mut self, status: u16) { + *self.inner.status_mut() = hyper::StatusCode::from_u16(status).unwrap(); + } + + // 新增: 设置响应头部 + fn set_header(&mut self, header_name: &str, header_value: &str) { + self.inner.headers_mut().insert( + hyper::header::HeaderName::from_bytes(header_name.as_bytes()).unwrap(), + hyper::header::HeaderValue::from_bytes(header_value.as_bytes()).unwrap(), + ); + } + + // 新增: 设置响应主体 + fn set_body(&mut self, body: String) { + *self.inner.body_mut() = body; + } + } + + impl fmt::Debug for ResponseWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Response") + .field("inner", &self.inner) + .finish() + } + } + + impl Object for ResponseWrapper { + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + match method { + "set_status" => { + if args.len() != 1 { + return Err(RuntimeError::invalid_argument_count(1, args.len())); + } + + if let Some(status) = args[0].value().downcast_ref::() { + self.set_status(*status); + return Ok(None); + } + + Err(RuntimeError::invalid_argument::(0, &args[0])) + } + + "set_header" => { + if args.len() != 2 { + return Err(RuntimeError::invalid_argument_count(2, args.len())); + } + + if let (Some(header_name), Some(header_value)) = ( + args[0].value().downcast_ref::(), + args[1].value().downcast_ref::(), + ) { + self.set_header(header_name, header_value); + return Ok(None); + } + + Err(RuntimeError::invalid_argument::(0, &args[0])) + } + + "set_body" => { + if args.len() != 1 { + return Err(RuntimeError::invalid_argument_count(1, args.len())); + } + + if let Some(body) = args[0].value().downcast_ref::() { + self.set_body(body.clone()); + return Ok(None); + } + + Err(RuntimeError::invalid_argument::(0, &args[0])) + } + + _ => Err(RuntimeError::missing_method::(method)), + } + } + } +} + +#[cfg(not(feature = "async"))] +fn main() { + println!("This example requires the 'async' feature"); +} diff --git a/src/ast.rs b/src/ast.rs deleted file mode 100644 index 8552d57..0000000 --- a/src/ast.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod ast; -// mod interpreter; -mod parser; - -pub use ast::*; -pub use parser::{ParseError, parse_file}; diff --git a/src/bytecode.rs b/src/bytecode.rs index ab772a7..1026673 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -26,56 +26,38 @@ impl Module { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct Bytecode { pub opcode: Opcode, - pub operands: [Operand; 4], + pub operands: [Operand; 3], } impl Bytecode { pub fn empty(opcode: Opcode) -> Self { Self { opcode, - operands: [Operand::Immd(0); 4], + operands: [Operand::Immd(0); 3], } } pub fn single(opcode: Opcode, operand: Operand) -> Self { Self { opcode, - operands: [ - operand, - Operand::Immd(0), - Operand::Immd(0), - Operand::Immd(0), - ], + operands: [operand, Operand::Immd(0), Operand::Immd(0)], } } pub fn double(opcode: Opcode, dst: Operand, src: Operand) -> Self { Self { opcode, - operands: [dst, src, Operand::Immd(0), Operand::Immd(0)], + operands: [dst, src, Operand::Immd(0)], } } pub fn triple(opcode: Opcode, dst: Operand, src1: Operand, src2: Operand) -> Self { Self { opcode, - operands: [dst, src1, src2, Operand::Immd(0)], - } - } - - pub fn quadruple( - opcode: Opcode, - dst: Operand, - src1: Operand, - src2: Operand, - src3: Operand, - ) -> Self { - Self { - opcode, - operands: [dst, src1, src2, src3], + operands: [dst, src1, src2], } } } @@ -141,8 +123,8 @@ pub enum Opcode { Mulx, /// divx dst, src1, src2 (object division) Divx, - /// modx dst, src1, src2 (object modulo) - Modx, + /// remx dst, src1, src2 (object remainder) + Remx, /// and dst, src1, src2 And, /// or dst, src1, src2 @@ -179,8 +161,6 @@ pub enum Opcode { RangeToInclusive, /// make_iter dst, src MakeIter, - /// iter_has_next dst, src - IterHasNext, /// iter_next dst, src IterNext, /// make_array dst @@ -195,12 +175,16 @@ pub enum Opcode { IndexSet, /// make_slice dst, object, range MakeSlice, + /// make_struct dst + MakeStruct, + /// make_struct_field obj, field, value + MakeStructField, /// prop_get dst, obj, prop PropGet, /// prop_set obj, prop, value PropSet, - /// prop_call dst, obj, prop - PropCall, + /// call_method dst, obj, method + CallMethod, /// await dst, promise Await, } @@ -231,7 +215,7 @@ impl fmt::Display for Opcode { Opcode::Subx => write!(f, "subx"), Opcode::Mulx => write!(f, "mulx"), Opcode::Divx => write!(f, "divx"), - Opcode::Modx => write!(f, "modx"), + Opcode::Remx => write!(f, "remx"), Opcode::And => write!(f, "and"), Opcode::Or => write!(f, "or"), Opcode::Less => write!(f, "lt"), @@ -247,7 +231,6 @@ impl fmt::Display for Opcode { Opcode::RangeTo => write!(f, "range_to"), Opcode::RangeToInclusive => write!(f, "range_to_inclusive"), Opcode::MakeIter => write!(f, "make_iter"), - Opcode::IterHasNext => write!(f, "iter_has_next"), Opcode::IterNext => write!(f, "iter_next"), Opcode::MakeArray => write!(f, "make_array"), Opcode::ArrayPush => write!(f, "array_push"), @@ -255,9 +238,11 @@ impl fmt::Display for Opcode { Opcode::IndexGet => write!(f, "index_get"), Opcode::IndexSet => write!(f, "index_set"), Opcode::MakeSlice => write!(f, "make_slice"), + Opcode::MakeStruct => write!(f, "make_struct"), + Opcode::MakeStructField => write!(f, "make_struct_field"), Opcode::PropGet => write!(f, "prop_get"), Opcode::PropSet => write!(f, "prop_set"), - Opcode::PropCall => write!(f, "prop_call"), + Opcode::CallMethod => write!(f, "call_method"), Opcode::Await => write!(f, "await"), } } @@ -338,13 +323,11 @@ pub enum Register { R14, R15, /// Stack pointer - RSP, - /// - RBP, - /// Program counter - PC, + Rsp, + /// Base pointer + Rbp, /// Return value - RV, + Rv, } impl Register { @@ -377,7 +360,7 @@ impl Register { [Register::R0, Register::R1, Register::R2, Register::R3] } - pub fn all() -> [Register; 20] { + pub fn all() -> [Register; 19] { [ Register::R0, Register::R1, @@ -395,10 +378,9 @@ impl Register { Register::R13, Register::R14, Register::R15, - Register::RSP, - Register::RBP, - Register::PC, - Register::RV, + Register::Rsp, + Register::Rbp, + Register::Rv, ] } } @@ -422,10 +404,9 @@ impl fmt::Display for Register { Register::R13 => write!(f, "r13"), Register::R14 => write!(f, "r14"), Register::R15 => write!(f, "r15"), - Register::RSP => write!(f, "rsp"), - Register::RBP => write!(f, "rbp"), - Register::PC => write!(f, "pc"), - Register::RV => write!(f, "rv"), + Register::Rsp => write!(f, "rsp"), + Register::Rbp => write!(f, "rbp"), + Register::Rv => write!(f, "rv"), } } } diff --git a/src/compiler.rs b/src/compiler.rs index 5171f20..868d6d6 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,7 +1,190 @@ +mod ast; mod codegen; -mod compiler; +mod ir; mod lowering; +mod parser; +mod regalloc; mod semantic; +mod typing; -pub use compiler::CompileError; -pub use compiler::Compiler; +use std::collections::HashMap; +use std::sync::Arc; + +use ir::builder::{InstBuilder, IrBuilder}; +use ir::instruction::IrUnit; +use log::debug; +use typing::TypeContext; + +use crate::Environment; +use crate::bytecode::{Module, Register}; +use ast::syntax::{Span, Type}; +use parser::ParseError; + +use codegen::Codegen; +use lowering::{ASTLower, SymbolTable}; +use semantic::SemanticAnalyzer; + +pub fn compile(script: &str, env: &crate::Environment) -> Result, CompileError> { + Compiler::new().compile(script, env) +} + +#[derive(Debug)] +pub enum CompileError { + Parse(ParseError), + Semantics(String), + UndefinedVariable { + name: String, + }, + UnknownType { + name: String, + }, + TypeMismatch { + expected: Box, + actual: Box, + span: Span, + }, + TypeInference(String), + TypeCheck(String), + ArgumentCountMismatch { + expected: usize, + actual: usize, + }, + NotCallable { + ty: Type, + span: Span, + }, + Unreachable, + BreakOutsideLoop { + span: Span, + }, + ContinueOutsideLoop { + span: Span, + }, + ReturnOutsideFunction { + span: Span, + }, + InvalidOperation { + message: String, + }, +} + +impl CompileError { + pub fn type_mismatch(expected: Type, actual: Type, span: Span) -> Self { + CompileError::TypeMismatch { + span, + expected: Box::new(expected), + actual: Box::new(actual), + } + } +} + +impl From for CompileError { + fn from(error: ParseError) -> Self { + CompileError::Parse(error) + } +} + +impl std::fmt::Display for CompileError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + CompileError::Parse(error) => write!(f, "Parse error: {error}"), + CompileError::Semantics(message) => write!(f, "Semantics error: {message}"), + CompileError::UndefinedVariable { name } => { + write!(f, "Undefined variable `{name}`") + } + CompileError::UnknownType { name } => { + write!(f, "Unknow type `{name}`") + } + CompileError::TypeMismatch { + expected, + actual, + span, + } => write!( + f, + "Type mismatch: expected `{expected:?}`, actual `{actual:?}` at {span:?}" + ), + CompileError::TypeInference(message) => write!(f, "Type inference error: {message}"), + CompileError::TypeCheck(message) => write!(f, "Type check error: {message}"), + CompileError::ArgumentCountMismatch { expected, actual } => write!( + f, + "Argument count mismatch: expected {expected}, actual {actual}" + ), + CompileError::NotCallable { ty, span } => { + write!(f, "Not callable: `{ty:?}` at {span:?}") + } + CompileError::Unreachable => write!(f, "Unreachable"), + CompileError::BreakOutsideLoop { span } => write!(f, "Break outside loop at {span:?}"), + CompileError::ContinueOutsideLoop { span } => { + write!(f, "Continue outside loop at {span:?}") + } + CompileError::ReturnOutsideFunction { span } => { + write!(f, "Return outside function at {span:?}") + } + CompileError::InvalidOperation { message } => { + write!(f, "Invalid operation, {message}") + } + } + } +} + +impl std::error::Error for CompileError {} + +pub struct Compiler {} + +impl Default for Compiler { + fn default() -> Self { + Self::new() + } +} + +impl Compiler { + pub fn new() -> Self { + Self {} + } + + pub fn compile(&self, input: &str, env: &Environment) -> Result, CompileError> { + // 解析输入 + let mut ast = parser::parse_file(input)?; + + debug!("AST: {ast:?}"); + + let mut type_cx = TypeContext::new(); + type_cx.process_env(env); + + // 语义分析 + let mut analyzer = SemanticAnalyzer::new(&mut type_cx); + analyzer.analyze_program(&mut ast, env)?; + + // IR生成, AST -> IR + let mut unit = IrUnit::new(); + let builder: &mut dyn InstBuilder = &mut IrBuilder::new(&mut unit); + let mut lower = ASTLower::new(builder, SymbolTable::new(), env, &type_cx); + lower.lower_program(ast)?; + + // code generation, IR -> bytecode + let mut codegen = Codegen::new(&Register::general()); + let insts = codegen.generate_code(unit.control_flow_graph); + + let mut instructions = insts.to_vec(); + + let mut symtab = HashMap::new(); + // relocate symbol table + let mut offset = instructions.len(); + for func in unit.functions { + let mut codegen = Codegen::new(&Register::general()); + let insts = codegen.generate_code(func.control_flow_graph); + symtab.insert(func.id, offset); + offset += insts.len(); + instructions.extend(insts.to_vec()); + } + + let module = Module { + name: None, + constants: unit.constants, + symtab, + instructions: instructions.to_vec(), + }; + + Ok(Arc::new(module)) + } +} diff --git a/src/compiler/ast.rs b/src/compiler/ast.rs new file mode 100644 index 0000000..4a39d2c --- /dev/null +++ b/src/compiler/ast.rs @@ -0,0 +1 @@ +pub mod syntax; diff --git a/src/ast/grammar.pest b/src/compiler/ast/grammar.pest similarity index 91% rename from src/ast/grammar.pest rename to src/compiler/ast/grammar.pest index ada0a8d..758ae72 100644 --- a/src/ast/grammar.pest +++ b/src/compiler/ast/grammar.pest @@ -108,8 +108,9 @@ tuple_pattern = { "(" ~ (pattern ~ ",")* ~ pattern ~ ")" } /// Expression expression = { prefix_operator* ~ primary ~ postfix* ~ (infix_operator ~ prefix_operator* ~ primary ~ postfix*)* } -type_expression = { type_bool | type_byte | type_int | type_float | type_char | type_string | type_array | type_tuple | type_generic | type_impl | type_user_defined } +type_expression = { type_any | type_bool | type_byte | type_int | type_float | type_char | type_string | type_array | type_tuple | type_generic | type_impl | type_user_defined } +type_any = { "any" } type_bool = { "bool" } type_byte = { "byte" } type_int = { "int" } @@ -123,17 +124,31 @@ type_impl = { "impl" ~ type_expression } type_generic = { identifier ~ "<" ~ type_expression ~ ("," ~ type_expression)* ~ ">" } /// Primary -primary = _{ atom | grouped_expression } +primary = _{ struct_expression | grouped_expression | atom } /// Grouped Expression grouped_expression = { "(" ~ expression ~ ")" } +/// Struct Expression +struct_expression = { + identifier ~ "{" ~ struct_expr_fields ~ "}" +} + +struct_expr_fields = { + struct_expr_field ~ ("," ~ struct_expr_field)* ~ ","? +} + +struct_expr_field = { + identifier ~ ":" ~ expression +} + + /// closure closure = { "|" ~ call_arg_list ~ "|" ~ block } /// Atom atom = { - literal + | literal | simple_path | identifier | tuple @@ -152,13 +167,13 @@ path_seg = { identifier | "super" | "self" | "crate" } tuple = { "(" ~ (((expression ~ ",")+ ~ expression) | (expression ~ ",")) ~ ")" } /// Array -array = { "[" ~ (expression ~ ("," ~ expression)*)? ~ "]" } +array = { "[" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ "]" } /// map item map_item = { expression ~ ":" ~ expression } /// map -map = { "{" ~ (map_item ~ ("," ~ map_item)*)? ~ "}" } +map = { "{" ~ (map_item ~ ("," ~ map_item)*)? ~ ","? ~ "}" } /// Literal literal = { null | boolean | float | integer | string | character } @@ -205,7 +220,7 @@ infix_operator = _{ | sub_assign_operator | mul_assign_operator | div_assign_operator - | mod_assign_operator + | rem_assign_operator | not_equal_operator | less_equal_operator | greater_equal_operator @@ -214,7 +229,7 @@ infix_operator = _{ | sub_operator | mul_operator | div_operator - | mod_operator + | rem_operator | pow_operator | range_operator | and_operator @@ -287,8 +302,8 @@ mul_operator = { "*" } /// A div operator. div_operator = { "/" } -/// A mod operator. -mod_operator = { "%" } +/// A rem operator. +rem_operator = { "%" } /// A pow operator. pow_operator = { "^" } @@ -339,7 +354,7 @@ mul_assign_operator = { "*=" } div_assign_operator = { "/=" } /// A mod assign operator. -mod_assign_operator = { "%=" } +rem_assign_operator = { "%=" } /// A comma terminal. comma = { "," } @@ -416,13 +431,8 @@ inner_doc = @{ (!newline ~ ANY)* } /// Keywords keywords = _{ - "null" - | "bool" - | "byte" - | "char" - | "int" - | "float" - | "string" + "any" + | "null" | "true" | "false" | "enum" @@ -443,6 +453,7 @@ keywords = _{ | "try" | "catch" | "finally" + | "throw" | "return" | "if" | "else" @@ -462,6 +473,7 @@ keywords = _{ | "crate" | "trait" | "mod" + | "where" } keyword = @{ keywords ~ !("_" | alpha_num) } diff --git a/src/ast/interpreter.rs b/src/compiler/ast/interpreter.rs similarity index 99% rename from src/ast/interpreter.rs rename to src/compiler/ast/interpreter.rs index bd5eedb..4a3f157 100644 --- a/src/ast/interpreter.rs +++ b/src/compiler/ast/interpreter.rs @@ -412,7 +412,7 @@ impl Interpreter { BinOp::Sub => left.get().sub(&right.get())?, BinOp::Mul => left.get().mul(&right.get())?, BinOp::Div => left.get().div(&right.get())?, - BinOp::Mod => left.get().modulo(&right.get())?, + BinOp::Rem => left.get().rem(&right.get())?, BinOp::LogicAnd => left.get().logic_and(&right.get())?, BinOp::LogicOr => left.get().logic_or(&right.get())?, BinOp::Equal => Value::new(left.get().compare(&right.get())?.is_eq()), diff --git a/src/ast/ast.rs b/src/compiler/ast/syntax.rs similarity index 79% rename from src/ast/ast.rs rename to src/compiler/ast/syntax.rs index ff4394f..4ca6355 100644 --- a/src/ast/ast.rs +++ b/src/compiler/ast/syntax.rs @@ -1,6 +1,7 @@ use std::{ - fmt, io, - io::{Error, ErrorKind}, + collections::HashMap, + fmt, + io::{self, Error, ErrorKind}, str::FromStr, }; @@ -71,47 +72,61 @@ impl Span { #[derive(Debug, Clone, PartialEq)] pub enum Type { - Void, - Null, + Any, Boolean, Byte, Integer, Float, Char, String, - Function { - params: Vec>, - return_ty: Option>, - }, - DynObject, Range, - EnvObject, + Tuple(Vec), + Array(Box), + Map(Box), Unknown, + UserDefined(String), + Decl(Declaration), } impl Type { pub fn is_boolean(&self) -> bool { - matches!(self, Type::Boolean | Type::Void) + matches!(self, Type::Boolean) } pub fn is_numeric(&self) -> bool { - matches!(self, Type::Byte | Type::Integer | Type::Float | Type::Void) + matches!(self, Type::Byte | Type::Integer | Type::Float) } pub fn is_string(&self) -> bool { matches!(self, Type::String) } - pub fn is_object(&self) -> bool { - matches!(self, Type::DynObject) + pub fn is_unknown(&self) -> bool { + matches!(self, Type::Unknown) } - pub fn is_function(&self) -> bool { - matches!(self, Type::Function { .. }) + pub fn is_collection(&self) -> bool { + matches!(self, Type::Array(_) | Type::Map(_)) } - pub fn is_unknown(&self) -> bool { - matches!(self, Type::Unknown) + pub fn is_any(&self) -> bool { + matches!(self, Type::Any) + } + + pub fn get_array_element_type(&self) -> Option<&Type> { + if let Type::Array(ty) = self { + Some(ty.as_ref()) + } else { + None + } + } + + pub fn get_map_value_type(&self) -> Option<&Type> { + if let Type::Map(ty) = self { + Some(ty.as_ref()) + } else { + None + } } } @@ -232,6 +247,7 @@ pub struct ReturnStatement { #[derive(Debug, Clone, PartialEq)] pub enum TypeExpression { + Any, Boolean, Byte, Integer, @@ -255,8 +271,6 @@ pub enum Expression { Array(ArrayExpression), Map(MapExpression), Closure(ClosureExpression), - Member(MemberExpression), - Index(IndexExpression), Range(RangeExpression), Slice(SliceExpression), Assign(AssignExpression), @@ -265,6 +279,12 @@ pub enum Expression { Await(Box), Prefix(PrefixExpression), Binary(BinaryExpression), + IndexGet(IndexGetExpression), + IndexSet(IndexSetExpression), + PropertyGet(PropertyGetExpression), + PropertySet(PropertySetExpression), + CallMethod(CallMethodExpression), + StructExpr(StructExpression), } impl Expression { @@ -292,24 +312,12 @@ pub struct AssignExpression { pub value: Box, } -#[derive(Debug, Clone, PartialEq)] -pub struct MemberExpression { - pub object: Box, - pub property: String, -} - #[derive(Debug, Clone, PartialEq)] pub struct CallExpression { pub func: Box, pub args: Vec, } -#[derive(Debug, Clone, PartialEq)] -pub struct IndexExpression { - pub object: Box, - pub index: Box, -} - #[derive(Debug, Clone, PartialEq)] pub struct RangeExpression { pub op: BinOp, @@ -344,7 +352,7 @@ pub enum BinOp { Sub, Mul, Div, - Mod, + Rem, LogicAnd, LogicOr, Less, @@ -366,7 +374,7 @@ impl fmt::Display for BinOp { BinOp::Sub => write!(f, "-"), BinOp::Mul => write!(f, "*"), BinOp::Div => write!(f, "/"), - BinOp::Mod => write!(f, "%"), + BinOp::Rem => write!(f, "%"), BinOp::LogicAnd => write!(f, "&&"), BinOp::LogicOr => write!(f, "||"), BinOp::Less => write!(f, "<"), @@ -392,7 +400,7 @@ impl FromStr for BinOp { "-" => Ok(BinOp::Sub), "*" => Ok(BinOp::Mul), "/" => Ok(BinOp::Div), - "%" => Ok(BinOp::Mod), + "%" => Ok(BinOp::Rem), "&&" => Ok(BinOp::LogicAnd), "||" => Ok(BinOp::LogicOr), "<" => Ok(BinOp::Less), @@ -489,3 +497,80 @@ pub enum PathSeg { Self_, Crate, } + +#[derive(Debug, Clone, PartialEq)] +pub struct IndexGetExpression { + pub object: Box, + pub index: Box, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct IndexSetExpression { + pub object: Box, + pub index: Box, + pub value: Box, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct PropertyGetExpression { + pub object: Box, + pub property: String, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct PropertySetExpression { + pub object: Box, + pub property: String, + pub value: Box, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct CallMethodExpression { + pub object: Box, + pub method: String, + pub args: Vec, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct StructExpression { + pub name: String, + pub fields: Vec, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct StructExprField { + pub name: String, + pub value: ExpressionNode, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum Declaration { + Function(FunctionDeclaration), + Struct(StructDeclaration), + Enum(EnumDeclaration), +} + +impl Declaration { + pub fn is_function(&self) -> bool { + matches!(self, Declaration::Function(_)) + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct FunctionDeclaration { + pub name: String, + pub params: Vec<(String, Option)>, + pub return_type: Option>, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct StructDeclaration { + pub name: String, + pub fields: HashMap, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct EnumDeclaration { + pub name: String, + pub variants: Vec<(String, Option)>, +} diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 1fdbf18..cf602ac 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -1,4 +1,709 @@ -mod codegen; -mod regalloc; +use std::collections::HashMap; -pub use codegen::Codegen; +use log::{debug, trace}; +use petgraph::visit::DfsPostOrder; + +use super::ir::instruction::{Block, ControlFlowGraph, Instruction, Value}; +use crate::bytecode::{Bytecode, Opcode, Operand, Register}; + +use super::regalloc::{Action, RegAlloc}; + +type PatchFn = Box; + +pub struct Codegen { + reg_alloc: RegAlloc, + codes: Vec, + block_map: HashMap, + inst_index: usize, +} + +impl Codegen { + pub fn new(registers: &[Register]) -> Self { + Self { + reg_alloc: RegAlloc::new(registers), + codes: Vec::new(), + block_map: HashMap::new(), + inst_index: 0, + } + } + + pub fn generate_code(&mut self, cfg: ControlFlowGraph) -> &[Bytecode] { + let mut cfg = cfg; + + Self::resort_blocks(&mut cfg); + + debug!("===IR==="); + let mut pos = 0; + for block in &cfg.blocks { + debug!("block({}):", block.id.as_usize()); + for inst in &block.instructions { + debug!("{pos}\t{inst}"); + pos += 1; + } + } + debug!("===IR==="); + + self.reg_alloc.arrange(&cfg); + + let mut patchs: Vec = Vec::new(); + + // alloc stack frame, need rewrite with actual stack size + // rsp = rsp + stack_size + let pos = self.codes.len(); + patchs.push(Box::new(move |this: &mut Self| { + this.codes[pos].operands[2] = Operand::new_immd(this.reg_alloc.stack_size() as isize) + })); + // placeholder + self.codes.push(Bytecode::triple( + Opcode::AddC, + Operand::Register(Register::Rsp), + Operand::Register(Register::Rsp), + Operand::new_immd(0), + )); + + for block in cfg.blocks.iter() { + self.block_map + .insert(block.id.as_usize() as isize, self.codes.len() as isize); + + for inst in &block.instructions { + debug!("inst[{}]: {inst:?}", self.inst_index); + debug!("register: {}", self.reg_alloc.reg_set); + + match inst.clone() { + // Function Call Instructions + Instruction::Call { func, args, result } => { + self.gen_call(func, &args, result); + } + Instruction::CallEx { + callable, + args, + result, + } => { + self.gen_call_ex(callable, &args, result); + } + Instruction::CallNative { func, args, result } => { + self.gen_call_native(func, &args, result); + } + Instruction::PropertyCall { + object, + property, + args, + result, + } => { + self.gen_prop_call(object, property, &args, result); + } + + // Load and Move Instructions + Instruction::LoadArg { dst, index } => { + let dst = self.gen_operand(dst); + let stack = self.reg_alloc.load_arg(index); + self.codes.push(Bytecode::double( + Opcode::Mov, + dst, + Operand::new_stack(stack), + )); + } + Instruction::LoadConst { dst, const_id } => { + let dst = self.gen_operand(dst); + + self.codes.push(Bytecode::double( + Opcode::LoadConst, + dst, + const_id.to_operand(), + )); + } + Instruction::LoadEnv { dst, name } => { + let dst = self.gen_operand(dst); + self.codes + .push(Bytecode::double(Opcode::LoadEnv, dst, name.to_operand())); + } + Instruction::Move { dst, src } => { + let src = self.gen_operand(src); + let dst = self.gen_operand(dst); + self.codes.push(Bytecode::double(Opcode::Mov, dst, src)); + } + + // Unary and Binary Operators + Instruction::UnaryOp { op, dst, src } => { + let src = self.gen_operand(src); + let dst = self.gen_operand(dst); + + self.codes.push(Bytecode::double(op, dst, src)); + } + Instruction::BinaryOp { op, dst, lhs, rhs } => { + let src1 = self.gen_operand(lhs); + let src2 = self.gen_operand(rhs); + let dst = self.gen_operand(dst); + self.codes.push(Bytecode::triple(op, dst, src1, src2)); + } + + // Range Instructions + Instruction::MakeRange { + op, + begin, + end, + result, + } => match (begin, end) { + (Some(begin), Some(end)) => { + let src1 = self.gen_operand(begin); + let src2 = self.gen_operand(end); + let dst = self.gen_operand(result); + self.codes.push(Bytecode::triple(op, dst, src1, src2)); + } + (Some(begin), None) => { + let src1 = self.gen_operand(begin); + let dst = self.gen_operand(result); + self.codes + .push(Bytecode::double(Opcode::RangeFrom, dst, src1)); + } + (None, Some(end)) => { + let src1 = self.gen_operand(end); + let dst = self.gen_operand(result); + match op { + Opcode::RangeInclusive => { + self.codes.push(Bytecode::double( + Opcode::RangeToInclusive, + dst, + src1, + )); + } + Opcode::Range => { + self.codes + .push(Bytecode::double(Opcode::RangeTo, dst, src1)); + } + _ => unreachable!("invalid op"), + } + } + (None, None) => { + let dst = self.gen_operand(result); + self.codes.push(Bytecode::single(Opcode::RangeFull, dst)); + } + }, + + // Collection / Structural Operations + Instruction::MakeArray { dst } => { + let dst = self.gen_operand(dst); + self.codes.push(Bytecode::single(Opcode::MakeArray, dst)); + } + Instruction::ArrayPush { array, value } => { + let array = self.gen_operand(array); + let value = self.gen_operand(value); + self.codes + .push(Bytecode::double(Opcode::ArrayPush, array, value)); + } + Instruction::MakeMap { dst } => { + let dst = self.gen_operand(dst); + self.codes.push(Bytecode::single(Opcode::MakeMap, dst)); + } + Instruction::IndexSet { + object, + index: idx, + value, + } => { + let object = self.gen_operand(object); + let idx = self.gen_operand(idx); + let value = self.gen_operand(value); + self.codes + .push(Bytecode::triple(Opcode::IndexSet, object, idx, value)); + } + Instruction::IndexGet { + dst, + object, + index: idx, + } => { + let dst = self.gen_operand(dst); + let object = self.gen_operand(object); + let idx = self.gen_operand(idx); + self.codes + .push(Bytecode::triple(Opcode::IndexGet, dst, object, idx)); + } + Instruction::MakeSlice { dst, object, range } => { + let dst = self.gen_operand(dst); + let object = self.gen_operand(object); + let range = self.gen_operand(range); + self.codes + .push(Bytecode::triple(Opcode::MakeSlice, dst, object, range)); + } + Instruction::PropertyGet { + dst, + object, + property, + } => { + let dst = self.gen_operand(dst); + let object = self.gen_operand(object); + let property = self.gen_operand(property); + self.codes + .push(Bytecode::triple(Opcode::PropGet, dst, object, property)); + } + Instruction::PropertySet { + object, + property, + value, + } => { + let object = self.gen_operand(object); + let property = self.gen_operand(property); + let value = self.gen_operand(value); + self.codes + .push(Bytecode::triple(Opcode::PropSet, object, property, value)); + } + Instruction::MakeStruct { dst } => { + let dst = self.gen_operand(dst); + self.codes.push(Bytecode::single(Opcode::MakeStruct, dst)); + } + Instruction::MakeStructField { + object, + field, + value, + } => { + let object = self.gen_operand(object); + let field = self.gen_operand(field); + let value = self.gen_operand(value); + self.codes.push(Bytecode::triple( + Opcode::MakeStructField, + object, + field, + value, + )); + } + + // Iteration Instructions + Instruction::MakeIterator { + src: iter, + dst: result, + } => { + let src = self.gen_operand(iter); + let dst = self.gen_operand(result); + self.codes + .push(Bytecode::double(Opcode::MakeIter, dst, src)); + } + Instruction::IterateNext { iter, dst: next } => { + let src = self.gen_operand(iter); + let dst = self.gen_operand(next); + self.codes + .push(Bytecode::double(Opcode::IterNext, dst, src)); + } + + // Control Flow Instructions + Instruction::Return { value } => { + if let Some(v) = value { + let ret = self.gen_operand(v); + self.codes.push(Bytecode::double( + Opcode::Mov, + Operand::new_register(Register::Rv), + ret, + )); + } + + self.codes.push(Bytecode::empty(Opcode::Ret)); + } + Instruction::Br { dst } => { + let dst = self.gen_operand(dst); + + let pos = self.codes.len(); + patchs.push(Box::new(move |this: &mut Self| { + let dst = this.codes[pos].operands[0].as_immd(); + this.codes[pos].operands[0] = + Operand::new_immd(this.block_map[&dst] - pos as isize); + })); + + self.codes.push(Bytecode::single(Opcode::Br, dst)); + } + Instruction::BrIf { + condition, + true_blk, + false_blk, + } => { + let condition = self.gen_operand(condition); + let true_blk = self.gen_operand(true_blk); + let false_blk = self.gen_operand(false_blk); + + let pos = self.codes.len(); + patchs.push(Box::new(move |this: &mut Self| { + let true_blk = this.codes[pos].operands[1].as_immd(); + this.codes[pos].operands[1] = + Operand::new_immd(this.block_map[&true_blk] - pos as isize); + let false_blk = this.codes[pos].operands[2].as_immd(); + this.codes[pos].operands[2] = + Operand::new_immd(this.block_map[&false_blk] - pos as isize); + })); + + self.codes.push(Bytecode::triple( + Opcode::BrIf, + condition, + true_blk, + false_blk, + )); + } + Instruction::Halt => { + self.codes.push(Bytecode::empty(Opcode::Halt)); + } + + // Async Support + Instruction::Await { promise, dst } => { + let promise = self.gen_operand(promise); + let dst = self.gen_operand(dst); + self.codes + .push(Bytecode::double(Opcode::Await, dst, promise)); + } + } + + let (defined, used) = inst.defined_and_used_vars(); + for var in defined { + if matches!(var, Value::Variable(_)) + && let Some(Action::Spill { stack, register }) = + self.reg_alloc.release(var, self.inst_index) + { + trace!("spilling({var}) {register} -> [rbp+{stack}]"); + self.codes.push(Bytecode::double( + Opcode::Mov, + Operand::Stack(stack as isize), + register.into(), + )); + } + } + + for var in used { + if matches!(var, Value::Variable(_)) + && let Some(Action::Spill { stack, register }) = + self.reg_alloc.release(var, self.inst_index) + { + trace!("spilling({var}) {register} -> [rbp+{stack}]"); + self.codes.push(Bytecode::double( + Opcode::Mov, + Operand::Stack(stack as isize), + register.into(), + )); + } + } + + self.inst_index += 1; + } + } + + for patch in patchs { + patch(self); + } + + &self.codes + } + + fn gen_call(&mut self, func: Value, args: &[Value], result: Value) { + // 1. Backup used registers + let in_use_registers = self.reg_alloc.in_use_registers(); + for reg in in_use_registers.iter().copied() { + self.codes.push(Bytecode::single(Opcode::Push, reg.into())); + } + + // 2. Push arguments onto the stack + self.store_args(args, self.inst_index); + + // 3. Set up new stack frame + self.codes.push(Bytecode::single( + Opcode::PushC, + Operand::new_register(Register::Rbp), + )); + self.codes.push(Bytecode::double( + Opcode::MovC, + Operand::new_register(Register::Rbp), + Operand::new_register(Register::Rsp), + )); + + // 4. Call the function + self.codes + .push(Bytecode::single(Opcode::Call, func.to_operand())); + + // 5. Restore stack pointer (reset to current base pointer) + self.codes.push(Bytecode::double( + Opcode::MovC, + Operand::new_register(Register::Rsp), + Operand::new_register(Register::Rbp), + )); + + // 6. Pop the saved base pointer + self.codes + .push(Bytecode::single(Opcode::PopC, Register::Rbp.into())); + + // 7. Clean up arguments from the stack + self.codes.push(Bytecode::triple( + Opcode::SubC, + Operand::Register(Register::Rsp), + Operand::Register(Register::Rsp), + Operand::new_immd(args.len() as isize), + )); + + // 8. Restore backed-up registers + for reg in in_use_registers.iter().rev().copied() { + self.codes.push(Bytecode::single(Opcode::Pop, reg.into())); + } + + // 9. Move return value to destination register + let result_reg = self.gen_operand(result); + self.codes.push(Bytecode::double( + Opcode::Mov, + result_reg, + Operand::new_register(Register::Rv), + )); + } + + fn gen_call_ex(&mut self, func: Value, args: &[Value], result: Value) { + let callable = self.gen_operand(func); + + // 1. Backup used registers + let in_use_registers = self.reg_alloc.in_use_registers(); + for reg in in_use_registers.iter().copied() { + self.codes.push(Bytecode::single(Opcode::Push, reg.into())); + } + + // 2. Push arguments onto the stack + self.store_args(args, self.inst_index); + + // 3. Set up new stack frame + self.codes.push(Bytecode::single( + Opcode::PushC, + Operand::new_register(Register::Rbp), + )); + self.codes.push(Bytecode::double( + Opcode::MovC, + Operand::new_register(Register::Rbp), + Operand::new_register(Register::Rsp), + )); + + // 4. Call the function (CallEx) + self.codes.push(Bytecode::single(Opcode::CallEx, callable)); + + // 5. Restore stack pointer to current base pointer + self.codes.push(Bytecode::double( + Opcode::MovC, + Operand::new_register(Register::Rsp), + Operand::new_register(Register::Rbp), + )); + + // 6. Pop saved base pointer + self.codes + .push(Bytecode::single(Opcode::PopC, Register::Rbp.into())); + + // 7. Clean up arguments from the stack + self.codes.push(Bytecode::triple( + Opcode::SubC, + Operand::Register(Register::Rsp), + Operand::Register(Register::Rsp), + Operand::new_immd(args.len() as isize), + )); + + // 8. Restore backed-up registers + for reg in in_use_registers.iter().rev().copied() { + self.codes.push(Bytecode::single(Opcode::Pop, reg.into())); + } + + // 9. Move return value to destination register + let result_reg = self.gen_operand(result); + self.codes.push(Bytecode::double( + Opcode::Mov, + result_reg, + Operand::new_register(Register::Rv), + )); + } + fn gen_call_native(&mut self, func: Value, args: &[Value], result: Value) { + let callable = self.gen_operand(func); + + // 1. Push arguments onto the stack + self.store_args(args, self.inst_index); + + // 2. Set up new stack frame + self.codes.push(Bytecode::single( + Opcode::PushC, + Operand::new_register(Register::Rbp), + )); + self.codes.push(Bytecode::double( + Opcode::MovC, + Operand::new_register(Register::Rbp), + Operand::new_register(Register::Rsp), + )); + + // 3. Call the native function + self.codes.push(Bytecode::double( + Opcode::CallNative, + callable, + Operand::new_immd(args.len() as isize), + )); + + // 4. Restore stack pointer to current base pointer + self.codes.push(Bytecode::double( + Opcode::MovC, + Operand::new_register(Register::Rsp), + Operand::new_register(Register::Rbp), + )); + + // 5. Pop saved base pointer + self.codes + .push(Bytecode::single(Opcode::PopC, Register::Rbp.into())); + + // 6. Clean up arguments from the stack + self.codes.push(Bytecode::triple( + Opcode::SubC, + Operand::Register(Register::Rsp), + Operand::Register(Register::Rsp), + Operand::new_immd(args.len() as isize), + )); + + // 7. Move return value to destination register + let result_reg = self.gen_operand(result); + self.codes.push(Bytecode::double( + Opcode::Mov, + result_reg, + Operand::new_register(Register::Rv), + )); + } + + fn gen_prop_call(&mut self, object: Value, property: Value, args: &[Value], result: Value) { + let callable = self.gen_operand(object); + + // 1. Push arguments onto the stack + self.store_args(args, self.inst_index); + + // 2. Set up new stack frame + self.codes.push(Bytecode::single( + Opcode::PushC, + Operand::new_register(Register::Rbp), + )); + self.codes.push(Bytecode::double( + Opcode::MovC, + Operand::new_register(Register::Rbp), + Operand::new_register(Register::Rsp), + )); + + let prop = self.gen_operand(property); + // 3. Call method on the object + self.codes.push(Bytecode::triple( + Opcode::CallMethod, + callable, + prop, + Operand::new_immd(args.len() as isize), + )); + + // 4. Restore stack pointer to current base pointer + self.codes.push(Bytecode::double( + Opcode::MovC, + Operand::new_register(Register::Rsp), + Operand::new_register(Register::Rbp), + )); + + // 5. Pop saved base pointer + self.codes + .push(Bytecode::single(Opcode::PopC, Register::Rbp.into())); + + // 6. Clean up arguments from the stack + self.codes.push(Bytecode::triple( + Opcode::SubC, + Operand::Register(Register::Rsp), + Operand::Register(Register::Rsp), + Operand::new_immd(args.len() as isize), + )); + + // 7. Move return value to destination register + let result_reg = self.gen_operand(result); + self.codes.push(Bytecode::double( + Opcode::Mov, + result_reg, + Operand::new_register(Register::Rv), + )); + } + + fn store_args(&mut self, args: &[Value], index: usize) { + for arg in args.iter().rev() { + let op = self.gen_operand(*arg); + self.codes.push(Bytecode::single(Opcode::Push, op)); + if let Some(action) = self.reg_alloc.release(*arg, index) { + match action { + Action::Spill { stack, register } => { + trace!("spilling({arg}) {register} -> [rbp+{stack}]"); + self.codes.push(Bytecode::double( + Opcode::Mov, + Operand::Stack(stack as isize), + register.into(), + )); + } + _ => unreachable!("action must be spill"), + } + } + } + } + + fn gen_operand(&mut self, value: Value) -> Operand { + match value { + Value::Primitive(v) => Operand::new_primitive(v), + Value::Constant(id) => Operand::new_immd(id.as_usize() as isize), + Value::Function(id) => Operand::new_symbol(id.as_usize() as u32), + Value::Block(id) => Operand::new_immd(id.as_usize() as isize), + Value::Variable(_) => { + let (register, unspill) = self.reg_alloc.alloc(value, self.inst_index); + + if let Some(Action::Restore { stack, register }) = unspill { + trace!("unspilling({value}) [rbp+{stack}] -> {register}"); + self.codes.push(Bytecode::double( + Opcode::Mov, + register.into(), + Operand::Stack(stack as isize), + )); + } + + Operand::new_register(register) + } + } + } + + fn resort_blocks(control_flow_graph: &mut ControlFlowGraph) { + // sort blocks by post order + let mut sorted = sort_graph_blocks(control_flow_graph); + + let mut iter = sorted.iter_mut().peekable(); + + while let Some(block) = iter.next() { + // remove instructions after return + if let Some(i) = block + .instructions + .iter() + .rposition(|item| matches!(item, Instruction::Return { .. })) + && i + 1 < block.instructions.len() + { + block.instructions.drain(i + 1..); + } + + let next_block_id = iter.peek().map(|b| b.id); + if let Some(Instruction::Br { dst }) = block.instructions.last() + && next_block_id == dst.as_block() + { + block.instructions.pop(); + } + } + + control_flow_graph.blocks = sorted; + } +} + +fn sort_graph_blocks(control_flow_graph: &ControlFlowGraph) -> Vec { + let graph = &control_flow_graph.graph; + let entry = control_flow_graph.entry().expect("no entry block"); + let start = control_flow_graph.block_node_map[&entry]; + + let mut dfs = DfsPostOrder::new(graph, start); + + let mut sorted = Vec::new(); + + while let Some(node) = dfs.next(graph) { + let block_id = graph[node]; + sorted.push(block_id); + } + + sorted.reverse(); + + sorted + .into_iter() + .map(|block_id| { + let block = control_flow_graph + .get_block(block_id) + .expect("no such block"); + block.clone() + }) + .collect() +} diff --git a/src/compiler/codegen/codegen.rs b/src/compiler/codegen/codegen.rs deleted file mode 100644 index d2da222..0000000 --- a/src/compiler/codegen/codegen.rs +++ /dev/null @@ -1,894 +0,0 @@ -use std::collections::HashMap; - -use log::{debug, trace}; -use petgraph::visit::DfsPostOrder; - -use crate::{ - bytecode::{Bytecode, Opcode, Operand, Register}, - compiler::codegen::regalloc::Action, - ir::instruction::{Block, ControlFlowGraph, Instruction, Value}, -}; - -use super::regalloc::RegAlloc; - -type PatchFn = Box; - -pub struct Codegen { - reg_alloc: RegAlloc, - codes: Vec, - block_map: HashMap, - inst_index: usize, -} - -impl Codegen { - pub fn new(registers: &[Register]) -> Self { - Self { - reg_alloc: RegAlloc::new(registers), - codes: Vec::new(), - block_map: HashMap::new(), - inst_index: 0, - } - } - - pub fn generate_code(&mut self, cfg: ControlFlowGraph) -> &[Bytecode] { - let mut cfg = cfg; - - Self::resort_blocks(&mut cfg); - - debug!("===IR==="); - let mut pos = 0; - for block in &cfg.blocks { - debug!("block({}):", block.id.as_usize()); - for inst in &block.instructions { - debug!("{pos}\t{inst}"); - pos += 1; - } - } - debug!("===IR==="); - - self.reg_alloc.arrange(&cfg); - - let mut patchs: Vec = Vec::new(); - - // alloc stack frame, need rewrite with actual stack size - // rsp = rsp + stack_size - let pos = self.codes.len(); - patchs.push(Box::new(move |this: &mut Self| { - this.codes[pos].operands[2] = Operand::new_immd(this.reg_alloc.stack_size() as isize) - })); - // placeholder - self.codes.push(Bytecode::triple( - Opcode::AddC, - Operand::Register(Register::RSP), - Operand::Register(Register::RSP), - Operand::new_immd(0), - )); - - for block in cfg.blocks.iter() { - self.block_map - .insert(block.id.as_usize() as isize, self.codes.len() as isize); - - for inst in &block.instructions { - // preload - // if !inst.is_call() { - // for action in self.reg_alloc.pre_allocate(index) { - // match action { - // Action::UnSpill { stack, register } => { - // self.codes.push(Bytecode::double( - // Opcode::Mov, - // register.into(), - // Operand::Stack(stack as isize), - // )); - // } - // _ => unreachable!(), - // } - // } - // } - - debug!("inst[{}]: {inst:?}", self.inst_index); - debug!("register: {}", self.reg_alloc.reg_set); - - match inst.clone() { - Instruction::Call { func, args, result } => { - self.gen_call(func, &args, result); - } - Instruction::CallEx { - callable, - args, - result, - } => { - self.gen_call_ex(callable, &args, result); - } - Instruction::CallNative { func, args, result } => { - self.gen_call_native(func, &args, result); - } - Instruction::LoadArg { dst, index } => { - let dst = self.gen_operand(dst); - let stack = self.reg_alloc.load_arg(index); - self.codes.push(Bytecode::double( - Opcode::Mov, - dst, - Operand::new_stack(stack), - )); - } - Instruction::LoadConst { dst, const_id } => { - let dst = self.gen_operand(dst); - - self.codes.push(Bytecode::double( - Opcode::LoadConst, - dst, - const_id.to_operand(), - )); - } - Instruction::LoadEnv { dst, name } => { - let dst = self.gen_operand(dst); - self.codes - .push(Bytecode::double(Opcode::LoadEnv, dst, name.to_operand())); - } - Instruction::Move { dst, src } => { - let src = self.gen_operand(src); - let dst = self.gen_operand(dst); - self.codes.push(Bytecode::double(Opcode::Mov, dst, src)); - } - Instruction::UnaryOp { op, dst, src } => { - let src = self.gen_operand(src); - let dst = self.gen_operand(dst); - - self.codes.push(Bytecode::double(op, dst, src)); - } - Instruction::BinaryOp { op, dst, lhs, rhs } => { - let src1 = self.gen_operand(lhs); - let src2 = self.gen_operand(rhs); - let dst = self.gen_operand(dst); - self.codes.push(Bytecode::triple(op, dst, src1, src2)); - } - Instruction::MakeRange { - op, - begin, - end, - result, - } => match (begin, end) { - (Some(begin), Some(end)) => { - let src1 = self.gen_operand(begin); - let src2 = self.gen_operand(end); - let dst = self.gen_operand(result); - self.codes.push(Bytecode::triple(op, dst, src1, src2)); - } - (Some(begin), None) => { - let src1 = self.gen_operand(begin); - let dst = self.gen_operand(result); - self.codes - .push(Bytecode::double(Opcode::RangeTo, dst, src1)); - } - (None, Some(end)) => { - let src1 = self.gen_operand(end); - let dst = self.gen_operand(result); - match op { - Opcode::RangeInclusive => { - self.codes.push(Bytecode::double( - Opcode::RangeToInclusive, - dst, - src1, - )); - } - Opcode::Range => { - self.codes - .push(Bytecode::double(Opcode::RangeTo, dst, src1)); - } - _ => unreachable!("invalid op"), - } - } - (None, None) => { - let dst = self.gen_operand(result); - self.codes.push(Bytecode::single(Opcode::RangeFull, dst)); - } - }, - Instruction::MakeIterator { - src: iter, - dst: result, - } => { - let src = self.gen_operand(iter); - let dst = self.gen_operand(result); - self.codes - .push(Bytecode::double(Opcode::MakeIter, dst, src)); - } - Instruction::IteratorHasNext { iter, dst: result } => { - let src = self.gen_operand(iter); - let dst = self.gen_operand(result); - self.codes - .push(Bytecode::double(Opcode::IterHasNext, dst, src)); - } - Instruction::IterateNext { iter, dst: next } => { - let src = self.gen_operand(iter); - let dst = self.gen_operand(next); - self.codes - .push(Bytecode::double(Opcode::IterNext, dst, src)); - } - Instruction::MakeArray { dst } => { - let dst = self.gen_operand(dst); - self.codes.push(Bytecode::single(Opcode::MakeArray, dst)); - } - Instruction::ArrayPush { array, value } => { - let array = self.gen_operand(array); - let value = self.gen_operand(value); - self.codes - .push(Bytecode::double(Opcode::ArrayPush, array, value)); - } - Instruction::MakeMap { dst } => { - let dst = self.gen_operand(dst); - self.codes.push(Bytecode::single(Opcode::MakeMap, dst)); - } - Instruction::IndexSet { - object, - index: idx, - value, - } => { - let object = self.gen_operand(object); - let idx = self.gen_operand(idx); - let value = self.gen_operand(value); - self.codes - .push(Bytecode::triple(Opcode::IndexSet, object, idx, value)); - } - Instruction::IndexGet { - dst, - object, - index: idx, - } => { - let dst = self.gen_operand(dst); - let object = self.gen_operand(object); - let idx = self.gen_operand(idx); - self.codes - .push(Bytecode::triple(Opcode::IndexGet, dst, object, idx)); - } - Instruction::MakeSlice { dst, object, range } => { - let dst = self.gen_operand(dst); - let object = self.gen_operand(object); - let range = self.gen_operand(range); - self.codes - .push(Bytecode::triple(Opcode::MakeSlice, dst, object, range)); - } - Instruction::PropertyCall { - object, - property, - args, - result, - } => { - self.gen_prop_call(object, property, &args, result); - } - Instruction::PropertyGet { - dst, - object, - property, - } => { - let dst = self.gen_operand(dst); - let object = self.gen_operand(object); - let property = self.gen_operand(property); - self.codes - .push(Bytecode::triple(Opcode::PropGet, dst, object, property)); - } - Instruction::PropertySet { - object, - property, - value, - } => { - let object = self.gen_operand(object); - let property = self.gen_operand(property); - let value = self.gen_operand(value); - self.codes - .push(Bytecode::triple(Opcode::PropSet, object, property, value)); - } - - Instruction::Return { value } => { - if let Some(v) = value { - let ret = self.gen_operand(v); - self.codes.push(Bytecode::double( - Opcode::Mov, - Operand::new_register(Register::RV), - ret, - )); - } - - self.codes.push(Bytecode::empty(Opcode::Ret)); - } - Instruction::Br { dst } => { - let dst = self.gen_operand(dst); - - let pos = self.codes.len(); - patchs.push(Box::new(move |this: &mut Self| { - let dst = this.codes[pos].operands[0].as_immd(); - this.codes[pos].operands[0] = - Operand::new_immd(this.block_map[&dst] - pos as isize); - })); - - self.codes.push(Bytecode::single(Opcode::Br, dst)); - } - Instruction::BrIf { - condition, - true_blk, - false_blk, - } => { - let condition = self.gen_operand(condition); - let true_blk = self.gen_operand(true_blk); - let false_blk = self.gen_operand(false_blk); - - let pos = self.codes.len(); - patchs.push(Box::new(move |this: &mut Self| { - let true_blk = this.codes[pos].operands[1].as_immd(); - this.codes[pos].operands[1] = - Operand::new_immd(this.block_map[&true_blk] - pos as isize); - let false_blk = this.codes[pos].operands[2].as_immd(); - this.codes[pos].operands[2] = - Operand::new_immd(this.block_map[&false_blk] - pos as isize); - })); - - self.codes.push(Bytecode::triple( - Opcode::BrIf, - condition, - true_blk, - false_blk, - )); - } - Instruction::Halt => { - self.codes.push(Bytecode::empty(Opcode::Halt)); - } - - Instruction::Await { promise, dst } => { - let promise = self.gen_operand(promise); - let dst = self.gen_operand(dst); - self.codes - .push(Bytecode::double(Opcode::Await, dst, promise)); - } - } - - let (defined, used) = inst.defined_and_used_vars(); - for var in defined { - if matches!(var, Value::Variable(_)) { - if let Some(Action::Spill { stack, register }) = - self.reg_alloc.release(var, self.inst_index) - { - trace!("spilling({var}) {register} -> [rbp+{stack}]"); - self.codes.push(Bytecode::double( - Opcode::Mov, - Operand::Stack(stack as isize), - register.into(), - )); - } - } - } - - for var in used { - if matches!(var, Value::Variable(_)) { - if let Some(Action::Spill { stack, register }) = - self.reg_alloc.release(var, self.inst_index) - { - trace!("spilling({var}) {register} -> [rbp+{stack}]"); - self.codes.push(Bytecode::double( - Opcode::Mov, - Operand::Stack(stack as isize), - register.into(), - )); - } - } - } - - self.inst_index += 1; - } - } - - for patch in patchs { - patch(self); - } - - &self.codes - } - - fn gen_call(&mut self, func: Value, args: &[Value], result: Value) { - // 0. result register - // let result_reg = self.gen_operand( result); - - // 1. backup registers - let in_use_registers = self.reg_alloc.in_use_registers(); - for reg in in_use_registers.iter().copied() { - self.codes.push(Bytecode::single(Opcode::Push, reg.into())); - } - - // 2. push arguments - self.store_args(args, self.inst_index); - - // 3. call function - self.codes.push(Bytecode::single( - Opcode::PushC, - Operand::new_register(Register::RBP), - )); - self.codes.push(Bytecode::double( - Opcode::MovC, - Operand::new_register(Register::RBP), - Operand::new_register(Register::RSP), - )); - - // call - self.codes - .push(Bytecode::single(Opcode::Call, func.to_operand())); - - self.codes.push(Bytecode::double( - Opcode::MovC, - Operand::new_register(Register::RSP), - Operand::new_register(Register::RBP), - )); - - self.codes - .push(Bytecode::single(Opcode::PopC, Register::RBP.into())); - - // 4. pop arguments - self.codes.push(Bytecode::triple( - Opcode::SubC, - Operand::Register(Register::RSP), - Operand::Register(Register::RSP), - Operand::new_immd(args.len() as isize), - )); - - // 5. restore registers - for reg in in_use_registers.iter().rev().copied() { - self.codes.push(Bytecode::single(Opcode::Pop, reg.into())); - } - - // 3. move result - let result_reg = self.gen_operand(result); - self.codes.push(Bytecode::double( - Opcode::Mov, - result_reg, - Operand::new_register(Register::RV), - )); - } - - fn gen_call_ex(&mut self, func: Value, args: &[Value], result: Value) { - let callable = self.gen_operand(func); - - // 1. backup registers - let in_use_registers = self.reg_alloc.in_use_registers(); - for reg in in_use_registers.iter().copied() { - self.codes.push(Bytecode::single(Opcode::Push, reg.into())); - } - - // 2. push arguments - self.store_args(args, self.inst_index); - - // 3. call function - self.codes.push(Bytecode::single( - Opcode::PushC, - Operand::new_register(Register::RBP), - )); - self.codes.push(Bytecode::double( - Opcode::MovC, - Operand::new_register(Register::RBP), - Operand::new_register(Register::RSP), - )); - - // call_ex - self.codes.push(Bytecode::single(Opcode::CallEx, callable)); - - self.codes.push(Bytecode::double( - Opcode::MovC, - Operand::new_register(Register::RSP), - Operand::new_register(Register::RBP), - )); - - self.codes - .push(Bytecode::single(Opcode::PopC, Register::RBP.into())); - - // 4. pop arguments - self.codes.push(Bytecode::triple( - Opcode::SubC, - Operand::Register(Register::RSP), - Operand::Register(Register::RSP), - Operand::new_immd(args.len() as isize), - )); - // 5. restore registers - for reg in in_use_registers.iter().rev().copied() { - self.codes.push(Bytecode::single(Opcode::Pop, reg.into())); - } - - // 3. move result - let result_reg = self.gen_operand(result); - self.codes.push(Bytecode::double( - Opcode::Mov, - result_reg, - Operand::new_register(Register::RV), - )); - } - - fn gen_call_native(&mut self, func: Value, args: &[Value], result: Value) { - let callable = self.gen_operand(func); - - // 1. push arguments - self.store_args(args, self.inst_index); - - // 3. call function - self.codes.push(Bytecode::single( - Opcode::PushC, - Operand::new_register(Register::RBP), - )); - self.codes.push(Bytecode::double( - Opcode::MovC, - Operand::new_register(Register::RBP), - Operand::new_register(Register::RSP), - )); - - // call_native - self.codes.push(Bytecode::double( - Opcode::CallNative, - callable, - Operand::new_immd(args.len() as isize), - )); - - self.codes.push(Bytecode::double( - Opcode::MovC, - Operand::new_register(Register::RSP), - Operand::new_register(Register::RBP), - )); - - self.codes - .push(Bytecode::single(Opcode::PopC, Register::RBP.into())); - - // 4. pop arguments - self.codes.push(Bytecode::triple( - Opcode::SubC, - Operand::Register(Register::RSP), - Operand::Register(Register::RSP), - Operand::new_immd(args.len() as isize), - )); - - // 6. move result - let result_reg = self.gen_operand(result); - self.codes.push(Bytecode::double( - Opcode::Mov, - result_reg, - Operand::new_register(Register::RV), - )); - } - - fn gen_prop_call(&mut self, object: Value, property: Value, args: &[Value], result: Value) { - let callable = self.gen_operand(object); - - // 1. push arguments - self.store_args(args, self.inst_index); - - // 3. call function - self.codes.push(Bytecode::single( - Opcode::PushC, - Operand::new_register(Register::RBP), - )); - self.codes.push(Bytecode::double( - Opcode::MovC, - Operand::new_register(Register::RBP), - Operand::new_register(Register::RSP), - )); - - let prop = self.gen_operand(property); - // prop_call - self.codes.push(Bytecode::triple( - Opcode::PropCall, - callable, - prop, - Operand::new_immd(args.len() as isize), - )); - - self.codes.push(Bytecode::double( - Opcode::MovC, - Operand::new_register(Register::RSP), - Operand::new_register(Register::RBP), - )); - - self.codes - .push(Bytecode::single(Opcode::PopC, Register::RBP.into())); - - // 4. pop arguments - self.codes.push(Bytecode::triple( - Opcode::SubC, - Operand::Register(Register::RSP), - Operand::Register(Register::RSP), - Operand::new_immd(args.len() as isize), - )); - - // 6. move result - let result_reg = self.gen_operand(result); - self.codes.push(Bytecode::double( - Opcode::Mov, - result_reg, - Operand::new_register(Register::RV), - )); - } - - fn store_args(&mut self, args: &[Value], index: usize) { - for arg in args.iter().rev() { - let op = self.gen_operand(*arg); - self.codes.push(Bytecode::single(Opcode::Push, op)); - if let Some(action) = self.reg_alloc.release(*arg, index) { - match action { - Action::Spill { stack, register } => { - trace!("spilling({arg}) {register} -> [rbp+{stack}]"); - self.codes.push(Bytecode::double( - Opcode::Mov, - Operand::Stack(stack as isize), - register.into(), - )); - } - _ => unreachable!("action must be spill"), - } - } - } - } - - fn gen_operand(&mut self, value: Value) -> Operand { - match value { - Value::Primitive(v) => Operand::new_primitive(v), - Value::Constant(id) => Operand::new_immd(id.as_usize() as isize), - Value::Function(id) => Operand::new_symbol(id.as_usize() as u32), - Value::Block(id) => Operand::new_immd(id.as_usize() as isize), - Value::Variable(_) => { - let (register, unspill) = self.reg_alloc.alloc(value, self.inst_index); - - if let Some(Action::Restore { stack, register }) = unspill { - trace!("unspilling({value}) [rbp+{stack}] -> {register}"); - self.codes.push(Bytecode::double( - Opcode::Mov, - register.into(), - Operand::Stack(stack as isize), - )); - } - - Operand::new_register(register) - } - } - } - - fn resort_blocks(control_flow_graph: &mut ControlFlowGraph) { - // sort blocks by post order - let mut sorted = sort_graph_blocks(control_flow_graph); - - let mut iter = sorted.iter_mut().peekable(); - - while let Some(block) = iter.next() { - // // remove instructions after return - // if let Some(i) = block - // .instructions - // .iter() - // .rposition(|item| matches!(item, Instruction::Return { .. })) - // { - // if i + 1 < block.instructions.len() { - // block.instructions.drain(i + 1..); - // } - // } - - let next_block_id = iter.peek().map(|b| b.id); - if let Some(Instruction::Br { dst }) = block.instructions.last() { - if next_block_id == dst.as_block() { - block.instructions.pop(); - } - } - } - - control_flow_graph.blocks = sorted; - } -} - -fn sort_graph_blocks(control_flow_graph: &ControlFlowGraph) -> Vec { - let graph = &control_flow_graph.graph; - let entry = control_flow_graph.entry().expect("no entry block"); - let start = control_flow_graph.block_node_map[&entry]; - - let mut dfs = DfsPostOrder::new(graph, start); - - let mut sorted = Vec::new(); - - while let Some(node) = dfs.next(graph) { - let block_id = graph[node]; - sorted.push(block_id); - } - - sorted.reverse(); - - sorted - .into_iter() - .map(|block_id| { - let block = control_flow_graph - .get_block(block_id) - .expect("no such block"); - block.clone() - }) - .collect() -} - -#[cfg(test)] -mod tests { - - use crate::{ - bytecode::{Opcode, Primitive}, - ir::instruction::VariableId, - }; - - use super::*; - - #[test] - fn test_register_allocator() { - // move %0, 3.141592653589793 - // move %1, 2.718281828459045 - // %2 = mul %0, %1 - // return %2 - let instructions = vec![ - Instruction::Move { - dst: Value::Variable(VariableId::new(0)), - src: Value::Primitive(Primitive::from(3.141592653589793)), - }, - Instruction::Move { - dst: Value::Variable(VariableId::new(1)), - src: Value::Primitive(Primitive::from(718281828459045)), - }, - Instruction::BinaryOp { - op: Opcode::Mulx, - dst: Value::Variable(VariableId::new(2)), - lhs: Value::Variable(VariableId::new(0)), - rhs: Value::Variable(VariableId::new(1)), - }, - Instruction::Return { - value: Some(Value::Variable(VariableId::new(2))), - }, - ]; - - let mut cfg = ControlFlowGraph::new(); - let entry = cfg.create_block_with_instructions("test", instructions); - cfg.set_entry(entry); - - let mut codegen = Codegen::new(&Register::small_general()); - - let bytecodes = codegen.generate_code(cfg); - - for bytecode in bytecodes { - println!("{bytecode};"); - } - } - - #[test] - fn test_register_allocator2() { - // %0 = add i1, i1; - // %1 = mul i2, i2; - // %2 = add %0, %1; - // return %2; - let instructions = vec![ - Instruction::BinaryOp { - op: Opcode::Addx, - dst: Value::Variable(VariableId::new(0)), - lhs: Value::Primitive(Primitive::from(1)), - rhs: Value::Primitive(Primitive::from(1)), - }, - Instruction::BinaryOp { - op: Opcode::Mulx, - dst: Value::Variable(VariableId::new(1)), - lhs: Value::Primitive(Primitive::from(2)), - rhs: Value::Primitive(Primitive::from(2)), - }, - Instruction::BinaryOp { - op: Opcode::Addx, - dst: Value::Variable(VariableId::new(2)), - lhs: Value::Variable(VariableId::new(0)), - rhs: Value::Variable(VariableId::new(1)), - }, - Instruction::Return { - value: Some(Value::Variable(VariableId::new(2))), - }, - ]; - - let mut cfg = ControlFlowGraph::new(); - let entry = cfg.create_block_with_instructions("test", instructions); - cfg.set_entry(entry); - - let mut codegen = Codegen::new(&Register::small_general()); - - let bytecodes = codegen.generate_code(cfg); - - for bytecode in bytecodes { - println!("{bytecode};"); - } - } - - #[test] - fn test_codegen() { - /* - block(1): - 0 %0 = move 0 - block(2): - 1 %1 = make_range 0..=2 - 2 %2 = make_iterator %1 - block(3): - 3 %3 = iterator_has_next %2 - 4 br_if %3, @block(4), @block(5) - block(5): - 5 return %0 - block(4): - 6 %4 = iterate_next %2 - 7 %5 = move %4 - 8 %6 = add %0, %5 - 9 %0 = move %6 - 10 br @block(3) - */ - - let mut cfg = ControlFlowGraph::new(); - - let block1 = cfg.create_block(None); - let block2 = cfg.create_block(None); - let block3 = cfg.create_block(None); - let block4 = cfg.create_block(None); - let block5 = cfg.create_block(None); - - cfg.set_entry(block1); - - // block(1) - cfg.switch_to_block(block1); - cfg.emit(Instruction::Move { - dst: Value::Variable(VariableId::new(0)), - src: Value::Primitive(Primitive::from(0)), - }); - - // block(2) - cfg.switch_to_block(block2); - cfg.emit(Instruction::MakeRange { - op: Opcode::RangeInclusive, - result: Value::Variable(VariableId::new(1)), - begin: Some(Value::Primitive(Primitive::from(0))), - end: Some(Value::Primitive(Primitive::from(2))), - }); - cfg.emit(Instruction::MakeIterator { - src: Value::Variable(VariableId::new(1)), - dst: Value::Variable(VariableId::new(2)), - }); - - // block(3) - cfg.switch_to_block(block3); - cfg.emit(Instruction::IteratorHasNext { - iter: Value::Variable(VariableId::new(2)), - dst: Value::Variable(VariableId::new(3)), - }); - cfg.emit(Instruction::BrIf { - condition: Value::Variable(VariableId::new(3)), - true_blk: Value::Block(block4), - false_blk: Value::Block(block5), - }); - - // block(4) - cfg.switch_to_block(block4); - cfg.emit(Instruction::IterateNext { - iter: Value::Variable(VariableId::new(2)), - dst: Value::Variable(VariableId::new(4)), - }); - cfg.emit(Instruction::Move { - dst: Value::Variable(VariableId::new(5)), - src: Value::Variable(VariableId::new(4)), - }); - cfg.emit(Instruction::BinaryOp { - op: Opcode::Addx, - dst: Value::Variable(VariableId::new(6)), - lhs: Value::Variable(VariableId::new(0)), - rhs: Value::Variable(VariableId::new(5)), - }); - cfg.emit(Instruction::Move { - dst: Value::Variable(VariableId::new(0)), - src: Value::Variable(VariableId::new(6)), - }); - cfg.emit(Instruction::Br { - dst: Value::Block(block3), - }); - - // block(5) - cfg.switch_to_block(block5); - cfg.emit(Instruction::Return { - value: Some(Value::Variable(VariableId::new(0))), - }); - - let mut codegen = Codegen::new(&Register::small_general()); - let bytecodes = codegen.generate_code(cfg); - - for bytecode in bytecodes { - println!("{bytecode};"); - } - } -} diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs deleted file mode 100644 index 73fcbdb..0000000 --- a/src/compiler/compiler.rs +++ /dev/null @@ -1,214 +0,0 @@ -use log::debug; - -use crate::bytecode::{Module, Register}; -use crate::{Environment, Error, ast::*}; - -use super::codegen::Codegen; -use super::lowering::lowering; -use super::semantic::SemanticAnalyzer; - -use std::collections::HashMap; - -#[derive(Debug)] -pub enum CompileError { - Parse(ParseError), - Semantics(String), - UndefinedVariable { - name: String, - span: Span, - }, - TypeMismatch { - expected: Type, - actual: Type, - span: Span, - }, - TypeInference(String), - TypeCheck(String), - ArgumentCountMismatch { - expected: usize, - actual: usize, - span: Span, - }, - NotCallable { - ty: Type, - span: Span, - }, - Unreachable, - BreakOutsideLoop { - span: Span, - }, - ContinueOutsideLoop { - span: Span, - }, - ReturnOutsideFunction { - span: Span, - }, -} - -impl From for CompileError { - fn from(error: ParseError) -> Self { - CompileError::Parse(error) - } -} - -impl std::fmt::Display for CompileError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - CompileError::Parse(error) => write!(f, "Parse error: {error}"), - CompileError::Semantics(message) => write!(f, "Semantics error: {message}"), - CompileError::UndefinedVariable { name, span } => { - write!(f, "Undefined variable `{name}` at {span:?}") - } - CompileError::TypeMismatch { - expected, - actual, - span, - } => write!( - f, - "Type mismatch: expected `{expected:?}`, actual `{actual:?}` at {span:?}" - ), - CompileError::TypeInference(message) => write!(f, "Type inference error: {message}"), - CompileError::TypeCheck(message) => write!(f, "Type check error: {message}"), - CompileError::ArgumentCountMismatch { - expected, - actual, - span, - } => write!( - f, - "Argument count mismatch: expected {expected}, actual {actual} at {span:?}" - ), - CompileError::NotCallable { ty, span } => { - write!(f, "Not callable: `{ty:?}` at {span:?}") - } - CompileError::Unreachable => write!(f, "Unreachable"), - CompileError::BreakOutsideLoop { span } => write!(f, "Break outside loop at {span:?}"), - CompileError::ContinueOutsideLoop { span } => { - write!(f, "Continue outside loop at {span:?}") - } - CompileError::ReturnOutsideFunction { span } => { - write!(f, "Return outside function at {span:?}") - } - } - } -} - -impl std::error::Error for CompileError {} - -pub struct Compiler {} - -impl Compiler { - pub fn new() -> Self { - Self {} - } - - pub fn compile(&self, input: &str, env: &Environment) -> Result { - // 解析输入 - let mut ast = parse_file(input)?; - - debug!("AST: {ast:?}"); - - // // 语义分析 - let mut analyzer = SemanticAnalyzer::new(); - analyzer.analyze_program(&mut ast, env)?; - - // IR生成 - let unit = lowering(ast, env)?; - - let mut codegen = Codegen::new(&Register::general()); - let insts = codegen.generate_code(unit.control_flow_graph); - - let mut instructions = insts.to_vec(); - - let mut symtab = HashMap::new(); - - let mut offset = instructions.len(); - for func in unit.functions { - let mut codegen = Codegen::new(&Register::general()); - let insts = codegen.generate_code(func.control_flow_graph); - symtab.insert(func.id, offset); - offset += insts.len(); - instructions.extend(insts.to_vec()); - } - - let module = Module { - name: None, - constants: unit.constants, - symtab, - instructions: instructions.to_vec(), - }; - - Ok(module) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_compile_if_else() { - let _ = env_logger::builder() - .filter_level(log::LevelFilter::Trace) - .is_test(true) - .try_init(); - - let input = r#" - fn add(a, b) { - let c = 1; - let d = 2; - let e = 3; - let f = c * d + e; - let g = 4; - - // 增加更多局部变量 - let h = 5; - let i = 6; - let j = 7; - let k = 8; - let l = 9; - let m = 10; - let n = 11; - let o = 12; - let p = 13; - let q = 14; - let r = 15; - let s = 16; - let t = 17; - let u = 18; - let v = 19; - let w = 20; - let x = 21; - let y = 22; - let z = 23; - - // 在不同作用域中使用局部变量 - if a > 0 { - let inner_a = a + h; - let inner_b = b + i; - return inner_a + inner_b; - } else { - let inner_c = a - j; - let inner_d = b - k; - return inner_c + inner_d; - } - } - return add(1, 2); - "#; - - let compiler = Compiler::new(); - let insts = compiler.compile(input, &Environment::new()).unwrap(); - // for func in insts.functions { - // println!("=== Function({}) ===", func.id.as_usize()); - // for inst in func.instructions { - // println!("{inst}"); - // } - // println!("=== End ==="); - // } - - println!("=== Global ==="); - - for inst in insts.instructions { - println!("{inst}"); - } - } -} diff --git a/src/ir.rs b/src/compiler/ir.rs similarity index 100% rename from src/ir.rs rename to src/compiler/ir.rs diff --git a/src/ir/builder.rs b/src/compiler/ir/builder.rs similarity index 94% rename from src/ir/builder.rs rename to src/compiler/ir/builder.rs index 978b3c1..cf56cb8 100644 --- a/src/ir/builder.rs +++ b/src/compiler/ir/builder.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::bytecode::Constant; use crate::bytecode::FunctionId; use crate::bytecode::Opcode; @@ -214,14 +216,6 @@ pub trait InstBuilder { result } - fn iterator_has_next(&mut self, iter: Value) -> Value { - let result = self.alloc(); - - self.emit(Instruction::IteratorHasNext { iter, dst: result }); - - result - } - fn iterate_next(&mut self, iter: Value) -> Value { let next = self.alloc(); self.emit(Instruction::IterateNext { iter, dst: next }); @@ -242,19 +236,6 @@ pub trait InstBuilder { result } - // fn make_range_inclusive(&mut self, op: Opcode, begin: Option, end: Option) -> Value { - // let result = self.alloc(); - - // self.emit(Instruction::MakeRangeInclusive { - // op, - // begin, - // end, - // result, - // }); - - // result - // } - fn make_array(&mut self) -> Value { let array = self.alloc(); self.emit(Instruction::MakeArray { dst: array }); @@ -292,6 +273,21 @@ pub trait InstBuilder { dst } + fn make_struct(&mut self, fields: HashMap) -> Value { + let object = self.alloc(); + self.emit(Instruction::MakeStruct { dst: object }); + + for (field, value) in fields { + self.emit(Instruction::MakeStructField { + object, + field, + value, + }); + } + + object + } + fn await_promise(&mut self, promise: Value) -> Value { let dst = self.alloc(); self.emit(Instruction::Await { dst, promise }); diff --git a/src/ir/instruction.rs b/src/compiler/ir/instruction.rs similarity index 94% rename from src/ir/instruction.rs rename to src/compiler/ir/instruction.rs index 5d26462..8713d4a 100644 --- a/src/ir/instruction.rs +++ b/src/compiler/ir/instruction.rs @@ -151,6 +151,7 @@ impl From for Value { #[derive(Debug, Clone)] pub enum Instruction { + // Load and Move Instructions LoadArg { dst: Value, index: usize, @@ -167,6 +168,8 @@ pub enum Instruction { dst: Value, src: Value, }, + + // Unary and Binary Operators UnaryOp { op: Opcode, dst: Value, @@ -178,10 +181,14 @@ pub enum Instruction { lhs: Value, rhs: Value, }, + + // Async Support Await { promise: Value, dst: Value, }, + + // Function Call Instructions Call { func: Value, args: Vec, @@ -197,6 +204,14 @@ pub enum Instruction { args: Vec, result: Value, }, + PropertyCall { + object: Value, + property: Value, + args: Vec, + result: Value, + }, + + // Property and Index Access PropertyGet { dst: Value, object: Value, @@ -207,79 +222,73 @@ pub enum Instruction { property: Value, value: Value, }, - PropertyCall { - object: Value, - property: Value, - args: Vec, - result: Value, - }, - Return { - value: Option, - }, - BrIf { - condition: Value, - true_blk: Value, - false_blk: Value, - }, - Br { - dst: Value, - }, - /// Create an iterator from an object. - /// The iterator will be stored in `result`. - MakeIterator { - dst: Value, - src: Value, - }, - /// Check if the iterator has another item. - IteratorHasNext { - dst: Value, - iter: Value, - }, - /// Get the next value from an iterator. - /// The next value will be stored in `next`. - IterateNext { + IndexGet { dst: Value, - iter: Value, + object: Value, + index: Value, }, - /// Create a range iterator. - MakeRange { - op: Opcode, - begin: Option, - end: Option, - result: Value, + IndexSet { + object: Value, + index: Value, + value: Value, }, - /// Create an array. + + // Collection / Structural Operations MakeArray { dst: Value, }, - /// Push a value to an array. ArrayPush { array: Value, value: Value, }, - /// Create a map. MakeMap { dst: Value, }, - /// Get a value from an indexable object. - IndexGet { + MakeSlice { dst: Value, object: Value, - index: Value, + range: Value, }, - /// Set a value to an indexable object. - IndexSet { + MakeStruct { + dst: Value, + }, + MakeStructField { object: Value, - index: Value, + field: Value, value: Value, }, - /// Create a slice. - MakeSlice { + + // Iteration Instructions + MakeIterator { + dst: Value, + src: Value, + }, + IterateNext { + dst: Value, + iter: Value, + }, + + // Control Flow Instructions + Return { + value: Option, + }, + BrIf { + condition: Value, + true_blk: Value, + false_blk: Value, + }, + Br { dst: Value, - object: Value, - range: Value, }, Halt, + + // Range Instructions + MakeRange { + op: Opcode, + begin: Option, + end: Option, + result: Value, + }, } impl Instruction { @@ -368,7 +377,6 @@ impl Instruction { dst: result, } => (vec![*result], vec![*iter]), Instruction::IterateNext { iter, dst: next } => (vec![*next], vec![*iter]), - Instruction::IteratorHasNext { iter, dst: result } => (vec![*result], vec![*iter]), Instruction::MakeRange { begin, end, result, .. } => match (begin, end) { @@ -387,6 +395,12 @@ impl Instruction { value, } => (vec![], vec![*object, *index, *value]), Instruction::MakeSlice { dst, object, range } => (vec![*dst], vec![*object, *range]), + Instruction::MakeStruct { dst } => (vec![*dst], vec![]), + Instruction::MakeStructField { + object, + field, + value, + } => (vec![], vec![*object, *field, *value]), Instruction::Halt => (vec![], vec![]), } } @@ -433,7 +447,7 @@ impl std::fmt::Display for Instruction { args, result: dst, } => { - write!(f, "{dst} = call_ex {callable}")?; + write!(f, "{dst} = call_ex {callable} ")?; for arg in args { write!(f, ", {arg}")?; } @@ -496,9 +510,6 @@ impl std::fmt::Display for Instruction { Instruction::MakeIterator { src, dst } => { write!(f, "{dst} = make_iterator {src}") } - Instruction::IteratorHasNext { iter, dst } => { - write!(f, "{dst} = iterator_has_next {iter}") - } Instruction::IterateNext { iter, dst } => { write!(f, "{dst} = iterate_next {iter}") } @@ -518,22 +529,6 @@ impl std::fmt::Display for Instruction { } Ok(()) } - // Instruction::MakeRangeInclusive { - // op, - // begin, - // end, - // result, - // } => { - // write!(f, "{result} = make_range {op} ")?; - // if let Some(begin) = begin { - // write!(f, "{}", begin)?; - // } - // write!(f, "..=",)?; - // if let Some(end) = end { - // write!(f, " {}", end)?; - // } - // Ok(()) - // } Instruction::MakeArray { dst: array } => { write!(f, "{array} = make_array")?; Ok(()) @@ -557,6 +552,16 @@ impl std::fmt::Display for Instruction { Instruction::MakeSlice { dst, object, range } => { write!(f, "{dst} = make_slice {object}[{range}]") } + Instruction::MakeStruct { dst } => { + write!(f, "{dst} = make_struct") + } + Instruction::MakeStructField { + object, + field, + value, + } => { + write!(f, "{object}.{field} = {value}") + } Instruction::Halt => write!(f, "halt"), } } @@ -804,7 +809,7 @@ impl Block { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct FuncParam { pub name: Name, } @@ -815,7 +820,7 @@ impl FuncParam { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct FuncSignature { pub name: Name, pub params: Vec, @@ -886,6 +891,11 @@ impl IrUnit { } pub fn declare_function(&mut self, signature: FuncSignature) -> FunctionId { + // maybe exists + if let Some(id) = self.functions.iter().position(|f| f.signature == signature) { + return FunctionId::new(id as u32); + } + let id = FunctionId::new(self.functions.len() as u32); self.functions.push(IrFunction::new(id, signature)); id diff --git a/src/compiler/lowering.rs b/src/compiler/lowering.rs index 90e16e5..182353f 100644 --- a/src/compiler/lowering.rs +++ b/src/compiler/lowering.rs @@ -1,45 +1,16 @@ +use std::collections::HashMap; use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; +use super::CompileError; +use super::ast::syntax::*; +use super::ir::{builder::*, instruction::*}; +use super::typing::TypeContext; use crate::{ - Environment, Error, - ast::*, - bytecode::{Opcode, Primitive}, - ir::{builder::*, instruction::*}, + Environment, + bytecode::{FunctionId, Opcode, Primitive}, + runtime::EnvVariable, }; -pub fn lowering(ast: Program, env: &Environment) -> Result { - let mut unit = IrUnit::new(); - - let builder: &mut dyn InstBuilder = &mut IrBuilder::new(&mut unit); - - let entry = builder.create_block("__entry".into()); - builder.switch_to_block(entry); - - let mut ast_lower = ASTLower::new(builder, SymbolTable::new(), env); - - let mut stmts = Vec::new(); - - // split program into statements and items - for stmt in ast.stmts { - match stmt.node { - Statement::Item(ItemStatement::Fn(func)) => { - ast_lower.lower_function_item(func); - } - Statement::Item(_) => { - unimplemented!("unsupported item statement") - } - Statement::Empty => {} - _ => { - stmts.push(stmt); - } - } - } - - ast_lower.lower_statements(stmts); - - Ok(unit) -} - struct LoopContext { pub(crate) break_point: BlockId, pub(crate) continue_point: BlockId, @@ -59,6 +30,7 @@ pub struct ASTLower<'a> { env: &'a Environment, symbols: SymbolTable, loop_contexts: Vec, + type_cx: &'a TypeContext, } impl<'a> ASTLower<'a> { @@ -66,26 +38,56 @@ impl<'a> ASTLower<'a> { builder: &'a mut dyn InstBuilder, symbols: SymbolTable, env: &'a Environment, + type_cx: &'a TypeContext, ) -> Self { Self { builder, env, symbols, loop_contexts: Vec::new(), + type_cx, } } - fn lower_statements(&mut self, stmts: Vec) { + pub fn lower_program(&mut self, prog: Program) -> Result { + let mut unit = IrUnit::new(); + + let builder: &mut dyn InstBuilder = &mut IrBuilder::new(&mut unit); + + let entry = builder.create_block("__entry".into()); + builder.switch_to_block(entry); + + // declare functions + for decl in self.type_cx.function_decls() { + if let Declaration::Function(func) = decl { + self.declare_function(func); + } + } + let entry = self.create_block("main"); self.builder.switch_to_block(entry); self.builder.set_entry(entry); - for stmt in stmts { - self.lower_statement(stmt); + // split program into statements and items + for stmt in prog.stmts { + match stmt.node { + Statement::Item(ItemStatement::Fn(func)) => { + self.lower_function_item(func); + } + Statement::Item(_) => { + // unimplemented!("unsupported item statement") + } + Statement::Empty => {} + _ => { + self.lower_statement(stmt); + } + } } // FIXME: This is a hack to make block not empty. self.builder.make_halt(); + + Ok(unit) } fn lower_statement(&mut self, statement: StatementNode) { @@ -109,6 +111,9 @@ impl<'a> ASTLower<'a> { Statement::Loop(loop_stmt) => { self.lower_loop_stmt(loop_stmt); } + Statement::While(while_stmt) => { + self.lower_while_stmt(while_stmt); + } Statement::For(for_stmt) => { self.lower_for_stmt(for_stmt); } @@ -118,8 +123,10 @@ impl<'a> ASTLower<'a> { Statement::Continue => { self.lower_continue_stmt(); } - - _ => unimplemented!("{:?}", statement), + Statement::Block(block_stmt) => { + self.lower_block(block_stmt); + } + Statement::Empty => {} // _ => unimplemented!("{:?}", statement), } } @@ -133,7 +140,7 @@ impl<'a> ASTLower<'a> { self.builder.assign(dst, value); } - self.symbols.declare(&name, Variable::new(dst)); + self.symbols.define(&name, Variable::new(dst)); } fn lower_item_stmt(&mut self, item: ItemStatement) { @@ -180,7 +187,7 @@ impl<'a> ASTLower<'a> { Pattern::Identifier(ident) => { let dst = self.builder.alloc(); self.builder.assign(dst, value); - self.symbols.declare(&ident, Variable::new(dst)); + self.symbols.define(&ident, Variable::new(dst)); } Pattern::Tuple(pats) => { @@ -220,14 +227,15 @@ impl<'a> ASTLower<'a> { // loop header, check if iterator has next self.builder.switch_to_block(loop_header); - let has_next = self.builder.iterator_has_next(iterable); + let next = self.builder.iterate_next(iterable); + let has_next = self.builder.call_property(next, "is_some", vec![]); self.builder.br_if(has_next, loop_body, after_blk); // loop body, get next value self.builder.switch_to_block(loop_body); let new_symbols = self.symbols.new_scope(); let old_symbols = std::mem::replace(&mut self.symbols, new_symbols); - let next = self.builder.iterate_next(iterable); + let next = self.builder.call_property(next, "unwrap", vec![]); self.lower_pattern(pat, next); self.lower_block(body); @@ -256,12 +264,39 @@ impl<'a> ASTLower<'a> { self.lower_block(body); - self.symbols = old_symbols; - self.builder.br(loop_body); // done loop self.level_loop_context(); + self.symbols = old_symbols; + self.builder.switch_to_block(after_blk); + } + + fn lower_while_stmt(&mut self, while_stmt: WhileStatement) { + let WhileStatement { condition, body } = while_stmt; + + let cond_blk = self.create_block("while_condition"); + let body_blk = self.create_block("while_body"); + let after_blk = self.create_block(None); + + self.enter_loop_context(after_blk, body_blk); + + self.builder.br(cond_blk); + self.builder.switch_to_block(cond_blk); + + let cond = self.lower_expression(condition); + self.builder.br_if(cond, body_blk, after_blk); + + self.builder.switch_to_block(body_blk); + let new_symbols = self.symbols.new_scope(); + let old_symbols = std::mem::replace(&mut self.symbols, new_symbols); + + self.lower_block(body); + + self.builder.br(cond_blk); + + self.level_loop_context(); + self.symbols = old_symbols; self.builder.switch_to_block(after_blk); } @@ -288,7 +323,7 @@ impl<'a> ASTLower<'a> { } = fn_item; let value = self.lower_function(Some(name.to_string()), params, body); - self.symbols.declare(name, Variable::new(value)); + self.symbols.define(name, Variable::new(value)); value } @@ -315,7 +350,7 @@ impl<'a> ASTLower<'a> { let mut func_builder = FunctionBuilder::new(self.builder.module_mut(), &mut func); - let mut func_lower = ASTLower::new(&mut func_builder, symbols, self.env); + let mut func_lower = ASTLower::new(&mut func_builder, symbols, self.env, self.type_cx); let entry = func_lower.create_block(name); func_lower.builder.set_entry(entry); @@ -326,7 +361,7 @@ impl<'a> ASTLower<'a> { func_lower .symbols - .declare(param.name.as_str(), Variable::new(arg)); + .define(param.name.as_str(), Variable::new(arg)); } func_lower.lower_block(body); @@ -347,41 +382,121 @@ impl<'a> ASTLower<'a> { Expression::Identifier(identifier) => self.lower_identifier(identifier), Expression::Prefix(expr) => self.lower_unary(expr), Expression::Binary(expr) => self.lower_binary(expr), - Expression::Member(member) => self.lower_get_property(member), Expression::Call(call) => self.lower_call(call), Expression::Assign(assign) => self.lower_assign(assign), Expression::Closure(closure) => self.lower_closure(closure), Expression::Array(array) => self.lower_array(array), - Expression::Index(index) => self.lower_index(index), Expression::Map(map) => self.lower_map(map), Expression::Slice(slice) => self.lower_slice(slice), Expression::Await(expr) => self.lower_await(*expr), + Expression::Environment(env) => self.lower_environment(env), + Expression::IndexGet(expr) => self.lower_index_get(expr), + Expression::IndexSet(expr) => self.lower_index_set(expr), + Expression::PropertyGet(expr) => self.lower_get_property(expr), + Expression::PropertySet(expr) => self.lower_set_property(expr), + Expression::CallMethod(expr) => self.lower_call_method(expr), + Expression::StructExpr(expr) => self.lower_struct_expr(expr), _ => unimplemented!("{:?}", expr), } } - fn lower_index_set(&mut self, expr: IndexExpression, value: Value) { - let IndexExpression { object, index } = expr; + fn lower_environment(&mut self, env: EnvironmentExpression) -> Value { + let EnvironmentExpression(env) = env; + + self.builder.load_external_variable(env) + } + + fn lower_index_get(&mut self, expr: IndexGetExpression) -> Value { + let IndexGetExpression { object, index } = expr; + let object = self.lower_expression(*object); + let index = self.lower_expression(*index); + self.builder.index_get(object, index) + } + + fn lower_index_set(&mut self, expr: IndexSetExpression) -> Value { + let IndexSetExpression { + object, + index, + value, + } = expr; + + let value = self.lower_expression(*value); let object = self.lower_expression(*object); let index = self.lower_expression(*index); self.builder.index_set(object, index, value); + + value } - fn lower_get_property(&mut self, expr: MemberExpression) -> Value { - let MemberExpression { object, property } = expr; + fn lower_get_property(&mut self, expr: PropertyGetExpression) -> Value { + let PropertyGetExpression { object, property } = expr; let object = self.lower_expression(*object); self.builder.get_property(object, &property) } - fn lower_set_property(&mut self, expr: MemberExpression, value: Value) { - let MemberExpression { object, property } = expr; + fn lower_set_property(&mut self, expr: PropertySetExpression) -> Value { + let PropertySetExpression { + object, + property, + value, + } = expr; + + let value = self.lower_expression(*value); let object = self.lower_expression(*object); - self.builder.set_property(object, &property, value) + self.builder.set_property(object, &property, value); + + value + } + + fn lower_struct_expr(&mut self, expr: StructExpression) -> Value { + let StructExpression { name, fields } = expr; + + let mut field_map = fields + .into_iter() + .map(|StructExprField { name, value }| (name, self.lower_expression(value))) + .collect::>(); + + let decl = self.type_cx.get_type_decl(&name).expect("struct not found"); + if let Declaration::Struct(StructDeclaration { + name, + fields: decl_fields, + }) = decl + { + for name in decl_fields.keys() { + if !field_map.contains_key(name) { + field_map.insert(name.clone(), Value::Primitive(Primitive::Null)); + } + } + } + + let field_map = field_map + .into_iter() + .map(|(name, value)| (self.builder.make_constant(name.into()), value)) + .collect(); + + self.builder.make_struct(field_map) + } + + fn lower_call_method(&mut self, expr: CallMethodExpression) -> Value { + let CallMethodExpression { + object, + method, + args, + } = expr; + + let args: Vec = args + .into_iter() + .map(|arg| self.lower_expression(arg)) + .collect(); + + let object = self.lower_expression(*object); + + self.builder.call_property(object, &method, args) } fn lower_call(&mut self, expr: CallExpression) -> Value { @@ -393,25 +508,18 @@ impl<'a> ASTLower<'a> { .collect(); match func.node { - Expression::Member(member) => { - let MemberExpression { object, property } = member; - - let object = self.lower_expression(*object); - - self.builder.call_property(object, &property, args) - } Expression::Identifier(IdentifierExpression(ref ident)) => { match self.builder.module().find_function(ident) { Some(func) => self.builder.call_function(func.id, args), None => match self.symbols.get(ident) { Some(var) => self.builder.make_call(var.0, args), None => match self.env.get(ident) { - Some(_) => { + Some(EnvVariable::Function(_)) => { let callable = self.builder.load_external_variable(ident.to_string()); self.builder.make_call_native(callable, args) } - None => { + _ => { panic!("unknown identifier: {ident}"); } }, @@ -429,21 +537,9 @@ impl<'a> ASTLower<'a> { let value = self.lower_expression(*value); - match object.node { - Expression::Member(member) => { - self.lower_set_property(member, value); - value - } - Expression::Index(expr) => { - self.lower_index_set(expr, value); - value - } - _ => { - let object = self.lower_expression(*object); - self.builder.assign(object, value); - value - } - } + let object = self.lower_expression(*object); + self.builder.assign(object, value); + value } fn lower_closure(&mut self, expr: ClosureExpression) -> Value { @@ -487,15 +583,6 @@ impl<'a> ASTLower<'a> { self.builder.await_promise(promise) } - fn lower_index(&mut self, expr: IndexExpression) -> Value { - let IndexExpression { object, index } = expr; - - let object = self.lower_expression(*object); - - let index = self.lower_expression(*index); - self.builder.index_get(object, index) - } - fn lower_range(&mut self, expr: RangeExpression) -> Value { let RangeExpression { begin, end, op } = expr; @@ -568,7 +655,7 @@ impl<'a> ASTLower<'a> { BinOp::Sub => self.builder.binop(Opcode::Subx, lhs, rhs), BinOp::Mul => self.builder.binop(Opcode::Mulx, lhs, rhs), BinOp::Div => self.builder.binop(Opcode::Divx, lhs, rhs), - BinOp::Mod => self.builder.binop(Opcode::Modx, lhs, rhs), + BinOp::Rem => self.builder.binop(Opcode::Remx, lhs, rhs), BinOp::Equal => self.builder.binop(Opcode::Equal, lhs, rhs), BinOp::NotEqual => self.builder.binop(Opcode::NotEqual, lhs, rhs), @@ -590,6 +677,19 @@ impl<'a> ASTLower<'a> { } } + fn declare_function(&mut self, func: &FunctionDeclaration) -> FunctionId { + let FunctionDeclaration { name, params, .. } = func; + + let func_sig = FuncSignature::new( + name.clone(), + params + .iter() + .map(|(name, _ty)| FuncParam::new(name.clone())) + .collect(), + ); + self.builder.module_mut().declare_function(func_sig.clone()) + } + fn create_block(&mut self, label: impl Into) -> BlockId { self.builder.create_block(label.into()) } @@ -627,7 +727,7 @@ pub struct SymbolNode { pub struct SymbolTable(Rc>); impl SymbolTable { - fn new() -> Self { + pub fn new() -> Self { SymbolTable(Rc::new(RefCell::new(SymbolNode { parent: None, symbols: BTreeMap::new(), @@ -644,7 +744,7 @@ impl SymbolTable { None } - fn declare(&mut self, name: impl Into, value: Variable) { + fn define(&mut self, name: impl Into, value: Variable) { self.0.borrow_mut().symbols.insert(name.into(), value); } diff --git a/src/ast/parser.rs b/src/compiler/parser.rs similarity index 85% rename from src/ast/parser.rs rename to src/compiler/parser.rs index cbae469..0b7cac3 100644 --- a/src/ast/parser.rs +++ b/src/compiler/parser.rs @@ -6,7 +6,7 @@ use pest::{ pratt_parser::{Assoc, Op, PrattParser}, }; -use super::ast::*; +use super::ast::syntax::*; #[derive(Debug)] pub struct ParseError(Box>); @@ -39,7 +39,7 @@ impl std::error::Error for ParseError {} type Result = std::result::Result; #[derive(pest_derive::Parser)] -#[grammar = "ast/grammar.pest"] +#[grammar = "compiler/ast/grammar.pest"] struct PestParser; pub fn parse_file(input: &str) -> Result { @@ -73,7 +73,7 @@ fn pratt_parser() -> &'static PrattParser { | Op::infix(Rule::sub_assign_operator, Assoc::Right) | Op::infix(Rule::mul_assign_operator, Assoc::Right) | Op::infix(Rule::div_assign_operator, Assoc::Right) - | Op::infix(Rule::mod_assign_operator, Assoc::Right)) + | Op::infix(Rule::rem_assign_operator, Assoc::Right)) .op(Op::infix(Rule::range_operator, Assoc::Left)) .op(Op::infix(Rule::or_operator, Assoc::Left)) .op(Op::infix(Rule::and_operator, Assoc::Left)) @@ -87,7 +87,7 @@ fn pratt_parser() -> &'static PrattParser { | Op::infix(Rule::sub_operator, Assoc::Left)) .op(Op::infix(Rule::mul_operator, Assoc::Left) | Op::infix(Rule::div_operator, Assoc::Left) - | Op::infix(Rule::mod_operator, Assoc::Left)) + | Op::infix(Rule::rem_operator, Assoc::Left)) .op(Op::infix(Rule::pow_operator, Assoc::Right)) .op(Op::prefix(Rule::negative_operator) | Op::prefix(Rule::not_operator)) .op(Op::postfix(Rule::try_operator)) @@ -388,6 +388,7 @@ fn parse_type_expression(pair: Pair) -> TypeExpression { let pair = pair.into_inner().next().unwrap(); match pair.as_rule() { + Rule::type_any => TypeExpression::Any, Rule::type_bool => TypeExpression::Boolean, Rule::type_byte => TypeExpression::Byte, Rule::type_int => TypeExpression::Integer, @@ -435,6 +436,7 @@ fn parse_primary(pair: Pair) -> Result { Rule::identifier | Rule::literal | Rule::atom => parse_atom(pair), Rule::expression => parse_expression(pair), Rule::grouped_expression => parse_expression(pair.into_inner().next().unwrap()), + Rule::struct_expression => parse_struct_expression(pair), _ => unreachable!("unknown primary: {:?}", pair), } } @@ -465,96 +467,36 @@ fn parse_infix( let expr = match op.as_rule() { Rule::assign_operator => { - let value = Box::new(rhs?); - let object = Box::new(lhs?); - - Expression::Assign(AssignExpression { object, value }) - } - Rule::add_assign_operator => { - let value = Box::new(rhs?); - let object = Box::new(lhs?); - - let expr = Expression::Binary(BinaryExpression { - op: BinOp::Add, - lhs: object.clone(), - rhs: value.clone(), - }); - - let node = AstNode::new(expr, span, Type::Unknown); - - Expression::Assign(AssignExpression { - object, - value: Box::new(node), - }) - } - Rule::sub_assign_operator => { - let value = Box::new(rhs?); - let object = Box::new(lhs?); - - let expr = Expression::Binary(BinaryExpression { - op: BinOp::Sub, - lhs: object.clone(), - rhs: value.clone(), - }); - - let node = AstNode::new(expr, span, Type::Unknown); - - Expression::Assign(AssignExpression { - object, - value: Box::new(node), - }) - } - Rule::mul_assign_operator => { - let value = Box::new(rhs?); - let object = Box::new(lhs?); - - let expr = Expression::Binary(BinaryExpression { - op: BinOp::Mul, - lhs: object.clone(), - rhs: value.clone(), - }); - - let node = AstNode::new(expr, span, Type::Unknown); - - Expression::Assign(AssignExpression { - object, - value: Box::new(node), - }) - } - Rule::div_assign_operator => { - let value = Box::new(rhs?); - let object = Box::new(lhs?); - - let expr = Expression::Binary(BinaryExpression { - op: BinOp::Div, - lhs: object.clone(), - rhs: value.clone(), - }); - - let node = AstNode::new(expr, span, Type::Unknown); - - Expression::Assign(AssignExpression { - object, - value: Box::new(node), - }) - } - Rule::mod_assign_operator => { - let value = Box::new(rhs?); - let object = Box::new(lhs?); - - let expr = Expression::Binary(BinaryExpression { - op: BinOp::Mod, - lhs: object.clone(), - rhs: value.clone(), - }); - - let node = AstNode::new(expr, span, Type::Unknown); + let lhs_expr = lhs?; + let rhs_expr = rhs?; + + match &lhs_expr.node { + Expression::PropertyGet(PropertyGetExpression { object, property }) => { + Expression::PropertySet(PropertySetExpression { + object: object.clone(), + property: property.clone(), + value: Box::new(rhs_expr), + }) + } + Expression::IndexGet(IndexGetExpression { object, index }) => { + Expression::IndexSet(IndexSetExpression { + object: object.clone(), + index: index.clone(), - Expression::Assign(AssignExpression { - object, - value: Box::new(node), - }) + value: Box::new(rhs_expr), + }) + } + _ => Expression::Assign(AssignExpression { + object: Box::new(lhs_expr), + value: Box::new(rhs_expr), + }), + } } + Rule::add_assign_operator => create_assign_binary_expression(lhs, rhs, span, BinOp::Add), + Rule::sub_assign_operator => create_assign_binary_expression(lhs, rhs, span, BinOp::Sub), + Rule::mul_assign_operator => create_assign_binary_expression(lhs, rhs, span, BinOp::Mul), + Rule::div_assign_operator => create_assign_binary_expression(lhs, rhs, span, BinOp::Div), + Rule::rem_assign_operator => create_assign_binary_expression(lhs, rhs, span, BinOp::Rem), _ => Expression::Binary(BinaryExpression { op: op.as_str().parse::().unwrap(), lhs: Box::new(lhs?), @@ -565,6 +507,50 @@ fn parse_infix( Ok(AstNode::new(expr, span, Type::Unknown)) } +fn create_assign_binary_expression( + lhs: Result, + rhs: Result, + span: Span, + bin_op: BinOp, +) -> Expression { + let lhs_expr = lhs.unwrap(); + let rhs_expr = rhs.unwrap(); + + if let Expression::PropertyGet(PropertyGetExpression { object, property }) = + &lhs_expr.clone().node + { + // 构造 BinaryExpression 作为 PropertySet 的 value + let binary = Expression::Binary(BinaryExpression { + op: bin_op, + lhs: Box::new(lhs_expr), + rhs: Box::new(rhs_expr), + }); + + let binary_node = AstNode::new(binary, span, Type::Unknown); + + // 构造 PropertySetExpression + Expression::PropertySet(PropertySetExpression { + object: object.clone(), + property: property.clone(), + value: Box::new(binary_node), + }) + } else { + // 否则构造普通的 Assign + Binary 操作 + let binary = Expression::Binary(BinaryExpression { + op: bin_op, + lhs: Box::new(lhs_expr.clone()), + rhs: Box::new(rhs_expr), + }); + + let binary_node = AstNode::new(binary, span, Type::Unknown); + + Expression::Assign(AssignExpression { + object: Box::new(lhs_expr), + value: Box::new(binary_node), + }) + } +} + fn parse_postfix(lhs: Result, op: Pair) -> Result { let span = lhs.as_ref().unwrap().span(); let span = span.merge(&Span::from_pair(&op)); @@ -575,19 +561,31 @@ fn parse_postfix(lhs: Result, op: Pair) -> Result Expression::Try(object), Rule::member_operator => { let property = op.into_inner().next().unwrap().as_str().to_string(); - let expr = MemberExpression { object, property }; - Expression::Member(expr) + let expr = PropertyGetExpression { object, property }; + Expression::PropertyGet(expr) } Rule::call_operator => { let args = op.into_inner().next().unwrap(); let args: Result> = args.into_inner().map(parse_expression).collect(); - let expr = CallExpression { - func: object, - args: args?, - }; - Expression::Call(expr) + match object.node { + Expression::PropertyGet(PropertyGetExpression { object, property }) => { + // Convert MemberExpression + Call to MethodCall + Expression::CallMethod(CallMethodExpression { + object, + method: property, + args: args?, + }) + } + _ => { + // Normal function call + Expression::Call(CallExpression { + func: object, + args: args?, + }) + } + } } Rule::index_operator => { let index = op.into_inner().next().unwrap(); @@ -632,12 +630,12 @@ fn parse_postfix(lhs: Result, op: Pair) -> Result { - let expr = IndexExpression { + let expr = IndexGetExpression { object, index: Box::new(inner), }; - Expression::Index(expr) + Expression::IndexGet(expr) } } } @@ -687,6 +685,49 @@ fn parse_postfix(lhs: Result, op: Pair) -> Result) -> Result { + println!("parse_struct_expression, {pair:?}"); + + let span = Span::from_pair(&pair); + + let mut pairs = pair.into_inner(); + + let name = pairs.next().unwrap(); + assert_eq!(name.as_rule(), Rule::identifier); + let name = name.as_str().to_string(); + + let fields = pairs.next().unwrap().into_inner(); + + let fields = fields + .map(|pair| parse_struct_expression_field(pair)) + .collect::>>()?; + + let expr = StructExpression { + name: name.clone(), + fields, + }; + + Ok(AstNode::new( + Expression::StructExpr(expr), + span, + Type::Unknown, + )) +} + +fn parse_struct_expression_field(pair: Pair) -> Result { + println!("parse_struct_expression_field, {pair:?}"); + + let mut pairs = pair.into_inner(); + + let name = pairs.next().unwrap(); + assert_eq!(name.as_rule(), Rule::identifier); + let name = name.as_str().to_string(); + + let value = parse_expression(pairs.next().unwrap())?; + + Ok(StructExprField { name, value }) +} + fn parse_atom(pair: Pair) -> Result { let pair = pair.into_inner().next().unwrap(); let span = Span::from_pair(&pair); @@ -1072,32 +1113,11 @@ mod test { } #[test] - fn test_member_expression() { - let input = r#"a.b.c"#; - let pairs = PestParser::parse(Rule::expression, input).unwrap(); - let expression = parse_expression_pairs(pairs).unwrap(); - if let Expression::Member(member) = expression.node { - assert_eq!(member.property, "c"); - if let Expression::Member(inner_member) = member.object.node { - assert_eq!(inner_member.property, "b"); - assert_eq!( - inner_member.object.node, - Expression::Identifier(IdentifierExpression("a".to_string())) - ); - } else { - panic!("Expected inner member expression"); - } - } else { - panic!("Expected member expression"); - } - } - - #[test] - fn test_index_expression() { + fn test_index_get_expression() { let input = r#"a[1]"#; let pairs = PestParser::parse(Rule::expression, input).unwrap(); let expression = parse_expression_pairs(pairs).unwrap(); - if let Expression::Index(index) = expression.node { + if let Expression::IndexGet(index) = expression.node { assert_eq!( index.object.node, Expression::Identifier(IdentifierExpression("a".to_string())) @@ -1396,7 +1416,7 @@ mod test { let pairs = PestParser::parse(Rule::expression, input).unwrap(); let expression = parse_expression_pairs(pairs).unwrap(); if let Expression::Binary(binary) = expression.node { - assert_eq!(binary.op, BinOp::Mod); + assert_eq!(binary.op, BinOp::Rem); assert_eq!( binary.lhs.node, Expression::Literal(LiteralExpression::Integer(7)) @@ -1917,4 +1937,174 @@ mod test { panic!("Expected expression statement"); } } + + #[test] + fn test_property_get_expression() { + let input = r#"a.b"#; + let pairs = PestParser::parse(Rule::expression, input).unwrap(); + let expression = parse_expression_pairs(pairs).unwrap(); + if let Expression::PropertyGet(property_get) = expression.node { + assert_eq!(property_get.property, "b"); + assert_eq!( + property_get.object.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + } else { + panic!("Expected property get expression"); + } + + let input = r#"a.b.c"#; + let pairs = PestParser::parse(Rule::expression, input).unwrap(); + let expression = parse_expression_pairs(pairs).unwrap(); + if let Expression::PropertyGet(property_get) = expression.node { + assert_eq!(property_get.property, "c"); + if let Expression::PropertyGet(inner_property_get) = property_get.object.node { + assert_eq!(inner_property_get.property, "b"); + assert_eq!( + inner_property_get.object.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + } else { + panic!("Expected inner member expression"); + } + } else { + panic!("Expected member expression"); + } + } + + #[test] + fn test_property_set_expression() { + let input = r#"a.b = 1"#; + let pairs = PestParser::parse(Rule::expression, input).unwrap(); + let expression = parse_expression_pairs(pairs).unwrap(); + if let Expression::PropertySet(property_set) = expression.node { + assert_eq!(property_set.property, "b"); + assert_eq!( + property_set.object.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + assert_eq!( + property_set.value.node, + Expression::Literal(LiteralExpression::Integer(1)) + ); + } else { + panic!("Expected property set expression"); + } + } + + #[test] + fn test_index_set_expression() { + let input = r#"a[1] = 42"#; + let pairs = PestParser::parse(Rule::expression, input).unwrap(); + let expression = parse_expression_pairs(pairs).unwrap(); + + if let Expression::IndexSet(IndexSetExpression { + object, + index, + value, + }) = expression.node + { + assert_eq!( + object.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + assert_eq!( + index.node, + Expression::Literal(LiteralExpression::Integer(1)) + ); + + assert_eq!( + value.node, + Expression::Literal(LiteralExpression::Integer(42)) + ); + } else { + panic!("Expected index set expression"); + } + } + + #[test] + fn test_call_method_expression() { + let input = r#"a.b(1, 2)"#; + let pairs = PestParser::parse(Rule::expression, input).unwrap(); + let expression = parse_expression_pairs(pairs).unwrap(); + if let Expression::CallMethod(call_method) = expression.node { + assert_eq!(call_method.method, "b"); + assert_eq!( + call_method.object.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + assert_eq!(call_method.args.len(), 2); + assert_eq!( + call_method.args[0].node, + Expression::Literal(LiteralExpression::Integer(1)) + ); + assert_eq!( + call_method.args[1].node, + Expression::Literal(LiteralExpression::Integer(2)) + ); + } else { + panic!("Expected method call expression"); + } + } + + #[test] + fn test_create_assign_binary_expression() { + // 测试 PropertyGet + Assign 操作 + let input = r#"a.b = a.b + 1"#; + let pairs = PestParser::parse(Rule::expression, input).unwrap(); + let expression = parse_expression_pairs(pairs).unwrap(); + if let Expression::PropertySet(property_set) = expression.node { + assert_eq!(property_set.property, "b"); + assert_eq!( + property_set.object.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + if let Expression::Binary(binary) = property_set.value.node { + assert_eq!(binary.op, BinOp::Add); + if let Expression::PropertyGet(property_get) = binary.lhs.node { + assert_eq!(property_get.property, "b"); + assert_eq!( + property_get.object.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + } else { + panic!("Expected PropertyGet on lhs"); + } + assert_eq!( + binary.rhs.node, + Expression::Literal(LiteralExpression::Integer(1)) + ); + } else { + panic!("Expected binary expression in value"); + } + } else { + panic!("Expected PropertySet expression"); + } + + // 测试普通变量的 Assign + Binary 操作 + let input = r#"a = a + 1"#; + let pairs = PestParser::parse(Rule::expression, input).unwrap(); + let expression = parse_expression_pairs(pairs).unwrap(); + if let Expression::Assign(assign) = expression.node { + assert_eq!( + assign.object.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + if let Expression::Binary(binary) = assign.value.node { + assert_eq!(binary.op, BinOp::Add); + assert_eq!( + binary.lhs.node, + Expression::Identifier(IdentifierExpression("a".to_string())) + ); + assert_eq!( + binary.rhs.node, + Expression::Literal(LiteralExpression::Integer(1)) + ); + } else { + panic!("Expected binary expression in value"); + } + } else { + panic!("Expected Assign expression"); + } + } } diff --git a/src/compiler/codegen/regalloc.rs b/src/compiler/regalloc.rs similarity index 96% rename from src/compiler/codegen/regalloc.rs rename to src/compiler/regalloc.rs index 439655c..82da9ad 100644 --- a/src/compiler/codegen/regalloc.rs +++ b/src/compiler/regalloc.rs @@ -7,10 +7,8 @@ use std::{ use log::trace; use petgraph::Direction::Outgoing; -use crate::{ - bytecode::{MIN_REQUIRED_REGISTER, Register}, - ir::instruction::{Block, BlockId, ControlFlowGraph, Instruction, Value}, -}; +use super::ir::instruction::{Block, BlockId, ControlFlowGraph, Instruction, Value}; +use crate::bytecode::{MIN_REQUIRED_REGISTER, Register}; #[derive(Debug, Clone)] pub struct LiveRange { @@ -325,10 +323,9 @@ impl LiveIntervalAnalyzer { let succ_block_id = cfg.graph[succ_node]; if let Some(succ_block) = cfg.blocks.iter().position(|b| b.id == succ_block_id) + && succ_block <= block_id { - if succ_block <= block_id { - interval.update_end(block_starts[succ_block]); - } + interval.update_end(block_starts[succ_block]); } } } else { @@ -377,7 +374,7 @@ impl RegAlloc { } pub fn alloc(&mut self, value: Value, index: usize) -> (Register, Option) { - trace!("allocating {}", value); + trace!("allocating {value}"); let interval = self.liveness.intervals.get(&value).unwrap(); @@ -411,20 +408,19 @@ impl RegAlloc { } pub fn release(&mut self, value: Value, index: usize) -> Option { - trace!("releasing {}", value); + trace!("releasing {value}"); if !matches!(value, Value::Variable(_)) { return None; } let interval = self.liveness.intervals.get(&value).unwrap(); - if interval.ranges.iter().any(|range| range.end == index) { - if let Some(stack) = interval.stack { - if let Some(register) = self.reg_set.release(value) { - let spill = Action::Spill { register, stack }; - return Some(spill); - } - } + if interval.ranges.iter().any(|range| range.end == index) + && let Some(stack) = interval.stack + && let Some(register) = self.reg_set.release(value) + { + let spill = Action::Spill { register, stack }; + return Some(spill); } None diff --git a/src/compiler/semantic.rs b/src/compiler/semantic.rs index 906d8b6..42d33d0 100644 --- a/src/compiler/semantic.rs +++ b/src/compiler/semantic.rs @@ -1,23 +1,20 @@ use super::CompileError; -use crate::{Environment, ast::*}; -use std::collections::HashMap; - -pub struct SemanticAnalyzer { - // 类型环境,存储变量名到类型的映射 - type_env: HashMap, - // 函数环境,存储函数名到签名的映射 - fn_env: HashMap, +use super::ast::syntax::*; +use super::typing::TypeContext; +use crate::Environment; + +pub struct SemanticAnalyzer<'a> { + type_cx: &'a mut TypeContext, // 当前函数的返回类型,用于检查return语句 current_function_return_type: Option, // 循环嵌套计数,用于检查break和continue语句 loop_depth: usize, } -impl SemanticAnalyzer { - pub fn new() -> Self { +impl<'a> SemanticAnalyzer<'a> { + pub fn new(type_cx: &'a mut TypeContext) -> Self { SemanticAnalyzer { - type_env: HashMap::new(), - fn_env: HashMap::new(), + type_cx, current_function_return_type: None, loop_depth: 0, } @@ -30,44 +27,13 @@ impl SemanticAnalyzer { env: &Environment, ) -> Result<(), CompileError> { // 第一阶段:收集环境变量 - for name in env.symbols.keys() { - self.type_env.insert(name.to_string(), Type::EnvObject); - } - - // 第二阶段:收集函数声明 - for stmt in &program.stmts { - if let Statement::Item(ItemStatement::Fn(FunctionItem { - name, - params, - return_ty, - .. - })) = &stmt.node - { - let param_types = params - .iter() - .map(|p| { - p.ty.clone() - .map(|t| self.type_from_type_expr(&t)) - .transpose() - }) - .collect::, _>>()?; - - let return_ty = return_ty - .as_ref() - .map(|t| self.type_from_type_expr(t)) - .transpose()?; - - self.fn_env.insert( - name.clone(), - Type::Function { - params: param_types, - return_ty: return_ty.map(Box::new), - }, - ); - } + self.type_cx.set_type(name.to_string(), Type::Any); } + // 第二阶段:收集声明 + self.type_cx.analyze_type_decl(&program.stmts); + // 第三阶段:分析所有语句 for stmt in &mut program.stmts { self.analyze_statement(stmt)?; @@ -80,27 +46,8 @@ impl SemanticAnalyzer { let span = stmt.span; match &mut stmt.node { - Statement::Let(LetStatement { name, ty, value }) => { - if let Some(expr) = value { - self.analyze_expression(expr)?; - - if let Some(type_expr) = ty { - let expected_type = self.type_from_type_expr(type_expr)?; - if expected_type != Type::Unknown && expr.ty != expected_type { - return Err(CompileError::TypeMismatch { - expected: expected_type, - actual: expr.ty.clone(), - span: expr.span, - }); - } - } - - self.type_env.insert(name.clone(), expr.ty.clone()); - } - Ok(()) - } - Statement::Expression(expr) => self.analyze_expression(expr), - Statement::Item(ItemStatement::Fn(func)) => self.analyze_function(func), + Statement::Expression(expr) => self.analyze_expression(expr).map(|_| ()), + Statement::Let(let_stmt) => self.analyze_let_statement(let_stmt), Statement::If(if_stmt) => self.analyze_if_statement(if_stmt), Statement::Loop(loop_stmt) => self.analyze_loop_statement(loop_stmt), Statement::While(while_stmt) => self.analyze_while_statement(while_stmt), @@ -110,28 +57,71 @@ impl SemanticAnalyzer { Statement::Break => self.analyze_break_statement(span), Statement::Continue => self.analyze_continue_statement(span), Statement::Empty => Ok(()), - Statement::Item(ItemStatement::Struct(StructItem { .. })) => { - unimplemented!("StructItem not implemented") - } + Statement::Item(ItemStatement::Fn(func)) => self.analyze_function_item(func), + Statement::Item(ItemStatement::Struct(item)) => self.analyze_struct_item(item), Statement::Item(ItemStatement::Enum(EnumItem { .. })) => { unimplemented!("EnumItem not implemented") } } } + fn analyze_let_statement(&mut self, let_stmt: &mut LetStatement) -> Result<(), CompileError> { + let LetStatement { name, ty, value } = let_stmt; + + let decl_ty = match ty { + Some(type_expr) => { + let decl_type = self.type_from_type_expr(type_expr)?; + Some(decl_type) + } + None => None, + }; + + let value_ty = match value { + Some(value) => { + let value_ty = self.analyze_expression(value)?; + Some(value_ty) + } + None => None, + }; + + match (decl_ty, value_ty) { + (Some(decl_type), Some(value_ty)) => { + if decl_type != value_ty { + return Err(CompileError::type_mismatch( + decl_type, + value_ty, + value.clone().unwrap().span(), + )); + } + self.type_cx.set_type(name.clone(), decl_type); + } + (Some(decl_type), None) => { + self.type_cx.set_type(name.clone(), decl_type); + } + (None, Some(value_ty)) => { + self.type_cx.set_type(name.clone(), value_ty); + } + (None, None) => { + self.type_cx.set_type(name.clone(), Type::Any); + } + } + + Ok(()) + } + /// 分析If语句 fn analyze_if_statement(&mut self, if_stmt: &mut IfStatement) -> Result<(), CompileError> { // 分析条件表达式 - self.analyze_expression(&mut if_stmt.condition)?; + let condition_ty = self.analyze_expression(&mut if_stmt.condition)?; // TODO: 条件必须是布尔类型 - // if if_stmt.condition.ty != Type::Boolean { - // return Err(CompileError::TypeMismatch { - // expected: Type::Boolean, - // actual: if_stmt.condition.ty.clone(), - // span: if_stmt.condition.span, - // }); - // } + if condition_ty != Type::Boolean && condition_ty != Type::Any { + return Err(CompileError::type_mismatch( + Type::Boolean, + condition_ty.clone(), + if_stmt.condition.span, + )); + } // 分析then分支 self.analyze_block(&mut if_stmt.then_branch)?; @@ -166,15 +156,15 @@ impl SemanticAnalyzer { while_stmt: &mut WhileStatement, ) -> Result<(), CompileError> { // 分析条件表达式 - self.analyze_expression(&mut while_stmt.condition)?; + let condition_ty = self.analyze_expression(&mut while_stmt.condition)?; // 条件必须是布尔类型 - if !while_stmt.condition.ty.is_boolean() { - return Err(CompileError::TypeMismatch { - expected: Type::Boolean, - actual: while_stmt.condition.ty.clone(), - span: while_stmt.condition.span, - }); + if !condition_ty.is_boolean() { + return Err(CompileError::type_mismatch( + Type::Boolean, + condition_ty.clone(), + while_stmt.condition.span, + )); } // 增加循环深度 @@ -192,7 +182,7 @@ impl SemanticAnalyzer { /// 分析For语句 fn analyze_for_statement(&mut self, for_stmt: &mut ForStatement) -> Result<(), CompileError> { // 创建新的作用域 - let old_env = self.type_env.clone(); + let old_env = std::mem::replace(self.type_cx, self.type_cx.clone()); // 分析迭代器表达式 // self.analyze_expression(&mut for_stmt.iterable)?; @@ -209,7 +199,7 @@ impl SemanticAnalyzer { self.loop_depth -= 1; // 恢复作用域 - self.type_env = old_env; + let _ = std::mem::replace(self.type_cx, old_env); Ok(()) } @@ -225,9 +215,7 @@ impl SemanticAnalyzer { match pattern { Pattern::Wildcard => {} Pattern::Identifier(id) => { - // self.type_env.insert(id.clone(), expr.ty.clone()); - // TODO - self.type_env.insert(id.clone(), Type::Void); + self.type_cx.set_type(id.clone(), Type::Any); } Pattern::Tuple(tuple) => { for pat in tuple.iter_mut() { @@ -266,55 +254,12 @@ impl SemanticAnalyzer { self.analyze_expression(expr)?; } Ok(()) - - // TODO: 检查函数返回类型是否匹配 - // 获取当前函数的返回类型 - // let expected_return_type = match &self.current_function_return_type { - // Some(ty) => ty.clone(), - // None => { - // return Err(CompileError::ReturnOutsideFunction { - // span: span, - // }); - // } - // }; - - // match (return_stmt.value, &expected_return_type) { - // // 有返回值,且函数返回类型不是void - // (Some(expr), ty) if *ty != Type::Void => { - // self.analyze_expression(&mut expr)?; - - // // 检查返回值类型是否匹配 - // if expr.ty != *ty && *ty != Type::Unknown { - // return Err(CompileError::TypeMismatch { - // expected: ty.clone(), - // actual: expr.ty.clone(), - // span: expr.span, - // }); - // } - // } - // // 无返回值,但函数返回类型不是void - // (None, ty) if *ty != Type::Void && *ty != Type::Unknown => { - // return Err(CompileError::MissingReturnValue { - // expected: ty.clone(), - // span: 0, // 这里需要一个合适的span - // }); - // } - // // 有返回值,但函数返回类型是void - // (Some(expr), Type::Void) => { - // self.analyze_expression(expr)?; - // return Err(CompileError::UnexpectedReturnValue { span: expr.span }); - // } - // // 其他情况都是合法的 - // _ => {} - // } - - // Ok(()) } /// 分析代码块 fn analyze_block(&mut self, block: &mut BlockStatement) -> Result<(), CompileError> { // 创建新的作用域 - let old_env = self.type_env.clone(); + let old_env = std::mem::replace(self.type_cx, self.type_cx.clone()); // 分析块中的所有语句 for stmt in &mut block.0 { @@ -322,221 +267,470 @@ impl SemanticAnalyzer { } // 恢复作用域 - self.type_env = old_env; + let _ = std::mem::replace(self.type_cx, old_env); Ok(()) } /// 分析函数定义 - fn analyze_function(&mut self, func: &mut FunctionItem) -> Result<(), CompileError> { + fn analyze_function_item(&mut self, func: &mut FunctionItem) -> Result<(), CompileError> { // 创建新的作用域 - let mut local_env = self.type_env.clone(); + let old_env = std::mem::replace(self.type_cx, self.type_cx.clone()); // 获取函数返回类型 let return_ty = if let Some(ty_expr) = &func.return_ty { self.type_from_type_expr(ty_expr)? } else { - Type::Unknown + Type::Any }; // 添加参数到环境 for param in &func.params { let param_ty = match ¶m.ty { Some(ty) => self.type_from_type_expr(ty)?, - None => Type::Void, + None => Type::Any, }; - local_env.insert(param.name.clone(), param_ty); + self.type_cx.set_type(param.name.clone(), param_ty); } // 保存当前函数的返回类型,用于检查return语句 let old_return_type = self.current_function_return_type.replace(return_ty.clone()); // 分析函数体 - let old_env = std::mem::replace(&mut self.type_env, local_env); - for stmt in &mut func.body.0 { - self.analyze_statement(stmt)?; - } + self.analyze_block(&mut func.body)?; // 恢复环境 - self.type_env = old_env; + let _ = std::mem::replace(self.type_cx, old_env); self.current_function_return_type = old_return_type; Ok(()) } + fn analyze_struct_item(&mut self, item: &mut StructItem) -> Result<(), CompileError> { + Ok(()) + } + /// 分析表达式并推断类型 - fn analyze_expression(&mut self, expr: &mut ExpressionNode) -> Result<(), CompileError> { - match &mut expr.node { - Expression::Literal(lit) => { - expr.ty = match lit { - LiteralExpression::Null => Type::Unknown, - LiteralExpression::Boolean(_) => Type::Boolean, - LiteralExpression::Integer(_) => Type::Integer, - LiteralExpression::Float(_) => Type::Float, - LiteralExpression::Char(_) => Type::Char, - LiteralExpression::String(_) => Type::String, - }; - Ok(()) + fn analyze_expression(&mut self, expr: &mut ExpressionNode) -> Result { + let ty = match &mut expr.node { + Expression::Literal(lit) => self.analyze_literal_expression(lit)?, + Expression::Identifier(ident) => self.anlyze_identifier_expression(ident)?, + Expression::Binary(expr) => self.analyze_binary_expression(expr)?, + Expression::Prefix(expr) => self.analyze_prefix_expression(expr)?, + Expression::Call(expr) => self.analyze_call_expression(expr)?, + Expression::Array(expr) => self.analyze_array_expression(expr)?, + Expression::Map(expr) => self.analyze_map_expression(expr)?, + Expression::IndexGet(expr) => self.analyze_index_get_expression(expr)?, + Expression::IndexSet(expr) => self.analyze_index_set_expression(expr)?, + Expression::PropertyGet(expr) => self.analyze_property_get_expression(expr)?, + Expression::PropertySet(expr) => self.analyze_property_set_expression(expr)?, + Expression::Assign(expr) => self.analyze_assign_expression(expr)?, + Expression::Range(expr) => self.analyze_range_expression(expr)?, + Expression::Slice(expr) => self.analyze_slice_expression(expr)?, + Expression::Try(expr) => self.analyze_try_expression(expr)?, + Expression::Await(expr) => self.analyze_await_expression(expr)?, + Expression::CallMethod(expr) => self.analyze_call_method_expression(expr)?, + _ => { + // 处理其他未实现的表达式类型 + Type::Any } - Expression::Identifier(ident) => { - // 先从变量环境查找 - if let Some(ty) = self.type_env.get(&ident.0) { - expr.ty = ty.clone(); - return Ok(()); - } - // 再从函数环境查找 - if let Some(ty) = self.fn_env.get(&ident.0) { - expr.ty = ty.clone(); - return Ok(()); + }; + + expr.ty = ty.clone(); + + Ok(ty) + } + + fn analyze_literal_expression( + &mut self, + lit: &mut LiteralExpression, + ) -> Result { + Ok(match lit { + LiteralExpression::Null => Type::Any, + LiteralExpression::Boolean(_) => Type::Boolean, + LiteralExpression::Integer(_) => Type::Integer, + LiteralExpression::Float(_) => Type::Float, + LiteralExpression::Char(_) => Type::Char, + LiteralExpression::String(_) => Type::String, + }) + } + + fn anlyze_identifier_expression( + &mut self, + ident: &mut IdentifierExpression, + ) -> Result { + if let Some(ty) = self.type_cx.get_type(&ident.0) { + return Ok(ty.clone()); + } + + Err(CompileError::UndefinedVariable { + name: ident.0.clone(), + }) + } + + fn analyze_binary_expression( + &mut self, + expr: &mut BinaryExpression, + ) -> Result { + let lhs_ty = self.analyze_expression(expr.lhs.as_mut())?; + let rhs_ty = self.analyze_expression(expr.rhs.as_mut())?; + + if lhs_ty == Type::Any || rhs_ty == Type::Any { + return Ok(Type::Any); // Object类型可以和任何类型比较 + } + + match expr.op { + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem => { + if (!lhs_ty.is_numeric() || rhs_ty != lhs_ty) + && lhs_ty != Type::String + && lhs_ty != Type::Char + { + return Err(CompileError::type_mismatch( + Type::Integer, + lhs_ty, + expr.lhs.span(), + )); } - Err(CompileError::UndefinedVariable { - name: ident.0.clone(), - span: expr.span, - }) } - Expression::Binary(BinaryExpression { op, lhs, rhs }) => { - self.analyze_expression(lhs)?; - self.analyze_expression(rhs)?; - - if lhs.ty == Type::Void - || rhs.ty == Type::Void - || lhs.ty == Type::Unknown - || rhs.ty == Type::Unknown - { - expr.ty = Type::Void; - return Ok(()); // void类型可以和任何类型比较 + BinOp::LogicAnd | BinOp::LogicOr => { + if lhs_ty != Type::Boolean || rhs_ty != Type::Boolean { + return Err(CompileError::type_mismatch( + Type::Boolean, + lhs_ty, + expr.lhs.span(), + )); } + } + _ => {} + } - match op { - BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod => { - if (!lhs.ty.is_numeric() || rhs.ty != lhs.ty) - && lhs.ty != Type::String - && lhs.ty != Type::Char - { - return Err(CompileError::TypeMismatch { - expected: Type::Integer, - actual: lhs.ty.clone(), - span: lhs.span, - }); - } - } - BinOp::LogicAnd | BinOp::LogicOr => { - if lhs.ty != Type::Boolean || rhs.ty != Type::Boolean { - return Err(CompileError::TypeMismatch { - expected: Type::Boolean, - actual: lhs.ty.clone(), - span: lhs.span, - }); - } - } - _ => {} - } + Ok(match expr.op { + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem => lhs_ty, + BinOp::LogicAnd | BinOp::LogicOr => Type::Boolean, + BinOp::Less + | BinOp::LessEqual + | BinOp::Greater + | BinOp::GreaterEqual + | BinOp::Equal + | BinOp::NotEqual => Type::Boolean, + _ => Type::Any, + }) + } - expr.ty = match op { - BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod => { - lhs.ty.clone() - } - BinOp::LogicAnd | BinOp::LogicOr => Type::Boolean, - BinOp::Less - | BinOp::LessEqual - | BinOp::Greater - | BinOp::GreaterEqual - | BinOp::Equal - | BinOp::NotEqual => Type::Boolean, - _ => Type::Unknown, - }; - Ok(()) + fn analyze_prefix_expression( + &mut self, + expr: &mut PrefixExpression, + ) -> Result { + let rhs_ty = self.analyze_expression(expr.rhs.as_mut())?; + + match expr.op { + PrefixOp::Neg => { + if !(rhs_ty.is_numeric() || rhs_ty == Type::Any) { + return Err(CompileError::type_mismatch( + Type::Integer, + rhs_ty, + expr.rhs.span(), + )); + } } - Expression::Prefix(PrefixExpression { op, rhs }) => { - self.analyze_expression(rhs)?; - - match op { - PrefixOp::Neg => { - if !rhs.ty.is_numeric() { - return Err(CompileError::TypeMismatch { - expected: Type::Integer, - actual: rhs.ty.clone(), - span: rhs.span, - }); - } - } - PrefixOp::Not => { - if !rhs.ty.is_boolean() { - return Err(CompileError::TypeMismatch { - expected: Type::Boolean, - actual: rhs.ty.clone(), - span: rhs.span, - }); - } - } + PrefixOp::Not => { + if !(rhs_ty.is_boolean() || rhs_ty == Type::Any) { + return Err(CompileError::type_mismatch( + Type::Boolean, + rhs_ty, + expr.rhs.span(), + )); } + } + } + + Ok(match expr.op { + PrefixOp::Neg => rhs_ty, + PrefixOp::Not => Type::Boolean, + }) + } + + fn analyze_call_expression(&mut self, expr: &mut CallExpression) -> Result { + let func_ty = self.analyze_expression(expr.func.as_mut())?; - expr.ty = match op { - PrefixOp::Neg => rhs.ty.clone(), - PrefixOp::Not => Type::Boolean, + if func_ty == Type::Any { + return Ok(Type::Any); + } + + if let Type::Decl(Declaration::Function(FunctionDeclaration { + name, + params, + return_type, + })) = &func_ty + { + if params.len() != expr.args.len() { + return Err(CompileError::ArgumentCountMismatch { + expected: params.len(), + actual: expr.args.len(), + }); + } + + for (arg, param_ty) in expr.args.iter_mut().zip(params.iter()) { + let arg_ty = self.analyze_expression(arg)?; + if let Some(ty) = ¶m_ty.1 + && arg_ty != *ty + && arg_ty != Type::Any + { + return Err(CompileError::type_mismatch(ty.clone(), arg_ty, arg.span())); }; - Ok(()) } - Expression::Call(CallExpression { func, args }) => { - self.analyze_expression(func)?; - - if let Type::Function { params, return_ty } = &func.ty { - if params.len() != args.len() { - return Err(CompileError::ArgumentCountMismatch { - expected: params.len(), - actual: args.len(), - span: expr.span, - }); - } - - for (arg, param_ty) in args.iter_mut().zip(params.iter()) { - self.analyze_expression(arg)?; - if let Some(ty) = param_ty { - if &arg.ty != ty && arg.ty != Type::Void && arg.ty != Type::Unknown { - return Err(CompileError::TypeMismatch { - expected: ty.clone(), - actual: arg.ty.clone(), - span: arg.span, - }); - }; - } - } - - let return_ty = return_ty - .as_ref() - .map(|ty| *(ty.clone())) - .unwrap_or(Type::Unknown); - - expr.ty = return_ty; - Ok(()) - } else if func.ty == Type::EnvObject { - // when func is a dyn object from env - return Ok(()); - } else { - // Err(CompileError::NotCallable { - // ty: func.ty.clone(), - // span: func.span, - // }) - // TODO: property call - Ok(()) + + Ok(return_type + .as_ref() + .map(|t| *t.clone()) + .unwrap_or(Type::Any)) + } else { + Err(CompileError::NotCallable { + ty: func_ty, + span: expr.func.span(), + }) + } + } + + fn analyze_array_expression( + &mut self, + expr: &mut ArrayExpression, + ) -> Result { + if expr.0.is_empty() { + return Ok(Type::Array(Box::new(Type::Any))); + } + + let mut elem_types = Vec::with_capacity(expr.0.len()); + + // 为每个元素创建临时变量并分析类型 + for elem in expr.0.iter_mut() { + let elem_ty = self.analyze_expression(elem)?; + elem_types.push(elem_ty); + } + + // 检查数组元素是否类型一致 + let first_ty = &elem_types[0]; + for (i, elem) in expr.0.iter().enumerate() { + if &elem_types[i] != first_ty && elem_types[i] != Type::Any { + return Err(CompileError::type_mismatch( + first_ty.clone(), + elem_types[i].clone(), + elem.span(), + )); + } + } + + Ok(Type::Array(Box::new(first_ty.clone()))) + } + + fn analyze_map_expression(&mut self, _expr: &mut MapExpression) -> Result { + Ok(Type::Map(Box::new(Type::Any))) + } + + fn analyze_index_get_expression( + &mut self, + expr: &mut IndexGetExpression, + ) -> Result { + let object_ty = self.analyze_expression(expr.object.as_mut())?; + let _index_ty = self.analyze_expression(expr.index.as_mut())?; + + // 根据集合类型确定返回类型 + match object_ty { + Type::Array(ty) => Ok(*ty.clone()), + Type::Map(value_ty) => Ok(*value_ty.clone()), + Type::Any => Ok(Type::Any), + _ => { + // 其他不支持的集合类型 + Err(CompileError::InvalidOperation { + message: format!("Cannot index non-array and non-map type({object_ty:?})"), + }) + } + } + } + + fn analyze_index_set_expression( + &mut self, + expr: &mut IndexSetExpression, + ) -> Result { + let object_ty = self.analyze_expression(expr.object.as_mut())?; + let index_ty = self.analyze_expression(expr.index.as_mut())?; + let value_ty = self.analyze_expression(expr.value.as_mut())?; + + match object_ty { + Type::Array(ty) => { + if *ty != value_ty && value_ty != Type::Any { + return Err(CompileError::type_mismatch( + *ty, + value_ty, + expr.value.span(), + )); } } - _ => Ok(()), + Type::Map(_) | Type::Any => { + // 对于Map,Any对象,允许设置任何属性 + } + _ => { + // 其他不支持的集合类型 + return Err(CompileError::InvalidOperation { + message: "Cannot index non-array and non-map type".to_string(), + }); + } + } + + Ok(Type::Any) + } + + fn analyze_property_get_expression( + &mut self, + expr: &mut PropertyGetExpression, + ) -> Result { + let object_ty = self.analyze_expression(expr.object.as_mut())?; + + match object_ty { + Type::Map(value_ty) if *value_ty == Type::String => Ok(*value_ty), + Type::Any => { + // 对于通用对象,允许访问任何属性 + Ok(Type::Any) + } + _ => { + // 其他不支持的集合类型 + Err(CompileError::InvalidOperation { + message: "Cannot access property on non-object type".to_string(), + }) + } + } + } + + fn analyze_property_set_expression( + &mut self, + expr: &mut PropertySetExpression, + ) -> Result { + let object_ty = self.analyze_expression(expr.object.as_mut())?; + let _property_ty = self.analyze_expression(expr.value.as_mut())?; + + match object_ty { + Type::Map(value_ty) if *value_ty == Type::String => Ok(Type::Any), + Type::Any => Ok(Type::Any), // 对于Any对象,允许设置任何属性 + _ => { + // 其他不支持的集合类型 + Err(CompileError::InvalidOperation { + message: "Cannot access property on non-object type".to_string(), + }) + } } } + fn analyze_assign_expression( + &mut self, + expr: &mut AssignExpression, + ) -> Result { + let object_ty = self.analyze_expression(expr.object.as_mut())?; + let value_ty = self.analyze_expression(expr.value.as_mut())?; + + // 检查赋值左右类型是否兼容 + if object_ty != Type::Any && value_ty != Type::Any && object_ty != value_ty { + return Err(CompileError::type_mismatch( + object_ty, + value_ty, + expr.value.span(), + )); + } + + Ok(object_ty) + } + + fn analyze_range_expression( + &mut self, + expr: &mut RangeExpression, + ) -> Result { + if let Some(ref mut begin_expr) = expr.begin { + let begin_ty = self.analyze_expression(begin_expr)?; + if begin_ty != Type::Integer && begin_ty != Type::Any { + return Err(CompileError::type_mismatch( + Type::Integer, + begin_ty, + begin_expr.span(), + )); + } + } + + if let Some(ref mut end_expr) = expr.end { + let end_ty = self.analyze_expression(end_expr)?; + if end_ty != Type::Integer && end_ty != Type::Any { + return Err(CompileError::type_mismatch( + Type::Integer, + end_ty, + end_expr.span(), + )); + } + } + + Ok(Type::Range) + } + + fn analyze_slice_expression( + &mut self, + expr: &mut SliceExpression, + ) -> Result { + let object_ty = self.analyze_expression(expr.object.as_mut())?; + self.analyze_range_expression(&mut expr.range.node)?; + + // 切片表达式的类型与原始对象类型相同 + Ok(object_ty) + } + + fn analyze_try_expression(&mut self, expr: &mut ExpressionNode) -> Result { + let expr_ty = self.analyze_expression(expr)?; + if expr_ty != Type::Any { + return Err(CompileError::InvalidOperation { + message: "Cannot try non-result type".to_string(), + }); + } + + // Try表达式的类型与内部表达式类型相同 + Ok(expr_ty) + } + + fn analyze_await_expression( + &mut self, + expr: &mut ExpressionNode, + ) -> Result { + let expr_ty = self.analyze_expression(expr)?; + if expr_ty != Type::Any { + return Err(CompileError::InvalidOperation { + message: "Cannot await non-promise type".to_string(), + }); + } + + // Await表达式的类型与内部表达式类型相同 + Ok(expr_ty) + } + + fn analyze_call_method_expression( + &mut self, + expr: &mut CallMethodExpression, + ) -> Result { + let object_ty = self.analyze_expression(expr.object.as_mut())?; + + // 分析方法参数 + for arg in &mut expr.args { + self.analyze_expression(arg)?; + } + + // 方法调用的结果类型取决于方法实现,这里简单处理为Any类型 + Ok(Type::Any) + } + /// 从类型表达式转换为Type - fn type_from_type_expr(&self, type_expr: &TypeExpression) -> Result { - match type_expr { - TypeExpression::Boolean => Ok(Type::Boolean), - TypeExpression::Byte => Ok(Type::Byte), - TypeExpression::Integer => Ok(Type::Integer), - TypeExpression::Float => Ok(Type::Float), - TypeExpression::Char => Ok(Type::Char), - TypeExpression::String => Ok(Type::String), - TypeExpression::UserDefined(_) => unimplemented!("UserDefined"), - _ => Ok(Type::Unknown), + fn type_from_type_expr(&mut self, type_expr: &TypeExpression) -> Result { + let ty = self.type_cx.resolve_type_decl(type_expr); + if ty == Type::Unknown { + Err(CompileError::UnknownType { + name: format!("{type_expr:?}"), + }) + } else { + Ok(ty) } } } diff --git a/src/compiler/typing.rs b/src/compiler/typing.rs new file mode 100644 index 0000000..a7ccdd3 --- /dev/null +++ b/src/compiler/typing.rs @@ -0,0 +1,164 @@ +use std::collections::HashMap; + +use crate::Environment; + +use super::ast::syntax::*; + +#[derive(Debug, Clone)] +pub struct TypeContext { + type_decls: HashMap, + type_env: HashMap, + // 新增:用于缓存已解析的类型声明 + resolved_types: HashMap, +} + +impl TypeContext { + pub fn new() -> Self { + TypeContext { + type_decls: HashMap::new(), + type_env: HashMap::new(), + resolved_types: HashMap::new(), // 初始化缓存 + } + } + + pub fn add_type_decl(&mut self, name: String, decl: Declaration) { + self.type_decls.insert(name.clone(), decl.clone()); + + if matches!(&decl, &Declaration::Function(_)) { + self.type_env.insert(name.to_string(), Type::Decl(decl)); + } + } + + pub fn get_type_decl(&self, name: &str) -> Option<&Declaration> { + self.type_decls.get(name) + } + + pub fn get_type(&self, name: &str) -> Option<&Type> { + self.type_env.get(name) + } + + pub fn set_type(&mut self, name: String, ty: Type) { + self.type_env.insert(name, ty); + } + + pub fn function_decls(&self) -> impl Iterator { + self.type_decls.values().filter(|decl| decl.is_function()) + } + + pub fn process_env(&mut self, env: &Environment) { + for (name, _value) in env.symbols.iter() { + self.set_type(name.clone(), Type::Any); + } + } + + pub fn analyze_type_decl(&mut self, stmts: &[StatementNode]) { + for stmt in stmts { + match &stmt.node { + Statement::Item(ItemStatement::Fn(func)) => { + let FunctionItem { + name, + params, + return_ty, + body, + } = func; + + let mut param_types = Vec::new(); + + for param in params { + let ty = param.ty.clone().map(|t| self.resolve_type_decl(&t)); + + param_types.push((param.name.clone(), ty)); + } + + let return_ty = return_ty + .as_ref() + .map(|t| Box::new(self.resolve_type_decl(t))); + + let func_decl = FunctionDeclaration { + name: name.clone(), + params: param_types, + return_type: return_ty, + }; + + self.add_type_decl(name.clone(), Declaration::Function(func_decl)); + } + Statement::Item(ItemStatement::Struct(item)) => { + let StructItem { name, fields } = item; + let struct_decl = StructDeclaration { + name: name.clone(), + fields: fields + .iter() + .map(|field| (field.name.clone(), self.resolve_type_decl(&field.ty))) + .collect(), + }; + + self.add_type_decl(name.clone(), Declaration::Struct(struct_decl)); + } + Statement::Item(ItemStatement::Enum(EnumItem { .. })) => {} + _ => {} + } + } + } + + // 新增:递归解析类型声明 + fn resolve_type_decl_recursive(&mut self, type_expr: &TypeExpression) -> Type { + match type_expr { + TypeExpression::Any => Type::Any, + TypeExpression::Boolean => Type::Boolean, + TypeExpression::Byte => Type::Byte, + TypeExpression::Integer => Type::Integer, + TypeExpression::Float => Type::Float, + TypeExpression::Char => Type::Char, + TypeExpression::String => Type::String, + TypeExpression::Tuple(types) => { + let types = types.iter().map(|ty| self.resolve_type_decl(ty)).collect(); + Type::Tuple(types) + } + TypeExpression::Array(ty) => { + let ty = self.resolve_type_decl(ty); + Type::Array(Box::new(ty)) + } + TypeExpression::UserDefined(ty) => { + // 检查缓存中是否存在已解析的类型 + if let Some(cached_type) = self.resolved_types.get(ty) { + return cached_type.clone(); + } + + // 检查是否已经存在于 type_env 中 + if let Some(ty) = self.get_type(ty) { + return ty.clone(); + } + + // 解析类型声明 + if let Some(decl) = self.get_type_decl(ty) { + let resolved_type = match decl { + Declaration::Function(func_decl) => { + Type::Decl(Declaration::Function(func_decl.clone())) + } + Declaration::Struct(struct_decl) => { + Type::Decl(Declaration::Struct(struct_decl.clone())) + } + Declaration::Enum(enum_decl) => { + Type::Decl(Declaration::Enum(enum_decl.clone())) + } + }; + + // 更新缓存 + self.resolved_types + .insert(ty.clone(), resolved_type.clone()); + self.set_type(ty.clone(), resolved_type.clone()); + resolved_type + } else { + // 如果无法解析,则返回 UserDefined + Type::UserDefined(ty.clone()) + } + } + _ => Type::Any, + } + } + + // 新增:对外暴露的解析函数 + pub fn resolve_type_decl(&mut self, type_expr: &TypeExpression) -> Type { + self.resolve_type_decl_recursive(type_expr) + } +} diff --git a/src/error.rs b/src/error.rs index 964c18d..bdcdd6f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,25 +1,11 @@ -use crate::{ast::ParseError, compiler::CompileError, runtime::RuntimeError}; +use crate::{compiler::CompileError, runtime::RuntimeError}; #[derive(Debug)] pub enum Error { - Io(std::io::Error), - Parse(ParseError), Compile(CompileError), Runtime(RuntimeError), } -impl From for Error { - fn from(error: std::io::Error) -> Self { - Error::Io(error) - } -} - -impl From for Error { - fn from(error: ParseError) -> Self { - Error::Parse(error) - } -} - impl From for Error { fn from(error: CompileError) -> Self { Error::Compile(error) diff --git a/src/interpreter.rs b/src/interpreter.rs index 5e30feb..b3ae8f2 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,658 +1,94 @@ -use std::collections::HashMap; - -use log::debug; - -#[cfg(feature = "async")] -pub use crate::Promise; -use crate::bytecode::{Bytecode, FunctionId, Module, Opcode, Operand, Register}; use crate::compiler::Compiler; -use crate::runtime::{Enumerator, Range, RuntimeError, UserFunction, VM}; -use crate::runtime::{Environment, ValueRef}; -use crate::{Error, NativeFunction, Object, Value}; - -pub struct Interpreter { - constants: Vec, - instructions: Vec, - symtab: HashMap, - env: Environment, - vm: VM, -} - -impl Interpreter { - pub fn new(module: Module, env: Environment, vm: VM) -> Self { - let Module { - constants, - instructions, - symtab: symbles, - .. - } = module; - - let constants = constants.into_iter().map(ValueRef::from_constant).collect(); - - Self { - constants, - instructions, - symtab: symbles, - env, - vm, - } - } - - #[cfg(not(feature = "async"))] - pub fn eval_script(script: &str, env: Environment) -> Result, Error> { - let compiler = Compiler::new(); - - let module = compiler.compile(script, &env)?; - - // log::trace!("module {module}"); - - let mut interpreter = Interpreter::new(module, env, VM::new()); - - debug!("===constants==="); - for (i, constant) in interpreter.constants.iter().enumerate() { - debug!("{i}\t{constant:?}"); - } - debug!("===instructions==="); - for (i, bytecode) in interpreter.instructions.iter().enumerate() { - debug!("{i}\t{bytecode:?}"); - } - debug!("===symtab==="); - for (i, (id, offset)) in interpreter.symtab.iter().enumerate() { - debug!("{i}\t{id:?}\t{offset}"); - } - - let ret = interpreter.run()?; +use crate::runtime::{Environment, VM}; +use crate::{Error, Object, RuntimeError, Value}; - Ok(ret.map(ValueRef::take)) - } - - #[cfg(feature = "async")] - pub fn eval_script(script: &str, env: Environment) -> Result, Error> { - futures::executor::block_on(Self::eval_script_async(script, env)) - } - - #[cfg(feature = "async")] - pub async fn eval_script_async(script: &str, env: Environment) -> Result, Error> { - let compiler = Compiler::new(); - - let module = compiler.compile(script, &env)?; +#[cfg(feature = "async")] +pub fn eval(script: &str, env: Environment) -> Result, Error> { + let compiler = Compiler::new(); + let module = compiler.compile(script, &env)?; - // log::trace!("module {module}"); + let mut vm = VM::new(module, env); - let mut interpreter = Interpreter::new(module, env, VM::new()); + let ret = futures::executor::block_on(async { vm.run().await })?; - debug!("===constants==="); - for (i, constant) in interpreter.constants.iter().enumerate() { - debug!("{i}\t{constant:?}"); - } - debug!("===instructions==="); - for (i, bytecode) in interpreter.instructions.iter().enumerate() { - debug!("{i}\t{bytecode:?}"); - } - debug!("===symtab==="); - for (i, (id, offset)) in interpreter.symtab.iter().enumerate() { - debug!("{i}\t{id:?}\t{offset}"); + match ret { + Some(v) => { + let v = v.take(); + v.into_inner::() + .map(|v| Some(v)) + .map_err(|err| RuntimeError::invalid_type::(err).into()) } - - #[cfg(feature = "async")] - let ret = interpreter.run_async().await?; - - Ok(ret.map(ValueRef::take)) + None => Ok(None), } +} - #[cfg(feature = "async")] - pub async fn run_async(&mut self) -> Result, RuntimeError> { - loop { - let bytecode = self.instructions.get(self.vm.pc()); - if bytecode.is_none() { - return Ok(None); - } - - let bytecode = bytecode.unwrap().clone(); - - debug!("{}", self.vm); - debug!("{bytecode:?}"); - - match bytecode.opcode { - Opcode::Halt => { - let ret = self.get_value(Operand::Register(Register::RV))?; - return Ok(Some(ret)); - } - - Opcode::Ret => { - if self.vm.ctrl_stack_reached_bottom() { - let ret = self.get_value(Operand::Register(Register::RV))?; - return Ok(Some(ret)); - } - let pc = self.vm.popc()?; +#[cfg(feature = "async")] +pub async fn eval_async( + script: &str, + env: Environment, +) -> Result, Error> { + let compiler = Compiler::new(); + let module = compiler.compile(script, &env)?; - self.vm.jump(pc); - } + let mut vm = VM::new(module, env); - Opcode::Await => { - let promise = self.get_value(bytecode.operands[1])?; - let mut promise = promise.take(); - let promise = promise - .downcast_mut::() - .ok_or(RuntimeError::internal("only can await promise"))?; - let ret = promise.await; - self.set_value(bytecode.operands[0], ret)?; - self.vm.jump_offset(1); - } + let ret = vm.run().await?; - _ => { - self.run_instruction(&bytecode)?; - } - } + match ret { + Some(v) => { + let v = v.take(); + v.into_inner::() + .map(|v| Some(v)) + .map_err(|err| RuntimeError::invalid_type::(err).into()) } + None => Ok(None), } +} - pub fn run(&mut self) -> Result, RuntimeError> { - loop { - let bytecode = self.instructions.get(self.vm.pc()); - if bytecode.is_none() { - return Ok(None); - } - - let bytecode = bytecode.unwrap().clone(); - - debug!("{}", self.vm); - debug!("{bytecode:?}"); - - match bytecode.opcode { - Opcode::Halt => { - let ret = self.get_value(Operand::Register(Register::RV))?; - return Ok(Some(ret)); - } +#[cfg(not(feature = "async"))] +pub fn eval(script: &str, env: Environment) -> Result, Error> { + let compiler = Compiler::new(); + let module = compiler.compile(script, &env)?; - Opcode::Ret => { - if self.vm.ctrl_stack_reached_bottom() { - let ret = self.get_value(Operand::Register(Register::RV))?; - return Ok(Some(ret)); - } - let pc = self.vm.popc()?; + let mut vm = VM::new(module, env); - self.vm.jump(pc); - } + let ret = vm.run()?; - _ => { - self.run_instruction(&bytecode)?; - } - } + match ret { + Some(v) => { + let v = v.take(); + v.into_inner::() + .map(|v| Some(v)) + .map_err(|err| RuntimeError::invalid_type::(err).into()) } + None => Ok(None), } +} - fn run_instruction(&mut self, bytecode: &Bytecode) -> Result<(), RuntimeError> { - match bytecode.opcode { - // ctrl stack opcode begin - Opcode::MovC => match (bytecode.operands[0], bytecode.operands[1]) { - (Operand::Register(Register::RSP), Operand::Register(Register::RBP)) => { - *self.vm.rsp_mut() = self.vm.rbp(); - } - (Operand::Register(Register::RBP), Operand::Register(Register::RSP)) => { - *self.vm.rbp_mut() = self.vm.rsp(); - } - - _ => unimplemented!("unsupported instruction:{bytecode:?}"), - }, - Opcode::PushC => match bytecode.operands[0] { - Operand::Register(Register::RSP) => { - self.vm.pushc(self.vm.rsp())?; - } - Operand::Register(Register::RBP) => { - self.vm.pushc(self.vm.rbp())?; - } - _ => unimplemented!("unsupported instruction:{bytecode:?}"), - }, - Opcode::PopC => match bytecode.operands[0] { - Operand::Register(Register::RSP) => { - let value = self.vm.popc()?; - *self.vm.rsp_mut() = value; - } - Operand::Register(Register::RBP) => { - let value = self.vm.popc()?; - *self.vm.rbp_mut() = value; - } - _ => unimplemented!("unsupported instruction:{bytecode:?}"), - }, - Opcode::AddC => match (bytecode.operands[0], bytecode.operands[1]) { - (Operand::Register(Register::RSP), Operand::Register(Register::RSP)) => { - *self.vm.rsp_mut() = self.vm.rsp() + bytecode.operands[2].as_immd() as usize; - } - _ => unimplemented!("unsupported instruction:{bytecode:?}"), - }, - Opcode::SubC => match (bytecode.operands[0], bytecode.operands[1]) { - (Operand::Register(Register::RSP), Operand::Register(Register::RSP)) => { - *self.vm.rsp_mut() = self.vm.rsp() - bytecode.operands[2].as_immd() as usize; - } - _ => unimplemented!("unsupported instruction:{bytecode:?}"), - }, - // ctrl stack opcode end - Opcode::Call => { - let func = bytecode.operands[0].as_immd(); - match self.symtab.get(&FunctionId::new(func as u32)) { - Some(location) => { - self.vm.pushc(self.vm.pc() + 1)?; - self.vm.jump(*location); - return Ok(()); - } - None => { - return Err(RuntimeError::SymbolNotFound { - name: format!("{func}"), - }); - } - } - } - Opcode::CallEx => { - match bytecode.operands[0] { - Operand::Symbol(sym) => match self.symtab.get(&FunctionId::new(sym)) { - Some(location) => { - self.vm.pushc(self.vm.pc() + 1)?; - self.vm.jump(*location); - return Ok(()); - } - None => { - return Err(RuntimeError::SymbolNotFound { - name: format!("{sym}"), - }); - } - }, - Operand::Register(_) | Operand::Stack(_) => { - let value = self.get_value(bytecode.operands[0])?; - match value.downcast_ref::() { - Some(func) => match self.symtab.get(&func.id()) { - Some(location) => { - self.vm.pushc(self.vm.pc() + 1)?; - self.vm.jump(*location); - return Ok(()); - } - None => { - return Err(RuntimeError::SymbolNotFound { - name: format!("{:?}", func.id()), - }); - } - }, - None => { - return Err(RuntimeError::invalid_operand(bytecode.operands[0])); - } - } - // value.get_mut().call(&[]); - // unimplemented!("call object {value:?}") - } - - _ => return Err(RuntimeError::invalid_operand(bytecode.operands[0])), - } - } - - Opcode::CallNative => { - let mut func = self.get_value(bytecode.operands[0])?; - let arg_count = bytecode.operands[1].as_immd() as usize; - match func.downcast_mut::() { - Some(mut func) => { - // load args from stack - let mut args = Vec::with_capacity(arg_count); - for i in 0..arg_count { - let arg = self.get_value(Operand::Stack(-(i as isize + 1)))?; - args.push(arg); - } - let ret = func.call(&args)?; - let ret = ret.unwrap_or(Value::null()); - self.vm.set_register(Register::RV, ValueRef::from(ret))?; - } - None => { - return Err(RuntimeError::invalid_operand(bytecode.operands[0])); - } - } - } - - Opcode::PropCall => { - let mut object = self.get_value(bytecode.operands[0])?; - let prop = self.load_string(bytecode.operands[1])?; - let arg_count = bytecode.operands[2].as_immd() as usize; - // load args from stack - let mut args = Vec::with_capacity(arg_count); - for i in 0..arg_count { - let arg = self.get_value(Operand::Stack(-(i as isize + 1)))?; - args.push(arg); - } - let ret = object.borrow_mut().property_call(&prop, &args)?; - let ret = ret.unwrap_or(Value::null()); - self.vm.set_register(Register::RV, ValueRef::from(ret))?; - } - - Opcode::Mov => { - let value = self.get_value(bytecode.operands[1])?; - match bytecode.operands[0] { - Operand::Register(reg) => { - self.vm.set_register(reg, value)?; - } - Operand::Stack(offset) => { - self.vm.set_value_to_stack(offset, value)?; - } - op => return Err(RuntimeError::invalid_operand(op)), - } - } - Opcode::Push => { - let value = self.get_value(bytecode.operands[0])?; - self.vm.push(value)?; - } - Opcode::Pop => { - let value = self.vm.pop()?; - self.set_value(bytecode.operands[0], value)?; - } - - Opcode::Not | Opcode::Neg => { - let value = self.get_value(bytecode.operands[1])?; - let value = value.borrow().negate()?; - self.set_value(bytecode.operands[0], ValueRef::from(value))?; - } - Opcode::Addx => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = lhs.borrow().add(&rhs.value())?; - self.set_value(bytecode.operands[0], value)?; - } - Opcode::Subx => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = lhs.borrow().sub(&rhs.value())?; - self.set_value(bytecode.operands[0], value)?; - } - Opcode::Mulx => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = lhs.borrow().mul(&rhs.value())?; - self.set_value(bytecode.operands[0], value)?; - } - Opcode::Divx => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = lhs.borrow().div(&rhs.value())?; - self.set_value(bytecode.operands[0], value)?; - } - Opcode::Modx => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = lhs.borrow().modulo(&rhs.value())?; - self.set_value(bytecode.operands[0], value)?; - } - - Opcode::And => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = lhs.borrow().logic_and(&rhs.value())?; - self.set_value(bytecode.operands[0], value)?; - } - Opcode::Or => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = lhs.borrow().logic_or(&rhs.value())?; - self.set_value(bytecode.operands[0], value)?; - } - - Opcode::Greater => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let ordering = lhs.borrow().compare(&rhs.value())?; - self.set_value( - bytecode.operands[0], - ValueRef::new(ordering == std::cmp::Ordering::Greater), - )?; - } - Opcode::GreaterEqual => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let ordering = lhs.borrow().compare(&rhs.value())?; - self.set_value( - bytecode.operands[0], - ValueRef::new( - ordering == std::cmp::Ordering::Greater - || ordering == std::cmp::Ordering::Equal, - ), - )?; - } - - Opcode::Less => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let ordering = lhs.borrow().compare(&rhs.value())?; - self.set_value( - bytecode.operands[0], - ValueRef::new(ordering == std::cmp::Ordering::Less), - )?; - } - - Opcode::LessEqual => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let ordering = lhs.borrow().compare(&rhs.value())?; - self.set_value( - bytecode.operands[0], - ValueRef::new( - ordering == std::cmp::Ordering::Less - || ordering == std::cmp::Ordering::Equal, - ), - )?; - } - - Opcode::Equal => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let ordering = lhs.borrow().compare(&rhs.value())?; - self.set_value( - bytecode.operands[0], - ValueRef::new(ordering == std::cmp::Ordering::Equal), - )?; - } - - Opcode::NotEqual => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let ordering = lhs.borrow().compare(&rhs.value())?; - self.set_value( - bytecode.operands[0], - ValueRef::new(ordering != std::cmp::Ordering::Equal), - )?; - } - - Opcode::LoadConst => { - let const_index = bytecode.operands[1].as_immd(); - let value = self.constants[const_index as usize].clone(); - self.set_value(bytecode.operands[0], value)?; - } - - Opcode::LoadEnv => { - let name = bytecode.operands[1].as_immd(); - let name = self.constants[name as usize].clone(); - let name = name - .downcast_ref::() - .ok_or(RuntimeError::invalid_type::(&name))?; - match self.env.get(name.as_str()) { - Some(value) => { - self.set_value(bytecode.operands[0], value.clone())?; - } - None => { - return Err(RuntimeError::symbol_not_found(name.as_str())); - } - } - } - - Opcode::Br => { - let offset = bytecode.operands[0].as_immd(); - self.vm.jump_offset(offset); - return Ok(()); - } - - Opcode::BrIf => { - let cond = self.get_value(bytecode.operands[0])?; - match cond.downcast_ref::() { - Some(b) => { - let offset = if *b { - bytecode.operands[1].as_immd() - } else { - bytecode.operands[2].as_immd() - }; - self.vm.jump_offset(offset); - } - None => return Err(RuntimeError::invalid_type::(&cond)), - } - return Ok(()); - } - - Opcode::Range => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = Range::new(lhs, rhs)?; - self.set_value(bytecode.operands[0], ValueRef::new(value))?; - } - - Opcode::RangeInclusive => { - let lhs = self.get_value(bytecode.operands[1])?; - let rhs = self.get_value(bytecode.operands[2])?; - let value = Range::inclusive(lhs, rhs)?; - self.set_value(bytecode.operands[0], ValueRef::new(value))?; - } - - Opcode::RangeFull => { - let value = Range::range_full(); - self.set_value(bytecode.operands[0], ValueRef::new(value))?; - } - - Opcode::RangeFrom => { - let lhs = self.get_value(bytecode.operands[1])?; - let value = Range::range_from(lhs)?; - self.set_value(bytecode.operands[0], ValueRef::new(value))?; - } - - Opcode::RangeTo => { - let lhs = self.get_value(bytecode.operands[1])?; - let value = Range::range_to(lhs)?; - self.set_value(bytecode.operands[0], ValueRef::new(value))?; - } - - Opcode::RangeToInclusive => { - let lhs = self.get_value(bytecode.operands[1])?; - let value = Range::range_to_inclusive(lhs)?; - self.set_value(bytecode.operands[0], ValueRef::new(value))?; - } - - Opcode::MakeIter => { - let obj = self.get_value(bytecode.operands[1])?; - let iterator = obj.borrow().make_iterator()?; - self.set_value( - bytecode.operands[0], - ValueRef::new(Enumerator::new(iterator)), - )?; - } - - Opcode::IterHasNext => { - let iterator = self.get_value(bytecode.operands[1])?; - let value = iterator.borrow().iterator_has_next()?; - self.set_value(bytecode.operands[0], ValueRef::new(value))?; - } - - Opcode::IterNext => { - let mut iterator = self.get_value(bytecode.operands[1])?; - let value = iterator.borrow_mut().iterate_next()?; - self.set_value(bytecode.operands[0], value)?; - } - - Opcode::MakeMap => { - let map: HashMap = HashMap::new(); - self.set_value(bytecode.operands[0], ValueRef::new(map))?; - } - - Opcode::IndexSet => { - let mut object = self.get_value(bytecode.operands[0])?; - let index = self.get_value(bytecode.operands[1])?; - let value = self.get_value(bytecode.operands[2])?; - object.borrow_mut().index_set(&index.value(), value)?; - } - - Opcode::IndexGet => { - let object = self.get_value(bytecode.operands[1])?; - let index = self.get_value(bytecode.operands[2])?; - let value = object.borrow().index_get(&index.value())?; - self.set_value(bytecode.operands[0], value)?; - } - - Opcode::MakeArray => { - let array: Vec = Vec::new(); - self.set_value(bytecode.operands[0], ValueRef::new(array))?; - } - - Opcode::ArrayPush => { - let mut array = self.get_value(bytecode.operands[0])?; - let value = self.get_value(bytecode.operands[1])?; - let array_cloned = array.clone(); - let mut array = array - .downcast_mut::>() - .ok_or(RuntimeError::invalid_type::>(array_cloned))?; - array.push(value); - } - - Opcode::MakeSlice => { - let object = self.get_value(bytecode.operands[1])?; - let range = self.get_value(bytecode.operands[2])?; - - let slice = object.borrow().make_slice(range)?; - self.set_value(bytecode.operands[0], slice)?; - } - Opcode::PropGet => { - let object = self.get_value(bytecode.operands[1])?; - let prop = self.load_string(bytecode.operands[2])?; - - let value = object.borrow().property_get(&prop)?; +pub struct Interpreter {} - self.set_value(bytecode.operands[0], value)?; - } - Opcode::PropSet => { - let mut object = self.get_value(bytecode.operands[0])?; - let prop = self.load_string(bytecode.operands[1])?; - let value = self.get_value(bytecode.operands[2])?; +impl Interpreter { + #[cfg(feature = "async")] + pub fn eval(script: &str, env: Environment) -> Result, Error> { + let compiler = Compiler::new(); + let module = compiler.compile(script, &env)?; - object.borrow_mut().property_set(&prop, value)?; - } - inst => unreachable!("unsupported instruction {inst:?}"), - } + let mut vm = VM::new(module, env); - self.vm.jump_offset(1); + let ret = futures::executor::block_on(async { vm.run().await })?; - Ok(()) + Ok(ret.map(|v| v.take())) } - fn get_value(&self, operand: Operand) -> Result { - match operand { - Operand::Primitive(primitive) => Ok(ValueRef::from_primitive(primitive)), - Operand::Register(reg) => self.vm.get_register(reg), - Operand::Stack(offset) => self.vm.get_value_from_stack(offset), - Operand::Immd(immd) => Ok(ValueRef::immd(immd)), - Operand::Symbol(symbol) => { - Ok(ValueRef::new(UserFunction::new(FunctionId::new(symbol)))) - } // op => Err(RuntimeError::UnsupportedOperand(format!("{:?}", op))), - } - } + #[cfg(not(feature = "async"))] + pub fn eval(script: &str, env: Environment) -> Result, Error> { + let compiler = Compiler::new(); + let module = compiler.compile(script, &env)?; - fn set_value( - &mut self, - operand: Operand, - value: impl Into, - ) -> Result<(), RuntimeError> { - let value = value.into(); + let mut vm = VM::new(module, env); - match operand { - Operand::Register(reg) => self.vm.set_register(reg, value), - Operand::Stack(offset) => self.vm.set_value_to_stack(offset, value), - op => Err(RuntimeError::invalid_operand(op)), - } - } + let ret = vm.run()?; - fn load_string(&self, operand: Operand) -> Result { - let const_id = operand.as_immd(); - let name = self.constants[const_id as usize].clone(); - let name = name - .downcast_ref::() - .ok_or(RuntimeError::invalid_type::(&name))?; - Ok(name.clone()) + Ok(ret.map(|v| v.take())) } } diff --git a/src/lib.rs b/src/lib.rs index 8df6954..f45eb60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,14 @@ -mod ast; mod bytecode; mod compiler; mod error; mod interpreter; -mod ir; mod runtime; +pub use bytecode::Module; +pub use compiler::{Compiler, compile}; pub use error::Error; -pub use interpreter::Interpreter; +pub use interpreter::{Interpreter, eval}; + #[cfg(feature = "async")] pub use runtime::Promise; -pub use runtime::{Environment, NativeFunction, Null, Object, RuntimeError, Value, ValueRef}; +pub use runtime::{Environment, NativeFunction, Null, Object, RuntimeError, VM, Value, ValueRef}; diff --git a/src/runtime.rs b/src/runtime.rs index bdd5ca8..3d8aac9 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,14 +1,15 @@ use std::any::type_name_of_val; -use object::OperateKind; - mod environment; mod object; mod value; mod vm; use crate::bytecode::{Operand, Register}; -pub use environment::Environment; + +use object::OperateKind; + +pub use environment::{EnvVariable, Environment}; #[cfg(feature = "async")] pub use object::Promise; pub use object::{Callable, Enumerator, NativeFunction, Null, Object, Range}; @@ -55,6 +56,22 @@ pub enum RuntimeError { InvalidOperand { operand: Operand, }, + MissingMethod { + object: String, + method: String, + }, + MissingProperty { + object: String, + property: String, + }, + MissingPropertyGetter { + object: String, + property: String, + }, + MissingPropertySetter { + object: String, + property: String, + }, } impl RuntimeError { @@ -109,6 +126,34 @@ impl RuntimeError { pub fn invalid_operand(operand: Operand) -> Self { RuntimeError::InvalidOperand { operand } } + + pub fn missing_method(method: impl ToString) -> Self { + RuntimeError::MissingMethod { + object: std::any::type_name::().to_string(), + method: method.to_string(), + } + } + + pub fn missing_property(property: impl ToString) -> Self { + RuntimeError::MissingProperty { + object: std::any::type_name::().to_string(), + property: property.to_string(), + } + } + + pub fn missing_property_getter(property: impl ToString) -> Self { + RuntimeError::MissingPropertyGetter { + object: std::any::type_name::().to_string(), + property: property.to_string(), + } + } + + pub fn missing_property_setter(property: impl ToString) -> Self { + RuntimeError::MissingPropertySetter { + object: std::any::type_name::().to_string(), + property: property.to_string(), + } + } } impl std::fmt::Display for RuntimeError { @@ -154,6 +199,18 @@ impl std::fmt::Display for RuntimeError { RuntimeError::InvalidOperand { operand } => { write!(f, "Invalid operand: {operand:?}") } + RuntimeError::MissingMethod { object, method } => { + write!(f, "Missing method: {method} for {object}") + } + RuntimeError::MissingProperty { object, property } => { + write!(f, "Missing property: {property} for {object}") + } + RuntimeError::MissingPropertyGetter { object, property } => { + write!(f, "Missing property getter: {property} for {object}") + } + RuntimeError::MissingPropertySetter { object, property } => { + write!(f, "Missing property setter: {property} for {object}") + } } } } diff --git a/src/runtime/environment.rs b/src/runtime/environment.rs index 0709ada..e133e51 100644 --- a/src/runtime/environment.rs +++ b/src/runtime/environment.rs @@ -1,9 +1,16 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; -use super::{Callable, NativeFunction, ValueRef}; +use super::{Callable, NativeFunction, Object, ValueRef}; +#[derive(Debug, Clone)] +pub enum EnvVariable { + Value(ValueRef), + Function(ValueRef), +} + +#[derive(Debug, Clone)] pub struct Environment { - pub(crate) symbols: HashMap, + pub(crate) symbols: BTreeMap, } impl Default for Environment { @@ -15,51 +22,68 @@ impl Default for Environment { impl Environment { pub fn new() -> Self { Environment { - symbols: HashMap::new(), + symbols: BTreeMap::new(), } } - pub fn with_variable(mut self, name: impl ToString, value: impl Into) -> Self { - self.define(name, value); + pub fn with_variable(mut self, name: impl ToString, value: T) -> Self { + self.insert(name, value); self } pub fn with_function( mut self, name: impl ToString, - callable: impl Callable + Send, + callable: impl Callable + Send + Sync + 'static, ) -> Self { self.define_function(name, callable); self } - pub fn define(&mut self, name: impl ToString, value: impl Into) { - self.symbols.insert(name.to_string(), value.into()); + pub fn insert(&mut self, name: impl ToString, value: T) { + self.symbols + .insert(name.to_string(), EnvVariable::Value(ValueRef::new(value))); } - // pub fn define_function(&mut self, name: impl ToString, func: F) - // where - // F: Fn(&[ValueRef]) -> Result, RuntimeError> + 'static, - // { - // let Value = Value.to_string(); - // self.define(Value.clone(), NativeFunction::new(Value, Box::new(func))); - // } - pub fn define_function( &mut self, name: impl ToString, - callable: impl Callable + Send, + callable: impl Callable + Send + Sync + 'static, ) { - self.define( + self.symbols.insert( name.to_string(), - ValueRef::new(NativeFunction::new( + EnvVariable::Function(ValueRef::new(NativeFunction::new( name, Box::new(callable.into_function()), - )), + ))), ); } - pub fn get(&self, name: impl AsRef) -> Option { - self.symbols.get(name.as_ref()).cloned() + pub fn get(&self, name: impl AsRef) -> Option<&EnvVariable> { + self.symbols.get(name.as_ref()) } + + pub fn remove_as(&mut self, name: impl AsRef) -> Option { + match self.symbols.remove(name.as_ref()) { + Some(EnvVariable::Value(value)) => { + let object = value.take(); + object.into_inner().ok() + } + _ => None, + } + } + + // pub fn get_var(&self, name: impl AsRef) -> Option<&&'a mut dyn Object> { + // self.symbols.get(name.as_ref()).and_then(|val| match val { + // EnvVariable::Value(value) => Some(value), + // _ => None, + // }) + // } + + // pub fn get_function_mut(&self, name: impl AsRef) -> Option<&NativeFunction> { + // self.symbols.get(name.as_ref()).and_then(|val| match val { + // EnvVariable::Function(func) => Some(func), + // _ => None, + // }) + // } } diff --git a/src/runtime/object.rs b/src/runtime/object.rs index adf7ed7..ce91cc1 100644 --- a/src/runtime/object.rs +++ b/src/runtime/object.rs @@ -6,30 +6,195 @@ mod function; mod immd; mod integer; mod map; +mod metatable; mod null; +mod optional; +#[cfg(feature = "async")] +mod promise; mod range; mod string; +mod structobject; mod tuple; -#[cfg(feature = "async")] -mod promise; - pub use emurator::Enumerator; pub use function::{Callable, NativeFunction, UserFunction}; pub use immd::Immd; pub use null::Null; -pub use range::Range; - #[cfg(feature = "async")] pub use promise::Promise; +pub use range::Range; +pub use structobject::StructObject; + +use super::{RuntimeError, Value, ValueRef}; -use std::fmt; +use std::{any::type_name_of_val, fmt}; #[cfg(feature = "async")] -use futures::Future; +pub trait Object: std::any::Any + std::fmt::Debug + Send + Sync { + fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&format!("{self:?}")) + } -use super::{RuntimeError, Value, ValueRef}; + /// arithmetic addition operation + fn add(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Add, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// arithmetic subtraction operation + fn sub(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Subtract, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// arithmetic multiplication operation + fn mul(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Multiply, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// arithmetic division operation + fn div(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Divide, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// arithmetic remainder operation + fn rem(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Remainder, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + fn equal(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Equal, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// compare operation + fn compare(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Compare, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// logic and operation + fn logic_and(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::LogicAnd, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// logic or operation + fn logic_or(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::LogicOr, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// negate operation + fn negate(&self) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Negate, + format!("rhs: {self:?}"), + )) + } + + fn call(&mut self, args: &[ValueRef]) -> Result, RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::Call, + "unimplemented", + )) + } + + /// index get operation + fn index_get(&self, index: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::IndexGet, + "unimplemented", + )) + } + + fn index_set(&mut self, index: &Value, value: ValueRef) -> Result<(), RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::IndexSet, + "unimplemented", + )) + } + + fn property_get(&self, property: &str) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::PropertyGet, + "unimplemented", + )) + } + + fn property_set(&mut self, property: &str, value: ValueRef) -> Result<(), RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::PropertySet, + "unimplemented", + )) + } + + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + Err(RuntimeError::MissingMethod { + object: type_name_of_val(self).to_string(), + method: method.to_string(), + }) + } + + fn make_iterator( + &self, + ) -> Result + Send + Sync>, RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::MakeIterator, + "unimplemented", + )) + } + + fn iterate_next(&mut self) -> Result, RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::IterateNext, + "unimplemented", + )) + } + + fn make_slice(&self, range: ValueRef) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::MakeSlice, + "unimplemented", + )) + } + + fn into_future( + self: Box, + ) -> Result + Unpin + Send + 'static>, RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::Await, + "unimplemented", + )) + } +} +#[cfg(not(feature = "async"))] pub trait Object: std::any::Any + std::fmt::Debug { fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&format!("{self:?}")) @@ -67,18 +232,17 @@ pub trait Object: std::any::Any + std::fmt::Debug { )) } - /// arithmetic modulo operation - fn modulo(&self, other: &Value) -> Result { + /// arithmetic remainder operation + fn rem(&self, other: &Value) -> Result { Err(RuntimeError::invalid_operation( - OperateKind::Modulo, + OperateKind::Remainder, format!("lhs: {self:?}, rhs: {other:?}"), )) } - /// arithmetic power operation - fn pow(&self, other: &Value) -> Result { + fn equal(&self, other: &Value) -> Result { Err(RuntimeError::invalid_operation( - OperateKind::Power, + OperateKind::Equal, format!("lhs: {self:?}, rhs: {other:?}"), )) } @@ -137,29 +301,29 @@ pub trait Object: std::any::Any + std::fmt::Debug { )) } - fn property_get(&self, member: &str) -> Result { + fn property_get(&self, property: &str) -> Result { Err(RuntimeError::invalid_operation( OperateKind::PropertyGet, "unimplemented", )) } - fn property_set(&mut self, member: &str, value: ValueRef) -> Result<(), RuntimeError> { + fn property_set(&mut self, property: &str, value: ValueRef) -> Result<(), RuntimeError> { Err(RuntimeError::invalid_operation( OperateKind::PropertySet, "unimplemented", )) } - fn property_call( + fn call_method( &mut self, - member: &str, + method: &str, args: &[ValueRef], - ) -> Result, RuntimeError> { - Err(RuntimeError::invalid_operation( - OperateKind::PropertyCall, - format!("unimplemented {member} property call for {self:?}"), - )) + ) -> Result, RuntimeError> { + Err(RuntimeError::MissingMethod { + object: type_name_of_val(self).to_string(), + method: method.to_string(), + }) } fn make_iterator(&self) -> Result>, RuntimeError> { @@ -169,14 +333,172 @@ pub trait Object: std::any::Any + std::fmt::Debug { )) } - fn iterator_has_next(&self) -> Result { + fn iterate_next(&mut self) -> Result, RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::IterateNext, + "unimplemented", + )) + } + + fn make_slice(&self, range: ValueRef) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::MakeSlice, + "unimplemented", + )) + } + + #[cfg(feature = "async")] + fn into_future( + self: Box, + ) -> Result + Unpin + Send + 'static>, RuntimeError> { Err(RuntimeError::invalid_operation( - OperateKind::IteratorHasNext, + OperateKind::Await, "unimplemented", )) } +} + +pub trait ObjectBase: std::any::Any + std::fmt::Debug { + fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&format!("{self:?}")) + } + + /// arithmetic addition operation + fn add(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Add, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// arithmetic subtraction operation + fn sub(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Subtract, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// arithmetic multiplication operation + fn mul(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Multiply, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// arithmetic division operation + fn div(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Divide, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// arithmetic remainder operation + fn rem(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Remainder, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } - fn iterate_next(&mut self) -> Result { + fn equal(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Equal, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// compare operation + fn compare(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Compare, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// logic and operation + fn logic_and(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::LogicAnd, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// logic or operation + fn logic_or(&self, other: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::LogicOr, + format!("lhs: {self:?}, rhs: {other:?}"), + )) + } + + /// negate operation + fn negate(&self) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::Negate, + format!("rhs: {self:?}"), + )) + } + + fn call(&mut self, args: &[ValueRef]) -> Result, RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::Call, + "unimplemented", + )) + } + + /// index get operation + fn index_get(&self, index: &Value) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::IndexGet, + "unimplemented", + )) + } + + fn index_set(&mut self, index: &Value, value: ValueRef) -> Result<(), RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::IndexSet, + "unimplemented", + )) + } + + fn property_get(&self, property: &str) -> Result { + Err(RuntimeError::invalid_operation( + OperateKind::PropertyGet, + "unimplemented", + )) + } + + fn property_set(&mut self, property: &str, value: ValueRef) -> Result<(), RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::PropertySet, + "unimplemented", + )) + } + + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + Err(RuntimeError::MissingMethod { + object: type_name_of_val(self).to_string(), + method: method.to_string(), + }) + } + + fn make_iterator( + &self, + ) -> Result + Send + Sync>, RuntimeError> { + Err(RuntimeError::invalid_operation( + OperateKind::MakeIterator, + "unimplemented", + )) + } + + fn iterate_next(&mut self) -> Result, RuntimeError> { Err(RuntimeError::invalid_operation( OperateKind::IterateNext, "unimplemented", @@ -190,6 +512,7 @@ pub trait Object: std::any::Any + std::fmt::Debug { )) } + #[cfg(feature = "async")] fn into_future( self: Box, ) -> Result + Unpin + Send + 'static>, RuntimeError> { @@ -206,8 +529,8 @@ pub enum OperateKind { Subtract, Multiply, Divide, - Modulo, - Power, + Remainder, + Equal, Compare, LogicAnd, LogicOr, @@ -220,7 +543,6 @@ pub enum OperateKind { PropertySet, PropertyCall, MakeIterator, - IteratorHasNext, IterateNext, MakeSlice, Display, @@ -235,8 +557,8 @@ impl fmt::Display for OperateKind { OperateKind::Subtract => write!(f, "subtract"), OperateKind::Multiply => write!(f, "multiply"), OperateKind::Divide => write!(f, "divide"), - OperateKind::Modulo => write!(f, "modulo"), - OperateKind::Power => write!(f, "power"), + OperateKind::Remainder => write!(f, "reminder"), + OperateKind::Equal => write!(f, "equal"), OperateKind::Compare => write!(f, "compare"), OperateKind::LogicAnd => write!(f, "logic_and"), OperateKind::LogicOr => write!(f, "logic_or"), @@ -249,7 +571,6 @@ impl fmt::Display for OperateKind { OperateKind::PropertySet => write!(f, "property_set"), OperateKind::PropertyCall => write!(f, "property_call"), OperateKind::MakeIterator => write!(f, "make_iterator"), - OperateKind::IteratorHasNext => write!(f, "iterator_has_next"), OperateKind::IterateNext => write!(f, "iterate_next"), OperateKind::MakeSlice => write!(f, "make_slice"), OperateKind::Display => write!(f, "display"), @@ -258,18 +579,3 @@ impl fmt::Display for OperateKind { } } } - -#[cfg(test)] -mod test { - use crate::runtime::{Value, ValueRef}; - - #[test] - fn test_null() { - let a = ValueRef::new(1_i64); - let b = Value::new(2_i64); - - let c = a.borrow().add(&b); - - assert_eq!(c.unwrap(), 3); - } -} diff --git a/src/runtime/object/array.rs b/src/runtime/object/array.rs index 31d713e..af19fc3 100644 --- a/src/runtime/object/array.rs +++ b/src/runtime/object/array.rs @@ -1,6 +1,6 @@ use crate::{Object, RuntimeError, Value, ValueRef}; -use super::Range; +use super::{Enumerator, Range, metatable::MetaTable}; impl Object for Vec { fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -28,7 +28,7 @@ impl Object for Vec { fn index_set(&mut self, index: &Value, value: ValueRef) -> Result<(), RuntimeError> { if let Some(index) = index.downcast_ref::() { if *index >= 0 && *index < self.len() as i64 { - if let Some(value) = value.downcast_ref::() { + if let Some(value) = value.value().downcast_ref::() { self[*index as usize] = value.clone(); return Ok(()); } else { @@ -47,6 +47,16 @@ impl Object for Vec { )) } + #[cfg(feature = "async")] + fn make_iterator( + &self, + ) -> Result + Send + Sync>, RuntimeError> { + Ok(Box::new( + self.clone().into_iter().map(|item| ValueRef::new(item)), + )) + } + + #[cfg(not(feature = "async"))] fn make_iterator(&self) -> Result>, RuntimeError> { Ok(Box::new( self.clone().into_iter().map(|item| ValueRef::new(item)), @@ -54,7 +64,7 @@ impl Object for Vec { } fn make_slice(&self, range: ValueRef) -> Result { - if let Some(range) = range.downcast_ref::() { + if let Some(range) = range.value().downcast_ref::() { let (start, end) = range.get_range(self.len())?; // 创建新的Vec并复制切片内容 @@ -69,13 +79,17 @@ impl Object for Vec { )) } - fn property_call( + fn call_method( &mut self, - member: &str, + method: &str, args: &[ValueRef], - ) -> Result, RuntimeError> { - match member { - "len" => Ok(Some(Value::new(self.len() as i64))), + ) -> Result, RuntimeError> { + match method { + "len" => Ok(Some(ValueRef::new(self.len() as i64))), + "clear" => { + self.clear(); + Ok(None) + } "enumerate" => { let i = self .clone() @@ -83,9 +97,50 @@ impl Object for Vec { .enumerate() .map(|(i, item)| (ValueRef::new(i as i64), ValueRef::new(item))) .collect::>(); - Ok(Some(Value::new(i))) + Ok(Some(ValueRef::new(i))) + } + "push" => { + if args.len() == 1 { + return match args[0].value().downcast_ref::() { + Some(item) => { + self.push(item.clone()); + Ok(None) + } + None => Err(RuntimeError::invalid_argument::(0, &args[0])), + }; + } + Err(RuntimeError::invalid_argument_count(1, args.len())) + } + "pop" => { + if args.is_empty() { + if let Some(item) = self.pop() { + return Ok(Some(ValueRef::new(item))); + } + return Ok(None); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) } - _ => Ok(None), + "remove" => { + if args.len() == 1 { + if let Some(index) = args[0].value().downcast_ref::() { + if *index >= 0 && *index < self.len() as i64 { + let removed = self.remove(*index as usize); + return Ok(Some(ValueRef::new(removed))); + } + return Err(RuntimeError::IndexOutOfBounds { + length: self.len() as i64, + index: *index, + }); + } + return Err(RuntimeError::invalid_argument::( + 0, + format!("cannot remove with {:?}", args[0]), + )); + } + + Err(RuntimeError::invalid_argument_count(1, args.len())) + } + _ => Err(RuntimeError::missing_method::(method)), } } } @@ -131,12 +186,20 @@ impl Object for Vec { )) } + #[cfg(feature = "async")] + fn make_iterator( + &self, + ) -> Result + Send + Sync>, RuntimeError> { + Ok(Box::new(self.clone().into_iter())) + } + + #[cfg(not(feature = "async"))] fn make_iterator(&self) -> Result>, RuntimeError> { Ok(Box::new(self.clone().into_iter())) } fn make_slice(&self, range: ValueRef) -> Result { - if let Some(range) = range.downcast_ref::() { + if let Some(range) = range.value().downcast_ref::() { let (start, end) = range.get_range(self.len())?; // 创建新的Vec并复制切片内容 @@ -151,23 +214,85 @@ impl Object for Vec { )) } - fn property_call( + fn call_method( &mut self, - member: &str, + method: &str, args: &[ValueRef], - ) -> Result, RuntimeError> { - match member { - "len" => Ok(Some(Value::new(self.len() as i64))), - "enumerate" => { - let i = self - .clone() - .into_iter() - .enumerate() - .map(|(i, item)| (ValueRef::new(i as i64), item)) - .collect::>(); - Ok(Some(Value::new(i))) - } - _ => Ok(None), - } + ) -> Result, RuntimeError> { + ARRAY_METATABLE.call_method(self, method, args) } } + +static ARRAY_METATABLE: std::sync::LazyLock>> = + std::sync::LazyLock::new(|| { + let table = MetaTable::new("array") + .with_method("len", |this: &mut Vec, args| { + if args.is_empty() { + return Ok(Some(ValueRef::new(this.len() as i64))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("clear", |this: &mut Vec, args| { + if args.is_empty() { + this.clear(); + return Ok(None); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("push", |this: &mut Vec, args| { + if args.len() == 1 { + this.push(args[0].clone()); + return Ok(None); + } + Err(RuntimeError::invalid_argument_count(1, args.len())) + }) + .with_method("pop", |this: &mut Vec, args| { + if args.is_empty() { + if let Some(value) = this.pop() { + return Ok(Some(value)); + } + return Ok(None); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("remove", |this: &mut Vec, args| { + if args.len() == 1 { + if let Some(index) = args[0].value().downcast_ref::() { + if *index >= 0 && *index < this.len() as i64 { + let removed = this.remove(*index as usize); + return Ok(Some(removed)); + } + return Err(RuntimeError::IndexOutOfBounds { + length: this.len() as i64, + index: *index, + }); + } + return Err(RuntimeError::invalid_argument::( + 0, + format!("cannot remove with {:?}", args[0]), + )); + } + + Err(RuntimeError::invalid_argument_count(1, args.len())) + }); + + #[cfg(feature = "async")] + let table = table.with_method("iter", |this: &mut Vec, args| { + if args.is_empty() { + let iter = this.clone().into_iter(); + return Ok(Some(ValueRef::new(Enumerator::new(Box::new(iter))))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }); + + #[cfg(not(feature = "async"))] + let table = table.with_method("iter", |this: &mut Vec, args| { + if args.is_empty() { + let iter = this.clone().into_iter(); + return Ok(Some(ValueRef::new(Enumerator::new(Box::new(iter))))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }); + + table + }); diff --git a/src/runtime/object/boolean.rs b/src/runtime/object/boolean.rs index 1adacce..a01c3ef 100644 --- a/src/runtime/object/boolean.rs +++ b/src/runtime/object/boolean.rs @@ -5,6 +5,14 @@ impl Object for bool { write!(f, "{self}") } + fn equal(&self, other: &Value) -> Result { + if let Some(other) = other.downcast_ref::() { + return Ok(Value::new(*self == *other)); + } + + Ok(Value::new(false)) + } + fn compare(&self, other: &Value) -> Result { if let Some(other) = other.downcast_ref::() { return Ok(self.cmp(other)); diff --git a/src/runtime/object/emurator.rs b/src/runtime/object/emurator.rs index 02ffaa4..eeb4011 100644 --- a/src/runtime/object/emurator.rs +++ b/src/runtime/object/emurator.rs @@ -2,17 +2,33 @@ use std::fmt; use crate::{Object, RuntimeError, ValueRef}; +use super::metatable::MetaTable; + +#[cfg(feature = "async")] +/// Enumerator +pub struct Enumerator { + iter: Box + Send + Sync>, +} + +#[cfg(not(feature = "async"))] /// Enumerator pub struct Enumerator { iter: Box>, - next: Option, } impl Enumerator { + #[cfg(feature = "async")] + pub fn new(iter: Box + Send + Sync>) -> Self { + Self { iter } + } + + #[cfg(not(feature = "async"))] pub fn new(iter: Box>) -> Self { - let mut iter = iter; - let next = iter.next(); - Self { iter, next } + Self { iter } + } + + pub fn next(&mut self) -> Option { + self.iter.next() } } @@ -27,13 +43,50 @@ impl Object for Enumerator { f.debug_struct("Enumerator").finish() } - fn iterate_next(&mut self) -> Result { - let old = self.next.take(); - self.next = self.iter.next(); - Ok(old.expect("iterator exhausted")) + fn iterate_next(&mut self) -> Result, RuntimeError> { + Ok(self.next()) } - fn iterator_has_next(&self) -> Result { - Ok(self.next.is_some()) + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + ENUMERATOR_META_TABLE.call_method(self, method, args) } } + +static ENUMERATOR_META_TABLE: std::sync::LazyLock> = + std::sync::LazyLock::new(|| { + MetaTable::new("Enumerator") + .with_method("next", |this: &mut Enumerator, args| { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + Ok(this.next()) + }) + .with_method("enumerate", |this: &mut Enumerator, args| { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + + let iter = std::mem::replace(&mut this.iter, Box::new(std::iter::empty())); + + let iter = iter + .enumerate() + .map(|(i, v)| ValueRef::new((ValueRef::new(i as i64), v))); + + Ok(Some(ValueRef::new(Enumerator::new(Box::new(iter))))) + }) + .with_method("count", |this, args| { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + + let iter = std::mem::replace(&mut this.iter, Box::new(std::iter::empty())); + + let count = iter.count(); + + Ok(Some(ValueRef::new(count as i64))) + }) + }); diff --git a/src/runtime/object/float.rs b/src/runtime/object/float.rs index bd6df31..cfb623c 100644 --- a/src/runtime/object/float.rs +++ b/src/runtime/object/float.rs @@ -1,10 +1,22 @@ -use crate::{Object, RuntimeError, Value}; +use crate::{Object, RuntimeError, Value, ValueRef}; impl Object for f32 { fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{self}") } + fn equal(&self, other: &Value) -> Result { + if let Some(other) = other.downcast_ref::() { + return Ok(Value::new(*self == *other)); + } + + if let Some(other) = other.downcast_ref::() { + return Ok(Value::new(*self as f64 == *other)); + } + + Ok(Value::new(false)) + } + fn compare(&self, other: &Value) -> Result { if let Some(other) = other.downcast_ref::() { return self @@ -53,6 +65,44 @@ impl Object for f32 { fn negate(&self) -> Result { Ok(Value::new(-self)) } + + fn call_method( + &mut self, + method: &str, + args: &[crate::ValueRef], + ) -> Result, RuntimeError> { + match method { + "to_string" => Ok(Some(ValueRef::new(self.to_string()))), + "to_int" => Ok(Some(ValueRef::new(*self as i64))), + "abs" => Ok(Some(ValueRef::new(self.abs()))), + "round" => Ok(Some(ValueRef::new(self.round()))), + "floor" => Ok(Some(ValueRef::new(self.floor()))), + "ceil" => Ok(Some(ValueRef::new(self.ceil()))), + "trunc" => Ok(Some(ValueRef::new(self.trunc()))), + "sqrt" => Ok(Some(ValueRef::new(self.sqrt()))), + "sin" => Ok(Some(ValueRef::new(self.sin()))), + "cos" => Ok(Some(ValueRef::new(self.cos()))), + "tan" => Ok(Some(ValueRef::new(self.tan()))), + "asin" => Ok(Some(ValueRef::new(self.asin()))), + "acos" => Ok(Some(ValueRef::new(self.acos()))), + "atan" => Ok(Some(ValueRef::new(self.atan()))), + "log" => { + if args.len() == 1 { + match args[0].value().downcast_ref::() { + Some(base) => Ok(Some(ValueRef::new(self.log(*base)))), + None => Err(RuntimeError::invalid_argument::(0, &args[0])), + } + } else { + Err(RuntimeError::invalid_argument_count(1, args.len())) + } + } + + _ => Err(RuntimeError::invalid_operation( + super::OperateKind::PropertyCall, + format!("Unknown method: {method}"), + )), + } + } } impl Object for f64 { @@ -107,6 +157,43 @@ impl Object for f64 { fn negate(&self) -> Result { Ok(Value::new(-self)) } + + fn call_method( + &mut self, + method: &str, + args: &[crate::ValueRef], + ) -> Result, RuntimeError> { + match method { + "to_string" => Ok(Some(ValueRef::new(self.to_string()))), + "to_int" => Ok(Some(ValueRef::new(*self as i64))), + "abs" => Ok(Some(ValueRef::new(self.abs()))), + "round" => Ok(Some(ValueRef::new(self.round()))), + "floor" => Ok(Some(ValueRef::new(self.floor()))), + "ceil" => Ok(Some(ValueRef::new(self.ceil()))), + "trunc" => Ok(Some(ValueRef::new(self.trunc()))), + "sqrt" => Ok(Some(ValueRef::new(self.sqrt()))), + "sin" => Ok(Some(ValueRef::new(self.sin()))), + "cos" => Ok(Some(ValueRef::new(self.cos()))), + "tan" => Ok(Some(ValueRef::new(self.tan()))), + "asin" => Ok(Some(ValueRef::new(self.asin()))), + "acos" => Ok(Some(ValueRef::new(self.acos()))), + "atan" => Ok(Some(ValueRef::new(self.atan()))), + "log" => { + if args.len() == 1 { + match args[0].value().downcast_ref::() { + Some(base) => Ok(Some(ValueRef::new(self.log(*base)))), + None => Err(RuntimeError::invalid_argument::(0, &args[0])), + } + } else { + Err(RuntimeError::invalid_argument_count(1, args.len())) + } + } + _ => Err(RuntimeError::invalid_operation( + super::OperateKind::PropertyCall, + format!("Unknown method: {method}"), + )), + } + } } impl PartialEq for Value { @@ -117,3 +204,12 @@ impl PartialEq for Value { } } } + +impl PartialEq for Value { + fn eq(&self, other: &f64) -> bool { + match self.downcast_ref::() { + Some(value) => *value == *other, + None => false, + } + } +} diff --git a/src/runtime/object/function.rs b/src/runtime/object/function.rs index fcd831d..71649a7 100644 --- a/src/runtime/object/function.rs +++ b/src/runtime/object/function.rs @@ -24,11 +24,11 @@ impl Object for UserFunction { /// NativeFunction pub struct NativeFunction { pub name: String, - pub func: Box, + pub func: Box, } impl NativeFunction { - pub fn new(name: impl ToString, func: Box) -> Self { + pub fn new(name: impl ToString, func: Box) -> Self { Self { name: name.to_string(), func, @@ -96,11 +96,11 @@ impl IntoRet for Result { } } -impl IntoRet for Result, RuntimeError> { - fn into_ret(self) -> Result, RuntimeError> { - self.map(|v| v.map(Value::new)) - } -} +// impl IntoRet for Result, RuntimeError> { +// fn into_ret(self) -> Result, RuntimeError> { +// self.map(|v| v.map(Value::new)) +// } +// } pub trait FromValue: Sized { fn from_value(value: &ValueRef) -> Result; @@ -111,7 +111,8 @@ where T: Object + Clone, { fn from_value(value: &ValueRef) -> Result { - let value = value + let v = value.value(); + let value = v .downcast_ref::() .ok_or(RuntimeError::invalid_type::(value))?; diff --git a/src/runtime/object/integer.rs b/src/runtime/object/integer.rs index 89eb0f3..a852639 100644 --- a/src/runtime/object/integer.rs +++ b/src/runtime/object/integer.rs @@ -7,6 +7,18 @@ macro_rules! impl_object_for_integer { write!(f, "{}", self) } + fn equal(&self, other: &Value) -> Result { + if let Some(other) = other.downcast_ref::<$ty>() { + return Ok(Value::new(*self == *other)); + } + + if let Some(other) = other.downcast_ref::() { + return Ok(Value::new(*self as i64 == *other)); + } + + Ok(Value::new(false)) + } + fn compare(&self, other: &Value) -> Result { match other.downcast_ref::<$ty>() { Some(other) => Ok(self.cmp(&other)), @@ -54,7 +66,7 @@ macro_rules! impl_object_for_integer { } } - fn modulo(&self, other: &Value) -> Result { + fn rem(&self, other: &Value) -> Result { match other.downcast_ref::<$ty>() { Some(other) => match self.checked_rem(*other) { Some(result) => Ok(Value::new(result)), diff --git a/src/runtime/object/map.rs b/src/runtime/object/map.rs index e5327bb..2c1e628 100644 --- a/src/runtime/object/map.rs +++ b/src/runtime/object/map.rs @@ -27,11 +27,11 @@ where } fn index_set(&mut self, index: &Value, value: ValueRef) -> Result<(), RuntimeError> { - if let Some(key) = index.downcast_ref::() { - if let Some(value) = value.downcast_ref::() { - self.insert(key.clone(), value.clone()); - return Ok(()); - } + if let Some(key) = index.downcast_ref::() + && let Some(value) = value.value().downcast_ref::() + { + self.insert(key.clone(), value.clone()); + return Ok(()); } Err(RuntimeError::invalid_operation( @@ -77,9 +77,83 @@ where )) } + #[cfg(feature = "async")] + fn make_iterator( + &self, + ) -> Result + Send + Sync>, RuntimeError> { + Ok(Box::new(self.clone().into_iter().map(|(k, v)| { + ValueRef::new((ValueRef::new(k.clone()), v.clone())) + }))) + } + + #[cfg(not(feature = "async"))] fn make_iterator(&self) -> Result>, RuntimeError> { Ok(Box::new(self.clone().into_iter().map(|(k, v)| { ValueRef::new((ValueRef::new(k.clone()), v.clone())) }))) } + + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + match method { + "len" => Ok(Some(ValueRef::new(self.len() as i64))), + "clear" => { + self.clear(); + Ok(None) + } + "insert" => { + if args.len() == 2 { + match args[0].value().downcast_ref::() { + Some(key) => { + self.insert(key.clone(), args[1].clone()); + return Ok(None); + } + None => { + return Err(RuntimeError::invalid_type::( + "insert() argument 1 must be a key".to_string(), + )); + } + }; + } + Err(RuntimeError::invalid_argument_count(1, args.len())) + } + "remove" => { + if args.len() == 1 { + match args[0].value().downcast_ref::() { + Some(key) => { + self.remove(key); + return Ok(None); + } + None => { + return Err(RuntimeError::invalid_type::( + "insert() argument 1 must be a key".to_string(), + )); + } + }; + } + + Err(RuntimeError::invalid_argument_count(1, args.len())) + } + "keys" => { + if args.is_empty() { + let keys = self.keys().cloned().collect::>(); + return Ok(Some(ValueRef::new(keys))); + } + + Err(RuntimeError::invalid_argument_count(0, args.len())) + } + "values" => { + if args.is_empty() { + let values = self.values().cloned().collect::>(); + return Ok(Some(ValueRef::new(values))); + } + + Err(RuntimeError::invalid_argument_count(0, args.len())) + } + _ => Ok(None), + } + } } diff --git a/src/runtime/object/metatable.rs b/src/runtime/object/metatable.rs new file mode 100644 index 0000000..ffc40ef --- /dev/null +++ b/src/runtime/object/metatable.rs @@ -0,0 +1,180 @@ +use std::{collections::HashMap, fmt::Debug}; + +use crate::{RuntimeError, Value, ValueRef}; + +type Method = fn(&mut T, &[ValueRef]) -> Result, RuntimeError>; +type Getter = fn(&T) -> Result; +type Setter = fn(&mut T, Value) -> Result<(), RuntimeError>; + +#[derive(Debug)] +pub struct MetaTable { + pub name: String, + pub methods: HashMap>, + pub properties: HashMap>, +} + +impl MetaTable { + pub fn new(name: impl ToString) -> Self { + Self { + name: name.to_string(), + methods: HashMap::new(), + properties: HashMap::new(), + } + } + + pub fn with_method(mut self, name: impl ToString, method: Method) -> Self { + self.methods.insert(name.to_string(), method); + self + } + + pub fn add_property(&mut self, property: MetaProperty) { + self.properties.insert(property.name.clone(), property); + } + + pub fn with_property_getter(mut self, name: &str, getter: Getter) -> Self { + self.properties.insert( + name.to_string(), + MetaProperty::new(name, Some(getter), None), + ); + self + } + + pub fn with_property_setter(mut self, name: &str, setter: Setter) -> Self { + self.properties.insert( + name.to_string(), + MetaProperty::new(name, None, Some(setter)), + ); + self + } + + pub fn property_get(&self, this: &T, name: &str) -> Result { + match self.properties.get(name) { + Some(property) => match property.getter { + Some(getter) => getter(this), + None => Err(RuntimeError::missing_property_getter::(name)), + }, + None => Err(RuntimeError::missing_property::(name)), + } + } + + pub fn property_set(&self, this: &mut T, name: &str, value: Value) -> Result<(), RuntimeError> { + match self.properties.get(name) { + Some(property) => match property.setter { + Some(setter) => setter(this, value), + None => Err(RuntimeError::missing_property_setter::(name)), + }, + None => Err(RuntimeError::missing_property::(name)), + } + } + + pub fn call_method( + &self, + this: &mut T, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + match self.methods.get(method) { + Some(method_fn) => (method_fn)(this, args), + None => Err(RuntimeError::missing_method::(method)), + } + } +} + +#[derive(Debug)] +pub struct MetaProperty { + pub name: String, + pub getter: Option>, + pub setter: Option>, +} + +impl MetaProperty { + pub fn new(name: &str, getter: Option>, setter: Option>) -> Self { + Self { + name: name.to_string(), + getter, + setter, + } + } +} + +// pub trait MetaObject: std::fmt::Debug + std::any::Any { +// fn get_meta_table(&self) -> &MetaTable; +// } + +// impl Object for dyn MetaObject { +// fn property_get(&self, member: &str) -> Result { +// match self.get_meta_table().properties.get(member) { +// Some(property) => match property.getter { +// Some(getter) => getter((self as &dyn std::any::Any).downcast_ref::().unwrap()), +// None => Err(RuntimeError::missing_property_getter::(member)), +// }, +// None => Err(RuntimeError::missing_property::(member)), +// } +// } + +// fn property_set(&mut self, member: &str, value: ValueRef) -> Result<(), RuntimeError> { +// match self.get_meta_table().properties.get(member) { +// Some(property) => match property.setter { +// Some(setter) => setter( +// (self as &mut dyn std::any::Any) +// .downcast_mut::() +// .unwrap(), +// value.take(), +// ), +// None => Err(RuntimeError::missing_property_setter::(member)), +// }, +// None => Err(RuntimeError::missing_property::(member)), +// } +// } + +// fn method_call( +// &mut self, +// method: &str, +// args: &[ValueRef], +// ) -> Result, RuntimeError> { +// match self.get_meta_table().methods.get(method) { +// Some(method) => (method)( +// (self as &mut dyn std::any::Any) +// .downcast_mut::() +// .unwrap(), +// args, +// ), +// None => Err(RuntimeError::missing_method::(method)), +// } +// } +// } + +// #[cfg(test)] +// mod tests { +// use super::*; + +// #[test] +// fn test_metatable() { +// #[derive(Debug)] +// struct Request {} + +// impl MetaObject for Request { +// fn get_meta_table(&self) -> &MetaTable { +// static META_TABLE: std::sync::LazyLock> = +// std::sync::LazyLock::new(|| { +// let mut table = MetaTable::new("Request"); +// table.add_property(MetaProperty::new( +// "method", +// Some(|_| Ok(Value::new("GET"))), +// None, +// )); +// table +// }); +// &META_TABLE +// } +// } + +// let req = Request {}; + +// let dyn_obj = &req as &dyn MetaObject; + +// let method = dyn_obj.property_get("method").unwrap(); + +// assert_eq!(method, "GET"); +// } +// } diff --git a/src/runtime/object/null.rs b/src/runtime/object/null.rs index 394298f..c071414 100644 --- a/src/runtime/object/null.rs +++ b/src/runtime/object/null.rs @@ -10,15 +10,11 @@ impl Object for Null { f.write_str("null") } - fn compare(&self, other: &super::Value) -> Result { - if let Some(other) = other.downcast_ref::() { - return Ok(self.partial_cmp(other).unwrap()); + fn equal(&self, other: &Value) -> Result { + match other.downcast_ref::() { + Some(_) => Ok(Value::new(true)), + None => Ok(Value::new(false)), } - // if let Some(other) = other.downcast_ref::>() { - // return Ok(std::cmp::Ordering::Equal); - // } - - Err(RuntimeError::invalid_type::(other)) } } diff --git a/src/runtime/object/optional.rs b/src/runtime/object/optional.rs new file mode 100644 index 0000000..58bbf08 --- /dev/null +++ b/src/runtime/object/optional.rs @@ -0,0 +1,101 @@ +use crate::{RuntimeError, Value, ValueRef}; + +use super::Object; + +impl Object for Option { + fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Option") + } + + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + match method { + "is_some" => { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + + Ok(Some(ValueRef::new(self.is_some()))) + } + "is_none" => { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + Ok(Some(ValueRef::new(self.is_none()))) + } + "unwrap" => { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + + match self { + Some(value) => Ok(Some(value.clone())), + None => Err(RuntimeError::internal("can not unwrap a None")), + } + } + _ => Err(RuntimeError::missing_method::(method)), + } + } +} + +impl Object for Option +where + T: Object + Clone, +{ + fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Option") + } + + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + match method { + "is_some" => { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + + Ok(Some(ValueRef::new(self.is_some()))) + } + "is_none" => { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + Ok(Some(ValueRef::new(self.is_none()))) + } + "unwrap" => { + if !args.is_empty() { + return Err(RuntimeError::invalid_argument_count(0, args.len())); + } + + match self { + Some(value) => Ok(Some(ValueRef::new(value.clone()))), + None => Err(RuntimeError::internal("can not unwrap a None")), + } + } + _ => Err(RuntimeError::missing_method::(method)), + } + } +} + +impl PartialEq> for Value { + fn eq(&self, other: &Option) -> bool { + match self.downcast_ref::>() { + Some(value) => *value == *other, + None => false, + } + } +} +impl PartialEq for Option { + fn eq(&self, other: &Value) -> bool { + match other.downcast_ref::>() { + Some(value) => *self == *value, + None => false, + } + } +} diff --git a/src/runtime/object/promise.rs b/src/runtime/object/promise.rs index 362cdfd..6d28cd0 100644 --- a/src/runtime/object/promise.rs +++ b/src/runtime/object/promise.rs @@ -5,10 +5,10 @@ use futures::FutureExt; use crate::{Object, Value}; /// Promise -pub struct Promise(pub(crate) Pin + Send + 'static>>); +pub struct Promise(pub(crate) Pin + Send + Sync + 'static>>); impl Promise { - pub fn new(fut: impl Future + Send + 'static) -> Self { + pub fn new(fut: impl Future + Send + Sync + 'static) -> Self { Self(Box::pin(fut)) } } diff --git a/src/runtime/object/range.rs b/src/runtime/object/range.rs index 28f49a7..f26ff70 100644 --- a/src/runtime/object/range.rs +++ b/src/runtime/object/range.rs @@ -15,12 +15,12 @@ pub enum Range { impl Range { pub fn new(begin: ValueRef, end: ValueRef) -> Result { - let begin = match begin.clone().downcast_ref::() { + let begin = match begin.clone().value().downcast_ref::() { Some(begin) => *begin, None => return Err(RuntimeError::invalid_type::(begin)), }; - let end = match end.clone().downcast_ref::() { + let end = match end.clone().value().downcast_ref::() { Some(end) => *end, None => return Err(RuntimeError::invalid_type::(end)), }; @@ -29,12 +29,12 @@ impl Range { } pub fn inclusive(begin: ValueRef, end: ValueRef) -> Result { - let begin = match begin.clone().downcast_ref::() { + let begin = match begin.clone().value().downcast_ref::() { Some(begin) => *begin, None => return Err(RuntimeError::invalid_type::(begin)), }; - let end = match end.clone().downcast_ref::() { + let end = match end.clone().value().downcast_ref::() { Some(end) => *end, None => return Err(RuntimeError::invalid_type::(end)), }; @@ -47,7 +47,7 @@ impl Range { } pub fn range_from(begin: ValueRef) -> Result { - let begin = match begin.clone().downcast_ref::() { + let begin = match begin.clone().value().downcast_ref::() { Some(begin) => *begin, None => return Err(RuntimeError::invalid_type::(begin)), }; @@ -56,7 +56,7 @@ impl Range { } pub fn range_to(end: ValueRef) -> Result { - let end = match end.clone().downcast_ref::() { + let end = match end.clone().value().downcast_ref::() { Some(end) => *end, None => return Err(RuntimeError::invalid_type::(end)), }; @@ -64,7 +64,7 @@ impl Range { } pub fn range_to_inclusive(end: ValueRef) -> Result { - let end = match end.clone().downcast_ref::() { + let end = match end.clone().value().downcast_ref::() { Some(end) => *end, None => return Err(RuntimeError::invalid_type::(end)), }; @@ -113,6 +113,26 @@ impl Range { } impl Object for Range { + #[cfg(feature = "async")] + fn make_iterator( + &self, + ) -> Result + Send + Sync>, RuntimeError> { + match self { + Range::Normal { begin, end } => { + Ok(Box::new((*begin..*end).map(|i| Value::new(i).into()))) + } + Range::Inclusive { begin, end } => { + Ok(Box::new((*begin..=*end).map(|i| Value::new(i).into()))) + } + Range::From { begin } => Ok(Box::new((*begin..).map(|i| Value::new(i).into()))), + _ => Err(RuntimeError::invalid_operation( + super::OperateKind::MakeIterator, + format!("range {self:?} is not iterable"), + )), + } + } + + #[cfg(not(feature = "async"))] fn make_iterator(&self) -> Result>, RuntimeError> { match self { Range::Normal { begin, end } => { @@ -128,6 +148,32 @@ impl Object for Range { )), } } + + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + match method { + "len" => { + if args.is_empty() { + let len = match self { + Range::Normal { begin, end } => *end - *begin, + Range::Inclusive { begin, end } => *end - *begin + 1, + Range::From { begin } => i64::MAX - *begin, + Range::To { end } => *end, + Range::ToInclusive { end } => *end + 1, + Range::Full => i64::MAX, + }; + + return Ok(Some(Value::new(len).into())); + } + + Err(RuntimeError::invalid_argument_count(0, args.len())) + } + _ => Err(RuntimeError::missing_method::(method)), + } + } } // 辅助函数:检查索引是否有效 diff --git a/src/runtime/object/string.rs b/src/runtime/object/string.rs index 383433e..1c0703a 100644 --- a/src/runtime/object/string.rs +++ b/src/runtime/object/string.rs @@ -1,22 +1,23 @@ use crate::{Object, RuntimeError, Value, ValueRef}; -use super::Range; +use super::{Range, metatable::MetaTable}; impl Object for String { fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "\"{self}\"") } - fn compare(&self, other: &Value) -> Result { + fn equal(&self, other: &Value) -> Result { + println!("equal string {self} {other:?}"); if let Some(other) = other.downcast_ref::() { - return Ok(self.cmp(other)); + return Ok(Value::new(self == other)); } if let Some(other) = other.downcast_ref::<&str>() { - return Ok(self.as_str().cmp(other)); + return Ok(Value::new(self == other)); } - Err(RuntimeError::invalid_type::(other)) + Ok(Value::new(false)) } fn add(&self, other: &Value) -> Result { @@ -31,6 +32,22 @@ impl Object for String { Err(RuntimeError::invalid_type::(other)) } + #[cfg(feature = "async")] + fn make_iterator( + &self, + ) -> Result + Send + Sync>, RuntimeError> { + let chars = self + .chars() + .clone() + .map(ValueRef::new) + .collect::>(); + + let iter = chars.into_iter(); + + Ok(Box::new(iter)) + } + + #[cfg(not(feature = "async"))] fn make_iterator(&self) -> Result>, RuntimeError> { let chars = self .chars() @@ -44,7 +61,7 @@ impl Object for String { } fn make_slice(&self, range: ValueRef) -> Result { - if let Some(range) = range.downcast_ref::() { + if let Some(range) = range.value().downcast_ref::() { let len = self.chars().count(); let (start, end) = range.get_range(len)?; @@ -63,6 +80,13 @@ impl Object for String { format!("cannot make_slice with {range:?}"), )) } + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, RuntimeError> { + STRING_META_TABLE.call_method(self, method, args) + } } impl PartialEq for Value { @@ -82,16 +106,16 @@ impl Object for &'static str { write!(f, "\"{self}\"") } - fn compare(&self, other: &Value) -> Result { - if let Some(other) = other.downcast_ref::<&str>() { - return Ok(self.cmp(other)); + fn equal(&self, other: &Value) -> Result { + if let Some(other) = other.downcast_ref::() { + return Ok(Value::new(self == other)); } - if let Some(other) = other.downcast_ref::() { - return Ok(self.cmp(&other.as_str())); + if let Some(other) = other.downcast_ref::<&str>() { + return Ok(Value::new(self == other)); } - Err(RuntimeError::invalid_type::(other)) + Ok(Value::new(false)) } } @@ -129,3 +153,97 @@ impl PartialEq for Value { } } } + +static STRING_META_TABLE: std::sync::LazyLock> = std::sync::LazyLock::new(|| { + MetaTable::new("String") + .with_method("len", |this: &mut String, args| { + if args.is_empty() { + return Ok(Some(ValueRef::new(this.len()))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("to_uppercase", |this: &mut String, args| { + if args.is_empty() { + return Ok(Some(ValueRef::new(this.to_uppercase()))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("to_lowercase", |this: &mut String, args| { + if args.is_empty() { + return Ok(Some(ValueRef::new(this.to_lowercase()))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("starts_with", |this: &mut String, args| { + if args.len() == 1 { + let other = args[0].value(); + let other = other.downcast_ref::().unwrap(); + return Ok(Some(ValueRef::new(this.starts_with(other.as_str())))); + } + Err(RuntimeError::invalid_argument_count(1, args.len())) + }) + .with_method("ends_with", |this: &mut String, args| { + if args.len() == 1 { + let other = args[0].value(); + let other = other.downcast_ref::().unwrap(); + return Ok(Some(ValueRef::new(this.ends_with(other.as_str())))); + } + Err(RuntimeError::invalid_argument_count(1, args.len())) + }) + .with_method("contains", |this: &mut String, args| { + if args.len() == 1 { + let other = args[0].value(); + let other = other.downcast_ref::().unwrap(); + return Ok(Some(ValueRef::new(this.contains(other.as_str())))); + } + Err(RuntimeError::invalid_argument_count(1, args.len())) + }) + .with_method("replace", |this: &mut String, args| { + if args.len() == 2 { + let old = args[0].value(); + let old = old.downcast_ref::().unwrap(); + let new = args[1].value(); + let new = new.downcast_ref::().unwrap(); + return Ok(Some(ValueRef::new( + this.replace(old.as_str(), new.as_str()), + ))); + } + Err(RuntimeError::invalid_argument_count(2, args.len())) + }) + .with_method("split", |this: &mut String, args| { + if args.len() == 1 { + let delimiter = args[0].value(); + let delimiter = delimiter.downcast_ref::().unwrap(); + return Ok(Some(ValueRef::new( + this.split(delimiter.as_str()) + .map(|s| s.to_string()) + .collect::>(), + ))); + } + Err(RuntimeError::invalid_argument_count(1, args.len())) + }) + .with_method("trim", |this: &mut String, args| { + if args.is_empty() { + return Ok(Some(ValueRef::new(this.trim().to_string()))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("trim_start", |this: &mut String, args| { + if args.is_empty() { + return Ok(Some(ValueRef::new(this.trim_start().to_string()))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("trim_end", |this: &mut String, args| { + if args.is_empty() { + return Ok(Some(ValueRef::new(this.trim_end().to_string()))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) + .with_method("chars", |this: &mut String, args| { + if args.is_empty() { + return Ok(Some(ValueRef::new(this.chars().collect::>()))); + } + Err(RuntimeError::invalid_argument_count(0, args.len())) + }) +}); diff --git a/src/runtime/object/structobject.rs b/src/runtime/object/structobject.rs new file mode 100644 index 0000000..9bcc4be --- /dev/null +++ b/src/runtime/object/structobject.rs @@ -0,0 +1,37 @@ +use std::collections::HashMap; + +use crate::ValueRef; + +use super::Object; + +#[derive(Debug, Clone)] +pub struct StructObject { + fields: HashMap, +} + +impl StructObject { + pub fn new() -> Self { + Self { + fields: HashMap::new(), + } + } + + pub fn make_field(&mut self, name: impl ToString, value: ValueRef) { + self.fields.insert(name.to_string(), value); + } +} + +impl Object for StructObject { + fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "StructObject") + } + + fn property_get(&self, property: &str) -> Result { + Ok(self.fields.get(property).unwrap().clone()) + } + + fn property_set(&mut self, property: &str, value: ValueRef) -> Result<(), crate::RuntimeError> { + self.fields.insert(property.to_string(), value); + Ok(()) + } +} diff --git a/src/runtime/object/tuple.rs b/src/runtime/object/tuple.rs index e33d0f9..7cd410a 100644 --- a/src/runtime/object/tuple.rs +++ b/src/runtime/object/tuple.rs @@ -23,111 +23,81 @@ impl Object for () { } } -impl Object for (ValueRef, ValueRef) { - fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:?}, {:?})", self.0, self.1) - } - - fn index_get(&self, index: &Value) -> Result { - let value = index - .downcast_ref::() - .ok_or(RuntimeError::invalid_type::(index))?; - - match *value { - 0 => Ok(self.0.clone()), - 1 => Ok(self.1.clone()), - _ => Err(RuntimeError::IndexOutOfBounds { - index: *value, - length: 2, - }), +macro_rules! impl_object_for_tuple { + ($n: expr, $($idx: tt => $t: ident),+) => { + impl Object for ($($t,)*) { + fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "({:?}, {:?})", self.0, self.1) + } + + fn index_get(&self, index: &Value) -> Result { + let value = index + .downcast_ref::() + .ok_or(RuntimeError::invalid_type::(index))?; + + match *value { + $( + $idx => Ok(self.$idx.clone()), + )* + _ => Err(RuntimeError::IndexOutOfBounds { + index: *value, + length: $n, + }), + } + } } - } + }; } -// impl Object for (ValueRef, ValueRef) { -// fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// write!(f, "({:?}, {:?})", self.0, self.1) -// } - -// fn index_get(&self, index: &Value) -> Result { -// let value = index -// .downcast_ref::() -// .ok_or(RuntimeError::invalid_type::(index))?; - -// match *value { -// 0 => Ok(self.0.clone()), -// 1 => Ok(self.1.clone()), -// _ => Err(RuntimeError::IndexOutOfBounds { -// index: *value, -// length: 2, -// }), -// } -// } -// } - -// impl Object for (T, Value) { -// fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// write!(f, "({:?}, {:?})", self.0, self.1) -// } - -// fn index_get(&self, index: &Value) -> Result { -// let value = index -// .downcast_ref::() -// .ok_or(RuntimeError::invalid_type::(index))?; - -// match *value { -// 0 => Ok(Value::new(self.0.clone())), -// 1 => Ok(self.1.clone()), -// _ => Err(RuntimeError::IndexOutOfBounds { -// index: *value, -// length: 2, -// }), -// } -// } -// } - -// impl Object for (usize, Value) { -// fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// write!(f, "({}, {})", self.0, self.1) -// } - -// fn index_get(&self, index: &Value) -> Result { -// let value = index -// .downcast_ref::() -// .ok_or(RuntimeError::invalid_type::(index))?; - -// match *value { -// 0 => Ok(Value::new(self.0.clone())), -// 1 => Ok(self.1.clone()), -// _ => Err(RuntimeError::IndexOutOfBounds { -// index: *value, -// length: 2, -// }), -// } -// } -// } - -impl Object for (T1, T2) -where - T1: Object + Clone, - T2: Object + Clone, -{ - fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "()") - } - - fn index_get(&self, index: &Value) -> Result { - let value = index - .downcast_ref::() - .ok_or(RuntimeError::invalid_type::(index))?; - - match *value { - 0 => Ok(ValueRef::new(self.0.clone())), - 1 => Ok(ValueRef::new(self.1.clone())), - _ => Err(RuntimeError::IndexOutOfBounds { - index: *value, - length: 2, - }), +impl_object_for_tuple!(2, 0=>ValueRef, 1=>ValueRef); +impl_object_for_tuple!(3, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef); +impl_object_for_tuple!(4, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef); +impl_object_for_tuple!(5, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef, 4=>ValueRef); +impl_object_for_tuple!(6, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef, 4=>ValueRef, 5=>ValueRef); +impl_object_for_tuple!(7, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef, 4=>ValueRef, 5=>ValueRef, 6=>ValueRef); +impl_object_for_tuple!(8, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef, 4=>ValueRef, 5=>ValueRef, 6=>ValueRef, 7=>ValueRef); +impl_object_for_tuple!(9, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef, 4=>ValueRef, 5=>ValueRef, 6=>ValueRef, 7=>ValueRef, 8=>ValueRef); +impl_object_for_tuple!(10, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef, 4=>ValueRef, 5=>ValueRef, 6=>ValueRef, 7=>ValueRef, 8=>ValueRef, 9=>ValueRef); +impl_object_for_tuple!(11, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef, 4=>ValueRef, 5=>ValueRef, 6=>ValueRef, 7=>ValueRef, 8=>ValueRef, 9=>ValueRef, 10=>ValueRef); +impl_object_for_tuple!(12, 0=>ValueRef, 1=>ValueRef, 2=>ValueRef, 3=>ValueRef, 4=>ValueRef, 5=>ValueRef, 6=>ValueRef, 7=>ValueRef, 8=>ValueRef, 9=>ValueRef, 10=>ValueRef, 11=>ValueRef); + +macro_rules! impl_object_for_object_tuple { + ($n: expr, $($idx: tt => $t: ident),+) => { + impl<$($t,)*> Object for ($($t,)*) + where + $($t: Object + Send + Clone),* + { + fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "({:?}, {:?})", self.0, self.1) + } + + fn index_get(&self, index: &Value) -> Result { + let value = index + .downcast_ref::() + .ok_or(RuntimeError::invalid_type::(index))?; + + match *value { + $( + $idx => Ok(ValueRef::new(self.$idx.clone())), + )* + _ => Err(RuntimeError::IndexOutOfBounds { + index: *value, + length: $n, + }), + } + } } - } + }; } + +impl_object_for_object_tuple!(2, 0 => T0, 1 => T1); +impl_object_for_object_tuple!(3, 0 => T0, 1 => T1, 2 => T2); +impl_object_for_object_tuple!(4, 0 => T0, 1 => T1, 2 => T2, 3 => T3); +impl_object_for_object_tuple!(5, 0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4); +impl_object_for_object_tuple!(6, 0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5); +impl_object_for_object_tuple!(7, 0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5, 6 => T6); +impl_object_for_object_tuple!(8, 0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5, 6 => T6, 7 => T7); +impl_object_for_object_tuple!(9, 0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5, 6 => T6, 7 => T7, 8 => T8); +impl_object_for_object_tuple!(10, 0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5, 6 => T6, 7 => T7, 8 => T8, 9 => T9); +impl_object_for_object_tuple!(11, 0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5, 6 => T6, 7 => T7, 8 => T8, 9 => T9, 10 => T10); +impl_object_for_object_tuple!(12, 0 => T0, 1 => T1, 2 => T2, 3 => T3, 4 => T4, 5 => T5, 6 => T6, 7 => T7, 8 => T8, 9 => T9, 10 => T10, 11 => T11); diff --git a/src/runtime/value.rs b/src/runtime/value.rs index d3a8f05..29354a6 100644 --- a/src/runtime/value.rs +++ b/src/runtime/value.rs @@ -1,12 +1,21 @@ +use std::fmt; + +#[cfg(not(feature = "async"))] use std::{ cell::{Ref, RefCell, RefMut}, - fmt, rc::Rc, }; -use crate::bytecode::{Constant, Primitive}; +#[cfg(feature = "async")] +use std::sync::Arc; + +#[cfg(feature = "async")] +use parking_lot::{ + MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard, +}; use super::{Immd, Null, Object}; +use crate::bytecode::{Constant, Primitive}; #[derive(Debug)] pub struct Value(Box); @@ -30,213 +39,154 @@ impl Value { any.downcast_mut::() } - pub fn object(&self) -> &dyn Object { + pub fn as_object(&self) -> &dyn Object { &*self.0 } + + pub fn as_object_mut(&mut self) -> &mut dyn Object { + &mut *self.0 + } + + pub fn into_inner(self) -> Result> { + (self.0 as Box) + .downcast::() + .map(|v| *v) + } } +#[cfg(feature = "async")] #[derive(Debug, Clone)] -pub struct ValueRef(Rc>); +pub struct ValueRef(Arc>); +#[cfg(feature = "async")] impl ValueRef { - pub fn new(object: T) -> Self { - ValueRef(Rc::new(RefCell::new(Value::new(object)))) + pub fn new(object: T) -> Self { + ValueRef(Arc::new(RwLock::new(Value::new(object)))) } pub fn from_value(value: Value) -> Self { - ValueRef(Rc::new(RefCell::new(value))) + ValueRef(Arc::new(RwLock::new(value))) } - pub fn value(&self) -> Ref { - self.0.borrow() + pub fn value(&self) -> RwLockReadGuard { + self.0.read() } - pub fn take(self) -> Value { - self.0.replace(Value::null()) + pub fn value_mut(&self) -> RwLockWriteGuard { + self.0.write() } - pub fn borrow(&self) -> Ref { - Ref::map(self.0.borrow(), |obj| obj.0.as_ref() as &dyn Object) + pub fn as_object(&self) -> MappedRwLockReadGuard<'_, dyn Object> { + let guard = self.0.read(); + RwLockReadGuard::map(guard, |value: &Value| value.as_object()) } - pub fn borrow_mut(&mut self) -> RefMut { - RefMut::map(self.0.borrow_mut(), |obj| obj.0.as_mut() as &mut dyn Object) + pub fn as_object_mut(&self) -> MappedRwLockWriteGuard<'_, dyn Object> { + let guard = self.0.write(); + RwLockWriteGuard::map(guard, |value: &mut Value| value.as_object_mut()) } pub fn null() -> Self { - ValueRef(Rc::new(RefCell::new(Value::new(Null)))) + ValueRef(Arc::new(RwLock::new(Value::null()))) } pub fn immd(immd: isize) -> Self { - ValueRef::new(Immd(immd)) + Self::new(Immd(immd)) + } + + pub fn take(&self) -> Value { + let mut lock = self.0.write(); + std::mem::replace(&mut *lock, Value::null()) } - pub fn from_constant(constant: Constant) -> Self { + pub fn from_constant(constant: &Constant) -> Self { match constant { - Constant::String(s) => ValueRef::new(s.as_str().to_string()), + Constant::String(s) => Self::new(s.to_string()), } } pub fn from_primitive(primitive: Primitive) -> Self { match primitive { - Primitive::Null => ValueRef::null(), - Primitive::Byte(b) => ValueRef::new(b), - Primitive::Boolean(b) => ValueRef::new(b), - Primitive::Integer(i) => ValueRef::new(i), - Primitive::Float(f) => ValueRef::new(f), - Primitive::Char(c) => ValueRef::new(c), + Primitive::Null => Self::null(), + Primitive::Byte(b) => Self::new(b), + Primitive::Boolean(b) => Self::new(b), + Primitive::Integer(i) => Self::new(i), + Primitive::Float(f) => Self::new(f), + Primitive::Char(c) => Self::new(c), } } +} + +#[cfg(not(feature = "async"))] +#[derive(Debug, Clone)] +pub struct ValueRef(Rc>); + +#[cfg(not(feature = "async"))] +impl ValueRef { + pub fn new(object: T) -> Self { + ValueRef(Rc::new(RefCell::new(Value::new(object)))) + } + + pub fn from_value(value: Value) -> Self { + ValueRef(Rc::new(RefCell::new(value))) + } + + pub fn value(&self) -> Ref { + self.0.borrow() + } + + pub fn value_mut(&self) -> RefMut { + self.0.borrow_mut() + } + + pub fn as_object(&self) -> Ref { + let guard = self.0.borrow(); + Ref::map(guard, |value| value.as_object()) + } + + pub fn as_object_mut(&self) -> RefMut { + let guard = self.0.borrow_mut(); + RefMut::map(guard, |value| value.as_object_mut()) + } + + pub fn null() -> Self { + Self::new(Null {}) + } - // pub fn downcast_ref<'a, T: Object + 'static>(&'a self) -> Option<&'a T> { - // let obj = self.0.borrow(); - // let any = (&*obj as &dyn std::any::Any); - // any.downcast_ref::() - // } + pub fn immd(immd: isize) -> Self { + Self::new(Immd(immd)) + } - pub fn downcast_ref(&self) -> Option> { - Ref::filter_map(self.0.borrow(), |obj| { - ((obj.0).as_ref() as &dyn std::any::Any).downcast_ref::() - }) - .ok() + pub fn take(&self) -> Value { + self.0.replace(Value::null()) + } + + pub fn from_constant(constant: &Constant) -> Self { + match constant { + Constant::String(s) => Self::new(s.to_string()), + } } - pub fn downcast_mut(&mut self) -> Option> { - RefMut::filter_map(self.0.borrow_mut(), |obj| { - ((obj.0).as_mut() as &mut dyn std::any::Any).downcast_mut::() - }) - .ok() + pub fn from_primitive(primitive: Primitive) -> Self { + match primitive { + Primitive::Null => Self::null(), + Primitive::Byte(b) => Self::new(b), + Primitive::Boolean(b) => Self::new(b), + Primitive::Integer(i) => Self::new(i), + Primitive::Float(f) => Self::new(f), + Primitive::Char(c) => Self::new(c), + } } } impl From for ValueRef { fn from(value: Value) -> Self { - ValueRef(Rc::new(RefCell::new(value))) + Self::from_value(value) } } -// impl From for Value { -// fn from(value: T) -> Self { -// Value::new(value) -// } -// } - impl fmt::Display for ValueRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.borrow().debug(f) + self.value().as_object().debug(f) } } - -// impl PartialEq for ValueRef { -// fn eq(&self, other: &T) -> bool { -// match self.borrow().compare(&Value::new(other)) { -// Ok(ordering) => ordering == std::cmp::Ordering::Equal, -// Err(_) => false, -// } -// } -// } - -// impl Object for ValueRef { -// fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// self.borrow().debug(f) -// } - -// fn add(&self, other: &ValueRef) -> Result { -// self.borrow().add(other) -// } - -// fn sub(&self, other: &ValueRef) -> Result { -// self.borrow().sub(other) -// } - -// fn mul(&self, other: &ValueRef) -> Result { -// self.borrow().mul(other) -// } - -// fn div(&self, other: &ValueRef) -> Result { -// self.borrow().div(other) -// } - -// fn modulo(&self, other: &ValueRef) -> Result { -// self.borrow().modulo(other) -// } - -// fn pow(&self, other: &ValueRef) -> Result { -// self.borrow().pow(other) -// } - -// fn compare(&self, other: &ValueRef) -> Result { -// self.borrow().compare(other) -// } - -// fn logic_and(&self, other: &ValueRef) -> Result { -// self.borrow().logic_and(other) -// } - -// fn logic_or(&self, other: &ValueRef) -> Result { -// self.borrow().logic_or(other) -// } - -// fn negate(&self) -> Result { -// self.borrow().negate() -// } - -// fn call(&mut self, args: &[ValueRef]) -> Result, RuntimeError> { -// self.borrow_mut().call(args) -// } - -// fn index_get(&self, index: &ValueRef) -> Result { -// self.borrow().index_get(index) -// } - -// fn index_set(&mut self, index: &ValueRef, value: ValueRef) -> Result<(), RuntimeError> { -// self.borrow_mut().index_set(index, value) -// } - -// fn property_get(&mut self, member: &str) -> Result { -// self.borrow_mut().property_get(member) -// } - -// fn property_set(&mut self, member: &str, value: ValueRef) -> Result<(), RuntimeError> { -// self.borrow_mut().property_set(member, value) -// } - -// fn property_call( -// &mut self, -// member: &str, -// args: &[ValueRef], -// ) -> Result, RuntimeError> { -// self.borrow_mut().property_call(member, args) -// } - -// fn make_iterator(&self) -> Result>, RuntimeError> { -// self.borrow().make_iterator() -// } - -// fn iterator_has_next(&self) -> Result { -// self.borrow().iterator_has_next() -// } - -// fn iterate_next(&mut self) -> Result { -// self.borrow_mut().iterate_next() -// } - -// fn make_slice(&self, range: &ValueRef) -> Result { -// self.borrow().make_slice(range) -// } - -// fn into_future( -// self: Box, -// ) -> Result + Unpin + Send + 'static>, RuntimeError> { -// // 这里需要特殊处理,因为我们需要获取内部的Box -// match Rc::try_unwrap(self.0) { -// Ok(refcell) => match refcell.into_inner() { -// inner => inner.0.into_future(), -// }, -// Err(_) => Err(RuntimeError::invalid_operation( -// OperateKind::Await, -// "Cannot convert shared value into future", -// )), -// } -// } -// } diff --git a/src/runtime/vm.rs b/src/runtime/vm.rs index 7e72a2d..af68b94 100644 --- a/src/runtime/vm.rs +++ b/src/runtime/vm.rs @@ -1,14 +1,636 @@ -use std::fmt; +use std::{ + collections::HashMap, + fmt::{self}, + sync::Arc, +}; -use crate::bytecode::Register; - -use super::{RuntimeError, value::ValueRef}; +#[cfg(feature = "async")] +use super::Promise; +use super::{ + Enumerator, EnvVariable, Environment, NativeFunction, Object, Range, RuntimeError, + UserFunction, Value, object::StructObject, value::ValueRef, +}; +use crate::bytecode::{Bytecode, Constant, FunctionId, Module, Opcode, Operand, Register}; +use log::debug; const STACK_MAX: usize = 0x0FFF; -/// VM -/// note: the stack is from bottom to top +#[derive(Debug)] pub struct VM { + state: State, + program: Arc, + env: Environment, +} + +impl VM { + pub fn new(program: Arc, env: Environment) -> Self { + Self { + state: State::new(), + program, + env, + } + } + + #[cfg(feature = "async")] + pub async fn run(&mut self) -> Result, RuntimeError> { + debug!("===constants==="); + for (i, constant) in self.program.constants.iter().enumerate() { + debug!("{i}: {constant:?}"); + } + debug!("===instructions==="); + for (i, inst) in self.program.instructions.iter().enumerate() { + debug!("{i}: {inst:?}"); + } + + while let Some(inst) = self.program.instructions.get(self.state.pc).cloned() { + debug!("{}", self.state); + debug!("{inst:?}"); + + let Bytecode { opcode, operands } = inst; + + match opcode { + Opcode::Halt => { + let ret = self.get_value(Operand::Register(Register::Rv))?; + return Ok(Some(ret)); + } + + Opcode::Ret => { + if self.state.ctrl_stack_reached_bottom() { + let ret = self.get_value(Operand::Register(Register::Rv))?; + return Ok(Some(ret)); + } + let pc = self.state.popc()?; + + self.state.jump(pc); + } + + Opcode::Await => { + let promise = self.get_value(operands[1])?; + let mut promise = promise.take(); + let promise = promise + .downcast_mut::() + .ok_or(RuntimeError::internal("only can await promise"))?; + let ret = promise.await; + self.set_value(operands[0], ret)?; + self.state.jump_offset(1); + } + + _ => { + self.run_instruction(&inst)?; + } + } + } + + Ok(None) + } + + #[cfg(not(feature = "async"))] + pub fn run(&mut self) -> Result, RuntimeError> { + debug!("===constants==="); + for (i, constant) in self.program.constants.iter().enumerate() { + debug!("{i}: {constant:?}"); + } + debug!("===instructions==="); + for (i, inst) in self.program.instructions.iter().enumerate() { + debug!("{i}: {inst:?}"); + } + + while let Some(inst) = self.program.instructions.get(self.state.pc).cloned() { + debug!("{}", self.state); + debug!("{inst:?}"); + + let Bytecode { opcode, operands } = inst; + + match opcode { + Opcode::Halt => { + let ret = self.get_value(Operand::Register(Register::Rv))?; + return Ok(Some(ret)); + } + + Opcode::Ret => { + if self.state.ctrl_stack_reached_bottom() { + let ret = self.get_value(Operand::Register(Register::Rv))?; + return Ok(Some(ret)); + } + let pc = self.state.popc()?; + + self.state.jump(pc); + } + + _ => { + self.run_instruction(&inst)?; + } + } + } + + Ok(None) + } + + fn run_instruction(&mut self, inst: &Bytecode) -> Result<(), RuntimeError> { + let Bytecode { opcode, operands } = inst; + + match opcode { + // Control Flow Instructions + Opcode::Call => { + let func = operands[0].as_immd(); + match self.program.symtab.get(&FunctionId::new(func as u32)) { + Some(location) => { + self.state.pushc(self.state.pc() + 1)?; + self.state.jump(*location); + return Ok(()); + } + None => { + return Err(RuntimeError::SymbolNotFound { + name: format!("{func}"), + }); + } + } + } + Opcode::CallEx => match operands[0] { + Operand::Symbol(sym) => match self.program.symtab.get(&FunctionId::new(sym)) { + Some(location) => { + self.state.pushc(self.state.pc() + 1)?; + self.state.jump(*location); + return Ok(()); + } + None => { + return Err(RuntimeError::SymbolNotFound { + name: format!("{sym}"), + }); + } + }, + Operand::Register(_) | Operand::Stack(_) => { + let value = self.get_value(operands[0])?; + match value.value().downcast_ref::() { + Some(func) => match self.program.symtab.get(&func.id()) { + Some(location) => { + self.state.pushc(self.state.pc() + 1)?; + self.state.jump(*location); + return Ok(()); + } + None => { + return Err(RuntimeError::SymbolNotFound { + name: format!("{:?}", func.id()), + }); + } + }, + None => { + return Err(RuntimeError::invalid_operand(operands[0])); + } + } + } + + _ => return Err(RuntimeError::invalid_operand(operands[0])), + }, + + Opcode::Br => { + let offset = operands[0].as_immd(); + self.state.jump_offset(offset); + return Ok(()); + } + + Opcode::BrIf => { + let cond = self.get_value(operands[0])?; + match cond.value().downcast_ref::() { + Some(b) => { + let offset = if *b { + operands[1].as_immd() + } else { + operands[2].as_immd() + }; + self.state.jump_offset(offset); + } + None => return Err(RuntimeError::invalid_type::(&cond)), + } + return Ok(()); + } + + // Stack and Register Manipulation + Opcode::Mov => { + let value = self.get_value(operands[1])?; + match operands[0] { + Operand::Register(reg) => { + self.state.set_register(reg, value)?; + } + Operand::Stack(offset) => { + self.state.set_value_to_stack(offset, value)?; + } + op => return Err(RuntimeError::invalid_operand(op)), + } + } + Opcode::Push => { + let value = self.get_value(operands[0])?; + self.state.push(value)?; + } + Opcode::Pop => { + let value = self.state.pop()?; + self.set_value(operands[0], value)?; + } + + Opcode::MovC => match (operands[0], operands[1]) { + (Operand::Register(Register::Rsp), Operand::Register(Register::Rbp)) => { + *self.state.rsp_mut() = self.state.rbp(); + } + (Operand::Register(Register::Rbp), Operand::Register(Register::Rsp)) => { + *self.state.rbp_mut() = self.state.rsp(); + } + + _ => unimplemented!("unsupported instruction:{inst:?}"), + }, + Opcode::PushC => match operands[0] { + Operand::Register(Register::Rsp) => { + self.state.pushc(self.state.rsp())?; + } + Operand::Register(Register::Rbp) => { + self.state.pushc(self.state.rbp())?; + } + _ => unimplemented!("unsupported instruction:{inst:?}"), + }, + Opcode::PopC => match operands[0] { + Operand::Register(Register::Rsp) => { + let value = self.state.popc()?; + *self.state.rsp_mut() = value; + } + Operand::Register(Register::Rbp) => { + let value = self.state.popc()?; + *self.state.rbp_mut() = value; + } + _ => unimplemented!("unsupported instruction:{inst:?}"), + }, + Opcode::AddC => match (operands[0], operands[1]) { + (Operand::Register(Register::Rsp), Operand::Register(Register::Rsp)) => { + *self.state.rsp_mut() = self.state.rsp() + operands[2].as_immd() as usize; + } + _ => unimplemented!("unsupported instruction:{inst:?}"), + }, + Opcode::SubC => match (operands[0], operands[1]) { + (Operand::Register(Register::Rsp), Operand::Register(Register::Rsp)) => { + *self.state.rsp_mut() = self.state.rsp() - operands[2].as_immd() as usize; + } + _ => unimplemented!("unsupported instruction:{inst:?}"), + }, + + // Arithmetic Operations + Opcode::Addx => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = lhs.value().as_object().add(&rhs.value())?; + self.set_value(operands[0], value)?; + } + Opcode::Subx => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = lhs.value().as_object().sub(&rhs.value())?; + self.set_value(operands[0], value)?; + } + Opcode::Mulx => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = lhs.value().as_object().mul(&rhs.value())?; + self.set_value(operands[0], value)?; + } + Opcode::Divx => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = lhs.value().as_object().div(&rhs.value())?; + self.set_value(operands[0], value)?; + } + Opcode::Remx => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = lhs.value().as_object().rem(&rhs.value())?; + self.set_value(operands[0], value)?; + } + + // Logical Operations + Opcode::Not | Opcode::Neg => { + let value = self.get_value(operands[1])?; + let value = value.value().as_object().negate()?; + self.set_value(operands[0], ValueRef::from(value))?; + } + Opcode::And => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = lhs.value().as_object().logic_and(&rhs.value())?; + self.set_value(operands[0], value)?; + } + Opcode::Or => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = lhs.value().as_object().logic_or(&rhs.value())?; + self.set_value(operands[0], value)?; + } + + // Comparison Operations + Opcode::Greater => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let ordering = lhs.value().as_object().compare(&rhs.value())?; + self.set_value( + operands[0], + ValueRef::new(ordering == std::cmp::Ordering::Greater), + )?; + } + Opcode::GreaterEqual => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let ordering = lhs.value().as_object().compare(&rhs.value())?; + self.set_value( + operands[0], + ValueRef::new( + ordering == std::cmp::Ordering::Greater + || ordering == std::cmp::Ordering::Equal, + ), + )?; + } + + Opcode::Less => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let ordering = lhs.value().as_object().compare(&rhs.value())?; + self.set_value( + operands[0], + ValueRef::new(ordering == std::cmp::Ordering::Less), + )?; + } + + Opcode::LessEqual => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let ordering = lhs.value().as_object().compare(&rhs.value())?; + self.set_value( + operands[0], + ValueRef::new( + ordering == std::cmp::Ordering::Less + || ordering == std::cmp::Ordering::Equal, + ), + )?; + } + + Opcode::Equal => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let eq = lhs.value().as_object().equal(&rhs.value())?; + self.set_value(operands[0], eq)?; + } + + Opcode::NotEqual => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let eq = lhs.value().as_object().equal(&rhs.value())?; + let not_eq = !*eq.downcast_ref::().unwrap(); + self.set_value(operands[0], Value::new(not_eq))?; + } + + // Load Instructions + Opcode::LoadConst => { + let const_index = operands[1].as_immd(); + let value = ValueRef::from_constant(&self.program.constants[const_index as usize]); + self.set_value(operands[0], value)?; + } + + Opcode::LoadEnv => { + let name = operands[1].as_immd(); + let name = &self.program.constants[name as usize]; + match name { + Constant::String(name) => match self.env.get(name.as_str()) { + Some(EnvVariable::Value(value)) => { + self.set_value(operands[0], value.clone())?; + } + Some(EnvVariable::Function(function)) => { + self.set_value(operands[0], function.clone())?; + } + None => { + return Err(RuntimeError::internal("undefined variable")); + } + }, + }; + } + + // Collection / Structural Operations + Opcode::MakeArray => { + let array: Vec = Vec::new(); + self.set_value(operands[0], ValueRef::new(array))?; + } + + Opcode::ArrayPush => { + let array = self.get_value(operands[0])?; + let value = self.get_value(operands[1])?; + let array_cloned = array.clone(); + let mut array = array.value_mut(); + let array = array + .downcast_mut::>() + .ok_or(RuntimeError::invalid_type::>(array_cloned))?; + array.push(value); + } + + Opcode::MakeMap => { + let map: HashMap = HashMap::new(); + self.set_value(operands[0], ValueRef::new(map))?; + } + + Opcode::MakeSlice => { + let object = self.get_value(operands[1])?; + let range = self.get_value(operands[2])?; + + let slice = object.value().as_object().make_slice(range)?; + self.set_value(operands[0], slice)?; + } + + Opcode::MakeStruct => { + let struct_object = StructObject::new(); + self.set_value(operands[0], ValueRef::new(struct_object))?; + } + + Opcode::MakeStructField => { + let struct_object = self.get_value(operands[0])?; + let field_value = self.get_value(operands[2])?; + + let st_cloned = struct_object.clone(); + let mut st_obj = struct_object.value_mut(); + let struct_object = st_obj + .downcast_mut::() + .ok_or(RuntimeError::invalid_type::>(st_cloned))?; + let field_name = self.load_string(operands[1])?; + struct_object.make_field(field_name, field_value); + } + + Opcode::IndexSet => { + let object = self.get_value(operands[0])?; + let index = self.get_value(operands[1])?; + let value = self.get_value(operands[2])?; + object.as_object_mut().index_set(&index.value(), value)?; + } + + Opcode::IndexGet => { + let object = self.get_value(operands[1])?; + let index = self.get_value(operands[2])?; + let value = object.value().as_object().index_get(&index.value())?; + self.set_value(operands[0], value)?; + } + + Opcode::PropGet => { + let object = self.get_value(operands[1])?; + let prop = self.load_string(operands[2])?; + + let value = object.value().as_object().property_get(&prop)?; + + self.set_value(operands[0], value)?; + } + Opcode::PropSet => { + let object = self.get_value(operands[0])?; + let prop = self.load_string(operands[1])?; + let value = self.get_value(operands[2])?; + + object.as_object_mut().property_set(&prop, value)?; + } + + // Range Operations + Opcode::Range => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = Range::new(lhs, rhs)?; + self.set_value(operands[0], ValueRef::new(value))?; + } + + Opcode::RangeInclusive => { + let lhs = self.get_value(operands[1])?; + let rhs = self.get_value(operands[2])?; + let value = Range::inclusive(lhs, rhs)?; + self.set_value(operands[0], ValueRef::new(value))?; + } + + Opcode::RangeFull => { + let value = Range::range_full(); + self.set_value(operands[0], ValueRef::new(value))?; + } + + Opcode::RangeFrom => { + let lhs = self.get_value(operands[1])?; + let value = Range::range_from(lhs)?; + self.set_value(operands[0], ValueRef::new(value))?; + } + + Opcode::RangeTo => { + let lhs = self.get_value(operands[1])?; + let value = Range::range_to(lhs)?; + self.set_value(operands[0], ValueRef::new(value))?; + } + + Opcode::RangeToInclusive => { + let lhs = self.get_value(operands[1])?; + let value = Range::range_to_inclusive(lhs)?; + self.set_value(operands[0], ValueRef::new(value))?; + } + + // Iteration Support + Opcode::MakeIter => { + let obj = self.get_value(operands[1])?; + match obj.value().downcast_ref::() { + Some(_) => { + self.set_value(operands[0], obj.clone())?; + } + None => { + let iterator = obj.value().as_object().make_iterator()?; + self.set_value(operands[0], ValueRef::new(Enumerator::new(iterator)))?; + } + } + } + + Opcode::IterNext => { + let iterator = self.get_value(operands[1])?; + let next = iterator.as_object_mut().iterate_next()?; + self.set_value(operands[0], Value::new(next))?; + } + + // Object Method Call + Opcode::CallMethod => { + let object = self.get_value(operands[0])?; + let prop = self.load_string(operands[1])?; + let arg_count = operands[2].as_immd() as usize; + // load args from stack + let mut args = Vec::with_capacity(arg_count); + for i in 0..arg_count { + let offset = -(i as isize + 1); + let arg = self.get_value(Operand::Stack(offset))?; + args.push(arg); + } + let ret = object.as_object_mut().call_method(&prop, &args)?; + let ret = ret.unwrap_or(ValueRef::null()); + self.state.set_register(Register::Rv, ret)?; + } + + // Native method call + Opcode::CallNative => { + let func = self.get_value(operands[0])?; + let arg_count = operands[1].as_immd() as usize; + match func.value_mut().downcast_mut::() { + Some(func) => { + // load args from stack + let mut args = Vec::with_capacity(arg_count); + for i in 0..arg_count { + let offset = -(i as isize + 1); + let arg = self.get_value(Operand::Stack(offset))?; + args.push(arg); + } + let ret = func.call(&args)?; + let ret = ret.unwrap_or(Value::null()); + self.state.set_register(Register::Rv, ValueRef::from(ret))?; + } + None => { + return Err(RuntimeError::invalid_operand(operands[0])); + } + } + } + + inst => unreachable!("unsupported instruction {inst:?}"), + } + + self.state.jump_offset(1); + + Ok(()) + } + + fn get_value(&self, operand: Operand) -> Result { + match operand { + Operand::Primitive(primitive) => Ok(ValueRef::from_primitive(primitive)), + Operand::Register(reg) => self.state.get_register(reg), + Operand::Stack(offset) => self.state.get_value_from_stack(offset), + Operand::Immd(immd) => Ok(ValueRef::immd(immd)), + Operand::Symbol(symbol) => { + Ok(ValueRef::new(UserFunction::new(FunctionId::new(symbol)))) + } + } + } + + fn set_value( + &mut self, + operand: Operand, + value: impl Into, + ) -> Result<(), RuntimeError> { + let value = value.into(); + + match operand { + Operand::Register(reg) => self.state.set_register(reg, value), + Operand::Stack(offset) => self.state.set_value_to_stack(offset, value), + op => Err(RuntimeError::invalid_operand(op)), + } + } + + fn load_string(&self, operand: Operand) -> Result, RuntimeError> { + let const_id = operand.as_immd(); + let name = &self.program.constants[const_id as usize]; + + match name { + Constant::String(name) => Ok(name.clone()), + } + } +} + +/// State +/// note: the stack is from bottom to top +#[derive(Debug)] +pub struct State { pub data_stack: [ValueRef; STACK_MAX], pub ctrl_stack: [usize; STACK_MAX], pub registers: [ValueRef; 20], @@ -18,13 +640,13 @@ pub struct VM { pub pc: usize, } -impl Default for VM { +impl Default for State { fn default() -> Self { Self::new() } } -impl VM { +impl State { pub fn new() -> Self { Self { data_stack: std::array::from_fn(|_| ValueRef::null()), @@ -71,9 +693,8 @@ impl VM { pub fn get_register(&self, reg: Register) -> Result { match reg { - Register::RSP => Err(RuntimeError::InvalidRegisterAccess(reg)), - Register::RBP => Err(RuntimeError::InvalidRegisterAccess(reg)), - Register::PC => Err(RuntimeError::InvalidRegisterAccess(reg)), + Register::Rsp => Err(RuntimeError::InvalidRegisterAccess(reg)), + Register::Rbp => Err(RuntimeError::InvalidRegisterAccess(reg)), _ => { let index = reg.as_usize(); if index >= self.registers.len() { @@ -86,9 +707,8 @@ impl VM { pub fn set_register(&mut self, reg: Register, value: ValueRef) -> Result<(), RuntimeError> { match reg { - Register::RSP => Err(RuntimeError::InvalidRegisterAccess(reg)), - Register::RBP => Err(RuntimeError::InvalidRegisterAccess(reg)), - Register::PC => Err(RuntimeError::InvalidRegisterAccess(reg)), + Register::Rsp => Err(RuntimeError::InvalidRegisterAccess(reg)), + Register::Rbp => Err(RuntimeError::InvalidRegisterAccess(reg)), _ => { let index = reg.as_usize(); if index >= self.registers.len() { @@ -156,7 +776,7 @@ impl VM { } } -impl fmt::Display for VM { +impl fmt::Display for State { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!( f, diff --git a/tests/eval.rs b/tests/eval.rs deleted file mode 100644 index c1b58f9..0000000 --- a/tests/eval.rs +++ /dev/null @@ -1,276 +0,0 @@ -use evalit::{Environment, Interpreter, ValueRef}; - -mod utils; - -use utils::init_logger; - -fn fib(n: i64) -> i64 { - if n < 1 { - return 0; - } - if n <= 2 { - return 1; - } - - fib(n - 1) + fib(n - 2) -} - -fn println(args: &[ValueRef]) { - let s = args - .iter() - .map(|v| format!("{v}")) - .collect::>() - .join(""); - - println!("{s}"); -} - -#[test] -fn test_simple() { - init_logger(); - - let env = Environment::new(); - - let script = r#" - let sum = 0; - sum = 1 + 2 + 3 + 4 + 5; - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - - println!("ret: {retval:?}"); - - assert_eq!(retval, 15); -} - -#[test] -fn test_eval_for_range() { - init_logger(); - - let env = Environment::new(); - - let script = r#" - let sum = 0; - for i in 0..=10 { - sum += i; - } - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - - assert_eq!(retval, 55); -} - -#[test] -fn test_eval_control_flow() { - init_logger(); - - let mut env = Environment::new(); - - env.define_function("println", println); - - let script = r#" - let sum = 0; - for i in 0..=10 { - println("i=", i); - if i % 2 == 0 { - continue; - } - sum += i; - - if i == 5 { - break; - } - println("sum=", sum); - } - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - - assert_eq!(retval, 9); -} - -#[test] -fn test_eval_array() { - init_logger(); - - let mut env = Environment::new(); - - env.define_function("println", println); - - let script = r#" - let sum = 0; - let array = [1, 2, 3, 4, 5]; - - println("array.len = ", array.len()); - - for (i, ele) in array.enumerate() { - println("array[", i, "]=", ele); - } - - for i in array { - sum += i; - } - - println("sum = ", sum); - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - - assert_eq!(retval, 15); -} - -#[test] -fn test_eval_map() { - let env = Environment::new(); - - let script = r#" - let sum = 0; - let map = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}; - for (k, v) in map { - sum += v; - } - sum += map["a"]; - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - - assert_eq!(retval, 16); -} - -#[test] -fn test_slice() { - init_logger(); - - let mut env = Environment::new(); - - env.define_function("println", println); - - let script = r#" - let sum = 0; - let array = [1, 2, 3, 4, 5]; - // println("array.len = ", array.len()); - - - let slice = array[..]; - slice = array[1..]; - slice = array[..3]; - slice = array[1..3]; - slice = array[1..=3]; - - for i in slice { - sum += i; - } - - println("sum = ", sum); - - - let str = "hello中文测试"; - - for c in str { - println("->", c); - } - - // println("str.len = ", str.len()); - - println(str[1..=5]); - - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - - assert_eq!(retval, 9); -} - -#[test] -fn test_eval_for() { - init_logger(); - - let mut env = Environment::new(); - - env.define_function("println", println); - - let script = r#" - - let arr = [1, 2, 3, 4, 5]; - for ele in arr { - println("->", ele); - } - - for (i, ele) in arr.enumerate() { - println("[", i, "]->", i); - } - - let map = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}; - for (k, v) in map { - println(k, "->", v); - } - "#; - - let retval = Interpreter::eval_script(script, env); - - println!("ret: {retval:?}"); - assert!(retval.is_ok()); -} - -#[test] -fn test_eval_env() { - init_logger(); - - let mut env = Environment::new(); - - env.define_function("fib", fib); - - let script = r#" - let sum = 0; - for i in 1..=10 { - sum += fib(i); - } - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap(); - - println!("ret: {retval:?}"); -} - -#[test] -fn test_eval() { - init_logger(); - - let env = Environment::new(); - - let script = r#" - fn fib(n) { - if n < 1 { - return 0; - } - if n <= 2 { - return 1; - } - - return fib(n - 1) + fib(n - 2); - } - - let f = fib; - - let sum = 0; - for i in 1..=10 { - sum += f(i); - } - - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap(); - - println!("ret: {retval:?}"); - - assert_eq!(retval.unwrap(), 143); -} diff --git a/tests/interpreter.rs b/tests/interpreter.rs deleted file mode 100644 index 31801fd..0000000 --- a/tests/interpreter.rs +++ /dev/null @@ -1,427 +0,0 @@ -use evalit::{Environment, Interpreter, RuntimeError}; - -mod utils; - -use utils::init_logger; - -#[test] -fn test_eval_undefine() { - let env = Environment::new(); - - let script = r#" - let x; - return x; - "#; - - let retval = Interpreter::eval_script(script, env); - assert!(retval.is_err()); -} - -#[test] -fn test_eval_boolean() { - init_logger(); - - let env = Environment::new(); - - let script = r#" - let a = true; - let b = false; - return a && !b; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, true); -} - -#[test] -fn test_eval_integer() { - init_logger(); - let env = Environment::new(); - - let script = r#" - let max = 9223372036854775807; // 2^63 - let min = -9223372036854775807; // -2^63 - return max + min; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 0); -} - -#[test] -fn test_eval_float() { - let env = Environment::new(); - - let script = r#" - let pi = 3.141592653589793; - let e = 2.718281828459045; - return pi * e; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - let diff = (*retval.downcast_ref::().unwrap() - 8.539734222673567).abs(); - println!("diff = {diff}"); - assert!(diff < 1e-10); -} - -#[test] -fn test_eval_string() { - let env = Environment::new(); - - let script = r#" - let greeting = "Hello, "; - let name = "World!"; - return greeting + name; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, "Hello, World!"); -} - -#[test] -fn test_eval_loop() { - let env = Environment::new(); - - let script = r#" - let i = 1; - let sum = 0; - loop { - sum += i; - i += 1; - if i > 10 { - break; - } - } - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 55); -} - -#[test] -fn test_eval_for_loop() { - let env = Environment::new(); - - let script = r#" - let sum = 0; - for i in 0..=10 { - sum += i; - } - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 55); -} - -#[test] -fn test_eval_if_statement() { - let env = Environment::new(); - - let script = r#" - let x = 10; - if x > 5 { - return "Greater than 5"; - } else { - return "Less than or equal to 5"; - } - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, "Greater than 5"); -} - -#[test] -fn test_eval_break_continue() { - let env = Environment::new(); - - let script = r#" - let sum = 0; - for i in 0..10 { - if i == 5 { - break; - } - if i % 2 == 0 { - continue; - } - sum += i; - } - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 4); // 1 + 3 -} - -#[test] -fn test_eval_for_with_if() { - let env = Environment::new(); - - let script = r#" - let sum = 0; - for i in 0..10 { - if i % 2 == 0 { - sum += i; - } - } - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 20); // 0 + 2 + 4 + 6 + 8 -} - -#[test] -fn test_eval_if_multiple_conditions() { - let env = Environment::new(); - - let script = r#" - let x = 10; - let y = 5; - if x > 5 && y < 10 || x == 10 { - return "Condition met"; - } else { - return "Condition not met"; - } - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, "Condition met"); -} - -#[test] -fn test_eval_map_iteration() { - let env = Environment::new(); - - let script = r#" - let sum = 0; - let map = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}; - for (k, v) in map { - sum += v; - } - sum += map["a"]; - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 16); -} - -#[test] -fn test_eval_null_variable() { - let env = Environment::new(); - - let script = r#" - return x; - "#; - - let result = Interpreter::eval_script(script, env); - assert!(result.is_err()); -} - -#[test] -fn test_eval_invalid_index_access() { - let env = Environment::new(); - - let script = r#" - let map = {"a": 1, "b": 2}; - return map["c"]; - "#; - - let result = Interpreter::eval_script(script, env); - assert!(result.is_err()); -} - -#[test] -fn test_eval_invalid_type_conversion() { - let env = Environment::new(); - - let script = r#" - let str = "123"; - return str + 1; - "#; - - let result = Interpreter::eval_script(script, env); - assert!(result.is_err()); -} - -#[test] -fn test_eval_simple_function_call() { - let env = Environment::new(); - - let script = r#" - fn add(a, b) { - return a + b; - } - - return add(3, 5); - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 8); -} - -#[test] -fn test_eval_function_with_multiple_parameters() { - let env = Environment::new(); - - let script = r#" - fn multiply(a, b, c) { - return a * b * c; - } - - return multiply(2, 3, 4); - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 24); -} - -#[test] -fn test_eval_recursive_function_fibonacci() { - let env = Environment::new(); - - let script = r#" - fn fib(n) { - if n < 1 { - return 0; - } - if n <= 2 { - return 1; - } - - return fib(n - 1) + fib(n - 2); - } - - let f = fib; - - let sum = 0; - for i in 1..=10 { - sum += f(i); - } - - return sum; - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 143); -} - -#[test] -fn test_eval_recursive_function_factorial() { - let env = Environment::new(); - - let script = r#" - fn factorial(n) { - if n <= 1 { - return 1; - } - return n * factorial(n - 1); - } - - return factorial(5); - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 120); -} - -#[test] -fn test_eval_higher_order_function() { - init_logger(); - let env = Environment::new(); - - let script = r#" - fn apply_twice(f, x) { - return f(f(x)); - } - - fn increment(x) { - return x + 1; - } - - return apply_twice(increment, 5); - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 7); // (5 + 1) + 1 = 7 -} - -#[test] -fn test_eval_null_function_call() { - let env = Environment::new(); - - let script = r#" - return unknown_function(); - "#; - - let result = Interpreter::eval_script(script, env); - assert!(result.is_err()); -} - -#[test] -fn test_eval_recursive_depth_exceeded() { - let env = Environment::new(); - - let script = r#" - fn recursive(n) { - if n > 0 { - return recursive(n - 1); - } - return 0; - } - - return recursive(10000); // 递归深度过大 - "#; - - let result = Interpreter::eval_script(script, env); - assert!(matches!( - result.err().unwrap(), - evalit::Error::Runtime(RuntimeError::StackOverflow) - )); -} - -#[test] -fn test_eval_function_call_chain() { - let env = Environment::new(); - - let script = r#" - fn add(a, b) { - return a + b; - } - - fn multiply(a, b) { - return a * b; - } - - return multiply(add(2, 3), add(4, 5)); - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, 45); // (2 + 3) * (4 + 5) = 5 * 9 = 45 -} - -#[test] -fn test_eval_function_with_control_flow() { - let env = Environment::new(); - - let script = r#" - fn calculate(n) { - let result = 0; - for i in 1..=n { - if i % 2 == 0 { - result += i; - } else { - result -= i; - } - } - return result; - } - - return calculate(5); - "#; - - let retval = Interpreter::eval_script(script, env).unwrap().unwrap(); - assert_eq!(retval, -3); // (-1) + 2 + (-3) + 4 + (-5) = -3 -} diff --git a/tests/test_basic_types.rs b/tests/test_basic_types.rs new file mode 100644 index 0000000..40d6d5c --- /dev/null +++ b/tests/test_basic_types.rs @@ -0,0 +1,273 @@ +mod utils; +use evalit::{Environment, Interpreter, Null}; +use utils::init_logger; + +#[test] +fn test_null() { + init_logger(); + + let env = Environment::new(); + let script = r#" + return null; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, Null); +} + +#[test] +fn test_boolean() { + init_logger(); + + let env = Environment::new(); + + // 测试true + let script = r#" + return true; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, true); + + let env = Environment::new(); + + // 测试false + let script = r#" + return false; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, false); +} + +#[test] +fn test_integer() { + init_logger(); + + let env = Environment::new(); + + { + // 测试正整数 + let script = r#" + return 42; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, 42); + } + { + let env = Environment::new(); + // 测试负整数 + let script = r#" + return -17; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, -17); + } +} + +#[test] +fn test_float() { + init_logger(); + + let env = Environment::new(); + + // 测试浮点数 + let script = r#" + return 3.1415; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, 3.1415); +} + +#[test] +fn test_string() { + init_logger(); + + let env = Environment::new(); + + // 测试字符串 + let script = r#" + return "hello world"; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, "hello world"); +} + +#[test] +fn test_array_methods() { + init_logger(); + + let env = Environment::new(); + + // 测试数组初始化和基本操作 + let script = r#" + let arr = [1, 2, 3]; + + // 测试数组长度 + if arr.len() != 3 { + return false; + }; + + // 测试push方法 + arr.push(4); + if arr.len() != 4 || arr[3] != 4 { + return false; + }; + + // 测试pop方法 + let val = arr.pop(); + if val != 4 || arr.len() != 3 { + return false; + }; + + // 测试remove方法 + let val = arr.remove(1); + if val != 2 || arr.len() != 2 || arr[0] != 1 || arr[1] != 3 { + return false; + }; + + // 测试数组迭代求和 + let sum = 0; + for i in arr { + sum += i; + } + + if sum != 4 { + return false; + }; + + // 测试enumerate迭代 + let arr = [1, 2, 3, 4, 5]; + let sum = 0; + for (i, ele) in arr.iter().enumerate() { + sum += i; + sum += ele; + } + + if sum != 0+1+1+2+2+3+3+4+4+5 { + return false; + }; + + return true; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + assert_eq!(retval, true); +} + +#[test] +fn test_map_basics() { + init_logger(); + + let env = Environment::new(); + + // 测试map创建和访问 + let script = r#" + let person = {"name": "Alice", "age": 30}; + + // 验证基本功能 + if person["name"] != "Alice" || person["age"] != 30 { + return false; + }; + + // 测试添加新属性 + person["score"] = 100; + if person.len() != 3 || person["score"] != 100 { + return false; + }; + + // 测试修改现有属性 + person["age"] = 31; + if person["age"] != 31 { + return false; + }; + + return true; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + assert_eq!(retval, true); +} + +#[test] +fn test_map_methods() { + init_logger(); + + let env = Environment::new(); + + // 测试map的方法 + let script = r#" + let person = {}; + + // 测试insert方法 + person.insert("name", "Alice"); + person.insert("age", 30); + person.insert("city", "New York"); + + if person.len() != 3 { + return false; + }; + + if person["name"] != "Alice" || person["age"] != 30 || person["city"] != "New York" { + return false; + }; + + // 测试remove方法 + person.remove("city"); + + if person.len() != 2 { + return false; + } + + // 测试keys方法 + let keys = person.keys(); + if keys.len() != 2 { + return false; + }; + + // 验证keys的正确性 + let has_name = false; + let has_age = false; + for key in keys { + if key == "name" { + has_name = true; + } else if key == "age" { + has_age = true; + } + } + + if !has_name || !has_age { + return false; + } + + // 测试values方法 + let values = person.values(); + if values.len() != 2 { + return false; + } + + // 验证values的正确性 + let has_Alice = false; + let has_30 = false; + for value in values { + if value == "Alice" { + has_Alice = true; + } else if value == 30 { + has_30 = true; + } + } + + return has_Alice && has_30; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + assert_eq!(retval, true); +} diff --git a/tests/test_control_flow.rs b/tests/test_control_flow.rs new file mode 100644 index 0000000..c01f0cc --- /dev/null +++ b/tests/test_control_flow.rs @@ -0,0 +1,315 @@ +mod utils; +use evalit::{Environment, Interpreter}; +use utils::init_logger; + +#[test] +fn test_if_statement() { + init_logger(); + + let env = Environment::new(); + + // 测试if-else语句 + let script = r#" + let a = 10; + let result = ""; + + if a == 10 { + result = "a is 10"; + } else if a == 20 { + result = "a is 20"; + } else { + result = "a is neither 10 nor 20"; + }; + + // 验证if-else结果 + if result != "a is 10" { + return false; + } + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_loop_statement() { + init_logger(); + + let env = Environment::new(); + + // 测试loop循环 + let script = r#" + let i = 0; + loop { + i = i + 1; + if i == 5 { + break; + }; + }; + + // 验证循环是否正常退出 + if i != 5 { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_while_statement() { + init_logger(); + + let env = Environment::new(); + + // 测试while循环 + let script = r#" + let j = 0; + while j < 5 { + j = j + 1; + }; + + // 验证while循环结果 + if j != 5 { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_for_statement() { + init_logger(); + + let env = Environment::new(); + + // 测试for循环 + let script = r#" + let sum = 0; + for k in 0..=10 { + if k == 5 { + continue; + }; + + if k == 8 { + break; + }; + + sum = sum + k; + }; + + // 验证for循环结果 + // sum = 0+1+2+3+4+6+7 = 23 + if sum != 23 { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_break_continue() { + init_logger(); + + let env = Environment::new(); + + // 测试break和continue语句 + let script = r#" + // 测试简单循环中的break + let i = 0; + loop { + i = i + 1; + if i < 5 { + continue; + }; + + break; + }; + + // 验证循环是否正常退出 + if i != 5 { + return false; + }; + + // 测试简单循环中的continue + let j = 0; + loop { + j = j + 1; + if j == 3 { + break; + }; + + if j == 2 { + continue; + }; + }; + + // 验证continue是否生效 + if j != 3 { + return false; + }; + + // 测试嵌套循环中的break + let m = 0; + let n = 0; + loop { + n = 0; + loop { + n = n + 1; + if n < 3 { + continue; + }; + + break; + }; + + if n != 3 { + return false; + }; + + m = m + 1; + if m == 2 { + break; + }; + }; + + // 验证嵌套循环结果 + if m != 2 || n != 3 { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_return_statement() { + init_logger(); + + let env = Environment::new(); + + // 测试函数返回值 + let script = r#" + fn test_return() { + return 42; + }; + + let ret_val = test_return(); + if ret_val != 42 { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_eval_control_flow() { + init_logger(); + + let env = Environment::new(); + + let script = r#" + let sum = 0; + for i in 0..=10 { + if i % 2 == 0 { + continue; + } + sum += i; + + if i == 5 { + break; + } + } + + // 验证sum的值是否符合预期(1+3+5) + if sum != 9 { + return false; + } + + return true; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + assert_eq!(retval, true); +} + +#[test] +fn test_eval_for() { + init_logger(); + + let env = Environment::new(); + + let script = r#" + // 测试数组迭代 + let arr = [1, 2, 3, 4, 5]; + let sum = 0; + for ele in arr { + sum += ele; + } + + // 验证数组迭代求和结果 + if sum != 15 { + return false; + } + + // 测试带索引的数组迭代 + let index_sum = 0; + let value_sum = 0; + for (i, ele) in arr.iter().enumerate() { + index_sum += i; + value_sum += ele; + } + + // 验证索引和元素迭代的正确性 + if index_sum != 0+1+2+3+4 || value_sum != 15 { + return false; + } + + // 测试map迭代 + let map = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}; + let key_sum = 0; + let value_sum = 0; + for (k, v) in map { + // 这里只是验证迭代可以进行 + key_sum = key_sum + 1; // 计数key的数量 + value_sum += v; + } + + // 验证map迭代结果 + if key_sum != 5 || value_sum != 15 { + return false; + } + + return true; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + assert_eq!(retval, true); +} diff --git a/tests/test_embed.rs b/tests/test_embed.rs new file mode 100644 index 0000000..66a520a --- /dev/null +++ b/tests/test_embed.rs @@ -0,0 +1,352 @@ +mod utils; +use std::sync::Arc; + +use evalit::{Environment, Error, Module, Object, RuntimeError, VM, Value, ValueRef, compile}; +use utils::init_logger; + +fn run_vm(program: Arc, env: Environment) -> Result { + let mut vm = VM::new(program, env); + #[cfg(not(feature = "async"))] + let ret = vm.run().unwrap(); + + #[cfg(feature = "async")] + let ret = futures::executor::block_on(async { + let ret = vm.run().await; + ret.unwrap() + }); + + Ok(ret.unwrap().take()) +} + +#[test] +fn test_basic_embedding() { + init_logger(); + + let env = Environment::new(); + + let script = r#" + // 定义一个简单的函数 + fn add(a, b) { + return a + b; + } + + // 执行一些计算 + let result1 = add(2, 3); + let result2 = add(result1, 5); + + // 返回最终结果 + return result2; + "#; + + let program = compile(script, &env).unwrap(); + + let retval = run_vm(program, env).unwrap(); + + assert_eq!(retval, 10); +} + +#[test] +fn test_rust_interop() { + init_logger(); + + // 定义一个Rust函数 + fn greet(name: String) -> String { + format!("Hello, {}!", name) + } + + let mut env = Environment::new(); + + // 将Rust函数注册到脚本环境中 + env.define_function("greet", greet); + + let script = r#" + // 使用Rust函数 + let message = greet("World"); + return true; + + // 操作返回值 + if message != "Hello, World!" { + return false; + } + + // 测试组合使用 + let composed = greet("Script") + " Welcome to Evalit"; + if composed != "Hello, Script! Welcome to Evalit" { + return false; + } + + return true; + "#; + + let program = compile(script, &env).unwrap(); + let retval = run_vm(program, env).unwrap(); + + assert_eq!(retval, true); +} + +#[test] +fn test_multiple_vm_instances() { + init_logger(); + + let env = Environment::new(); + + let script = r#" + fn add(a, b) { + return a + b; + } + + return add(1, 1); + "#; + + let program = compile(script, &env).unwrap(); + + let retval1 = run_vm(program.clone(), env.clone()).unwrap(); + + let retval2 = run_vm(program, env).unwrap(); + + assert_eq!(retval1, 2); + assert_eq!(retval2, 2); +} + +#[test] +fn test_shared_compiled_program() { + init_logger(); + + let env = Environment::new(); + + // 创建一个可共享的程序 + let script = r#" + fn add(a, b) { + return a + b; + } + + // 测试基础调用 + return add(2, 3); + "#; + + // 编译一次 + let program = compile(script, &env).unwrap(); + + // 在多个线程中复用编译后的程序 + use std::thread; + + for _ in 0..5 { + let program = program.clone(); + thread::spawn(move || { + // 每个线程创建一个新的VM来运行相同的程序 + let env = Environment::new(); + let retval = run_vm(program, env).unwrap(); + assert_eq!(retval, 5); + }); + } +} + +#[test] +fn test_rust_object_interop() { + init_logger(); + + // 定义一个简单的结构体 + #[derive(Debug)] + struct MyStruct { + value: i64, + } + + impl Object for MyStruct { + fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "MyStruct") + } + + fn property_get(&self, property: &str) -> Result { + match property { + "value" => Ok(ValueRef::new(self.value)), + _ => Err(RuntimeError::missing_property_getter::(property)), + } + } + + fn property_set(&mut self, property: &str, value: ValueRef) -> Result<(), RuntimeError> { + match property { + "value" => { + match value.value().downcast_ref::() { + Some(value) => self.value = *value, + _ => return Err(RuntimeError::invalid_argument::(0, &value)), + } + Ok(()) + } + _ => Err(RuntimeError::missing_property_setter::(property)), + } + } + + fn call_method( + &mut self, + method: &str, + args: &[ValueRef], + ) -> Result, evalit::RuntimeError> { + match method { + "increase" => { + if args.len() != 1 { + return Err(evalit::RuntimeError::invalid_argument_count(1, 0)); + } + + match args[0].value().downcast_ref::() { + Some(arg) => { + self.value += *arg; + Ok(None) + } + None => Err(evalit::RuntimeError::invalid_argument::(0, &args[0])), + } + } + "value" => { + if !args.is_empty() { + return Err(evalit::RuntimeError::invalid_argument_count(0, args.len())); + } + Ok(Some(ValueRef::new(self.value))) + } + _ => return Err(evalit::RuntimeError::missing_method::(method)), + } + } + } + + let mut env = Environment::new(); + + let my_struct = MyStruct { value: 42 }; + + // 将结构体注册到环境中 + env.insert("myObj", my_struct); + + let script = r#" + myObj.increase(10); + if myObj.value != 52 { + return false; + } + + myObj.value = 100; + + + return myObj.value() == 100; + "#; + + let program = compile(script, &env).unwrap(); + let retval = run_vm(program, env.clone()).unwrap(); + + assert_eq!(retval, true); + + // 从环境中获取变量并还原为原始类型 + let my_obj: MyStruct = env.remove_as("myObj").unwrap(); + + assert_eq!(my_obj.value, 100); +} + +#[cfg(feature = "async")] +mod async_embed { + use evalit::{Environment, VM, Value, compile}; + + use crate::utils::init_logger; + + #[tokio::test] + async fn test_rust_async_interop() { + use evalit::Promise; + use tokio::time::Instant; + + init_logger(); + + // 定义一个异步Rust函数 + fn greet_async(name: String) -> Promise { + Promise::new(async move { + println!("Hello, {}!", name); + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + Value::new(format!("Hello, {}!", name)) + }) + } + + let mut env = Environment::new(); + + // 将异步Rust函数注册到脚本环境中 + env.define_function("greet_async", greet_async); + + let script = r#" + // 使用Rust异步函数 + let message = greet_async("World").await; + if message != "Hello, World!" { + return false; + } + + // 测试组合使用 + let composed = greet_async("Script").await + " Welcome to Evalit"; + if composed != "Hello, Script! Welcome to Evalit" { + return false; + } + + return true; + "#; + + let program = compile(script, &env).unwrap(); + + let start = Instant::now(); + let mut vm = VM::new(program, env); + let retval = vm.run().await.unwrap().unwrap().take(); + let elapsed = start.elapsed(); + + assert_eq!(retval, true); + assert!(elapsed.as_secs() > 1); + } + + #[tokio::test] + async fn test_rust_tcp_interop() { + use evalit::Promise; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + use tokio::net::{TcpListener, TcpStream}; + + init_logger(); + + // 启动一个本地TCP服务器 + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + let addr = addr.to_string(); + + // 在后台启动一个异步任务来处理连接 + tokio::spawn(async move { + let (mut stream, _) = listener.accept().await.unwrap(); + let mut buffer = [0; 512]; + let n = stream.read(&mut buffer).await.unwrap(); + stream.write_all(b"Echo: ").await.unwrap(); + stream.write_all(&buffer[0..n]).await.unwrap(); + }); + + // 定义一个异步TCP客户端函数 + async fn tcp_client(addr: std::net::SocketAddr) -> String { + let mut stream = TcpStream::connect(addr).await.unwrap(); + stream.write_all(b"Hello, TCP Server!").await.unwrap(); + let mut response = vec![0; 512]; + let n = stream.read(&mut response).await.unwrap(); + String::from_utf8_lossy(&response[..n]).to_string() + } + + let mut env = Environment::new(); + + env.insert("addr", addr); + + // 将异步Rust函数注册到脚本环境中 + env.define_function("tcp_client", move |addr: String| { + let addr: std::net::SocketAddr = addr.parse().unwrap(); + Promise::new(async move { + let s = tcp_client(addr).await; + Value::new(s) + }) + }); + + let script = r#" + let response = tcp_client(addr).await; + if !response.contains("Echo: Hello, TCP Server!") { + return false; + } + + return true; + "#; + + let program = compile(script, &env).unwrap(); + let mut vm = VM::new(program, env); + let retval = vm.run().await.unwrap().unwrap().take(); + + assert_eq!(retval, true); + } +} diff --git a/tests/test_function.rs b/tests/test_function.rs new file mode 100644 index 0000000..12f9ade --- /dev/null +++ b/tests/test_function.rs @@ -0,0 +1,299 @@ +mod utils; +use evalit::{Environment, Interpreter, RuntimeError}; +use utils::init_logger; + +#[test] +fn test_basic_function() { + init_logger(); + + let env = Environment::new(); + + // 测试无参数无返回值的函数 + let script = r#" + fn hello() { + let msg = "Hello"; + } + hello(); + "#; + assert!(Interpreter::eval(script, env).is_ok()); +} + +#[test] +fn test_function_with_params() { + let env = Environment::new(); + + // 测试带参数的函数 + let script = r#" + fn add(a, b) { + return a + b; + } + + let result = add(2, 3); + if result != 5 { + return false; + } + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, true); +} + +#[test] +fn test_function_scope() { + let env = Environment::new(); + + // 测试函数作用域 + let script = r#" + let x = 1; + fn modify() { + let x = 2; + return x; + } + let y = modify(); + return x; // 应该返回外部作用域的x值 + "#; + + let ret = Interpreter::eval(script, env).unwrap(); + assert_eq!(ret.unwrap(), 1); +} + +#[test] +fn test_recursive_function() { + let env = Environment::new(); + + // 测试递归函数 + let script = r#" + fn factorial(n) { + if n <= 1 { + return 1; + } + return n * factorial(n - 1); + } + let result = factorial(5); + return result; + "#; + let ret = Interpreter::eval(script, env).unwrap(); + assert_eq!(ret.unwrap(), 120); +} + +#[test] +fn test_fibonacci() { + let env = Environment::new(); + + // 测试README中的fibonacci示例 + let script = r#" + fn fib(n) { + if n <= 0 { + return 0; + } + if n <= 2 { + return 1; + } + return fib(n-1) + fib(n-2); + } + let sum = 0; + for i in 0..=10 { + sum += fib(i); + } + return sum; + "#; + let ret = Interpreter::eval(script, env).unwrap(); + assert_eq!(ret.unwrap(), 143); +} + +#[test] +fn test_multiple_returns() { + let env = Environment::new(); + + // 测试多个return语句 + let script = r#" + fn max(a, b) { + if a > b { + return a; + } + return b; + } + let result = max(10, 5); + return result; + "#; + let ret = Interpreter::eval(script, env).unwrap(); + assert_eq!(ret.unwrap(), 10); +} + +#[test] +fn test_function_simple_call() { + init_logger(); + let env = Environment::new(); + + let script = r#" + fn add(a, b) { + return a + b; + } + + return add(3, 5); + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, 8); +} + +#[test] +fn test_function_multiple_parameters() { + init_logger(); + let env = Environment::new(); + + let script = r#" + fn multiply(a, b, c) { + return a * b * c; + } + + return multiply(2, 3, 4); + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, 24); +} + +#[test] +fn test_function_higher_order() { + init_logger(); + let env = Environment::new(); + + let script = r#" + fn apply_twice(f, x) { + return f(f(x)); + } + + fn increment(x) { + return x + 1; + } + + return apply_twice(increment, 5); + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, 7); // (5 + 1) + 1 = 7 +} + +#[test] +fn test_function_call_chain() { + init_logger(); + let env = Environment::new(); + + let script = r#" + fn add(a, b) { + return a + b; + } + + fn multiply(a, b) { + return a * b; + } + + return multiply(add(2, 3), add(4, 5)); + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, 45); // (2 + 3) * (4 + 5) = 5 * 9 = 45 +} + +#[test] +fn test_function_with_control_flow() { + init_logger(); + let env = Environment::new(); + + let script = r#" + fn calculate(n) { + let result = 0; + for i in 1..=n { + if i % 2 == 0 { + result += i; + } else { + result -= i; + } + } + return result; + } + + return calculate(5); + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, -3); // (-1) + 2 + (-3) + 4 + (-5) = -3 +} + +#[test] +fn test_function_recursive_depth_exceeded() { + init_logger(); + let env = Environment::new(); + + let script = r#" + fn recursive(n) { + if n > 0 { + return recursive(n - 1); + } + return 0; + } + + return recursive(10000); // 递归深度过大 + "#; + + let result = Interpreter::eval(script, env); + assert!(matches!( + result.err().unwrap(), + evalit::Error::Runtime(RuntimeError::StackOverflow) + )); +} + +#[test] +fn test_function_mutual_recursion() { + init_logger(); + let env = Environment::new(); + + let script = r#" + fn is_even(n) { + if n == 0 { + return true; + } + return is_odd(n - 1); + } + + fn is_odd(n) { + if n == 0 { + return false; + } + return is_even(n - 1); + } + + return is_even(100); // 应该返回true + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + assert_eq!(retval, true); +} + +#[test] +fn test_function_tail_call_optimization() { + init_logger(); + let env = Environment::new(); + + let script = r#" + fn tail_recursive(n, acc) { + if n == 0 { + return acc; + } + return tail_recursive(n - 1, n * acc); + } + + return tail_recursive(1000, 1); // 应该能正常计算而不溢出 + "#; + + let result = Interpreter::eval(script, env); + // 计算1000!的值太大,我们只验证是否能正常执行而不会栈溢出 + // 这里可以添加更复杂的验证逻辑,但为了简单起见,我们只检查返回值类型 + + assert!(matches!( + result.err().unwrap(), + evalit::Error::Runtime(RuntimeError::Overflow) + )); +} diff --git a/tests/test_operators.rs b/tests/test_operators.rs new file mode 100644 index 0000000..e037278 --- /dev/null +++ b/tests/test_operators.rs @@ -0,0 +1,353 @@ +mod utils; +use evalit::{Environment, Interpreter}; +use utils::init_logger; + +#[test] +fn test_arithmetic_operators() { + init_logger(); + + let env = Environment::new(); + + // 测试算术运算符 + let script = r#" + if 2 + 3 != 5 { + return false; + }; + + if 5 - 2 != 3 { + return false; + }; + + if 3 * 4 != 12 { + return false; + }; + + if 10 / 2 != 5 { + return false; + }; + + if 10 % 3 != 1 { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_unary_operators() { + init_logger(); + + let env = Environment::new(); + + // 测试一元运算符 + let script = r#" + let a = 5; + + if -a != -5 { + return false; + }; + + if !(true) != false { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_comparison_operators() { + init_logger(); + + let env = Environment::new(); + + // 测试比较运算符 + let script = r#" + if 1 == 1 == false { + return false; + }; + + if 1 != 2 == false { + return false; + }; + + if 3 < 4 == false { + return false; + }; + + if 4 > 3 == false { + return false; + }; + + if 4 <= 4 == false { + return false; + }; + + if 5 >= 5 == false { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_logical_operators() { + init_logger(); + + let env = Environment::new(); + + // 测试逻辑运算符 + let script = r#" + // 测试逻辑与 + if true && true != true { + return false; + }; + + if true && false != false { + return false; + }; + + if false && true != false { + return false; + }; + + if false && false != false { + return false; + }; + + // 测试逻辑或 + if (true || true) != true { + return false; + }; + + if (true || false) != true { + return false; + }; + + if (false || true) != true { + return false; + }; + + if (false || false) != false { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_assignment_operators() { + init_logger(); + + let env = Environment::new(); + + // 测试赋值运算符 + let script = r#" + let b = 0; + + b += 5; + if b != 5 { + return false; + }; + + b -= 3; + if b != 2 { + return false; + }; + + b *= 4; + if b != 8 { + return false; + }; + + b /= 2; + if b != 4 { + return false; + }; + + b %= 3; + if b != 1 { + return false; + }; + + return true; + "#; + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + println!("ret: {:?}", retval); + assert_eq!(retval, true); +} + +#[test] +fn test_range_operations() { + init_logger(); + + let env = Environment::new(); + + let script = r#" + // 测试不同形式的range + + // 简单range求和 + let sum = 0; + for i in 0..5 { + sum += i; + } + if sum != 10 { + return false; + } + + // 测试包含上界的range + let sum = 0; + for i in 0..=5 { + sum += i; + } + if sum != 15 { + return false; + } + + // 测试带变量的range + let start = 2; + let end = 5; + let sum = 0; + for i in start..end { + sum += i; + } + if sum != 9 { + return false; + } + + // 测试空range + let count = 0; + for i in 5..3 { + count += 1; + } + if count != 0 { + return false; + } + + // 测试长度为0的range + let range = 0..0; + if range.len() != 0 { + return false; + } + + // 测试长度为非零的range + let range = 0..5; + if range.len() != 5 { + return false; + } + + return true; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + assert_eq!(retval, true); +} + +#[test] +fn test_slice_operations() { + init_logger(); + + let env = Environment::new(); + + let script = r#" + let array = [1, 2, 3, 4, 5]; + // 验证不同的切片形式并验证结果 + + // 全部元素 + let slice1 = array[..]; + if slice1.len() != 5 || slice1[0] != 1 || slice1[1] != 2 || slice1[2] != 3 || slice1[3] != 4 || slice1[4] != 5 { + return false; + } + + // 从索引1到末尾 + let slice2 = array[1..]; + if slice2.len() != 4 || slice2[0] != 2 || slice2[1] != 3 || slice2[2] != 4 || slice2[3] != 5 { + return false; + } + + // 从开头到索引3(不包含3) + let slice3 = array[..3]; + if slice3.len() != 3 || slice3[0] != 1 || slice3[1] != 2 || slice3[2] != 3 { + return false; + } + + // 从索引1到3(不包含3) + let slice4 = array[1..3]; + if slice4.len() != 2 || slice4[0] != 2 || slice4[1] != 3 { + return false; + } + + // 从索引1到3(包含3) + let slice5 = array[1..=3]; + if slice5.len() != 3 || slice5[0] != 2 || slice5[1] != 3 || slice5[2] != 4 { + return false; + } + + // 验证切片求和 + let sum = 0; + for i in slice5 { + sum += i; + } + + // 返回验证结果 + return sum; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + assert_eq!(retval, 9); +} + +#[test] +fn test_make_iterator() { + init_logger(); + + let env = Environment::new(); + + let script = r#" + // 测试数组迭代器 + let arr = [1, 2, 3, 4, 5]; + let iter = arr.iter(); + + // 验证next方法 + if iter.next() != 1 || iter.next() != 2 || iter.next() != 3 || iter.next() != 4 || iter.next() != 5 || iter.next() != null { + return false; + } + + // 测试再次迭代 + let iter = arr.iter(); + + // 验证next方法 + if iter.next() != 1 || iter.next() != 2 || iter.next() != 3 || iter.next() != 4 || iter.next() != 5 || iter.next() != null { + return false; + } + + + return true; + "#; + + let retval = Interpreter::eval(script, env).unwrap().unwrap(); + + assert_eq!(retval, true); +} diff --git a/tests/test_struct.rs b/tests/test_struct.rs new file mode 100644 index 0000000..31a4d0e --- /dev/null +++ b/tests/test_struct.rs @@ -0,0 +1,173 @@ +mod utils; +use evalit::{Environment, Interpreter}; +use utils::init_logger; + +#[test] +fn test_struct_type_simple() { + init_logger(); + + let script = r#" + struct Person { + name: string, + age: int, + } + + let person = Person { + name: "Alice", + age: 18, + }; + + return person.name == "Alice" && person.age == 18; + "#; + + let result = Interpreter::eval(script, Environment::new()) + .unwrap() + .unwrap(); + + assert_eq!(result, true); +} + +#[test] +fn test_struct_decl() { + init_logger(); + + let script = r#" + struct Point { + x: int, + y: int, + } + + struct Rectangle { + point: Point, + width: int, + height: int, + un_init: any, + } + + let a = Rectangle { + point: Point { + x: 1, + y: 2, + }, + width: 3, + height: 4, + }; + + + return a.point.x == 1 && a.point.y == 2 && a.width == 3 && a.height == 4 && a.un_init == null; + "#; + + let result = Interpreter::eval(script, Environment::new()) + .unwrap() + .unwrap(); + + assert_eq!(result, true); +} + +#[test] +fn test_nested_struct() { + init_logger(); + + let script = r#" + struct Address { + street: string, + city: string, + zip: int, + } + + struct Person { + name: string, + age: int, + address: Address, + } + + let person = Person { + name: "Bob", + age: 25, + address: Address { + street: "123 Main St", + city: "Anytown", + zip: 12345, + }, + }; + + return person.name == "Bob" && person.age == 25 && person.address.street == "123 Main St" && person.address.city == "Anytown" && person.address.zip == 12345; + "#; + + let result = Interpreter::eval(script, Environment::new()) + .unwrap() + .unwrap(); + + assert_eq!(result, true); +} + +#[test] +fn test_struct_array() { + init_logger(); + + let script = r#" + struct Point { + x: int, + y: int, + } + + let points = [ + Point { x: 1, y: 2 }, + Point { x: 3, y: 4 }, + Point { x: 5, y: 6 }, + ]; + + return points[0].x == 1 && points[0].y == 2 && points[1].x == 3 && points[1].y == 4 && points[2].x == 5 && points[2].y == 6; + "#; + + let result = Interpreter::eval(script, Environment::new()) + .unwrap() + .unwrap(); + + assert_eq!(result, true); +} + +#[test] +fn test_struct_mutual_reference() { + init_logger(); + + let script = r#" + struct Person { + name: string, + address: Address, + } + + struct Address { + street: string, + city: string, + owner: Person, + } + + let person = Person { + name: "Alice", + address: Address { + street: "123 Main St", + city: "Anytown", + owner: Person { + name: "Bob", + address: Address { + street: "456 Elm St", + city: "Othertown", + owner: Person { + name: "Charlie", + address: null, + }, + }, + }, + }, + }; + + return person.name == "Alice" && person.address.street == "123 Main St" && person.address.city == "Anytown" && person.address.owner.name == "Bob" && person.address.owner.address.street == "456 Elm St" && person.address.owner.address.city == "Othertown" && person.address.owner.address.owner.name == "Charlie"; + "#; + + let result = Interpreter::eval(script, Environment::new()) + .unwrap() + .unwrap(); + + assert_eq!(result, true); +}