From 4a310ff31758a0c275232a32fc0b0db887aa36cf Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 3 May 2025 20:33:59 +0800 Subject: [PATCH] refactor: type --- src/builtins/mod.rs | 67 +---------- src/bytecode.rs | 41 ++++--- src/compile/compile.rs | 73 ++++++++---- src/compile/ir.rs | 45 +++++--- src/lib.rs | 2 +- src/ty/common.rs | 26 +++++ src/{vm/value => ty/internal}/attrset.rs | 17 +-- src/{value => ty/internal}/cnst.rs | 4 +- src/ty/internal/func.rs | 25 +++++ src/{vm/value => ty/internal}/list.rs | 14 +-- src/{vm/value => ty/internal}/mod.rs | 55 +++++---- src/ty/internal/primop.rs | 67 +++++++++++ src/{vm/value => ty/internal}/string.rs | 0 src/ty/mod.rs | 3 + src/ty/public/cnst.rs | 136 +++++++++++++++++++++++ src/ty/public/mod.rs | 43 +++++++ src/value/mod.rs | 111 ------------------ src/vm/env.rs | 3 +- src/vm/mod.rs | 4 +- src/vm/stack.rs | 2 +- src/vm/test.rs | 8 +- src/vm/vm.rs | 36 ++---- src/vm/vmthunk.rs | 2 +- 23 files changed, 475 insertions(+), 309 deletions(-) create mode 100644 src/ty/common.rs rename src/{vm/value => ty/internal}/attrset.rs (78%) rename src/{value => ty/internal}/cnst.rs (98%) create mode 100644 src/ty/internal/func.rs rename src/{vm/value => ty/internal}/list.rs (70%) rename src/{vm/value => ty/internal}/mod.rs (85%) create mode 100644 src/ty/internal/primop.rs rename src/{vm/value => ty/internal}/string.rs (100%) create mode 100644 src/ty/mod.rs create mode 100644 src/ty/public/cnst.rs create mode 100644 src/ty/public/mod.rs delete mode 100644 src/value/mod.rs diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 4fb6158..7db747d 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -1,7 +1,8 @@ use derive_more::Constructor; -use crate::vm::{Env, Symbol, Value, AttrSet}; -use crate::value::Const; +use crate::vm::Env; +use crate::ty::internal::{Const, Value, AttrSet, PrimOp}; +use crate::ty::common::Symbol; pub fn env() -> Env { let mut env = Env::empty(); @@ -44,65 +45,3 @@ pub fn env() -> Env { env } -#[derive(Debug, Clone, Constructor)] -pub struct PrimOp { - name: &'static str, - arity: u8, - func: fn(Vec) -> Value, -} - -impl PartialEq for PrimOp { - fn eq(&self, _: &Self) -> bool { - false - } -} - -impl PrimOp { - pub fn call(self, args: Vec) -> Value { - if (args.len() as u8) < self.arity { - Value::PartialPrimOp(PartialPrimOp { - name: self.name, - arity: self.arity - args.len() as u8, - args, - func: self.func, - }) - } else if args.len() as u8 == self.arity { - (self.func)(args) - } else { - unimplemented!() - } - } -} - -#[derive(Debug, Clone)] -pub struct PartialPrimOp { - name: &'static str, - arity: u8, - args: Vec, - func: fn(Vec) -> Value, -} - -impl PartialEq for PartialPrimOp { - fn eq(&self, _: &Self) -> bool { - false - } -} - -impl PartialPrimOp { - pub fn call(mut self, args: Vec) -> Value { - let len = args.len() as u8; - self.args.extend(args); - if len < self.arity { - Value::PartialPrimOp(PartialPrimOp { - name: self.name, - arity: self.arity - len, - args: self.args, - func: self.func, - }) - } else if len == self.arity { - (self.func)(self.args) - } else { - unimplemented!() - } - } -} diff --git a/src/bytecode.rs b/src/bytecode.rs index 4fc5279..7356972 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -2,7 +2,7 @@ use std::hash::Hash; use ecow::EcoString; -use crate::value::Const; +use crate::ty::internal::{Const, Param}; type Slice = Box<[T]>; @@ -12,17 +12,13 @@ pub type SymIdx = usize; pub type OpCodes = Slice; pub type Consts = Slice; pub type Thunks = Slice; -pub type Args = Slice; #[derive(Debug, Clone)] pub struct Thunk { pub opcodes: OpCodes, } -#[derive(Debug, Clone, Hash)] -pub enum Arg {} - -#[derive(Debug, Clone, Hash)] +#[derive(Debug, Clone)] pub enum OpCode { /// load a constant onto stack Const { value: Const }, @@ -34,17 +30,25 @@ pub enum OpCode { LoadValue { idx: ThunkIdx }, /// force TOS to value ForceValue, + /// [ .. func args @ .. ] consume (`arity` + 2) elements, call `func` with args` of length `arity` /// Example: __add 1 2 => [ LookUp("__add") Const(1) Const(2) Call(2) ] Call { arity: usize }, + /// return a value + Ret, + /// make a function + Func { param: Param, length: usize }, + /// consume 1 element, assert TOS is true Assert, + /// jump forward Jmp { step: usize }, /// [ .. cond ] consume 1 element, if `cond`` is true, then jump forward JmpIfTrue { step: usize }, /// [ .. cond ] consume 1 element, if `cond` is false, then jump forward JmpIfFalse { step: usize }, + /// push an empty attribute set onto stack AttrSet, /// push an empty recursive attribute set onto stack @@ -53,10 +57,15 @@ pub enum OpCode { PushStaticAttr { name: EcoString }, /// [ .. set name value ] consume 2 elements, push a dynamic kv pair (`name`, `value`) in to `set` PushDynamicAttr, + /// push an empty list onto stack List, /// [ .. list elem ] consume 1 element, push `elem` into `list` PushElem, + + /// convert the string as TOS to a path + Path, + /// [ .. a b ] consume 2 elements, perform a string concatenation `a` + `b` ConcatString, /// [ .. a b ] consume 2 elements, perform a binary operation `a` `op` `b` @@ -69,23 +78,19 @@ pub enum OpCode { HasDynamicAttr, /// [ .. set ] select `sym` from `set` Select { sym: EcoString }, - /// TODO: - SelectWithDefault { sym: EcoString }, - /// TODO: - SelectOrEmpty { sym: EcoString }, - /// TODO: + /// [ .. set default ] select `sym` from `set` or `default` + SelectOrDefault { sym: EcoString }, + /// [ .. set sym ] select `sym` from `set` SelectDynamic, - /// TODO: - SelectDynamicOrEmpty, - /// TODO: - SelectDynamicWithDefault, + /// [ .. set sym default ] select `sym` from `set` or `default` + + SelectDynamicOrDefault, /// enter the environment of the attribute set at TOS EnterEnv, /// exit current envrironment LeaveEnv, - /// return a value - Ret, - /// no operation + + /// no operation, used as termporary placeholder NoOp, } diff --git a/src/compile/compile.rs b/src/compile/compile.rs index ff9b326..12649bd 100644 --- a/src/compile/compile.rs +++ b/src/compile/compile.rs @@ -1,5 +1,5 @@ use crate::bytecode::*; -use crate::value::*; +use crate::ty::internal::Const; use super::ir; @@ -275,23 +275,29 @@ impl Compile for ir::HasAttr { for attr in self.rhs { match attr { ir::Attr::Str(sym) => { - comp.push(OpCode::SelectOrEmpty { sym }); - } + comp.push(OpCode::AttrSet); + comp.push(OpCode::SelectOrDefault { sym }) + }, ir::Attr::Dynamic(dynamic) => { dynamic.compile(comp); - comp.push(OpCode::SelectDynamicOrEmpty); + comp.push(OpCode::AttrSet); + comp.push(OpCode::SelectDynamicOrDefault); } ir::Attr::Strs(string) => { string.compile(comp); - comp.push(OpCode::SelectDynamicOrEmpty); + comp.push(OpCode::AttrSet); + comp.push(OpCode::SelectDynamicOrDefault); } } } - match comp.pop().unwrap() { - OpCode::SelectOrEmpty { sym } => comp.push(OpCode::HasAttr { sym }), - OpCode::SelectDynamicOrEmpty => comp.push(OpCode::HasDynamicAttr), + let last = comp.pop().unwrap(); + let _ = comp.pop(); + match last { + OpCode::SelectOrDefault { sym } => comp.push(OpCode::HasAttr { sym }), + OpCode::SelectDynamicOrDefault => comp.push(OpCode::HasDynamicAttr), _ => unreachable!(), } + } } @@ -300,32 +306,42 @@ impl Compile for ir::Select { self.expr.compile(comp); for attr in self.attrpath { match attr { - ir::Attr::Str(sym) => comp.push(OpCode::SelectOrEmpty { sym }), + ir::Attr::Str(sym) => { + comp.push(OpCode::AttrSet); + comp.push(OpCode::SelectOrDefault { sym }) + }, ir::Attr::Dynamic(dynamic) => { dynamic.compile(comp); - comp.push(OpCode::SelectDynamicOrEmpty); + comp.push(OpCode::AttrSet); + comp.push(OpCode::SelectDynamicOrDefault); } ir::Attr::Strs(string) => { string.compile(comp); - comp.push(OpCode::SelectDynamicOrEmpty); + comp.push(OpCode::AttrSet); + comp.push(OpCode::SelectDynamicOrDefault); } } } match self.default { Some(default) => { let last = comp.pop().unwrap(); + let _ = comp.pop(); default.compile(comp); match last { - OpCode::SelectOrEmpty { sym } => comp.push(OpCode::SelectWithDefault { sym }), - OpCode::SelectDynamicOrEmpty => comp.push(OpCode::SelectDynamicWithDefault), + OpCode::SelectOrDefault { sym } => comp.push(OpCode::SelectOrDefault { sym }), + OpCode::SelectDynamicOrDefault => comp.push(OpCode::SelectDynamicOrDefault), + _ => unreachable!(), + } + } + None => { + let last = comp.pop().unwrap(); + let _ = comp.pop(); + match last { + OpCode::SelectOrDefault { sym } => comp.push(OpCode::Select { sym }), + OpCode::SelectDynamicOrDefault => comp.push(OpCode::SelectDynamic), _ => unreachable!(), } } - None => match comp.pop().unwrap() { - OpCode::SelectOrEmpty { sym } => comp.push(OpCode::Select { sym }), - OpCode::SelectDynamicOrEmpty => comp.push(OpCode::SelectDynamic), - _ => unreachable!(), - }, } } } @@ -389,19 +405,28 @@ impl Compile for ir::Assert { } impl Compile for ir::Func { - fn compile(self, _comp: &mut Compiler) { - todo!() + fn compile(self, comp: &mut Compiler) { + let idx = comp.idx(); + comp.push(OpCode::NoOp); + let length = self.body.compile_with_length(comp); + comp.modify(idx, OpCode::Func { param: self.param.into(), length }); } } impl Compile for ir::Call { - fn compile(self, _comp: &mut Compiler) { - todo!() + fn compile(self, comp: &mut Compiler) { + let arity = self.args.len(); + self.func.compile(comp); + self.args.into_iter().for_each(|arg| { + arg.compile(comp); + }); + comp.push(OpCode::Call { arity }); } } impl Compile for ir::Path { - fn compile(self, _comp: &mut Compiler) { - todo!() + fn compile(self, comp: &mut Compiler) { + self.expr.compile(comp); + comp.push(OpCode::Path); } } diff --git a/src/compile/ir.rs b/src/compile/ir.rs index 93b9c21..606e523 100644 --- a/src/compile/ir.rs +++ b/src/compile/ir.rs @@ -5,7 +5,7 @@ use ecow::EcoString; use rnix::ast::{self, Expr}; use crate::bytecode::{ConstIdx, Consts, ThunkIdx}; -use crate::value::Const as Const_; +use crate::ty::internal as i; use super::compile::*; use super::env::IrEnv; @@ -116,14 +116,14 @@ ir! { UnOp => { rhs: Box, kind: UnOpKind }, Select => { expr: Box, attrpath: Vec, default: Option> }, If => { cond: Box, consq: Box, alter: Box }, - Func => { args: Vec, body: Box }, + Func => { param: Param, body: Box }, Call => { func: Box, args: Vec }, Let => { attrs: Attrs, expr: Box }, With => { namespace: Box, expr: Box }, Assert => { assertion: Box, expr: Box }, ConcatStrings => { parts: Vec }, - Const => { value: Const_ }, + Const => { value: i::Const }, Var => { sym: EcoString }, #[derive(Copy)] Thunk => { idx: ThunkIdx }, @@ -163,8 +163,8 @@ pub struct DowngradeError { pub struct DowngradeState { envs: Vec, thunks: Vec, - consts: Vec, - consts_table: HashMap, + consts: Vec, + consts_table: HashMap, } pub struct Downgraded { @@ -355,12 +355,33 @@ impl From for UnOpKind { pub enum Param { Ident(EcoString), Formals { - formals: Vec<(EcoString, Option)>, + formals: Vec<(EcoString, Option)>, ellipsis: bool, alias: Option, }, } +impl Into for Param { + fn into(self) -> i::Param { + use i::Param::*; + match self { + Param::Ident(ident) => Ident(ident), + Param::Formals { + formals, + ellipsis, + alias, + } => Formals { + formals: formals + .into_iter() + .map(|(ident, default)| (ident, default.map(|thunk| thunk.idx))) + .collect(), + ellipsis, + alias, + }, + } + } +} + trait Downgrade where Self: Sized, @@ -607,14 +628,10 @@ impl Downgrade for ast::With { impl Downgrade for ast::Lambda { fn downgrade(self, state: &mut DowngradeState) -> Result { - let mut body = self.body().unwrap(); - let mut args = vec![downgrade_param(self.param().unwrap(), state)?]; - while let ast::Expr::Lambda(func) = body { - body = func.body().unwrap(); - args.push(downgrade_param(func.param().unwrap(), state)?); - } + let body = self.body().unwrap(); + let param = downgrade_param(self.param().unwrap(), state)?; let body = body.downgrade(state)?.boxed(); - Func { args, body }.ir().ok() + Func { param, body }.ir().ok() } } @@ -651,7 +668,7 @@ fn downgrade_pattern(pattern: ast::Pattern, state: &mut DowngradeState) -> Resul .default() .unwrap() .downgrade(state) - .map(|ok| (ident, Some(ok))) + .map(|ok| (ident, Some(state.new_thunk(ok)))) } }) .collect::>>()?; diff --git a/src/lib.rs b/src/lib.rs index 91a874f..844fb06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,5 +4,5 @@ mod builtins; mod bytecode; mod compile; mod downcast; -mod value; +mod ty; mod vm; diff --git a/src/ty/common.rs b/src/ty/common.rs new file mode 100644 index 0000000..127b5ab --- /dev/null +++ b/src/ty/common.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +use ecow::EcoString; +use derive_more::Constructor; + +#[derive(Clone, Debug, PartialEq, Constructor)] +pub struct Catchable { + msg: Option, +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)] +pub struct Symbol(EcoString); + +impl> From for Symbol { + fn from(value: T) -> Self { + Symbol(value.into()) + } +} + +impl Deref for Symbol { + type Target = str; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + diff --git a/src/vm/value/attrset.rs b/src/ty/internal/attrset.rs similarity index 78% rename from src/vm/value/attrset.rs rename to src/ty/internal/attrset.rs index 3b9e858..0551888 100644 --- a/src/vm/value/attrset.rs +++ b/src/ty/internal/attrset.rs @@ -1,10 +1,11 @@ use derive_more::Constructor; use rpds::HashTrieMapSync; -use crate::value::{self, Value as Value_}; +use super::super::public as p; +use super::super::common::Symbol; -use super::super::vm::VM; -use super::{Symbol, ToValue, Value}; +use crate::vm::VM; +use super::{ToPublic, Value}; #[derive(Debug, Constructor, Clone, PartialEq)] pub struct AttrSet { @@ -47,15 +48,15 @@ impl AttrSet { } } -impl ToValue for AttrSet { - fn to_value(self, vm: &VM) -> Value_ { - Value_::AttrSet(value::AttrSet::new( +impl ToPublic for AttrSet { + fn to_public(self, vm: &VM) -> p::Value { + p::Value::AttrSet(p::AttrSet::new( self.data .iter() .map(|(sym, value)| { ( - value::Symbol::new(sym.0.clone()), - value.clone().to_value(vm), + sym.clone(), + value.clone().to_public(vm), ) }) .collect(), diff --git a/src/value/cnst.rs b/src/ty/internal/cnst.rs similarity index 98% rename from src/value/cnst.rs rename to src/ty/internal/cnst.rs index dc8c2ca..05f2745 100644 --- a/src/value/cnst.rs +++ b/src/ty/internal/cnst.rs @@ -110,7 +110,7 @@ impl PartialEq for Const { impl Eq for Const {} -impl Hash for Const { +/* impl Hash for Const { fn hash(&self, state: &mut H) { use Const::*; match self { @@ -121,4 +121,4 @@ impl Hash for Const { Func(func) => func.hash(state), } } -} +} */ diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs new file mode 100644 index 0000000..d87e5a2 --- /dev/null +++ b/src/ty/internal/func.rs @@ -0,0 +1,25 @@ +use ecow::EcoString; + +use crate::bytecode::{OpCodes, ThunkIdx}; + +#[derive(Debug, Clone)] +pub enum Param { + Ident(EcoString), + Formals { + formals: Vec<(EcoString, Option)>, + ellipsis: bool, + alias: Option, + }, +} + +#[derive(Debug, Clone)] +pub struct Func { + pub param: Param, + pub opcodes: OpCodes +} + +impl PartialEq for Func { + fn eq(&self, _: &Self) -> bool { + false + } +} diff --git a/src/vm/value/list.rs b/src/ty/internal/list.rs similarity index 70% rename from src/vm/value/list.rs rename to src/ty/internal/list.rs index cb0ab2d..91582d2 100644 --- a/src/vm/value/list.rs +++ b/src/ty/internal/list.rs @@ -1,10 +1,10 @@ use derive_more::Constructor; use rpds::VectorSync; -use crate::value::{self, Value as Value_}; +use crate::ty::public as p; -use super::super::vm::VM; -use super::{ToValue, Value}; +use crate::vm::VM; +use super::{ToPublic, Value}; #[derive(Debug, Constructor, Clone, PartialEq)] pub struct List { @@ -30,12 +30,12 @@ impl List { } } -impl ToValue for List { - fn to_value(self, vm: &VM) -> Value_ { - Value_::List(value::List::new( +impl ToPublic for List { + fn to_public(self, vm: &VM) -> p::Value { + p::Value::List(p::List::new( self.data .iter() - .map(|value| value.clone().to_value(vm)) + .map(|value| value.clone().to_public(vm)) .collect(), )) } diff --git a/src/vm/value/mod.rs b/src/ty/internal/mod.rs similarity index 85% rename from src/vm/value/mod.rs rename to src/ty/internal/mod.rs index dd8eb2a..a8fd615 100644 --- a/src/vm/value/mod.rs +++ b/src/ty/internal/mod.rs @@ -1,31 +1,30 @@ use anyhow::Result; use derive_more::{Constructor, IsVariant, Unwrap}; -use ecow::EcoString; -use crate::value::{Value as Value_, Const, Catchable}; +use super::public as p; +use super::common as c; -use super::env::Env; -use super::vm::VM; +use c::Symbol; + +use crate::vm::Env; +use crate::vm::VM; mod attrset; mod list; mod string; +mod func; +mod cnst; +mod primop; pub use attrset::AttrSet; pub use list::List; pub use string::ContextfulString; +pub use func::*; +pub use primop::*; +pub use cnst::Const; -pub trait ToValue { - fn to_value(self, vm: &VM) -> Value_; -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Constructor)] -pub struct Symbol(EcoString); - -impl> From for Symbol { - fn from(value: T) -> Self { - Symbol(value.into()) - } +pub trait ToPublic { + fn to_public(self, vm: &VM) -> p::Value; } #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Constructor)] @@ -37,9 +36,9 @@ pub enum Value { Thunk(Thunk), AttrSet(AttrSet), List(List), - Catchable(crate::value::Catchable), - PrimOp(crate::builtins::PrimOp), - PartialPrimOp(crate::builtins::PartialPrimOp), + Catchable(c::Catchable), + PrimOp(PrimOp), + PartialPrimOp(PartialPrimOp), } use Value::Const as VmConst; @@ -191,7 +190,7 @@ impl Value { if let Value::AttrSet(attrs) = self { let val = attrs .select(sym.clone()) - .unwrap_or(Value::Catchable(Catchable::new(Some(format!( + .unwrap_or(Value::Catchable(c::Catchable::new(Some(format!( "{sym:?} not found" ))))); *self = val; @@ -239,16 +238,16 @@ impl Value { } } -impl ToValue for Value { - fn to_value(self, vm: &VM) -> Value_ { +impl ToPublic for Value { + fn to_public(self, vm: &VM) -> p::Value { match self { - Value::AttrSet(attrs) => attrs.to_value(vm), - Value::List(list) => list.to_value(vm), - Value::Catchable(catchable) => Value_::Catchable(catchable), - Value::Const(cnst) => Value_::Const(cnst), - Value::Thunk(_) => Value_::Thunk, - Value::PrimOp(_) => Value_::PrimOp, - Value::PartialPrimOp(_) => Value_::PartialPrimOp, + Value::AttrSet(attrs) => attrs.to_public(vm), + Value::List(list) => list.to_public(vm), + Value::Catchable(catchable) => p::Value::Catchable(catchable), + Value::Const(cnst) => p::Value::Const(cnst.into()), + Value::Thunk(_) => p::Value::Thunk, + Value::PrimOp(_) => p::Value::PrimOp, + Value::PartialPrimOp(_) => p::Value::PartialPrimOp, } } } diff --git a/src/ty/internal/primop.rs b/src/ty/internal/primop.rs new file mode 100644 index 0000000..8784022 --- /dev/null +++ b/src/ty/internal/primop.rs @@ -0,0 +1,67 @@ +use derive_more::Constructor; + +use super::Value; + +#[derive(Debug, Clone, Constructor)] +pub struct PrimOp { + pub name: &'static str, + arity: u8, + func: fn(Vec) -> Value, +} + +impl PartialEq for PrimOp { + fn eq(&self, _: &Self) -> bool { + false + } +} + +impl PrimOp { + pub fn call(self, args: Vec) -> Value { + if (args.len() as u8) < self.arity { + Value::PartialPrimOp(PartialPrimOp { + name: self.name, + arity: self.arity - args.len() as u8, + args, + func: self.func, + }) + } else if args.len() as u8 == self.arity { + (self.func)(args) + } else { + unimplemented!() + } + } +} + +#[derive(Debug, Clone)] +pub struct PartialPrimOp { + pub name: &'static str, + arity: u8, + args: Vec, + func: fn(Vec) -> Value, +} + +impl PartialEq for PartialPrimOp { + fn eq(&self, _: &Self) -> bool { + false + } +} + +impl PartialPrimOp { + pub fn call(mut self, args: Vec) -> Value { + let len = args.len() as u8; + self.args.extend(args); + if len < self.arity { + Value::PartialPrimOp(PartialPrimOp { + name: self.name, + arity: self.arity - len, + args: self.args, + func: self.func, + }) + } else if len == self.arity { + (self.func)(self.args) + } else { + unimplemented!() + } + } +} + diff --git a/src/vm/value/string.rs b/src/ty/internal/string.rs similarity index 100% rename from src/vm/value/string.rs rename to src/ty/internal/string.rs diff --git a/src/ty/mod.rs b/src/ty/mod.rs new file mode 100644 index 0000000..c4fca9c --- /dev/null +++ b/src/ty/mod.rs @@ -0,0 +1,3 @@ +pub mod public; +pub mod internal; +pub mod common; diff --git a/src/ty/public/cnst.rs b/src/ty/public/cnst.rs new file mode 100644 index 0000000..4d1def7 --- /dev/null +++ b/src/ty/public/cnst.rs @@ -0,0 +1,136 @@ +use std::hash::{Hash, Hasher}; + +use anyhow::Error; +use derive_more::{IsVariant, Unwrap}; +use ecow::EcoString; + +use super::super::internal as i; + +#[derive(Debug, Clone, IsVariant, Unwrap)] +pub enum Const { + Bool(bool), + Int(i64), + Float(f64), + String(EcoString), + Func +} + +impl From for Const { + fn from(value: i::Const) -> Self { + use i::Const::*; + match value { + Bool(bool) => Const::Bool(bool), + Int(int) => Const::Int(int), + Float(float) => Const::Float(float), + String(string) => Const::String(string), + Func(func) => Const::Func + } + } +} + +impl From for Const { + fn from(value: bool) -> Self { + Const::Bool(value) + } +} + +impl From for Const { + fn from(value: i64) -> Self { + Const::Int(value) + } +} + +impl From for Const { + fn from(value: f64) -> Self { + Const::Float(value) + } +} + +impl From for Const { + fn from(value: EcoString) -> Self { + Const::String(value) + } +} + +impl From for Const { + fn from(value: String) -> Self { + Const::String(value.into()) + } +} + +impl From<&str> for Const { + fn from(value: &str) -> Self { + Const::String(value.into()) + } +} + +impl<'a> TryFrom<&'a Const> for &'a bool { + type Error = Error; + + fn try_from(value: &'a Const) -> Result { + match value { + Const::Bool(b) => Ok(b), + _ => panic!(), + } + } +} +impl<'a> TryFrom<&'a Const> for &'a i64 { + type Error = Error; + + fn try_from(value: &'a Const) -> Result { + match value { + Const::Int(int) => Ok(int), + _ => panic!(), + } + } +} + +impl<'a> TryFrom<&'a Const> for &'a f64 { + type Error = Error; + + fn try_from(value: &'a Const) -> Result { + match value { + Const::Float(float) => Ok(float), + _ => panic!(), + } + } +} + +impl<'a> TryFrom<&'a Const> for &'a str { + type Error = Error; + + fn try_from(value: &'a Const) -> Result { + match value { + Const::String(string) => Ok(string), + _ => panic!(), + } + } +} + +impl PartialEq for Const { + fn eq(&self, other: &Self) -> bool { + use Const::*; + match (self, other) { + (Bool(a), Bool(b)) => a == b, + (Int(a), Int(b)) => a == b, + (Float(a), Float(b)) => a == b, + (String(a), String(b)) => a == b, + _ => false, + } + } +} + +impl Eq for Const {} + +impl Hash for Const { + fn hash(&self, state: &mut H) { + use Const::*; + match self { + Bool(b) => b.hash(state), + Int(int) => int.hash(state), + Float(float) => float.to_bits().hash(state), + String(string) => string.hash(state), + func @ Func => func.hash(state), + } + } +} diff --git a/src/ty/public/mod.rs b/src/ty/public/mod.rs new file mode 100644 index 0000000..38a72d5 --- /dev/null +++ b/src/ty/public/mod.rs @@ -0,0 +1,43 @@ +use std::fmt::{Debug, Formatter, Result as FmtResult}; + +use derive_more::{Constructor, IsVariant, Unwrap}; +use rpds::{HashTrieMapSync, VectorSync}; + +use super::common::*; + +mod cnst; + +pub use cnst::Const; + +#[derive(Constructor, Clone, PartialEq)] +pub struct AttrSet { + data: HashTrieMapSync, +} + +impl Debug for AttrSet { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "{{ ")?; + for (k, v) in self.data.iter() { + write!(f, "{k:?} = {v:?}; ")?; + } + write!(f, "}}") + } +} + +#[derive(Constructor, Clone, Debug, PartialEq)] +pub struct List { + data: VectorSync, +} + + +#[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)] +pub enum Value { + Const(Const), + AttrSet(AttrSet), + List(List), + Catchable(Catchable), + Thunk, + Func, + PrimOp, + PartialPrimOp, +} diff --git a/src/value/mod.rs b/src/value/mod.rs deleted file mode 100644 index 3f83517..0000000 --- a/src/value/mod.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::fmt::{Debug, Formatter, Result as FmtResult}; -use std::ops::Deref; - -use derive_more::{Constructor, IsVariant, Unwrap}; -use ecow::EcoString; -use rpds::{HashTrieMapSync, VectorSync}; - -use crate::bytecode::{Args, OpCodes}; - -mod cnst; - -pub use cnst::Const; - -#[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)] -pub struct Symbol(EcoString); - -impl> From for Symbol { - fn from(value: T) -> Self { - Symbol(value.into()) - } -} - -impl Deref for Symbol { - type Target = str; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, Clone, Hash)] -pub struct Func { - pub args: Args, - pub opcodes: OpCodes, -} - -impl PartialEq for Func { - fn eq(&self, _: &Self) -> bool { - false - } -} - -/* #[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)] -pub enum Const { - Int(i64), - Float(f64), - Bool(bool), - String(EcoString), - Func(Arc), -} - -impl Display for Const { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "Const::")?; - match self { - Const::Int(int) => write!(f, "Int@{}", int), - Const::Float(float) => write!(f, "Float@{}", float), - Const::Bool(bool) => write!(f, "Bool@{}", bool), - Const::String(string) => write!(f, r#"String@"{}""#, string.as_ref()), - Const::Func(func) => write!(f, "Func@{:?}", func.as_ref() as *const Func), - } - } -} - -impl From for Const { - fn from(value: ByteCodeConst) -> Self { - use ByteCodeConst::*; - match value { - Int(int) => Const::Int(int), - Float(float) => Const::Float(float), - Bool(bool) => Const::Bool(bool), - String(string) => Const::String(EcoString::from(string)), - Func(func) => Const::Func(Arc::new(func)), - } - } -} */ - -#[derive(Constructor, Clone, PartialEq)] -pub struct AttrSet { - data: HashTrieMapSync, -} - -impl Debug for AttrSet { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - write!(f, "{{ ")?; - for (k, v) in self.data.iter() { - write!(f, "{k:?} = {v:?}; ")?; - } - write!(f, "}}") - } -} - -#[derive(Constructor, Clone, Debug, PartialEq)] -pub struct List { - data: VectorSync, -} - -#[derive(Clone, Debug, PartialEq, Constructor)] -pub struct Catchable { - msg: Option, -} - -#[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)] -pub enum Value { - Const(Const), - AttrSet(AttrSet), - List(List), - Catchable(Catchable), - Thunk, - PrimOp, - PartialPrimOp, -} diff --git a/src/vm/env.rs b/src/vm/env.rs index ec5422b..9bb21b4 100644 --- a/src/vm/env.rs +++ b/src/vm/env.rs @@ -1,6 +1,7 @@ use rpds::HashTrieMapSync; -use super::value::{Symbol, Value}; +use crate::ty::common::Symbol; +use crate::ty::internal::Value; pub struct Env { last: Option>, diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 5d273f3..cebf8f7 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,6 +1,5 @@ mod env; mod stack; -mod value; mod vm; mod vmthunk; @@ -8,5 +7,4 @@ mod vmthunk; mod test; pub use env::Env; -pub use value::Symbol; -pub use value::*; +pub use vm::VM; diff --git a/src/vm/stack.rs b/src/vm/stack.rs index 14ae85e..e054c06 100644 --- a/src/vm/stack.rs +++ b/src/vm/stack.rs @@ -3,7 +3,7 @@ use std::ops::Deref; use anyhow::{Result, anyhow}; -use super::value::Value; +use crate::ty::internal::Value; pub const STACK_SIZE: usize = 8 * 1024 / size_of::(); diff --git a/src/vm/test.rs b/src/vm/test.rs index 4153bbb..174b325 100644 --- a/src/vm/test.rs +++ b/src/vm/test.rs @@ -2,7 +2,8 @@ use ecow::EcoString; use rpds::{ht_map_sync, vector_sync}; use crate::compile::compile; -use crate::value::*; +use crate::ty::public::*; +use crate::ty::common::Symbol; use super::vm::run; @@ -166,3 +167,8 @@ fn test_let() { attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } }, ); } + +#[test] +fn test_func() { + test_expr("(x: x) 1", int!(1)); +} diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 5c9e6da..eccef44 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -1,17 +1,18 @@ use anyhow::Result; use crate::builtins::env; -use crate::bytecode::{self, *}; -use crate::value::{Const, Value as Value_}; +use crate::bytecode::{self, Program, OpCode, OpCodes, Thunks, UnOp, BinOp}; +use crate::ty::internal::*; +use crate::ty::common::Symbol; +use crate::ty::public as p; use super::env::Env; use super::stack::{STACK_SIZE, Stack}; -use super::value::{self as vmValue, *}; use super::vmthunk::*; -pub fn run(prog: Program) -> Result { +pub fn run(prog: Program) -> Result { let vm = VM::new(prog.thunks); - Ok(vm.eval(prog.top_level, &mut env())?.to_value(&vm)) + Ok(vm.eval(prog.top_level, &mut env())?.to_public(&vm)) } pub struct VM { @@ -54,7 +55,7 @@ impl VM { match opcode { OpCode::NoOp => (), OpCode::Const { value } => stack.push(Value::Const(value))?, - OpCode::LoadThunk { idx } => stack.push(Value::Thunk(vmValue::Thunk::new(idx)))?, + OpCode::LoadThunk { idx } => stack.push(Value::Thunk(Thunk::new(idx)))?, OpCode::LoadValue { idx } => { stack.push(self.get_thunk_value(idx, env)?)?; } @@ -128,17 +129,11 @@ impl VM { OpCode::Select { sym } => { stack.tos_mut()?.select(Symbol::new(sym)).force(self, env)?; } - OpCode::SelectWithDefault { sym } => { + OpCode::SelectOrDefault { sym } => { let default = stack.pop()?; stack .tos_mut()? - .select_with_default(Symbol::new(sym), default.clone()); - } - OpCode::SelectOrEmpty { sym } => { - stack.tos_mut()?.select_with_default( - Symbol::new(sym), - Value::AttrSet(AttrSet::empty()), - ); + .select_with_default(Symbol::new(sym), default); } OpCode::SelectDynamic => { let mut val = stack.pop().unwrap(); @@ -146,21 +141,12 @@ impl VM { let sym = val.unwrap_const().unwrap_string().into(); stack.tos_mut()?.select(sym); } - OpCode::SelectDynamicWithDefault => { - let mut val = stack.pop().unwrap(); - val.coerce_to_string(); - let sym = val.unwrap_const().unwrap_string().into(); + OpCode::SelectDynamicOrDefault => { let default = stack.pop()?; - stack.tos_mut()?.select_with_default(sym, default.clone()); - } - OpCode::SelectDynamicOrEmpty => { let mut val = stack.pop().unwrap(); val.coerce_to_string(); let sym = val.unwrap_const().unwrap_string().into(); - stack.tos_mut()?.select_with_default( - sym, - Value::AttrSet(AttrSet::empty()), - ); + stack.tos_mut()?.select_with_default(sym, default); } OpCode::HasAttr { sym } => { stack.tos_mut()?.has_attr(Symbol::new(sym)); diff --git a/src/vm/vmthunk.rs b/src/vm/vmthunk.rs index 3c1e6af..5b72812 100644 --- a/src/vm/vmthunk.rs +++ b/src/vm/vmthunk.rs @@ -7,7 +7,7 @@ use derive_more::{IsVariant, Unwrap}; use crate::bytecode::OpCodes; use super::env::Env; -use super::value::Value; +use crate::ty::internal::Value; use super::vm::VM; pub struct VmThunk {