refactor: type

This commit is contained in:
2025-05-03 20:33:59 +08:00
parent 3f0cb2c2fa
commit 4a310ff317
23 changed files with 475 additions and 309 deletions

View File

@@ -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>) -> Value,
}
impl PartialEq for PrimOp {
fn eq(&self, _: &Self) -> bool {
false
}
}
impl PrimOp {
pub fn call(self, args: Vec<Value>) -> 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<Value>,
func: fn(Vec<Value>) -> Value,
}
impl PartialEq for PartialPrimOp {
fn eq(&self, _: &Self) -> bool {
false
}
}
impl PartialPrimOp {
pub fn call(mut self, args: Vec<Value>) -> 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!()
}
}
}

View File

@@ -2,7 +2,7 @@ use std::hash::Hash;
use ecow::EcoString;
use crate::value::Const;
use crate::ty::internal::{Const, Param};
type Slice<T> = Box<[T]>;
@@ -12,17 +12,13 @@ pub type SymIdx = usize;
pub type OpCodes = Slice<OpCode>;
pub type Consts = Slice<Const>;
pub type Thunks = Slice<Thunk>;
pub type Args = Slice<Arg>;
#[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,
}

View File

@@ -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);
}
}

View File

@@ -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<Ir>, kind: UnOpKind },
Select => { expr: Box<Ir>, attrpath: Vec<Attr>, default: Option<Box<Ir>> },
If => { cond: Box<Ir>, consq: Box<Ir>, alter: Box<Ir> },
Func => { args: Vec<Param>, body: Box<Ir> },
Func => { param: Param, body: Box<Ir> },
Call => { func: Box<Ir>, args: Vec<Ir> },
Let => { attrs: Attrs, expr: Box<Ir> },
With => { namespace: Box<Ir>, expr: Box<Ir> },
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
ConcatStrings => { parts: Vec<Ir> },
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<Env>,
thunks: Vec<Ir>,
consts: Vec<Const_>,
consts_table: HashMap<Const_, ConstIdx>,
consts: Vec<i::Const>,
consts_table: HashMap<i::Const, ConstIdx>,
}
pub struct Downgraded {
@@ -355,12 +355,33 @@ impl From<ast::UnaryOpKind> for UnOpKind {
pub enum Param {
Ident(EcoString),
Formals {
formals: Vec<(EcoString, Option<Ir>)>,
formals: Vec<(EcoString, Option<Thunk>)>,
ellipsis: bool,
alias: Option<EcoString>,
},
}
impl Into<i::Param> 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<Ir> {
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::<Result<Vec<_>>>()?;

View File

@@ -4,5 +4,5 @@ mod builtins;
mod bytecode;
mod compile;
mod downcast;
mod value;
mod ty;
mod vm;

26
src/ty/common.rs Normal file
View File

@@ -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<String>,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)]
pub struct Symbol(EcoString);
impl<T: Into<EcoString>> From<T> for Symbol {
fn from(value: T) -> Self {
Symbol(value.into())
}
}
impl Deref for Symbol {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}

View File

@@ -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(),

View File

@@ -110,7 +110,7 @@ impl PartialEq for Const {
impl Eq for Const {}
impl Hash for Const {
/* impl Hash for Const {
fn hash<H: Hasher>(&self, state: &mut H) {
use Const::*;
match self {
@@ -121,4 +121,4 @@ impl Hash for Const {
Func(func) => func.hash(state),
}
}
}
} */

25
src/ty/internal/func.rs Normal file
View File

@@ -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<ThunkIdx>)>,
ellipsis: bool,
alias: Option<EcoString>,
},
}
#[derive(Debug, Clone)]
pub struct Func {
pub param: Param,
pub opcodes: OpCodes
}
impl PartialEq for Func {
fn eq(&self, _: &Self) -> bool {
false
}
}

View File

@@ -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(),
))
}

View File

@@ -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<T: Into<EcoString>> From<T> 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,
}
}
}

67
src/ty/internal/primop.rs Normal file
View File

@@ -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>) -> Value,
}
impl PartialEq for PrimOp {
fn eq(&self, _: &Self) -> bool {
false
}
}
impl PrimOp {
pub fn call(self, args: Vec<Value>) -> 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<Value>,
func: fn(Vec<Value>) -> Value,
}
impl PartialEq for PartialPrimOp {
fn eq(&self, _: &Self) -> bool {
false
}
}
impl PartialPrimOp {
pub fn call(mut self, args: Vec<Value>) -> 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!()
}
}
}

3
src/ty/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
pub mod public;
pub mod internal;
pub mod common;

136
src/ty/public/cnst.rs Normal file
View File

@@ -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<i::Const> 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<bool> for Const {
fn from(value: bool) -> Self {
Const::Bool(value)
}
}
impl From<i64> for Const {
fn from(value: i64) -> Self {
Const::Int(value)
}
}
impl From<f64> for Const {
fn from(value: f64) -> Self {
Const::Float(value)
}
}
impl From<EcoString> for Const {
fn from(value: EcoString) -> Self {
Const::String(value)
}
}
impl From<String> 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<Self, Self::Error> {
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<Self, Self::Error> {
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<Self, Self::Error> {
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<Self, Self::Error> {
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<H: Hasher>(&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),
}
}
}

43
src/ty/public/mod.rs Normal file
View File

@@ -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<Symbol, Value>,
}
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<Value>,
}
#[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)]
pub enum Value {
Const(Const),
AttrSet(AttrSet),
List(List),
Catchable(Catchable),
Thunk,
Func,
PrimOp,
PartialPrimOp,
}

View File

@@ -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<T: Into<EcoString>> From<T> 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<Func>),
}
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<ByteCodeConst> 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<Symbol, Value>,
}
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<Value>,
}
#[derive(Clone, Debug, PartialEq, Constructor)]
pub struct Catchable {
msg: Option<String>,
}
#[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)]
pub enum Value {
Const(Const),
AttrSet(AttrSet),
List(List),
Catchable(Catchable),
Thunk,
PrimOp,
PartialPrimOp,
}

View File

@@ -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<Box<Env>>,

View File

@@ -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;

View File

@@ -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::<Value>();

View File

@@ -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));
}

View File

@@ -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<Value_> {
pub fn run(prog: Program) -> Result<p::Value> {
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));

View File

@@ -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 {