feat: refactor
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -228,15 +228,14 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix-rs"
|
name = "nixjit"
|
||||||
version = "0.1.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"ecow",
|
"ecow",
|
||||||
"itertools",
|
"itertools",
|
||||||
"num_cpus",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rnix",
|
"rnix",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nix-rs"
|
name = "nixjit"
|
||||||
version = "0.1.0"
|
version = "0.0.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -14,6 +14,5 @@ tokio = { version = "1.38", features = [ "full" ] }
|
|||||||
rpds = "1.1"
|
rpds = "1.1"
|
||||||
derive_more = "0.99"
|
derive_more = "0.99"
|
||||||
crossbeam-channel = "0.5"
|
crossbeam-channel = "0.5"
|
||||||
num_cpus = "1.0"
|
|
||||||
ecow = "0.2"
|
ecow = "0.2"
|
||||||
once_cell = "1.19"
|
once_cell = "1.19"
|
||||||
|
|||||||
@@ -3,39 +3,55 @@ use derive_more::Constructor;
|
|||||||
use super::vm::Env;
|
use super::vm::Env;
|
||||||
use super::vm::Symbol;
|
use super::vm::Symbol;
|
||||||
use super::vm::Value;
|
use super::vm::Value;
|
||||||
use crate::bytecode::Const;
|
use crate::value::Const;
|
||||||
|
|
||||||
pub fn env() -> Env {
|
pub fn env() -> Env {
|
||||||
let mut env = Env::empty();
|
let mut env = Env::empty();
|
||||||
env.insert(Symbol::from("true"), Value::Const(Const::Bool(true)));
|
env.insert(Symbol::from("true"), Value::Const(Const::Bool(true)));
|
||||||
env.insert(Symbol::from("false"), Value::Const(Const::Bool(false)));
|
env.insert(Symbol::from("false"), Value::Const(Const::Bool(false)));
|
||||||
|
|
||||||
env.insert(Symbol::from("__add"), Value::PrimOp(PrimOp::new(2, |args| {
|
env.insert(
|
||||||
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
Symbol::from("__add"),
|
||||||
first.add(second)
|
Value::PrimOp(PrimOp::new("add", 2, |args| {
|
||||||
})));
|
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
||||||
env.insert(Symbol::from("__sub"), Value::PrimOp(PrimOp::new(2, |args| {
|
first.add(second)
|
||||||
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
})),
|
||||||
first.add(second.neg())
|
);
|
||||||
})));
|
env.insert(
|
||||||
env.insert(Symbol::from("__mul"), Value::PrimOp(PrimOp::new(2, |args| {
|
Symbol::from("__sub"),
|
||||||
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
Value::PrimOp(PrimOp::new("sub", 2, |args| {
|
||||||
first.mul(second)
|
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
||||||
})));
|
first.add(second.neg())
|
||||||
env.insert(Symbol::from("__div"), Value::PrimOp(PrimOp::new(2, |args| {
|
})),
|
||||||
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
);
|
||||||
first.div(second)
|
env.insert(
|
||||||
})));
|
Symbol::from("__mul"),
|
||||||
env.insert(Symbol::from("__lessThan"), Value::PrimOp(PrimOp::new(2, |args| {
|
Value::PrimOp(PrimOp::new("mul", 2, |args| {
|
||||||
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
||||||
first.lt(second)
|
first.mul(second)
|
||||||
})));
|
})),
|
||||||
|
);
|
||||||
|
env.insert(
|
||||||
|
Symbol::from("__div"),
|
||||||
|
Value::PrimOp(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| {
|
||||||
|
let [first, second]: [Value; 2] = args.try_into().unwrap();
|
||||||
|
first.lt(second)
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
env
|
env
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Constructor)]
|
#[derive(Debug, Clone, Constructor)]
|
||||||
pub struct PrimOp {
|
pub struct PrimOp {
|
||||||
|
name: &'static str,
|
||||||
arity: u8,
|
arity: u8,
|
||||||
func: fn(Vec<Value>) -> Value,
|
func: fn(Vec<Value>) -> Value,
|
||||||
}
|
}
|
||||||
@@ -49,7 +65,12 @@ impl PartialEq for PrimOp {
|
|||||||
impl PrimOp {
|
impl PrimOp {
|
||||||
pub fn call(self, args: Vec<Value>) -> Value {
|
pub fn call(self, args: Vec<Value>) -> Value {
|
||||||
if (args.len() as u8) < self.arity {
|
if (args.len() as u8) < self.arity {
|
||||||
Value::PartialPrimOp(PartialPrimOp { arity: self.arity - args.len() as u8, args, func: self.func })
|
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 {
|
} else if args.len() as u8 == self.arity {
|
||||||
(self.func)(args)
|
(self.func)(args)
|
||||||
} else {
|
} else {
|
||||||
@@ -58,11 +79,12 @@ impl PrimOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PartialPrimOp {
|
pub struct PartialPrimOp {
|
||||||
|
name: &'static str,
|
||||||
arity: u8,
|
arity: u8,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
func: fn(Vec<Value>) -> Value
|
func: fn(Vec<Value>) -> Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for PartialPrimOp {
|
impl PartialEq for PartialPrimOp {
|
||||||
@@ -76,7 +98,12 @@ impl PartialPrimOp {
|
|||||||
let len = args.len() as u8;
|
let len = args.len() as u8;
|
||||||
self.args.extend(args);
|
self.args.extend(args);
|
||||||
if len < self.arity {
|
if len < self.arity {
|
||||||
Value::PartialPrimOp(PartialPrimOp { arity: self.arity - len, args: self.args, func: self.func })
|
Value::PartialPrimOp(PartialPrimOp {
|
||||||
|
name: self.name,
|
||||||
|
arity: self.arity - len,
|
||||||
|
args: self.args,
|
||||||
|
func: self.func,
|
||||||
|
})
|
||||||
} else if len == self.arity {
|
} else if len == self.arity {
|
||||||
(self.func)(self.args)
|
(self.func)(self.args)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
169
src/bytecode.rs
169
src/bytecode.rs
@@ -1,11 +1,10 @@
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hash;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use anyhow::Error;
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
|
||||||
|
|
||||||
use crate::slice::Slice;
|
use crate::value::Const;
|
||||||
use crate::value::Func;
|
|
||||||
|
type Slice<T> = Box<[T]>;
|
||||||
|
|
||||||
pub type ThunkIdx = usize;
|
pub type ThunkIdx = usize;
|
||||||
pub type ConstIdx = usize;
|
pub type ConstIdx = usize;
|
||||||
@@ -23,122 +22,6 @@ pub struct Thunk {
|
|||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum Arg {}
|
pub enum Arg {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, IsVariant, Unwrap)]
|
|
||||||
pub enum Const {
|
|
||||||
Bool(bool),
|
|
||||||
Int(i64),
|
|
||||||
Float(f64),
|
|
||||||
String(EcoString),
|
|
||||||
Func(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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum OpCode {
|
pub enum OpCode {
|
||||||
/// load a constant onto stack
|
/// load a constant onto stack
|
||||||
@@ -151,60 +34,58 @@ pub enum OpCode {
|
|||||||
LoadValue { idx: ThunkIdx },
|
LoadValue { idx: ThunkIdx },
|
||||||
/// force TOS to value
|
/// force TOS to value
|
||||||
ForceValue,
|
ForceValue,
|
||||||
/// [ ... func, args @ .. ] call func with `arity` numbers of arg
|
/// [ .. 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 },
|
Call { arity: usize },
|
||||||
/// assert TOS is true then consume it
|
/// consume 1 element, assert TOS is true
|
||||||
Assert,
|
Assert,
|
||||||
/// jump forward
|
/// jump forward
|
||||||
Jmp { step: usize },
|
Jmp { step: usize },
|
||||||
/// [ ... cond ] 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 ] 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
|
||||||
RecAttrSet,
|
RecAttrSet,
|
||||||
/// [ ... set, value ] push the static kv pair (name, (value)) into (set)
|
/// [ .. set value ] consume 1 element, push a static kv pair (`name`, `value`) into `set`
|
||||||
PushStaticAttr { name: EcoString },
|
PushStaticAttr { name: EcoString },
|
||||||
/// [ ... set, name, value ] push the 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 ] push (elem) into (list)
|
/// [ .. list elem ] consume 1 element, push `elem` into `list`
|
||||||
PushElem,
|
PushElem,
|
||||||
/// [ ... a, b ] perform a binary operation ((a) `op` (b))
|
/// [ .. a b ] consume 2 elements, perform a string concatenation `a` + `b`
|
||||||
BinOp { op: BinOp },
|
|
||||||
/// [ ... a ] perform a unary operation (`op` (a))
|
|
||||||
UnOp { op: UnOp },
|
|
||||||
/// TODO:
|
|
||||||
ConcatString,
|
ConcatString,
|
||||||
/// TODO:
|
/// [ .. a b ] consume 2 elements, perform a binary operation `a` `op` `b`
|
||||||
|
BinOp { op: BinOp },
|
||||||
|
/// [ .. a ] consume 1 element, perform a unary operation `op` `a`
|
||||||
|
UnOp { op: UnOp },
|
||||||
|
/// set TOS to the bool value of whether TOS contains `sym`
|
||||||
HasAttr { sym: EcoString },
|
HasAttr { sym: EcoString },
|
||||||
/// TODO:
|
/// [ .. set sym ] consume 2 elements, set TOS to the bool value of whether `set` contains `sym`
|
||||||
HasDynamicAttr,
|
HasDynamicAttr,
|
||||||
// HasAttr { arity: usize },
|
/// [ .. set ] select `sym` from `set`
|
||||||
/// TODO:
|
|
||||||
Select { sym: EcoString },
|
Select { sym: EcoString },
|
||||||
// Select { arity: usize },
|
|
||||||
/// TODO:
|
/// TODO:
|
||||||
SelectDynamic,
|
SelectWithDefault { sym: EcoString },
|
||||||
// SelectDynamic { arity: usize },
|
|
||||||
/// TODO:
|
/// TODO:
|
||||||
SelectOrEmpty { sym: EcoString },
|
SelectOrEmpty { sym: EcoString },
|
||||||
/// TODO:
|
/// TODO:
|
||||||
SelectDynamicOrEmpty,
|
SelectDynamic,
|
||||||
/// TODO:
|
/// TODO:
|
||||||
SelectWithDefault { sym: EcoString },
|
SelectDynamicOrEmpty,
|
||||||
/// TODO:
|
/// TODO:
|
||||||
SelectDynamicWithDefault,
|
SelectDynamicWithDefault,
|
||||||
/// enter the environment of the attribute set at TOS
|
/// enter the environment of the attribute set at TOS
|
||||||
EnterEnv,
|
EnterEnv,
|
||||||
/// exit the envrironment
|
/// exit current envrironment
|
||||||
LeaveEnv,
|
LeaveEnv,
|
||||||
/// return a value
|
/// return a value
|
||||||
Ret,
|
Ret,
|
||||||
/// no-op
|
/// no operation
|
||||||
NoOp,
|
NoOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::bytecode::*;
|
use crate::bytecode::*;
|
||||||
|
use crate::value::*;
|
||||||
|
|
||||||
use super::ir;
|
use super::ir;
|
||||||
|
|
||||||
@@ -93,6 +94,27 @@ impl Compile for ir::Thunk {
|
|||||||
|
|
||||||
impl Compile for ir::Attrs {
|
impl Compile for ir::Attrs {
|
||||||
fn compile(self, comp: &mut Compiler) {
|
fn compile(self, comp: &mut Compiler) {
|
||||||
|
if self.rec {
|
||||||
|
comp.push(OpCode::AttrSet);
|
||||||
|
for dynamic in self.dyns.clone() {
|
||||||
|
dynamic.0.compile(comp);
|
||||||
|
dynamic.1.compile(comp);
|
||||||
|
comp.push(OpCode::PushDynamicAttr)
|
||||||
|
}
|
||||||
|
comp.push(OpCode::EnterEnv);
|
||||||
|
comp.push(OpCode::AttrSet);
|
||||||
|
for stc in self.stcs {
|
||||||
|
stc.1.compile(comp);
|
||||||
|
comp.push(OpCode::PushStaticAttr { name: stc.0 });
|
||||||
|
}
|
||||||
|
for dynamic in self.dyns {
|
||||||
|
dynamic.0.compile(comp);
|
||||||
|
dynamic.1.compile(comp);
|
||||||
|
comp.push(OpCode::PushDynamicAttr)
|
||||||
|
}
|
||||||
|
comp.push(OpCode::LeaveEnv);
|
||||||
|
return
|
||||||
|
}
|
||||||
comp.push(OpCode::AttrSet);
|
comp.push(OpCode::AttrSet);
|
||||||
for stc in self.stcs {
|
for stc in self.stcs {
|
||||||
stc.1.compile(comp);
|
stc.1.compile(comp);
|
||||||
@@ -106,29 +128,6 @@ impl Compile for ir::Attrs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compile for ir::RecAttrs {
|
|
||||||
fn compile(self, comp: &mut Compiler) {
|
|
||||||
comp.push(OpCode::AttrSet);
|
|
||||||
for dynamic in self.dyns.clone() {
|
|
||||||
dynamic.0.compile(comp);
|
|
||||||
dynamic.1.compile(comp);
|
|
||||||
comp.push(OpCode::PushDynamicAttr)
|
|
||||||
}
|
|
||||||
comp.push(OpCode::EnterEnv);
|
|
||||||
comp.push(OpCode::AttrSet);
|
|
||||||
for stc in self.stcs {
|
|
||||||
stc.1.compile(comp);
|
|
||||||
comp.push(OpCode::PushStaticAttr { name: stc.0 });
|
|
||||||
}
|
|
||||||
for dynamic in self.dyns {
|
|
||||||
dynamic.0.compile(comp);
|
|
||||||
dynamic.1.compile(comp);
|
|
||||||
comp.push(OpCode::PushDynamicAttr)
|
|
||||||
}
|
|
||||||
comp.push(OpCode::LeaveEnv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Compile for ir::List {
|
impl Compile for ir::List {
|
||||||
fn compile(self, comp: &mut Compiler) {
|
fn compile(self, comp: &mut Compiler) {
|
||||||
comp.push(OpCode::List);
|
comp.push(OpCode::List);
|
||||||
@@ -144,8 +143,12 @@ impl Compile for ir::UnOp {
|
|||||||
use ir::UnOpKind::*;
|
use ir::UnOpKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Neg => {
|
Neg => {
|
||||||
comp.push(OpCode::LookUp { sym: "__sub".into() });
|
comp.push(OpCode::LookUp {
|
||||||
comp.push(OpCode::Const { value: Const::Int(0) });
|
sym: "__sub".into(),
|
||||||
|
});
|
||||||
|
comp.push(OpCode::Const {
|
||||||
|
value: Const::Int(0),
|
||||||
|
});
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::Call { arity: 2 });
|
||||||
}
|
}
|
||||||
@@ -167,13 +170,17 @@ impl Compile for ir::BinOp {
|
|||||||
comp.push(OpCode::BinOp { op: BinOp::Add });
|
comp.push(OpCode::BinOp { op: BinOp::Add });
|
||||||
}
|
}
|
||||||
Mul => {
|
Mul => {
|
||||||
comp.push(OpCode::LookUp { sym: "__mul".into() });
|
comp.push(OpCode::LookUp {
|
||||||
|
sym: "__mul".into(),
|
||||||
|
});
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::Call { arity: 2 });
|
||||||
}
|
}
|
||||||
Div => {
|
Div => {
|
||||||
comp.push(OpCode::LookUp { sym: "__div".into() });
|
comp.push(OpCode::LookUp {
|
||||||
|
sym: "__div".into(),
|
||||||
|
});
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::Call { arity: 2 });
|
||||||
@@ -194,7 +201,9 @@ impl Compile for ir::BinOp {
|
|||||||
comp.push(OpCode::BinOp { op: BinOp::Eq });
|
comp.push(OpCode::BinOp { op: BinOp::Eq });
|
||||||
}
|
}
|
||||||
Lt => {
|
Lt => {
|
||||||
comp.push(OpCode::LookUp { sym: "__lessThan".into() });
|
comp.push(OpCode::LookUp {
|
||||||
|
sym: "__lessThan".into(),
|
||||||
|
});
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::Call { arity: 2 });
|
||||||
@@ -211,7 +220,9 @@ impl Compile for ir::BinOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Sub => {
|
Sub => {
|
||||||
comp.push(OpCode::LookUp { sym: "__sub".into() });
|
comp.push(OpCode::LookUp {
|
||||||
|
sym: "__sub".into(),
|
||||||
|
});
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::Call { arity: 2 });
|
||||||
@@ -229,20 +240,26 @@ impl Compile for ir::BinOp {
|
|||||||
comp.push(OpCode::UnOp { op: UnOp::Not });
|
comp.push(OpCode::UnOp { op: UnOp::Not });
|
||||||
}
|
}
|
||||||
Gt => {
|
Gt => {
|
||||||
comp.push(OpCode::LookUp { sym: "__lessThan".into() });
|
comp.push(OpCode::LookUp {
|
||||||
|
sym: "__lessThan".into(),
|
||||||
|
});
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::Call { arity: 2 });
|
||||||
}
|
}
|
||||||
Leq => {
|
Leq => {
|
||||||
comp.push(OpCode::LookUp { sym: "__lessThan".into() });
|
comp.push(OpCode::LookUp {
|
||||||
|
sym: "__lessThan".into(),
|
||||||
|
});
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::Call { arity: 2 });
|
||||||
comp.push(OpCode::UnOp { op: UnOp::Not });
|
comp.push(OpCode::UnOp { op: UnOp::Not });
|
||||||
}
|
}
|
||||||
Geq => {
|
Geq => {
|
||||||
comp.push(OpCode::LookUp { sym: "__lessThan".into() });
|
comp.push(OpCode::LookUp {
|
||||||
|
sym: "__lessThan".into(),
|
||||||
|
});
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::Call { arity: 2 });
|
||||||
@@ -372,19 +389,19 @@ 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!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compile for ir::Call {
|
impl Compile for ir::Call {
|
||||||
fn compile(self, comp: &mut Compiler) {
|
fn compile(self, _comp: &mut Compiler) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compile for ir::Path {
|
impl Compile for ir::Path {
|
||||||
fn compile(self, comp: &mut Compiler) {
|
fn compile(self, _comp: &mut Compiler) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
// TODO: Error Handling
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{Result, anyhow};
|
||||||
use rnix::ast::{self, Expr};
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
use rnix::ast::{self, Expr};
|
||||||
|
|
||||||
use crate::bytecode::{Const as ByteCodeConst, ConstIdx, Consts, ThunkIdx};
|
use crate::bytecode::{ConstIdx, Consts, ThunkIdx};
|
||||||
use crate::slice::Slice;
|
use crate::value::Const as Const_;
|
||||||
|
|
||||||
use super::compile::*;
|
use super::compile::*;
|
||||||
use super::env::IrEnv;
|
use super::env::IrEnv;
|
||||||
use super::symtable::*;
|
|
||||||
|
|
||||||
pub fn downgrade(expr: Expr) -> Result<Downgraded> {
|
pub fn downgrade(expr: Expr) -> Result<Downgraded> {
|
||||||
let mut state = DowngradeState::new();
|
let mut state = DowngradeState::new();
|
||||||
@@ -112,8 +109,7 @@ macro_rules! ir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ir! {
|
ir! {
|
||||||
Attrs => { stcs: HashMap<EcoString, Ir>, dyns: Vec<DynamicAttrPair> },
|
Attrs => { stcs: HashMap<EcoString, Ir>, dyns: Vec<DynamicAttrPair>, rec: bool },
|
||||||
RecAttrs => { stcs: HashMap<EcoString, Ir>, dyns: Vec<DynamicAttrPair> },
|
|
||||||
List => { items: Vec<Ir> },
|
List => { items: Vec<Ir> },
|
||||||
HasAttr => { lhs: Box<Ir>, rhs: Vec<Attr> },
|
HasAttr => { lhs: Box<Ir>, rhs: Vec<Attr> },
|
||||||
BinOp => { lhs: Box<Ir>, rhs: Box<Ir>, kind: BinOpKind },
|
BinOp => { lhs: Box<Ir>, rhs: Box<Ir>, kind: BinOpKind },
|
||||||
@@ -127,7 +123,7 @@ 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: ByteCodeConst },
|
Const => { value: Const_ },
|
||||||
Var => { sym: EcoString },
|
Var => { sym: EcoString },
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
Thunk => { idx: ThunkIdx },
|
Thunk => { idx: ThunkIdx },
|
||||||
@@ -165,23 +161,21 @@ pub struct DowngradeError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct DowngradeState {
|
pub struct DowngradeState {
|
||||||
sym_table: SymTable,
|
|
||||||
envs: Vec<Env>,
|
envs: Vec<Env>,
|
||||||
thunks: Vec<Ir>,
|
thunks: Vec<Ir>,
|
||||||
consts: Vec<ByteCodeConst>,
|
consts: Vec<Const_>,
|
||||||
consts_table: HashMap<ByteCodeConst, ConstIdx>,
|
consts_table: HashMap<Const_, ConstIdx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Downgraded {
|
pub struct Downgraded {
|
||||||
pub top_level: Ir,
|
pub top_level: Ir,
|
||||||
pub consts: Consts,
|
pub consts: Consts,
|
||||||
pub thunks: Slice<Ir>,
|
pub thunks: Box<[Ir]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DowngradeState {
|
impl DowngradeState {
|
||||||
fn new() -> DowngradeState {
|
fn new() -> DowngradeState {
|
||||||
DowngradeState {
|
DowngradeState {
|
||||||
sym_table: SymTable::new(),
|
|
||||||
envs: Vec::new(),
|
envs: Vec::new(),
|
||||||
thunks: Vec::new(),
|
thunks: Vec::new(),
|
||||||
consts: Vec::new(),
|
consts: Vec::new(),
|
||||||
@@ -214,6 +208,7 @@ impl Attrs {
|
|||||||
.and_then(|attrs: &mut Attrs| attrs._insert(path, name, value))
|
.and_then(|attrs: &mut Attrs| attrs._insert(path, name, value))
|
||||||
} else {
|
} else {
|
||||||
let mut attrs = Attrs {
|
let mut attrs = Attrs {
|
||||||
|
rec: false,
|
||||||
stcs: HashMap::new(),
|
stcs: HashMap::new(),
|
||||||
dyns: Vec::new(),
|
dyns: Vec::new(),
|
||||||
};
|
};
|
||||||
@@ -224,6 +219,7 @@ impl Attrs {
|
|||||||
}
|
}
|
||||||
Attr::Strs(string) => {
|
Attr::Strs(string) => {
|
||||||
let mut attrs = Attrs {
|
let mut attrs = Attrs {
|
||||||
|
rec: false,
|
||||||
stcs: HashMap::new(),
|
stcs: HashMap::new(),
|
||||||
dyns: Vec::new(),
|
dyns: Vec::new(),
|
||||||
};
|
};
|
||||||
@@ -233,6 +229,7 @@ impl Attrs {
|
|||||||
}
|
}
|
||||||
Attr::Dynamic(dynamic) => {
|
Attr::Dynamic(dynamic) => {
|
||||||
let mut attrs = Attrs {
|
let mut attrs = Attrs {
|
||||||
|
rec: false,
|
||||||
stcs: HashMap::new(),
|
stcs: HashMap::new(),
|
||||||
dyns: Vec::new(),
|
dyns: Vec::new(),
|
||||||
};
|
};
|
||||||
@@ -317,8 +314,8 @@ pub enum BinOpKind {
|
|||||||
|
|
||||||
impl From<ast::BinOpKind> for BinOpKind {
|
impl From<ast::BinOpKind> for BinOpKind {
|
||||||
fn from(op: ast::BinOpKind) -> Self {
|
fn from(op: ast::BinOpKind) -> Self {
|
||||||
use ast::BinOpKind as astkind;
|
|
||||||
use BinOpKind::*;
|
use BinOpKind::*;
|
||||||
|
use ast::BinOpKind as astkind;
|
||||||
match op {
|
match op {
|
||||||
astkind::Concat => Con,
|
astkind::Concat => Con,
|
||||||
astkind::Update => Upd,
|
astkind::Update => Upd,
|
||||||
@@ -366,7 +363,7 @@ pub enum Param {
|
|||||||
|
|
||||||
trait Downgrade
|
trait Downgrade
|
||||||
where
|
where
|
||||||
Self: Sized
|
Self: Sized,
|
||||||
{
|
{
|
||||||
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir>;
|
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir>;
|
||||||
}
|
}
|
||||||
@@ -427,9 +424,11 @@ impl Downgrade for ast::Path {
|
|||||||
.parts()
|
.parts()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => Const { value: lit.to_string().into() }
|
ast::InterpolPart::Literal(lit) => Const {
|
||||||
.ir()
|
value: lit.to_string().into(),
|
||||||
.ok(),
|
}
|
||||||
|
.ir()
|
||||||
|
.ok(),
|
||||||
ast::InterpolPart::Interpolation(interpol) => {
|
ast::InterpolPart::Interpolation(interpol) => {
|
||||||
interpol.expr().unwrap().downgrade(state)
|
interpol.expr().unwrap().downgrade(state)
|
||||||
}
|
}
|
||||||
@@ -455,9 +454,7 @@ impl Downgrade for ast::Str {
|
|||||||
.normalized_parts()
|
.normalized_parts()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => {
|
ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(),
|
||||||
Const { value: lit.into() }.ir().ok()
|
|
||||||
}
|
|
||||||
ast::InterpolPart::Interpolation(interpol) => {
|
ast::InterpolPart::Interpolation(interpol) => {
|
||||||
interpol.expr().unwrap().downgrade(state)
|
interpol.expr().unwrap().downgrade(state)
|
||||||
}
|
}
|
||||||
@@ -472,11 +469,17 @@ impl Downgrade for ast::Str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Downgrade for ast::Literal {
|
impl Downgrade for ast::Literal {
|
||||||
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> {
|
fn downgrade(self, _state: &mut DowngradeState) -> Result<Ir> {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
ast::LiteralKind::Integer(int) => Const { value: int.value().unwrap().into() },
|
ast::LiteralKind::Integer(int) => Const {
|
||||||
ast::LiteralKind::Float(float) => Const { value: float.value().unwrap().into() },
|
value: int.value().unwrap().into(),
|
||||||
ast::LiteralKind::Uri(uri) => Const { value: uri.to_string().into() },
|
},
|
||||||
|
ast::LiteralKind::Float(float) => Const {
|
||||||
|
value: float.value().unwrap().into(),
|
||||||
|
},
|
||||||
|
ast::LiteralKind::Uri(uri) => Const {
|
||||||
|
value: uri.to_string().into(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
.ir()
|
.ir()
|
||||||
.ok()
|
.ok()
|
||||||
@@ -486,7 +489,7 @@ impl Downgrade for ast::Literal {
|
|||||||
impl Downgrade for ast::Ident {
|
impl Downgrade for ast::Ident {
|
||||||
fn downgrade(self, _state: &mut DowngradeState) -> Result<Ir> {
|
fn downgrade(self, _state: &mut DowngradeState) -> Result<Ir> {
|
||||||
Var {
|
Var {
|
||||||
sym: self.to_string().into()
|
sym: self.to_string().into(),
|
||||||
}
|
}
|
||||||
.ir()
|
.ir()
|
||||||
.ok()
|
.ok()
|
||||||
@@ -584,12 +587,7 @@ impl Downgrade for ast::LetIn {
|
|||||||
let body = self.body().unwrap();
|
let body = self.body().unwrap();
|
||||||
let attrs = downgrade_has_entry(self, true, state)?;
|
let attrs = downgrade_has_entry(self, true, state)?;
|
||||||
let expr = body.downgrade(state)?.boxed();
|
let expr = body.downgrade(state)?.boxed();
|
||||||
Let {
|
Let { attrs, expr }.ir().ok()
|
||||||
attrs,
|
|
||||||
expr
|
|
||||||
}
|
|
||||||
.ir()
|
|
||||||
.ok()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,9 +634,7 @@ impl Downgrade for ast::Apply {
|
|||||||
|
|
||||||
fn downgrade_param(param: ast::Param, state: &mut DowngradeState) -> Result<Param> {
|
fn downgrade_param(param: ast::Param, state: &mut DowngradeState) -> Result<Param> {
|
||||||
match param {
|
match param {
|
||||||
ast::Param::IdentParam(ident) => {
|
ast::Param::IdentParam(ident) => Ok(Param::Ident(ident.to_string().into())),
|
||||||
Ok(Param::Ident(ident.to_string().into()))
|
|
||||||
}
|
|
||||||
ast::Param::Pattern(pattern) => downgrade_pattern(pattern, state),
|
ast::Param::Pattern(pattern) => downgrade_pattern(pattern, state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -677,6 +673,7 @@ fn downgrade_has_entry(
|
|||||||
) -> Result<Attrs> {
|
) -> Result<Attrs> {
|
||||||
let entires = has_entry.entries();
|
let entires = has_entry.entries();
|
||||||
let mut attrs = Attrs {
|
let mut attrs = Attrs {
|
||||||
|
rec,
|
||||||
stcs: HashMap::new(),
|
stcs: HashMap::new(),
|
||||||
dyns: Vec::new(),
|
dyns: Vec::new(),
|
||||||
};
|
};
|
||||||
@@ -684,9 +681,7 @@ fn downgrade_has_entry(
|
|||||||
for entry in entires {
|
for entry in entires {
|
||||||
match entry {
|
match entry {
|
||||||
ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, state)?,
|
ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, state)?,
|
||||||
ast::Entry::AttrpathValue(value) => {
|
ast::Entry::AttrpathValue(value) => downgrade_attrpathvalue(value, &mut attrs, state)?,
|
||||||
downgrade_attrpathvalue(value, &mut attrs, state)?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,7 +705,7 @@ fn downgrade_inherit(
|
|||||||
_ => return Err(anyhow!("dynamic attributes not allowed in inherit")),
|
_ => return Err(anyhow!("dynamic attributes not allowed in inherit")),
|
||||||
};
|
};
|
||||||
let expr = from.map_or_else(
|
let expr = from.map_or_else(
|
||||||
|| Var { sym: ident.clone() }.ir().ok(),
|
|| Var { sym: ident.clone() }.ir().ok(),
|
||||||
|from| {
|
|from| {
|
||||||
Ok(Select {
|
Ok(Select {
|
||||||
expr: from.ir().boxed(),
|
expr: from.ir().boxed(),
|
||||||
@@ -739,9 +734,7 @@ fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result<Attr> {
|
|||||||
let parts = parts
|
let parts = parts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => {
|
ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(),
|
||||||
Const { value: lit.into() }.ir().ok()
|
|
||||||
}
|
|
||||||
ast::InterpolPart::Interpolation(interpol) => {
|
ast::InterpolPart::Interpolation(interpol) => {
|
||||||
interpol.expr().unwrap().downgrade(state)
|
interpol.expr().unwrap().downgrade(state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
mod compile;
|
mod compile;
|
||||||
mod env;
|
mod env;
|
||||||
mod ir;
|
mod ir;
|
||||||
mod symtable;
|
|
||||||
|
|
||||||
pub fn compile(expr: &str) -> anyhow::Result<crate::bytecode::Program> {
|
pub fn compile(expr: &str) -> anyhow::Result<crate::bytecode::Program> {
|
||||||
let expr = rnix::Root::parse(expr).tree().expr().unwrap();
|
let expr = rnix::Root::parse(expr).tree().expr().unwrap();
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::bytecode::SymIdx;
|
|
||||||
use crate::slice::Slice;
|
|
||||||
|
|
||||||
// FIXME: don't store syms twice to make it more memory efficient?
|
|
||||||
|
|
||||||
pub struct SymTable {
|
|
||||||
syms: Vec<String>,
|
|
||||||
syms_table: HashMap<String, SymIdx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SymTable {
|
|
||||||
pub fn new() -> SymTable {
|
|
||||||
SymTable {
|
|
||||||
syms: Vec::new(),
|
|
||||||
syms_table: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lookup(&mut self, name: String) -> SymIdx {
|
|
||||||
if let Some(sym) = self.syms_table.get(&name) {
|
|
||||||
*sym
|
|
||||||
} else {
|
|
||||||
let sym = self.syms.len();
|
|
||||||
self.syms.push(name.clone());
|
|
||||||
self.syms_table.insert(name, sym);
|
|
||||||
sym
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn syms(self) -> Slice<String> {
|
|
||||||
self.syms.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,5 @@ mod builtins;
|
|||||||
mod bytecode;
|
mod bytecode;
|
||||||
mod compile;
|
mod compile;
|
||||||
mod downcast;
|
mod downcast;
|
||||||
mod slice;
|
|
||||||
mod value;
|
mod value;
|
||||||
mod vm;
|
mod vm;
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
pub type Slice<T> = Box<[T]>;
|
|
||||||
|
|
||||||
124
src/value/cnst.rs
Normal file
124
src/value/cnst.rs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
use anyhow::Error;
|
||||||
|
use derive_more::{IsVariant, Unwrap};
|
||||||
|
|
||||||
|
use ecow::EcoString;
|
||||||
|
|
||||||
|
use super::Func;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, IsVariant, Unwrap)]
|
||||||
|
pub enum Const {
|
||||||
|
Bool(bool),
|
||||||
|
Int(i64),
|
||||||
|
Float(f64),
|
||||||
|
String(EcoString),
|
||||||
|
Func(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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
|
use std::fmt::{Debug, Formatter, Result as FmtResult};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
use derive_more::{Constructor, IsVariant, Unwrap};
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use rpds::{HashTrieMapSync, VectorSync};
|
use rpds::{HashTrieMapSync, VectorSync};
|
||||||
|
|
||||||
use crate::bytecode::{Args, Const, OpCodes};
|
use crate::bytecode::{Args, OpCodes};
|
||||||
|
|
||||||
|
mod cnst;
|
||||||
|
|
||||||
|
pub use cnst::Const;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)]
|
||||||
pub struct Symbol(EcoString);
|
pub struct Symbol(EcoString);
|
||||||
@@ -93,7 +96,7 @@ pub struct List {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Constructor)]
|
#[derive(Clone, Debug, PartialEq, Constructor)]
|
||||||
pub struct Catchable {
|
pub struct Catchable {
|
||||||
msg: Option<String>
|
msg: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)]
|
#[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use rpds::HashTrieMapSync;
|
|||||||
use super::value::{Symbol, VmValue};
|
use super::value::{Symbol, VmValue};
|
||||||
|
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
last: Option<*mut Env>,
|
last: Option<Box<Env>>,
|
||||||
map: HashTrieMapSync<Symbol, VmValue>,
|
map: HashTrieMapSync<Symbol, VmValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ impl Env {
|
|||||||
if let Some(value) = self.map.get(&symbol) {
|
if let Some(value) = self.map.get(&symbol) {
|
||||||
value.clone()
|
value.clone()
|
||||||
} else {
|
} else {
|
||||||
let last = unsafe { &*self.last.unwrap() };
|
let last = self.last.as_ref().unwrap();
|
||||||
last.lookup(symbol)
|
last.lookup(symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,19 +29,13 @@ impl Env {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter(&mut self, map: HashTrieMapSync<Symbol, VmValue>) {
|
pub fn enter(&mut self, map: HashTrieMapSync<Symbol, VmValue>) {
|
||||||
let last = std::mem::replace(
|
let last = std::mem::replace(self, Env { last: None, map });
|
||||||
self,
|
self.last = Some(Box::new(last));
|
||||||
Env {
|
|
||||||
last: None,
|
|
||||||
map,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
self.last = Some(Box::leak(Box::new(last)) as *mut Env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn leave(&mut self) {
|
pub fn leave(&mut self) {
|
||||||
let last = unsafe { &*self.last.unwrap() };
|
let last = std::mem::replace(&mut self.last, None).unwrap();
|
||||||
self.last = last.last;
|
let _ = std::mem::replace(&mut self.last, last.last);
|
||||||
self.map = last.map.clone();
|
self.map = last.map.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::mem::{size_of, transmute, MaybeUninit};
|
use std::mem::{MaybeUninit, size_of, transmute};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{Result, anyhow};
|
||||||
|
|
||||||
use super::value::VmValue;
|
use super::value::VmValue;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use rpds::{ht_map_sync, vector_sync};
|
|||||||
|
|
||||||
use crate::compile::compile;
|
use crate::compile::compile;
|
||||||
use crate::value::*;
|
use crate::value::*;
|
||||||
use crate::bytecode::Const;
|
|
||||||
|
|
||||||
use super::vm::run;
|
use super::vm::run;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,14 @@ pub struct AttrSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AttrSet {
|
impl AttrSet {
|
||||||
|
pub fn push_attr_force(&mut self, sym: Symbol, val: VmValue) {
|
||||||
|
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: VmValue) {
|
||||||
|
if self.data.get(&sym).is_some() {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
self.data.insert_mut(sym, val);
|
self.data.insert_mut(sym, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +33,7 @@ impl AttrSet {
|
|||||||
|
|
||||||
pub fn update(mut self, other: AttrSet) -> AttrSet {
|
pub fn update(mut self, other: AttrSet) -> AttrSet {
|
||||||
for (k, v) in other.data.iter() {
|
for (k, v) in other.data.iter() {
|
||||||
self.push_attr(k.clone(), v.clone())
|
self.push_attr_force(k.clone(), v.clone())
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -41,7 +48,12 @@ impl ToValue for AttrSet {
|
|||||||
Value::AttrSet(value::AttrSet::new(
|
Value::AttrSet(value::AttrSet::new(
|
||||||
self.data
|
self.data
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(sym, value)| (value::Symbol::new(sym.0.clone()), value.clone().to_value(vm)))
|
.map(|(sym, value)| {
|
||||||
|
(
|
||||||
|
value::Symbol::new(sym.0.clone()),
|
||||||
|
value.clone().to_value(vm),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use derive_more::{Constructor, IsVariant, Unwrap};
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
|
||||||
use crate::value::*;
|
use crate::value::*;
|
||||||
use crate::bytecode::Const;
|
|
||||||
|
|
||||||
use super::vm::VM;
|
|
||||||
use super::env::Env;
|
use super::env::Env;
|
||||||
|
use super::vm::VM;
|
||||||
|
|
||||||
mod attrset;
|
mod attrset;
|
||||||
mod list;
|
mod list;
|
||||||
@@ -40,7 +39,7 @@ pub enum VmValue {
|
|||||||
List(List),
|
List(List),
|
||||||
Catchable(crate::value::Catchable),
|
Catchable(crate::value::Catchable),
|
||||||
PrimOp(crate::builtins::PrimOp),
|
PrimOp(crate::builtins::PrimOp),
|
||||||
PartialPrimOp(crate::builtins::PartialPrimOp)
|
PartialPrimOp(crate::builtins::PartialPrimOp),
|
||||||
}
|
}
|
||||||
|
|
||||||
use VmValue::Const as VmConst;
|
use VmValue::Const as VmConst;
|
||||||
@@ -49,7 +48,7 @@ impl VmValue {
|
|||||||
match self {
|
match self {
|
||||||
VmValue::PrimOp(func) => func.call(args),
|
VmValue::PrimOp(func) => func.call(args),
|
||||||
VmValue::PartialPrimOp(func) => func.call(args),
|
VmValue::PartialPrimOp(func) => func.call(args),
|
||||||
_ => todo!()
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +89,7 @@ impl VmValue {
|
|||||||
(VmConst(Float(a)), VmConst(Int(b))) => a < b as f64,
|
(VmConst(Float(a)), VmConst(Int(b))) => a < b as f64,
|
||||||
(VmConst(Float(a)), VmConst(Float(b))) => a < b,
|
(VmConst(Float(a)), VmConst(Float(b))) => a < b,
|
||||||
(VmConst(String(a)), VmConst(String(b))) => a < b,
|
(VmConst(String(a)), VmConst(String(b))) => a < b,
|
||||||
_ => todo!()
|
_ => todo!(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +143,9 @@ impl VmValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn concat_string(&mut self, mut other: VmValue) -> &mut Self {
|
pub fn concat_string(&mut self, mut other: VmValue) -> &mut Self {
|
||||||
if let (VmConst(Const::String(a)), VmConst(Const::String(b))) = (self.coerce_to_string(), other.coerce_to_string()) {
|
if let (VmConst(Const::String(a)), VmConst(Const::String(b))) =
|
||||||
|
(self.coerce_to_string(), other.coerce_to_string())
|
||||||
|
{
|
||||||
a.push_str(b.as_str());
|
a.push_str(b.as_str());
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
@@ -190,7 +191,9 @@ impl VmValue {
|
|||||||
if let VmValue::AttrSet(attrs) = self {
|
if let VmValue::AttrSet(attrs) = self {
|
||||||
let val = attrs
|
let val = attrs
|
||||||
.select(sym.clone())
|
.select(sym.clone())
|
||||||
.unwrap_or(VmValue::Catchable(Catchable::new(Some(format!("{sym:?} not found")))));
|
.unwrap_or(VmValue::Catchable(Catchable::new(Some(format!(
|
||||||
|
"{sym:?} not found"
|
||||||
|
)))));
|
||||||
*self = val;
|
*self = val;
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
|
|||||||
30
src/vm/vm.rs
30
src/vm/vm.rs
@@ -1,13 +1,12 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::Result;
|
||||||
use rpds::{HashTrieMap, HashTrieMapSync, Vector};
|
use rpds::{HashTrieMap, HashTrieMapSync, Vector};
|
||||||
|
|
||||||
use crate::bytecode::{self, *};
|
|
||||||
use crate::slice::*;
|
|
||||||
use crate::value::{self, Value};
|
|
||||||
use crate::builtins::env;
|
use crate::builtins::env;
|
||||||
|
use crate::bytecode::{self, *};
|
||||||
|
use crate::value::{Const, Value};
|
||||||
|
|
||||||
use super::env::Env;
|
use super::env::Env;
|
||||||
use super::stack::{Stack, STACK_SIZE};
|
use super::stack::{STACK_SIZE, Stack};
|
||||||
use super::value::{self as vmValue, *};
|
use super::value::{self as vmValue, *};
|
||||||
use super::vmthunk::*;
|
use super::vmthunk::*;
|
||||||
|
|
||||||
@@ -17,7 +16,7 @@ pub fn run(prog: Program) -> Result<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct VM {
|
pub struct VM {
|
||||||
thunks: Slice<VmThunk>,
|
thunks: Box<[VmThunk]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VM {
|
impl VM {
|
||||||
@@ -26,9 +25,7 @@ impl VM {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|bytecode::Thunk { opcodes }| VmThunk::new(opcodes))
|
.map(|bytecode::Thunk { opcodes }| VmThunk::new(opcodes))
|
||||||
.collect();
|
.collect();
|
||||||
VM {
|
VM { thunks }
|
||||||
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<VmValue> {
|
||||||
@@ -77,7 +74,7 @@ impl VM {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpCode::Call { arity } => {
|
OpCode::Call { arity } => {
|
||||||
let mut args = Vec::with_capacity(arity);
|
let mut args = Vec::with_capacity(arity);
|
||||||
for _ in 0..arity {
|
for _ in 0..arity {
|
||||||
args.insert(0, stack.pop()?);
|
args.insert(0, stack.pop()?);
|
||||||
}
|
}
|
||||||
@@ -139,9 +136,10 @@ impl VM {
|
|||||||
.select_with_default(Symbol::new(sym), default.clone());
|
.select_with_default(Symbol::new(sym), default.clone());
|
||||||
}
|
}
|
||||||
OpCode::SelectOrEmpty { sym } => {
|
OpCode::SelectOrEmpty { sym } => {
|
||||||
stack
|
stack.tos_mut()?.select_with_default(
|
||||||
.tos_mut()?
|
Symbol::new(sym),
|
||||||
.select_with_default(Symbol::new(sym), VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync())));
|
VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
OpCode::SelectDynamic => {
|
OpCode::SelectDynamic => {
|
||||||
let mut val = stack.pop().unwrap();
|
let mut val = stack.pop().unwrap();
|
||||||
@@ -160,7 +158,10 @@ impl VM {
|
|||||||
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(sym, VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync())));
|
stack.tos_mut()?.select_with_default(
|
||||||
|
sym,
|
||||||
|
VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
OpCode::HasAttr { sym } => {
|
OpCode::HasAttr { sym } => {
|
||||||
stack.tos_mut()?.has_attr(Symbol::new(sym));
|
stack.tos_mut()?.has_attr(Symbol::new(sym));
|
||||||
@@ -185,4 +186,3 @@ impl VM {
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{Result, anyhow};
|
||||||
use derive_more::{IsVariant, Unwrap};
|
use derive_more::{IsVariant, Unwrap};
|
||||||
|
|
||||||
use crate::bytecode::OpCodes;
|
use crate::bytecode::OpCodes;
|
||||||
|
|
||||||
use super::vm::VM;
|
|
||||||
use super::env::Env;
|
use super::env::Env;
|
||||||
use super::value::VmValue;
|
use super::value::VmValue;
|
||||||
|
use super::vm::VM;
|
||||||
|
|
||||||
pub struct VmThunk {
|
pub struct VmThunk {
|
||||||
thunk: RefCell<_VmThunk>,
|
thunk: RefCell<_VmThunk>,
|
||||||
lock: RwLock<()>
|
lock: RwLock<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(IsVariant, Unwrap)]
|
#[derive(IsVariant, Unwrap)]
|
||||||
@@ -26,7 +26,7 @@ impl VmThunk {
|
|||||||
pub fn new(opcodes: OpCodes) -> VmThunk {
|
pub fn new(opcodes: OpCodes) -> VmThunk {
|
||||||
VmThunk {
|
VmThunk {
|
||||||
thunk: RefCell::new(_VmThunk::Code(opcodes)),
|
thunk: RefCell::new(_VmThunk::Code(opcodes)),
|
||||||
lock: RwLock::new(())
|
lock: RwLock::new(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ impl VmThunk {
|
|||||||
_VmThunk::Value(value) => return Ok(value.clone()),
|
_VmThunk::Value(value) => return Ok(value.clone()),
|
||||||
_VmThunk::SuspendedFrom(from) => {
|
_VmThunk::SuspendedFrom(from) => {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"already suspended from {from:p} (infinite recursion encountered)"
|
"already suspended from {from:p} (infinite recursion encountered)"
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
_VmThunk::Code(_) => (),
|
_VmThunk::Code(_) => (),
|
||||||
}
|
}
|
||||||
@@ -48,9 +48,13 @@ impl VmThunk {
|
|||||||
let opcodes = std::mem::replace(
|
let opcodes = std::mem::replace(
|
||||||
&mut *self.thunk.borrow_mut(),
|
&mut *self.thunk.borrow_mut(),
|
||||||
_VmThunk::SuspendedFrom(self as *const VmThunk),
|
_VmThunk::SuspendedFrom(self as *const VmThunk),
|
||||||
).unwrap_code();
|
)
|
||||||
|
.unwrap_code();
|
||||||
let value = vm.eval(opcodes, env).unwrap();
|
let value = vm.eval(opcodes, env).unwrap();
|
||||||
let _ = std::mem::replace(&mut *self.thunk.borrow_mut(), _VmThunk::Value(value.clone()));
|
let _ = std::mem::replace(
|
||||||
|
&mut *self.thunk.borrow_mut(),
|
||||||
|
_VmThunk::Value(value.clone()),
|
||||||
|
);
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user