feat: simple functions

This commit is contained in:
2025-05-04 14:42:22 +08:00
parent 6ecd20854a
commit bc50464db9
6 changed files with 77 additions and 27 deletions

View File

@@ -1,8 +1,11 @@
use ecow::EcoString; use ecow::EcoString;
use rpds::HashTrieMap;
use crate::bytecode::{OpCodes, ThunkIdx}; use crate::bytecode::{OpCodes, ThunkIdx};
use crate::ty::internal::Value; use crate::ty::internal::Value;
use crate::vm::{LockedEnv, VM};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Param { pub enum Param {
Ident(EcoString), Ident(EcoString),
@@ -15,20 +18,31 @@ pub enum Param {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Func { pub struct Func {
pub env: LockedEnv,
pub param: Option<Param>, pub param: Option<Param>,
pub opcodes: OpCodes, pub opcodes: OpCodes,
} }
impl Func { impl Func {
pub fn new(opcodes: OpCodes) -> Func { pub fn new(env: LockedEnv, opcodes: OpCodes) -> Func {
Func { Func {
param: None, env,
opcodes, opcodes,
param: None,
} }
} }
pub fn call(self, _arg: Value) -> Value { pub fn call(self, vm: &VM, arg: Value) -> Value {
todo!() 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) { pub fn push_ident_param(&mut self, param: EcoString) {

View File

@@ -109,7 +109,7 @@ impl Value {
} }
} }
pub fn call(self, args: Vec<Value>) -> Value { pub fn call(self, vm: &VM, args: Vec<Value>) -> Value {
use Value::*; use Value::*;
match self { match self {
PrimOp(func) => func.call(args), PrimOp(func) => func.call(args),
@@ -120,7 +120,7 @@ impl Value {
func = match func { func = match func {
PrimOp(func) => return func.call([arg].into_iter().chain(iter).collect()), PrimOp(func) => return func.call([arg].into_iter().chain(iter).collect()),
PartialPrimOp(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!() _ => todo!()
} }
} }

View File

@@ -8,6 +8,11 @@ pub struct Env {
map: HashTrieMapSync<Symbol, Value>, map: HashTrieMapSync<Symbol, Value>,
} }
#[derive(Debug, Clone)]
pub struct LockedEnv {
map: HashTrieMapSync<Symbol, Value>
}
impl Env { impl Env {
pub fn empty() -> Env { pub fn empty() -> Env {
Env { Env {
@@ -16,20 +21,19 @@ impl Env {
} }
} }
pub fn lookup(&self, symbol: Symbol) -> Value { pub fn lookup(&self, symbol: Symbol) -> Option<Value> {
if let Some(value) = self.map.get(&symbol) { self.map.get(&symbol).cloned()
value.clone()
} else {
let last = self.last.as_ref().unwrap();
last.lookup(symbol)
}
} }
pub fn insert(&mut self, symbol: Symbol, value: Value) { pub fn insert(&mut self, symbol: Symbol, value: Value) {
self.map.insert_mut(symbol, value); self.map.insert_mut(symbol, value);
} }
pub fn enter(&mut self, map: HashTrieMapSync<Symbol, Value>) { pub fn enter(&mut self, new: HashTrieMapSync<Symbol, Value>) {
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 }); let last = std::mem::replace(self, Env { last: None, map });
self.last = Some(Box::new(last)); self.last = Some(Box::new(last));
} }
@@ -37,6 +41,23 @@ impl Env {
pub fn leave(&mut self) { pub fn leave(&mut self) {
let last = std::mem::replace(&mut self.last, None).unwrap(); let last = std::mem::replace(&mut self.last, None).unwrap();
let _ = std::mem::replace(&mut self.last, last.last); 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<Value> {
self.map.get(&symbol).cloned()
}
pub fn unlocked(self) -> Env {
Env {
map: self.map,
last: None
}
} }
} }

View File

@@ -6,5 +6,5 @@ mod vmthunk;
#[cfg(test)] #[cfg(test)]
mod test; mod test;
pub use env::Env; pub use env::{Env, LockedEnv};
pub use vm::VM; pub use vm::VM;

View File

@@ -171,4 +171,6 @@ fn test_let() {
#[test] #[test]
fn test_func() { fn test_func() {
test_expr("(x: x) 1", int!(1)); 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));
} }

View File

@@ -1,11 +1,9 @@
use std::ops::Index; use anyhow::{Result, anyhow};
use anyhow::Result;
use crate::builtins::env; use crate::builtins::env;
use crate::bytecode::{self, Program, OpCode, OpCodes, Thunks, UnOp, BinOp}; use crate::bytecode::{self, BinOp, OpCode, OpCodes, Program, Thunks, UnOp};
use crate::ty::internal::*;
use crate::ty::common::Symbol; use crate::ty::common::Symbol;
use crate::ty::internal::*;
use crate::ty::public as p; use crate::ty::public as p;
use super::env::Env; use super::env::Env;
@@ -81,19 +79,31 @@ impl VM {
args.insert(0, stack.pop()?); args.insert(0, stack.pop()?);
} }
let func = stack.pop()?; let func = stack.pop()?;
stack.push(func.call(args))?; stack.push(func.call(self, args))?;
} }
OpCode::Func { idx } => { 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 } => { 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 } => { 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 } => { 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 => { OpCode::SetEllipsis => {
stack.tos_mut()?.as_mut().unwrap_func().set_ellipsis(); stack.tos_mut()?.as_mut().unwrap_func().set_ellipsis();
@@ -184,7 +194,10 @@ impl VM {
stack.tos_mut()?.has_attr(sym); stack.tos_mut()?.has_attr(sym);
} }
OpCode::LookUp { 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 => { OpCode::EnterEnv => {
env.enter(stack.pop()?.unwrap_attr_set().to_data()); env.enter(stack.pop()?.unwrap_attr_set().to_data());