refactor: builtins, value

This commit is contained in:
2025-05-03 17:04:28 +08:00
parent 030c61df52
commit 3f0cb2c2fa
9 changed files with 123 additions and 119 deletions

View File

@@ -1,8 +1,6 @@
use derive_more::Constructor;
use super::vm::Env;
use super::vm::Symbol;
use super::vm::Value;
use crate::vm::{Env, Symbol, Value, AttrSet};
use crate::value::Const;
pub fn env() -> Env {
@@ -10,42 +8,39 @@ pub fn env() -> Env {
env.insert(Symbol::from("true"), Value::Const(Const::Bool(true)));
env.insert(Symbol::from("false"), Value::Const(Const::Bool(false)));
env.insert(
Symbol::from("__add"),
Value::PrimOp(PrimOp::new("add", 2, |args| {
let primops = [
PrimOp::new("add", 2, |args| {
let [first, second]: [Value; 2] = args.try_into().unwrap();
first.add(second)
})),
);
env.insert(
Symbol::from("__sub"),
Value::PrimOp(PrimOp::new("sub", 2, |args| {
}),
PrimOp::new("sub", 2, |args| {
let [first, second]: [Value; 2] = args.try_into().unwrap();
first.add(second.neg())
})),
);
env.insert(
Symbol::from("__mul"),
Value::PrimOp(PrimOp::new("mul", 2, |args| {
}),
PrimOp::new("mul", 2, |args| {
let [first, second]: [Value; 2] = args.try_into().unwrap();
first.mul(second)
})),
);
env.insert(
Symbol::from("__div"),
Value::PrimOp(PrimOp::new("div", 2, |args| {
}),
PrimOp::new("div", 2, |args| {
let [first, second]: [Value; 2] = args.try_into().unwrap();
first.div(second)
})),
);
env.insert(
Symbol::from("__lessThan"),
Value::PrimOp(PrimOp::new("lessThan", 2, |args| {
}),
PrimOp::new("lessThan", 2, |args| {
let [first, second]: [Value; 2] = args.try_into().unwrap();
first.lt(second)
})),
);
})
];
let mut builtins = AttrSet::empty();
for primop in primops {
env.insert(
Symbol::from(format!("__{}", primop.name)),
Value::PrimOp(primop.clone()),
);
builtins.push_attr(Symbol::from(primop.name), Value::PrimOp(primop));
}
env.insert(Symbol::from("builtins"), Value::AttrSet(builtins));
env
}

View File

@@ -1,10 +1,10 @@
use rpds::HashTrieMapSync;
use super::value::{Symbol, VmValue};
use super::value::{Symbol, Value};
pub struct Env {
last: Option<Box<Env>>,
map: HashTrieMapSync<Symbol, VmValue>,
map: HashTrieMapSync<Symbol, Value>,
}
impl Env {
@@ -15,7 +15,7 @@ impl Env {
}
}
pub fn lookup(&self, symbol: Symbol) -> VmValue {
pub fn lookup(&self, symbol: Symbol) -> Value {
if let Some(value) = self.map.get(&symbol) {
value.clone()
} else {
@@ -24,11 +24,11 @@ impl Env {
}
}
pub fn insert(&mut self, symbol: Symbol, value: VmValue) {
pub fn insert(&mut self, symbol: Symbol, value: Value) {
self.map.insert_mut(symbol, value);
}
pub fn enter(&mut self, map: HashTrieMapSync<Symbol, VmValue>) {
pub fn enter(&mut self, map: HashTrieMapSync<Symbol, Value>) {
let last = std::mem::replace(self, Env { last: None, map });
self.last = Some(Box::new(last));
}

View File

@@ -9,4 +9,4 @@ mod test;
pub use env::Env;
pub use value::Symbol;
pub use value::VmValue as Value;
pub use value::*;

View File

@@ -3,12 +3,12 @@ use std::ops::Deref;
use anyhow::{Result, anyhow};
use super::value::VmValue;
use super::value::Value;
pub const STACK_SIZE: usize = 8 * 1024 / size_of::<VmValue>();
pub const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
pub struct Stack<const CAP: usize> {
items: Box<[MaybeUninit<VmValue>; CAP]>,
items: Box<[MaybeUninit<Value>; CAP]>,
top: usize,
}
@@ -24,7 +24,7 @@ impl<const CAP: usize> Stack<CAP> {
}
}
pub fn push(&mut self, item: VmValue) -> Result<()> {
pub fn push(&mut self, item: Value) -> Result<()> {
self.items
.get_mut(self.top)
.map_or(Err(anyhow!("stack overflow")), |ok| Ok(ok))?
@@ -33,7 +33,7 @@ impl<const CAP: usize> Stack<CAP> {
Ok(())
}
pub fn pop(&mut self) -> Result<VmValue> {
pub fn pop(&mut self) -> Result<Value> {
self.top -= 1;
let item = self
.items
@@ -42,7 +42,7 @@ impl<const CAP: usize> Stack<CAP> {
unsafe { Ok(std::mem::replace(item, MaybeUninit::uninit()).assume_init()) }
}
pub fn tos(&self) -> Result<&VmValue> {
pub fn tos(&self) -> Result<&Value> {
if self.top == 0 {
Err(anyhow!(""))
} else {
@@ -50,7 +50,7 @@ impl<const CAP: usize> Stack<CAP> {
}
}
pub fn tos_mut(&mut self) -> Result<&mut VmValue> {
pub fn tos_mut(&mut self) -> Result<&mut Value> {
if self.top == 0 {
Err(anyhow!(""))
} else {
@@ -58,7 +58,7 @@ impl<const CAP: usize> Stack<CAP> {
}
}
pub fn with_tos(&self, func: impl Fn(&VmValue)) -> Result<()> {
pub fn with_tos(&self, func: impl Fn(&Value)) -> Result<()> {
if self.top != 0 {
Err(anyhow!(""))
} else {
@@ -66,7 +66,7 @@ impl<const CAP: usize> Stack<CAP> {
Ok(())
}
}
pub fn with_tos_mut(&mut self, func: impl Fn(&mut VmValue)) -> Result<()> {
pub fn with_tos_mut(&mut self, func: impl Fn(&mut Value)) -> Result<()> {
if self.top != 0 {
Err(anyhow!(""))
} else {
@@ -77,7 +77,7 @@ impl<const CAP: usize> Stack<CAP> {
}
impl<const CAP: usize> Deref for Stack<CAP> {
type Target = [VmValue];
type Target = [Value];
fn deref(&self) -> &Self::Target {
unsafe { transmute(&self.items[0..self.top]) }
}

View File

@@ -1,29 +1,33 @@
use derive_more::Constructor;
use rpds::HashTrieMapSync;
use crate::value::{self, Value};
use crate::value::{self, Value as Value_};
use super::super::vm::VM;
use super::{Symbol, ToValue, VmValue};
use super::{Symbol, ToValue, Value};
#[derive(Debug, Constructor, Clone, PartialEq)]
pub struct AttrSet {
data: HashTrieMapSync<Symbol, VmValue>,
data: HashTrieMapSync<Symbol, Value>,
}
impl AttrSet {
pub fn push_attr_force(&mut self, sym: Symbol, val: VmValue) {
pub fn empty() -> AttrSet {
AttrSet { data: HashTrieMapSync::new_sync() }
}
pub fn push_attr_force(&mut self, sym: Symbol, val: Value) {
self.data.insert_mut(sym, val);
}
pub fn push_attr(&mut self, sym: Symbol, val: VmValue) {
pub fn push_attr(&mut self, sym: Symbol, val: Value) {
if self.data.get(&sym).is_some() {
todo!()
}
self.data.insert_mut(sym, val);
}
pub fn select(&self, sym: Symbol) -> Option<VmValue> {
pub fn select(&self, sym: Symbol) -> Option<Value> {
self.data.get(&sym).cloned()
}
@@ -38,14 +42,14 @@ impl AttrSet {
self
}
pub fn to_data(self) -> HashTrieMapSync<Symbol, VmValue> {
pub fn to_data(self) -> HashTrieMapSync<Symbol, Value> {
self.data
}
}
impl ToValue for AttrSet {
fn to_value(self, vm: &VM) -> Value {
Value::AttrSet(value::AttrSet::new(
fn to_value(self, vm: &VM) -> Value_ {
Value_::AttrSet(value::AttrSet::new(
self.data
.iter()
.map(|(sym, value)| {

View File

@@ -1,18 +1,24 @@
use derive_more::Constructor;
use rpds::VectorSync;
use crate::value::{self, Value};
use crate::value::{self, Value as Value_};
use super::super::vm::VM;
use super::{ToValue, VmValue};
use super::{ToValue, Value};
#[derive(Debug, Constructor, Clone, PartialEq)]
pub struct List {
data: VectorSync<VmValue>,
data: VectorSync<Value>,
}
impl List {
pub fn push(&mut self, elem: VmValue) {
pub fn empty() -> List {
List {
data: VectorSync::new_sync()
}
}
pub fn push(&mut self, elem: Value) {
self.data.push_back_mut(elem);
}
@@ -25,8 +31,8 @@ impl List {
}
impl ToValue for List {
fn to_value(self, vm: &VM) -> Value {
Value::List(value::List::new(
fn to_value(self, vm: &VM) -> Value_ {
Value_::List(value::List::new(
self.data
.iter()
.map(|value| value.clone().to_value(vm))

View File

@@ -2,7 +2,7 @@ use anyhow::Result;
use derive_more::{Constructor, IsVariant, Unwrap};
use ecow::EcoString;
use crate::value::*;
use crate::value::{Value as Value_, Const, Catchable};
use super::env::Env;
use super::vm::VM;
@@ -16,7 +16,7 @@ pub use list::List;
pub use string::ContextfulString;
pub trait ToValue {
fn to_value(self, vm: &VM) -> Value;
fn to_value(self, vm: &VM) -> Value_;
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Constructor)]
@@ -32,7 +32,7 @@ impl<T: Into<EcoString>> From<T> for Symbol {
pub struct Thunk(usize);
#[derive(Debug, IsVariant, Unwrap, Clone, PartialEq)]
pub enum VmValue {
pub enum Value {
Const(Const),
Thunk(Thunk),
AttrSet(AttrSet),
@@ -42,17 +42,17 @@ pub enum VmValue {
PartialPrimOp(crate::builtins::PartialPrimOp),
}
use VmValue::Const as VmConst;
impl VmValue {
pub fn call(self, args: Vec<VmValue>) -> VmValue {
use Value::Const as VmConst;
impl Value {
pub fn call(self, args: Vec<Value>) -> Value {
match self {
VmValue::PrimOp(func) => func.call(args),
VmValue::PartialPrimOp(func) => func.call(args),
Value::PrimOp(func) => func.call(args),
Value::PartialPrimOp(func) => func.call(args),
_ => todo!(),
}
}
pub fn not(self) -> VmValue {
pub fn not(self) -> Value {
use Const::*;
match self {
VmConst(Bool(bool)) => VmConst(Bool(!bool)),
@@ -60,7 +60,7 @@ impl VmValue {
}
}
pub fn and(self, other: VmValue) -> VmValue {
pub fn and(self, other: Value) -> Value {
use Const::*;
match (self, other) {
(VmConst(Bool(a)), VmConst(Bool(b))) => VmConst(Bool(a && b)),
@@ -68,7 +68,7 @@ impl VmValue {
}
}
pub fn or(self, other: VmValue) -> VmValue {
pub fn or(self, other: Value) -> Value {
use Const::*;
match (self, other) {
(VmConst(Bool(a)), VmConst(Bool(b))) => VmConst(Bool(a || b)),
@@ -76,12 +76,12 @@ impl VmValue {
}
}
pub fn eq(self, other: VmValue) -> VmValue {
pub fn eq(self, other: Value) -> Value {
use Const::Bool;
VmConst(Bool(self == other))
}
pub fn lt(self, other: VmValue) -> VmValue {
pub fn lt(self, other: Value) -> Value {
use Const::*;
VmConst(Bool(match (self, other) {
(VmConst(Int(a)), VmConst(Int(b))) => a < b,
@@ -93,7 +93,7 @@ impl VmValue {
}))
}
pub fn neg(self) -> VmValue {
pub fn neg(self) -> Value {
use Const::*;
match self {
VmConst(Int(int)) => VmConst(Int(-int)),
@@ -102,7 +102,7 @@ impl VmValue {
}
}
pub fn add(self, other: VmValue) -> VmValue {
pub fn add(self, other: Value) -> Value {
use Const::*;
match (self, other) {
(VmConst(Int(a)), VmConst(Int(b))) => VmConst(Int(a + b)),
@@ -118,7 +118,7 @@ impl VmValue {
}
}
pub fn mul(self, other: VmValue) -> VmValue {
pub fn mul(self, other: Value) -> Value {
use Const::*;
match (self, other) {
(VmConst(Int(a)), VmConst(Int(b))) => VmConst(Int(a * b)),
@@ -129,7 +129,7 @@ impl VmValue {
}
}
pub fn div(self, other: VmValue) -> VmValue {
pub fn div(self, other: Value) -> Value {
use Const::*;
match (self, other) {
(_, VmConst(Int(0))) => todo!(),
@@ -142,7 +142,7 @@ impl VmValue {
}
}
pub fn concat_string(&mut self, mut other: VmValue) -> &mut Self {
pub fn concat_string(&mut self, mut other: Value) -> &mut Self {
if let (VmConst(Const::String(a)), VmConst(Const::String(b))) =
(self.coerce_to_string(), other.coerce_to_string())
{
@@ -153,8 +153,8 @@ impl VmValue {
self
}
pub fn push(&mut self, elem: VmValue) -> &mut Self {
if let VmValue::List(list) = self {
pub fn push(&mut self, elem: Value) -> &mut Self {
if let Value::List(list) = self {
list.push(elem);
} else {
todo!()
@@ -162,16 +162,16 @@ impl VmValue {
self
}
pub fn concat(self, other: VmValue) -> VmValue {
if let (VmValue::List(a), VmValue::List(b)) = (self, other) {
VmValue::List(a.concat(b))
pub fn concat(self, other: Value) -> Value {
if let (Value::List(a), Value::List(b)) = (self, other) {
Value::List(a.concat(b))
} else {
todo!()
}
}
pub fn push_attr(&mut self, sym: Symbol, val: VmValue) -> &mut Self {
if let VmValue::AttrSet(attrs) = self {
pub fn push_attr(&mut self, sym: Symbol, val: Value) -> &mut Self {
if let Value::AttrSet(attrs) = self {
attrs.push_attr(sym, val)
} else {
todo!()
@@ -179,19 +179,19 @@ impl VmValue {
self
}
pub fn update(self, other: VmValue) -> VmValue {
if let (VmValue::AttrSet(a), VmValue::AttrSet(b)) = (self, other) {
VmValue::AttrSet(a.update(b))
pub fn update(self, other: Value) -> Value {
if let (Value::AttrSet(a), Value::AttrSet(b)) = (self, other) {
Value::AttrSet(a.update(b))
} else {
todo!()
}
}
pub fn select(&mut self, sym: Symbol) -> &mut Self {
if let VmValue::AttrSet(attrs) = self {
if let Value::AttrSet(attrs) = self {
let val = attrs
.select(sym.clone())
.unwrap_or(VmValue::Catchable(Catchable::new(Some(format!(
.unwrap_or(Value::Catchable(Catchable::new(Some(format!(
"{sym:?} not found"
)))));
*self = val;
@@ -201,8 +201,8 @@ impl VmValue {
self
}
pub fn select_with_default(&mut self, sym: Symbol, default: VmValue) -> &mut Self {
if let VmValue::AttrSet(attrs) = self {
pub fn select_with_default(&mut self, sym: Symbol, default: Value) -> &mut Self {
if let Value::AttrSet(attrs) = self {
let val = attrs.select(sym).unwrap_or(default);
*self = val;
} else {
@@ -212,7 +212,7 @@ impl VmValue {
}
pub fn has_attr(&mut self, sym: Symbol) -> &mut Self {
if let VmValue::AttrSet(attrs) = self {
if let Value::AttrSet(attrs) = self {
let val = VmConst(Const::Bool(attrs.has_attr(sym)));
*self = val;
} else {
@@ -231,7 +231,7 @@ impl VmValue {
}
pub fn force(&mut self, vm: &VM, env: &mut Env) -> Result<&mut Self> {
if let VmValue::Thunk(thunk) = self {
if let Value::Thunk(thunk) = self {
let value = vm.get_thunk_value(thunk.0, env)?;
*self = value
}
@@ -239,16 +239,16 @@ impl VmValue {
}
}
impl ToValue for VmValue {
fn to_value(self, vm: &VM) -> Value {
impl ToValue for Value {
fn to_value(self, vm: &VM) -> Value_ {
match self {
VmValue::AttrSet(attrs) => attrs.to_value(vm),
VmValue::List(list) => list.to_value(vm),
VmValue::Catchable(catchable) => Value::Catchable(catchable),
VmValue::Const(cnst) => Value::Const(cnst),
VmValue::Thunk(_) => Value::Thunk,
VmValue::PrimOp(_) => Value::PrimOp,
VmValue::PartialPrimOp(_) => Value::PartialPrimOp,
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,
}
}
}

View File

@@ -1,16 +1,15 @@
use anyhow::Result;
use rpds::{HashTrieMap, HashTrieMapSync, Vector};
use crate::builtins::env;
use crate::bytecode::{self, *};
use crate::value::{Const, Value};
use crate::value::{Const, Value as Value_};
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<Value_> {
let vm = VM::new(prog.thunks);
Ok(vm.eval(prog.top_level, &mut env())?.to_value(&vm))
}
@@ -28,11 +27,11 @@ impl VM {
VM { thunks }
}
pub fn get_thunk_value(&self, idx: usize, env: &mut Env) -> Result<VmValue> {
pub fn get_thunk_value(&self, idx: usize, env: &mut Env) -> Result<Value> {
self.thunks.get(idx).unwrap().force(self, env)
}
pub fn eval(&self, opcodes: OpCodes, env: &mut Env) -> Result<VmValue> {
pub fn eval(&self, opcodes: OpCodes, env: &mut Env) -> Result<Value> {
let mut stack = Stack::<STACK_SIZE>::new();
let mut iter = opcodes.into_iter();
while let Some(opcode) = iter.next() {
@@ -54,8 +53,8 @@ impl VM {
) -> Result<usize> {
match opcode {
OpCode::NoOp => (),
OpCode::Const { value } => stack.push(VmValue::Const(value))?,
OpCode::LoadThunk { idx } => stack.push(VmValue::Thunk(vmValue::Thunk::new(idx)))?,
OpCode::Const { value } => stack.push(Value::Const(value))?,
OpCode::LoadThunk { idx } => stack.push(Value::Thunk(vmValue::Thunk::new(idx)))?,
OpCode::LoadValue { idx } => {
stack.push(self.get_thunk_value(idx, env)?)?;
}
@@ -64,12 +63,12 @@ impl VM {
}
OpCode::Jmp { step } => return Ok(step),
OpCode::JmpIfTrue { step } => {
if let VmValue::Const(Const::Bool(true)) = stack.pop()? {
if let Value::Const(Const::Bool(true)) = stack.pop()? {
return Ok(step);
}
}
OpCode::JmpIfFalse { step } => {
if let VmValue::Const(Const::Bool(false)) = stack.pop()? {
if let Value::Const(Const::Bool(false)) = stack.pop()? {
return Ok(step);
}
}
@@ -106,14 +105,14 @@ impl VM {
stack.tos_mut()?.concat_string(rhs);
}
OpCode::List => {
stack.push(VmValue::List(List::new(Vector::new_sync())))?;
stack.push(Value::List(List::empty()))?;
}
OpCode::PushElem => {
let elem = stack.pop()?;
stack.tos_mut()?.push(elem);
}
OpCode::AttrSet => {
stack.push(VmValue::AttrSet(AttrSet::new(HashTrieMap::new_sync())))?;
stack.push(Value::AttrSet(AttrSet::empty()))?;
}
OpCode::PushStaticAttr { name } => {
let val = stack.pop()?;
@@ -138,7 +137,7 @@ impl VM {
OpCode::SelectOrEmpty { sym } => {
stack.tos_mut()?.select_with_default(
Symbol::new(sym),
VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync())),
Value::AttrSet(AttrSet::empty()),
);
}
OpCode::SelectDynamic => {
@@ -160,7 +159,7 @@ impl VM {
let sym = val.unwrap_const().unwrap_string().into();
stack.tos_mut()?.select_with_default(
sym,
VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync())),
Value::AttrSet(AttrSet::empty()),
);
}
OpCode::HasAttr { sym } => {

View File

@@ -7,7 +7,7 @@ use derive_more::{IsVariant, Unwrap};
use crate::bytecode::OpCodes;
use super::env::Env;
use super::value::VmValue;
use super::value::Value;
use super::vm::VM;
pub struct VmThunk {
@@ -19,7 +19,7 @@ pub struct VmThunk {
enum _VmThunk {
Code(OpCodes),
SuspendedFrom(*const VmThunk),
Value(VmValue),
Value(Value),
}
impl VmThunk {
@@ -30,7 +30,7 @@ impl VmThunk {
}
}
pub fn force(&self, vm: &VM, env: &mut Env) -> Result<VmValue> {
pub fn force(&self, vm: &VM, env: &mut Env) -> Result<Value> {
{
let _guard = self.lock.read().unwrap();
match &*self.thunk.borrow() {
@@ -59,7 +59,7 @@ impl VmThunk {
}
}
pub fn value(&self) -> Option<VmValue> {
pub fn value(&self) -> Option<Value> {
let _guard = self.lock.read();
match &*self.thunk.borrow() {
_VmThunk::Value(value) => Some(value.clone()),