refactor: type
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
|
|
||||||
use crate::vm::{Env, Symbol, Value, AttrSet};
|
use crate::vm::Env;
|
||||||
use crate::value::Const;
|
use crate::ty::internal::{Const, Value, AttrSet, PrimOp};
|
||||||
|
use crate::ty::common::Symbol;
|
||||||
|
|
||||||
pub fn env() -> Env {
|
pub fn env() -> Env {
|
||||||
let mut env = Env::empty();
|
let mut env = Env::empty();
|
||||||
@@ -44,65 +45,3 @@ pub fn env() -> 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!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::hash::Hash;
|
|||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
|
||||||
use crate::value::Const;
|
use crate::ty::internal::{Const, Param};
|
||||||
|
|
||||||
type Slice<T> = Box<[T]>;
|
type Slice<T> = Box<[T]>;
|
||||||
|
|
||||||
@@ -12,17 +12,13 @@ pub type SymIdx = usize;
|
|||||||
pub type OpCodes = Slice<OpCode>;
|
pub type OpCodes = Slice<OpCode>;
|
||||||
pub type Consts = Slice<Const>;
|
pub type Consts = Slice<Const>;
|
||||||
pub type Thunks = Slice<Thunk>;
|
pub type Thunks = Slice<Thunk>;
|
||||||
pub type Args = Slice<Arg>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Thunk {
|
pub struct Thunk {
|
||||||
pub opcodes: OpCodes,
|
pub opcodes: OpCodes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Arg {}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
|
||||||
pub enum OpCode {
|
pub enum OpCode {
|
||||||
/// load a constant onto stack
|
/// load a constant onto stack
|
||||||
Const { value: Const },
|
Const { value: Const },
|
||||||
@@ -34,17 +30,25 @@ pub enum OpCode {
|
|||||||
LoadValue { idx: ThunkIdx },
|
LoadValue { idx: ThunkIdx },
|
||||||
/// force TOS to value
|
/// force TOS to value
|
||||||
ForceValue,
|
ForceValue,
|
||||||
|
|
||||||
/// [ .. func args @ .. ] consume (`arity` + 2) elements, call `func` with args` of length `arity`
|
/// [ .. 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) ]
|
/// Example: __add 1 2 => [ LookUp("__add") Const(1) Const(2) Call(2) ]
|
||||||
Call { arity: usize },
|
Call { arity: usize },
|
||||||
|
/// return a value
|
||||||
|
Ret,
|
||||||
|
/// make a function
|
||||||
|
Func { param: Param, length: usize },
|
||||||
|
|
||||||
/// consume 1 element, assert TOS is true
|
/// consume 1 element, assert TOS is true
|
||||||
Assert,
|
Assert,
|
||||||
|
|
||||||
/// jump forward
|
/// jump forward
|
||||||
Jmp { step: usize },
|
Jmp { step: usize },
|
||||||
/// [ .. cond ] consume 1 element, if `cond`` is true, then jump forward
|
/// [ .. cond ] consume 1 element, if `cond`` is true, then jump forward
|
||||||
JmpIfTrue { step: usize },
|
JmpIfTrue { step: usize },
|
||||||
/// [ .. cond ] consume 1 element, if `cond` is false, then jump forward
|
/// [ .. cond ] consume 1 element, if `cond` is false, then jump forward
|
||||||
JmpIfFalse { step: usize },
|
JmpIfFalse { step: usize },
|
||||||
|
|
||||||
/// push an empty attribute set onto stack
|
/// push an empty attribute set onto stack
|
||||||
AttrSet,
|
AttrSet,
|
||||||
/// push an empty recursive attribute set onto stack
|
/// push an empty recursive attribute set onto stack
|
||||||
@@ -53,10 +57,15 @@ pub enum OpCode {
|
|||||||
PushStaticAttr { name: EcoString },
|
PushStaticAttr { name: EcoString },
|
||||||
/// [ .. set name value ] consume 2 elements, push a dynamic kv pair (`name`, `value`) in to `set`
|
/// [ .. set name value ] consume 2 elements, push a dynamic kv pair (`name`, `value`) in to `set`
|
||||||
PushDynamicAttr,
|
PushDynamicAttr,
|
||||||
|
|
||||||
/// push an empty list onto stack
|
/// push an empty list onto stack
|
||||||
List,
|
List,
|
||||||
/// [ .. list elem ] consume 1 element, push `elem` into `list`
|
/// [ .. list elem ] consume 1 element, push `elem` into `list`
|
||||||
PushElem,
|
PushElem,
|
||||||
|
|
||||||
|
/// convert the string as TOS to a path
|
||||||
|
Path,
|
||||||
|
|
||||||
/// [ .. a b ] consume 2 elements, perform a string concatenation `a` + `b`
|
/// [ .. a b ] consume 2 elements, perform a string concatenation `a` + `b`
|
||||||
ConcatString,
|
ConcatString,
|
||||||
/// [ .. a b ] consume 2 elements, perform a binary operation `a` `op` `b`
|
/// [ .. a b ] consume 2 elements, perform a binary operation `a` `op` `b`
|
||||||
@@ -69,23 +78,19 @@ pub enum OpCode {
|
|||||||
HasDynamicAttr,
|
HasDynamicAttr,
|
||||||
/// [ .. set ] select `sym` from `set`
|
/// [ .. set ] select `sym` from `set`
|
||||||
Select { sym: EcoString },
|
Select { sym: EcoString },
|
||||||
/// TODO:
|
/// [ .. set default ] select `sym` from `set` or `default`
|
||||||
SelectWithDefault { sym: EcoString },
|
SelectOrDefault { sym: EcoString },
|
||||||
/// TODO:
|
/// [ .. set sym ] select `sym` from `set`
|
||||||
SelectOrEmpty { sym: EcoString },
|
|
||||||
/// TODO:
|
|
||||||
SelectDynamic,
|
SelectDynamic,
|
||||||
/// TODO:
|
/// [ .. set sym default ] select `sym` from `set` or `default`
|
||||||
SelectDynamicOrEmpty,
|
|
||||||
/// TODO:
|
SelectDynamicOrDefault,
|
||||||
SelectDynamicWithDefault,
|
|
||||||
/// enter the environment of the attribute set at TOS
|
/// enter the environment of the attribute set at TOS
|
||||||
EnterEnv,
|
EnterEnv,
|
||||||
/// exit current envrironment
|
/// exit current envrironment
|
||||||
LeaveEnv,
|
LeaveEnv,
|
||||||
/// return a value
|
|
||||||
Ret,
|
/// no operation, used as termporary placeholder
|
||||||
/// no operation
|
|
||||||
NoOp,
|
NoOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::bytecode::*;
|
use crate::bytecode::*;
|
||||||
use crate::value::*;
|
use crate::ty::internal::Const;
|
||||||
|
|
||||||
use super::ir;
|
use super::ir;
|
||||||
|
|
||||||
@@ -275,23 +275,29 @@ impl Compile for ir::HasAttr {
|
|||||||
for attr in self.rhs {
|
for attr in self.rhs {
|
||||||
match attr {
|
match attr {
|
||||||
ir::Attr::Str(sym) => {
|
ir::Attr::Str(sym) => {
|
||||||
comp.push(OpCode::SelectOrEmpty { sym });
|
comp.push(OpCode::AttrSet);
|
||||||
}
|
comp.push(OpCode::SelectOrDefault { sym })
|
||||||
|
},
|
||||||
ir::Attr::Dynamic(dynamic) => {
|
ir::Attr::Dynamic(dynamic) => {
|
||||||
dynamic.compile(comp);
|
dynamic.compile(comp);
|
||||||
comp.push(OpCode::SelectDynamicOrEmpty);
|
comp.push(OpCode::AttrSet);
|
||||||
|
comp.push(OpCode::SelectDynamicOrDefault);
|
||||||
}
|
}
|
||||||
ir::Attr::Strs(string) => {
|
ir::Attr::Strs(string) => {
|
||||||
string.compile(comp);
|
string.compile(comp);
|
||||||
comp.push(OpCode::SelectDynamicOrEmpty);
|
comp.push(OpCode::AttrSet);
|
||||||
|
comp.push(OpCode::SelectDynamicOrDefault);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match comp.pop().unwrap() {
|
let last = comp.pop().unwrap();
|
||||||
OpCode::SelectOrEmpty { sym } => comp.push(OpCode::HasAttr { sym }),
|
let _ = comp.pop();
|
||||||
OpCode::SelectDynamicOrEmpty => comp.push(OpCode::HasDynamicAttr),
|
match last {
|
||||||
|
OpCode::SelectOrDefault { sym } => comp.push(OpCode::HasAttr { sym }),
|
||||||
|
OpCode::SelectDynamicOrDefault => comp.push(OpCode::HasDynamicAttr),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,32 +306,42 @@ impl Compile for ir::Select {
|
|||||||
self.expr.compile(comp);
|
self.expr.compile(comp);
|
||||||
for attr in self.attrpath {
|
for attr in self.attrpath {
|
||||||
match attr {
|
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) => {
|
ir::Attr::Dynamic(dynamic) => {
|
||||||
dynamic.compile(comp);
|
dynamic.compile(comp);
|
||||||
comp.push(OpCode::SelectDynamicOrEmpty);
|
comp.push(OpCode::AttrSet);
|
||||||
|
comp.push(OpCode::SelectDynamicOrDefault);
|
||||||
}
|
}
|
||||||
ir::Attr::Strs(string) => {
|
ir::Attr::Strs(string) => {
|
||||||
string.compile(comp);
|
string.compile(comp);
|
||||||
comp.push(OpCode::SelectDynamicOrEmpty);
|
comp.push(OpCode::AttrSet);
|
||||||
|
comp.push(OpCode::SelectDynamicOrDefault);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.default {
|
match self.default {
|
||||||
Some(default) => {
|
Some(default) => {
|
||||||
let last = comp.pop().unwrap();
|
let last = comp.pop().unwrap();
|
||||||
|
let _ = comp.pop();
|
||||||
default.compile(comp);
|
default.compile(comp);
|
||||||
match last {
|
match last {
|
||||||
OpCode::SelectOrEmpty { sym } => comp.push(OpCode::SelectWithDefault { sym }),
|
OpCode::SelectOrDefault { sym } => comp.push(OpCode::SelectOrDefault { sym }),
|
||||||
OpCode::SelectDynamicOrEmpty => comp.push(OpCode::SelectDynamicWithDefault),
|
OpCode::SelectDynamicOrDefault => comp.push(OpCode::SelectDynamicOrDefault),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => match comp.pop().unwrap() {
|
None => {
|
||||||
OpCode::SelectOrEmpty { sym } => comp.push(OpCode::Select { sym }),
|
let last = comp.pop().unwrap();
|
||||||
OpCode::SelectDynamicOrEmpty => comp.push(OpCode::SelectDynamic),
|
let _ = comp.pop();
|
||||||
|
match last {
|
||||||
|
OpCode::SelectOrDefault { sym } => comp.push(OpCode::Select { sym }),
|
||||||
|
OpCode::SelectDynamicOrDefault => comp.push(OpCode::SelectDynamic),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -389,19 +405,28 @@ impl Compile for ir::Assert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Compile for ir::Func {
|
impl Compile for ir::Func {
|
||||||
fn compile(self, _comp: &mut Compiler) {
|
fn compile(self, comp: &mut Compiler) {
|
||||||
todo!()
|
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 {
|
impl Compile for ir::Call {
|
||||||
fn compile(self, _comp: &mut Compiler) {
|
fn compile(self, comp: &mut Compiler) {
|
||||||
todo!()
|
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 {
|
impl Compile for ir::Path {
|
||||||
fn compile(self, _comp: &mut Compiler) {
|
fn compile(self, comp: &mut Compiler) {
|
||||||
todo!()
|
self.expr.compile(comp);
|
||||||
|
comp.push(OpCode::Path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use ecow::EcoString;
|
|||||||
use rnix::ast::{self, Expr};
|
use rnix::ast::{self, Expr};
|
||||||
|
|
||||||
use crate::bytecode::{ConstIdx, Consts, ThunkIdx};
|
use crate::bytecode::{ConstIdx, Consts, ThunkIdx};
|
||||||
use crate::value::Const as Const_;
|
use crate::ty::internal as i;
|
||||||
|
|
||||||
use super::compile::*;
|
use super::compile::*;
|
||||||
use super::env::IrEnv;
|
use super::env::IrEnv;
|
||||||
@@ -116,14 +116,14 @@ ir! {
|
|||||||
UnOp => { rhs: Box<Ir>, kind: UnOpKind },
|
UnOp => { rhs: Box<Ir>, kind: UnOpKind },
|
||||||
Select => { expr: Box<Ir>, attrpath: Vec<Attr>, default: Option<Box<Ir>> },
|
Select => { expr: Box<Ir>, attrpath: Vec<Attr>, default: Option<Box<Ir>> },
|
||||||
If => { cond: Box<Ir>, consq: Box<Ir>, alter: 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> },
|
Call => { func: Box<Ir>, args: Vec<Ir> },
|
||||||
|
|
||||||
Let => { attrs: Attrs, expr: Box<Ir> },
|
Let => { attrs: Attrs, expr: Box<Ir> },
|
||||||
With => { namespace: Box<Ir>, expr: Box<Ir> },
|
With => { namespace: Box<Ir>, expr: Box<Ir> },
|
||||||
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
|
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
|
||||||
ConcatStrings => { parts: Vec<Ir> },
|
ConcatStrings => { parts: Vec<Ir> },
|
||||||
Const => { value: Const_ },
|
Const => { value: i::Const },
|
||||||
Var => { sym: EcoString },
|
Var => { sym: EcoString },
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
Thunk => { idx: ThunkIdx },
|
Thunk => { idx: ThunkIdx },
|
||||||
@@ -163,8 +163,8 @@ pub struct DowngradeError {
|
|||||||
pub struct DowngradeState {
|
pub struct DowngradeState {
|
||||||
envs: Vec<Env>,
|
envs: Vec<Env>,
|
||||||
thunks: Vec<Ir>,
|
thunks: Vec<Ir>,
|
||||||
consts: Vec<Const_>,
|
consts: Vec<i::Const>,
|
||||||
consts_table: HashMap<Const_, ConstIdx>,
|
consts_table: HashMap<i::Const, ConstIdx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Downgraded {
|
pub struct Downgraded {
|
||||||
@@ -355,12 +355,33 @@ impl From<ast::UnaryOpKind> for UnOpKind {
|
|||||||
pub enum Param {
|
pub enum Param {
|
||||||
Ident(EcoString),
|
Ident(EcoString),
|
||||||
Formals {
|
Formals {
|
||||||
formals: Vec<(EcoString, Option<Ir>)>,
|
formals: Vec<(EcoString, Option<Thunk>)>,
|
||||||
ellipsis: bool,
|
ellipsis: bool,
|
||||||
alias: Option<EcoString>,
|
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
|
trait Downgrade
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@@ -607,14 +628,10 @@ impl Downgrade for ast::With {
|
|||||||
|
|
||||||
impl Downgrade for ast::Lambda {
|
impl Downgrade for ast::Lambda {
|
||||||
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> {
|
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> {
|
||||||
let mut body = self.body().unwrap();
|
let body = self.body().unwrap();
|
||||||
let mut args = vec![downgrade_param(self.param().unwrap(), state)?];
|
let param = 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 = body.downgrade(state)?.boxed();
|
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()
|
.default()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.downgrade(state)
|
.downgrade(state)
|
||||||
.map(|ok| (ident, Some(ok)))
|
.map(|ok| (ident, Some(state.new_thunk(ok))))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ mod builtins;
|
|||||||
mod bytecode;
|
mod bytecode;
|
||||||
mod compile;
|
mod compile;
|
||||||
mod downcast;
|
mod downcast;
|
||||||
mod value;
|
mod ty;
|
||||||
mod vm;
|
mod vm;
|
||||||
|
|||||||
26
src/ty/common.rs
Normal file
26
src/ty/common.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use rpds::HashTrieMapSync;
|
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 crate::vm::VM;
|
||||||
use super::{Symbol, ToValue, Value};
|
use super::{ToPublic, Value};
|
||||||
|
|
||||||
#[derive(Debug, Constructor, Clone, PartialEq)]
|
#[derive(Debug, Constructor, Clone, PartialEq)]
|
||||||
pub struct AttrSet {
|
pub struct AttrSet {
|
||||||
@@ -47,15 +48,15 @@ impl AttrSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToValue for AttrSet {
|
impl ToPublic for AttrSet {
|
||||||
fn to_value(self, vm: &VM) -> Value_ {
|
fn to_public(self, vm: &VM) -> p::Value {
|
||||||
Value_::AttrSet(value::AttrSet::new(
|
p::Value::AttrSet(p::AttrSet::new(
|
||||||
self.data
|
self.data
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(sym, value)| {
|
.map(|(sym, value)| {
|
||||||
(
|
(
|
||||||
value::Symbol::new(sym.0.clone()),
|
sym.clone(),
|
||||||
value.clone().to_value(vm),
|
value.clone().to_public(vm),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
@@ -110,7 +110,7 @@ impl PartialEq for Const {
|
|||||||
|
|
||||||
impl Eq for Const {}
|
impl Eq for Const {}
|
||||||
|
|
||||||
impl Hash for Const {
|
/* impl Hash for Const {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
use Const::*;
|
use Const::*;
|
||||||
match self {
|
match self {
|
||||||
@@ -121,4 +121,4 @@ impl Hash for Const {
|
|||||||
Func(func) => func.hash(state),
|
Func(func) => func.hash(state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
25
src/ty/internal/func.rs
Normal file
25
src/ty/internal/func.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use rpds::VectorSync;
|
use rpds::VectorSync;
|
||||||
|
|
||||||
use crate::value::{self, Value as Value_};
|
use crate::ty::public as p;
|
||||||
|
|
||||||
use super::super::vm::VM;
|
use crate::vm::VM;
|
||||||
use super::{ToValue, Value};
|
use super::{ToPublic, Value};
|
||||||
|
|
||||||
#[derive(Debug, Constructor, Clone, PartialEq)]
|
#[derive(Debug, Constructor, Clone, PartialEq)]
|
||||||
pub struct List {
|
pub struct List {
|
||||||
@@ -30,12 +30,12 @@ impl List {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToValue for List {
|
impl ToPublic for List {
|
||||||
fn to_value(self, vm: &VM) -> Value_ {
|
fn to_public(self, vm: &VM) -> p::Value {
|
||||||
Value_::List(value::List::new(
|
p::Value::List(p::List::new(
|
||||||
self.data
|
self.data
|
||||||
.iter()
|
.iter()
|
||||||
.map(|value| value.clone().to_value(vm))
|
.map(|value| value.clone().to_public(vm))
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -1,31 +1,30 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
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 c::Symbol;
|
||||||
use super::vm::VM;
|
|
||||||
|
use crate::vm::Env;
|
||||||
|
use crate::vm::VM;
|
||||||
|
|
||||||
mod attrset;
|
mod attrset;
|
||||||
mod list;
|
mod list;
|
||||||
mod string;
|
mod string;
|
||||||
|
mod func;
|
||||||
|
mod cnst;
|
||||||
|
mod primop;
|
||||||
|
|
||||||
pub use attrset::AttrSet;
|
pub use attrset::AttrSet;
|
||||||
pub use list::List;
|
pub use list::List;
|
||||||
pub use string::ContextfulString;
|
pub use string::ContextfulString;
|
||||||
|
pub use func::*;
|
||||||
|
pub use primop::*;
|
||||||
|
pub use cnst::Const;
|
||||||
|
|
||||||
pub trait ToValue {
|
pub trait ToPublic {
|
||||||
fn to_value(self, vm: &VM) -> Value_;
|
fn to_public(self, vm: &VM) -> p::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())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Constructor)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Constructor)]
|
||||||
@@ -37,9 +36,9 @@ pub enum Value {
|
|||||||
Thunk(Thunk),
|
Thunk(Thunk),
|
||||||
AttrSet(AttrSet),
|
AttrSet(AttrSet),
|
||||||
List(List),
|
List(List),
|
||||||
Catchable(crate::value::Catchable),
|
Catchable(c::Catchable),
|
||||||
PrimOp(crate::builtins::PrimOp),
|
PrimOp(PrimOp),
|
||||||
PartialPrimOp(crate::builtins::PartialPrimOp),
|
PartialPrimOp(PartialPrimOp),
|
||||||
}
|
}
|
||||||
|
|
||||||
use Value::Const as VmConst;
|
use Value::Const as VmConst;
|
||||||
@@ -191,7 +190,7 @@ impl Value {
|
|||||||
if let Value::AttrSet(attrs) = self {
|
if let Value::AttrSet(attrs) = self {
|
||||||
let val = attrs
|
let val = attrs
|
||||||
.select(sym.clone())
|
.select(sym.clone())
|
||||||
.unwrap_or(Value::Catchable(Catchable::new(Some(format!(
|
.unwrap_or(Value::Catchable(c::Catchable::new(Some(format!(
|
||||||
"{sym:?} not found"
|
"{sym:?} not found"
|
||||||
)))));
|
)))));
|
||||||
*self = val;
|
*self = val;
|
||||||
@@ -239,16 +238,16 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToValue for Value {
|
impl ToPublic for Value {
|
||||||
fn to_value(self, vm: &VM) -> Value_ {
|
fn to_public(self, vm: &VM) -> p::Value {
|
||||||
match self {
|
match self {
|
||||||
Value::AttrSet(attrs) => attrs.to_value(vm),
|
Value::AttrSet(attrs) => attrs.to_public(vm),
|
||||||
Value::List(list) => list.to_value(vm),
|
Value::List(list) => list.to_public(vm),
|
||||||
Value::Catchable(catchable) => Value_::Catchable(catchable),
|
Value::Catchable(catchable) => p::Value::Catchable(catchable),
|
||||||
Value::Const(cnst) => Value_::Const(cnst),
|
Value::Const(cnst) => p::Value::Const(cnst.into()),
|
||||||
Value::Thunk(_) => Value_::Thunk,
|
Value::Thunk(_) => p::Value::Thunk,
|
||||||
Value::PrimOp(_) => Value_::PrimOp,
|
Value::PrimOp(_) => p::Value::PrimOp,
|
||||||
Value::PartialPrimOp(_) => Value_::PartialPrimOp,
|
Value::PartialPrimOp(_) => p::Value::PartialPrimOp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
67
src/ty/internal/primop.rs
Normal file
67
src/ty/internal/primop.rs
Normal 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
3
src/ty/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod public;
|
||||||
|
pub mod internal;
|
||||||
|
pub mod common;
|
||||||
136
src/ty/public/cnst.rs
Normal file
136
src/ty/public/cnst.rs
Normal 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
43
src/ty/public/mod.rs
Normal 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,
|
||||||
|
}
|
||||||
111
src/value/mod.rs
111
src/value/mod.rs
@@ -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,
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
use rpds::HashTrieMapSync;
|
use rpds::HashTrieMapSync;
|
||||||
|
|
||||||
use super::value::{Symbol, Value};
|
use crate::ty::common::Symbol;
|
||||||
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
last: Option<Box<Env>>,
|
last: Option<Box<Env>>,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
mod env;
|
mod env;
|
||||||
mod stack;
|
mod stack;
|
||||||
mod value;
|
|
||||||
mod vm;
|
mod vm;
|
||||||
mod vmthunk;
|
mod vmthunk;
|
||||||
|
|
||||||
@@ -8,5 +7,4 @@ mod vmthunk;
|
|||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
pub use env::Env;
|
pub use env::Env;
|
||||||
pub use value::Symbol;
|
pub use vm::VM;
|
||||||
pub use value::*;
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::ops::Deref;
|
|||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
|
|
||||||
use super::value::Value;
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
pub const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
|
pub const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use ecow::EcoString;
|
|||||||
use rpds::{ht_map_sync, vector_sync};
|
use rpds::{ht_map_sync, vector_sync};
|
||||||
|
|
||||||
use crate::compile::compile;
|
use crate::compile::compile;
|
||||||
use crate::value::*;
|
use crate::ty::public::*;
|
||||||
|
use crate::ty::common::Symbol;
|
||||||
|
|
||||||
use super::vm::run;
|
use super::vm::run;
|
||||||
|
|
||||||
@@ -166,3 +167,8 @@ fn test_let() {
|
|||||||
attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } },
|
attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_func() {
|
||||||
|
test_expr("(x: x) 1", int!(1));
|
||||||
|
}
|
||||||
|
|||||||
36
src/vm/vm.rs
36
src/vm/vm.rs
@@ -1,17 +1,18 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::builtins::env;
|
use crate::builtins::env;
|
||||||
use crate::bytecode::{self, *};
|
use crate::bytecode::{self, Program, OpCode, OpCodes, Thunks, UnOp, BinOp};
|
||||||
use crate::value::{Const, Value as Value_};
|
use crate::ty::internal::*;
|
||||||
|
use crate::ty::common::Symbol;
|
||||||
|
use crate::ty::public as p;
|
||||||
|
|
||||||
use super::env::Env;
|
use super::env::Env;
|
||||||
use super::stack::{STACK_SIZE, Stack};
|
use super::stack::{STACK_SIZE, Stack};
|
||||||
use super::value::{self as vmValue, *};
|
|
||||||
use super::vmthunk::*;
|
use super::vmthunk::*;
|
||||||
|
|
||||||
pub fn run(prog: Program) -> Result<Value_> {
|
pub fn run(prog: Program) -> Result<p::Value> {
|
||||||
let vm = VM::new(prog.thunks);
|
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 {
|
pub struct VM {
|
||||||
@@ -54,7 +55,7 @@ impl VM {
|
|||||||
match opcode {
|
match opcode {
|
||||||
OpCode::NoOp => (),
|
OpCode::NoOp => (),
|
||||||
OpCode::Const { value } => stack.push(Value::Const(value))?,
|
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 } => {
|
OpCode::LoadValue { idx } => {
|
||||||
stack.push(self.get_thunk_value(idx, env)?)?;
|
stack.push(self.get_thunk_value(idx, env)?)?;
|
||||||
}
|
}
|
||||||
@@ -128,17 +129,11 @@ impl VM {
|
|||||||
OpCode::Select { sym } => {
|
OpCode::Select { sym } => {
|
||||||
stack.tos_mut()?.select(Symbol::new(sym)).force(self, env)?;
|
stack.tos_mut()?.select(Symbol::new(sym)).force(self, env)?;
|
||||||
}
|
}
|
||||||
OpCode::SelectWithDefault { sym } => {
|
OpCode::SelectOrDefault { sym } => {
|
||||||
let default = stack.pop()?;
|
let default = stack.pop()?;
|
||||||
stack
|
stack
|
||||||
.tos_mut()?
|
.tos_mut()?
|
||||||
.select_with_default(Symbol::new(sym), default.clone());
|
.select_with_default(Symbol::new(sym), default);
|
||||||
}
|
|
||||||
OpCode::SelectOrEmpty { sym } => {
|
|
||||||
stack.tos_mut()?.select_with_default(
|
|
||||||
Symbol::new(sym),
|
|
||||||
Value::AttrSet(AttrSet::empty()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
OpCode::SelectDynamic => {
|
OpCode::SelectDynamic => {
|
||||||
let mut val = stack.pop().unwrap();
|
let mut val = stack.pop().unwrap();
|
||||||
@@ -146,21 +141,12 @@ impl VM {
|
|||||||
let sym = val.unwrap_const().unwrap_string().into();
|
let sym = val.unwrap_const().unwrap_string().into();
|
||||||
stack.tos_mut()?.select(sym);
|
stack.tos_mut()?.select(sym);
|
||||||
}
|
}
|
||||||
OpCode::SelectDynamicWithDefault => {
|
OpCode::SelectDynamicOrDefault => {
|
||||||
let mut val = stack.pop().unwrap();
|
|
||||||
val.coerce_to_string();
|
|
||||||
let sym = val.unwrap_const().unwrap_string().into();
|
|
||||||
let default = stack.pop()?;
|
let default = stack.pop()?;
|
||||||
stack.tos_mut()?.select_with_default(sym, default.clone());
|
|
||||||
}
|
|
||||||
OpCode::SelectDynamicOrEmpty => {
|
|
||||||
let mut val = stack.pop().unwrap();
|
let mut val = stack.pop().unwrap();
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = val.unwrap_const().unwrap_string().into();
|
let sym = val.unwrap_const().unwrap_string().into();
|
||||||
stack.tos_mut()?.select_with_default(
|
stack.tos_mut()?.select_with_default(sym, default);
|
||||||
sym,
|
|
||||||
Value::AttrSet(AttrSet::empty()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
OpCode::HasAttr { sym } => {
|
OpCode::HasAttr { sym } => {
|
||||||
stack.tos_mut()?.has_attr(Symbol::new(sym));
|
stack.tos_mut()?.has_attr(Symbol::new(sym));
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use derive_more::{IsVariant, Unwrap};
|
|||||||
use crate::bytecode::OpCodes;
|
use crate::bytecode::OpCodes;
|
||||||
|
|
||||||
use super::env::Env;
|
use super::env::Env;
|
||||||
use super::value::Value;
|
use crate::ty::internal::Value;
|
||||||
use super::vm::VM;
|
use super::vm::VM;
|
||||||
|
|
||||||
pub struct VmThunk {
|
pub struct VmThunk {
|
||||||
|
|||||||
Reference in New Issue
Block a user