From bc50464db984014bfe8c3c06a154398f878aa0f8 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sun, 4 May 2025 14:42:22 +0800 Subject: [PATCH] feat: simple functions --- src/ty/internal/func.rs | 22 ++++++++++++++++++---- src/ty/internal/mod.rs | 4 ++-- src/vm/env.rs | 39 ++++++++++++++++++++++++++++++--------- src/vm/mod.rs | 2 +- src/vm/test.rs | 2 ++ src/vm/vm.rs | 35 ++++++++++++++++++++++++----------- 6 files changed, 77 insertions(+), 27 deletions(-) diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index defc542..69c16c0 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -1,8 +1,11 @@ use ecow::EcoString; +use rpds::HashTrieMap; use crate::bytecode::{OpCodes, ThunkIdx}; use crate::ty::internal::Value; +use crate::vm::{LockedEnv, VM}; + #[derive(Debug, Clone)] pub enum Param { Ident(EcoString), @@ -15,20 +18,31 @@ pub enum Param { #[derive(Debug, Clone)] pub struct Func { + pub env: LockedEnv, pub param: Option, pub opcodes: OpCodes, } impl Func { - pub fn new(opcodes: OpCodes) -> Func { + pub fn new(env: LockedEnv, opcodes: OpCodes) -> Func { Func { - param: None, + env, opcodes, + param: None, } } - pub fn call(self, _arg: Value) -> Value { - todo!() + pub fn call(self, vm: &VM, arg: Value) -> Value { + use Param::*; + + let mut env = self.env.unlocked(); + + match self.param.unwrap() { + Ident(ident) => env.enter(HashTrieMap::new_sync().insert(ident.into(), arg)), + Formals { .. } => todo!() + } + + vm.eval(self.opcodes, &mut env).unwrap() } pub fn push_ident_param(&mut self, param: EcoString) { diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index a995da9..1c2ec15 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -109,7 +109,7 @@ impl Value { } } - pub fn call(self, args: Vec) -> Value { + pub fn call(self, vm: &VM, args: Vec) -> Value { use Value::*; match self { PrimOp(func) => func.call(args), @@ -120,7 +120,7 @@ impl Value { func = match func { PrimOp(func) => return func.call([arg].into_iter().chain(iter).collect()), PartialPrimOp(func) => return func.call([arg].into_iter().chain(iter).collect()), - Func(func) => func.call(arg), + Func(func) => func.call(vm, arg), _ => todo!() } } diff --git a/src/vm/env.rs b/src/vm/env.rs index 9bb21b4..a132f12 100644 --- a/src/vm/env.rs +++ b/src/vm/env.rs @@ -8,6 +8,11 @@ pub struct Env { map: HashTrieMapSync, } +#[derive(Debug, Clone)] +pub struct LockedEnv { + map: HashTrieMapSync +} + impl Env { pub fn empty() -> Env { Env { @@ -16,20 +21,19 @@ impl Env { } } - pub fn lookup(&self, symbol: Symbol) -> Value { - if let Some(value) = self.map.get(&symbol) { - value.clone() - } else { - let last = self.last.as_ref().unwrap(); - last.lookup(symbol) - } + pub fn lookup(&self, symbol: Symbol) -> Option { + self.map.get(&symbol).cloned() } pub fn insert(&mut self, symbol: Symbol, value: Value) { self.map.insert_mut(symbol, value); } - pub fn enter(&mut self, map: HashTrieMapSync) { + pub fn enter(&mut self, new: HashTrieMapSync) { + let mut map = self.map.clone(); + for (k, v) in new.iter() { + map.insert_mut(k.clone(), v.clone()); + } let last = std::mem::replace(self, Env { last: None, map }); self.last = Some(Box::new(last)); } @@ -37,6 +41,23 @@ impl Env { pub fn leave(&mut self) { let last = std::mem::replace(&mut self.last, None).unwrap(); let _ = std::mem::replace(&mut self.last, last.last); - self.map = last.map.clone(); + self.map = last.map; + } + + pub fn locked(&self) -> LockedEnv { + LockedEnv { map: self.map.clone() } + } +} + +impl LockedEnv { + pub fn lookup(&self, symbol: Symbol) -> Option { + self.map.get(&symbol).cloned() + } + + pub fn unlocked(self) -> Env { + Env { + map: self.map, + last: None + } } } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index cebf8f7..f79ba37 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -6,5 +6,5 @@ mod vmthunk; #[cfg(test)] mod test; -pub use env::Env; +pub use env::{Env, LockedEnv}; pub use vm::VM; diff --git a/src/vm/test.rs b/src/vm/test.rs index 174b325..4691c7d 100644 --- a/src/vm/test.rs +++ b/src/vm/test.rs @@ -171,4 +171,6 @@ fn test_let() { #[test] fn test_func() { test_expr("(x: x) 1", int!(1)); + test_expr("(x: x) (x: x) 1", int!(1)); + test_expr("(x: y: x + y) 1 1", int!(2)); } diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 3dca267..290b2b4 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -1,11 +1,9 @@ -use std::ops::Index; - -use anyhow::Result; +use anyhow::{Result, anyhow}; use crate::builtins::env; -use crate::bytecode::{self, Program, OpCode, OpCodes, Thunks, UnOp, BinOp}; -use crate::ty::internal::*; +use crate::bytecode::{self, BinOp, OpCode, OpCodes, Program, Thunks, UnOp}; use crate::ty::common::Symbol; +use crate::ty::internal::*; use crate::ty::public as p; use super::env::Env; @@ -81,19 +79,31 @@ impl VM { args.insert(0, stack.pop()?); } let func = stack.pop()?; - stack.push(func.call(args))?; + stack.push(func.call(self, args))?; } OpCode::Func { idx } => { - stack.push(Value::Func(Func::new(self.thunks[idx].unwrap_code())))?; + stack.push(Value::Func(Func::new(env.locked(), self.thunks[idx].unwrap_code())))?; } OpCode::PushIdentParam { sym } => { - stack.tos_mut()?.as_mut().unwrap_func().push_ident_param(sym); + stack + .tos_mut()? + .as_mut() + .unwrap_func() + .push_ident_param(sym); } OpCode::PushFormalParam { sym } => { - stack.tos_mut()?.as_mut().unwrap_func().push_formal_param(sym); + stack + .tos_mut()? + .as_mut() + .unwrap_func() + .push_formal_param(sym); } OpCode::PushDefaultParam { idx } => { - stack.tos_mut()?.as_mut().unwrap_func().push_default_param(idx); + stack + .tos_mut()? + .as_mut() + .unwrap_func() + .push_default_param(idx); } OpCode::SetEllipsis => { stack.tos_mut()?.as_mut().unwrap_func().set_ellipsis(); @@ -184,7 +194,10 @@ impl VM { stack.tos_mut()?.has_attr(sym); } OpCode::LookUp { sym } => { - stack.push(env.lookup(Symbol::new(sym)))?; + stack.push( + env.lookup(Symbol::new(sym.clone())) + .ok_or(anyhow!(r#""{sym}" not found"#))?, + )?; } OpCode::EnterEnv => { env.enter(stack.pop()?.unwrap_attr_set().to_data());