feat: a lot
This commit is contained in:
@@ -3,7 +3,7 @@ use std::rc::Rc;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use nixjit_error::{Error, Result};
|
||||
use nixjit_ir::{self as ir, ExprId};
|
||||
use nixjit_ir::{self as ir, ArgIdx, ExprId, PrimOpId};
|
||||
use nixjit_lir as lir;
|
||||
use nixjit_value::{Const, Symbol};
|
||||
|
||||
@@ -12,35 +12,31 @@ pub use crate::value::*;
|
||||
mod value;
|
||||
|
||||
pub trait EvalContext: Sized {
|
||||
fn eval(&mut self, expr: ExprId) -> Result<Value<Self>>;
|
||||
fn eval(&mut self, expr: &ExprId) -> Result<Value>;
|
||||
fn with_with_env<T>(
|
||||
&mut self,
|
||||
namespace: Rc<HashMap<String, Value<Self>>>,
|
||||
namespace: Rc<HashMap<String, Value>>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T;
|
||||
fn with_args_env<T>(
|
||||
&mut self,
|
||||
args: Vec<Value<Self>>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> (Vec<Value<Self>>, T);
|
||||
fn lookup_with<'a>(&'a self, ident: &str) -> Option<&'a Value<Self>>;
|
||||
fn lookup_arg<'a>(&'a self, offset: usize) -> Option<&'a Value<Self>>;
|
||||
fn pop_frame(&mut self) -> Vec<Value<Self>>;
|
||||
fn consume_arg(&mut self, func: ExprId) -> Result<bool>;
|
||||
fn with_args_env<T>(&mut self, args: Vec<Value>, f: impl FnOnce(&mut Self) -> T) -> (Vec<Value>, T);
|
||||
fn lookup_with<'a>(&'a self, ident: &str) -> Option<&'a Value>;
|
||||
fn lookup_arg<'a>(&'a self, idx: ArgIdx) -> &'a Value;
|
||||
fn pop_frame(&mut self) -> Vec<Value>;
|
||||
fn call_primop(&mut self, id: PrimOpId, args: Vec<Value>) -> Result<Value>;
|
||||
}
|
||||
|
||||
pub trait Evaluate<Ctx: EvalContext> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>>;
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value>;
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ExprId {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
ctx.eval(*self)
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
ctx.eval(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for lir::Lir {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
use lir::Lir::*;
|
||||
match self {
|
||||
AttrSet(x) => x.eval(ctx),
|
||||
@@ -58,26 +54,16 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for lir::Lir {
|
||||
Str(x) => x.eval(ctx),
|
||||
Var(x) => x.eval(ctx),
|
||||
Path(x) => x.eval(ctx),
|
||||
ExprRef(expr) => expr.eval(ctx),
|
||||
&FuncRef(func) => {
|
||||
if ctx.consume_arg(func)? {
|
||||
ctx.eval(func)
|
||||
} else {
|
||||
Ok(Value::Func(func))
|
||||
}
|
||||
},
|
||||
&ArgRef(arg) => {
|
||||
let idx: usize = unsafe { core::mem::transmute(arg) };
|
||||
ctx.lookup_arg(idx)
|
||||
.cloned()
|
||||
.ok_or_else(|| Error::EvalError("argument not found".to_string()))
|
||||
}
|
||||
ExprRef(expr) => ctx.eval(expr),
|
||||
FuncRef(func) => Ok(Value::Func(unsafe { func.clone() })),
|
||||
&ArgRef(idx) => Ok(ctx.lookup_arg(idx).clone()),
|
||||
&PrimOp(primop) => Ok(Value::PrimOp(primop)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::AttrSet {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
let mut attrs = AttrSet::new(
|
||||
self.stcs
|
||||
.iter()
|
||||
@@ -99,7 +85,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::AttrSet {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::List {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
let items = self
|
||||
.items
|
||||
.iter()
|
||||
@@ -111,7 +97,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::List {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::HasAttr {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
use ir::Attr::*;
|
||||
let mut val = self.lhs.eval(ctx)?;
|
||||
val.has_attr(self.rhs.iter().map(|attr| {
|
||||
@@ -130,7 +116,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::HasAttr {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::BinOp {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
use ir::BinOpKind::*;
|
||||
let mut lhs = self.lhs.eval(ctx)?;
|
||||
let mut rhs = self.rhs.eval(ctx)?;
|
||||
@@ -169,9 +155,9 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::BinOp {
|
||||
}
|
||||
Con => lhs.concat(rhs),
|
||||
Upd => lhs.update(rhs),
|
||||
PipeL => lhs.call(vec![rhs], ctx)?,
|
||||
PipeL => lhs.call(core::iter::once(Ok(rhs)), ctx)?,
|
||||
PipeR => {
|
||||
rhs.call(vec![lhs], ctx)?;
|
||||
rhs.call(core::iter::once(Ok(lhs)), ctx)?;
|
||||
lhs = rhs;
|
||||
}
|
||||
}
|
||||
@@ -180,7 +166,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::BinOp {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::UnOp {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
use ir::UnOpKind::*;
|
||||
let mut rhs = self.rhs.eval(ctx)?;
|
||||
match self.kind {
|
||||
@@ -196,7 +182,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::UnOp {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Select {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
use ir::Attr::*;
|
||||
let mut val = self.expr.eval(ctx)?;
|
||||
if let Some(default) = &self.default {
|
||||
@@ -232,7 +218,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Select {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::If {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
// TODO: Error Handling
|
||||
let cond = self.cond.eval(ctx)?;
|
||||
let cond = cond
|
||||
@@ -248,21 +234,22 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::If {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Call {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
let mut func = self.func.eval(ctx)?;
|
||||
// FIXME: ?
|
||||
let ctx_mut = unsafe { &mut *(ctx as *mut Ctx) };
|
||||
func.call(
|
||||
self.args
|
||||
.iter()
|
||||
.map(|arg| arg.eval(ctx))
|
||||
.collect::<Result<_>>()?,
|
||||
ctx,
|
||||
.map(|arg| arg.eval(ctx)),
|
||||
ctx_mut,
|
||||
)?;
|
||||
Ok(func.ok().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::With {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
let namespace = self.namespace.eval(ctx)?;
|
||||
ctx.with_with_env(
|
||||
namespace
|
||||
@@ -275,7 +262,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::With {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Assert {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
let cond = self.assertion.eval(ctx)?;
|
||||
let cond = cond
|
||||
.try_unwrap_bool()
|
||||
@@ -289,7 +276,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Assert {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::ConcatStrings {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
let mut parts = self
|
||||
.parts
|
||||
.iter()
|
||||
@@ -310,14 +297,14 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::ConcatStrings {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Str {
|
||||
fn eval(&self, _: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, _: &mut Ctx) -> Result<Value> {
|
||||
let result = Value::String(self.val.clone()).ok();
|
||||
Ok(result.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Const {
|
||||
fn eval(&self, _: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, _: &mut Ctx) -> Result<Value> {
|
||||
let result = match self.val {
|
||||
Const::Null => Value::Null,
|
||||
Const::Int(x) => Value::Int(x),
|
||||
@@ -330,7 +317,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Const {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Var {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
ctx.lookup_with(&self.sym)
|
||||
.ok_or_else(|| {
|
||||
Error::EvalError(format!(
|
||||
@@ -343,7 +330,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Var {
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Path {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
|
||||
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use derive_more::Constructor;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
@@ -15,11 +15,11 @@ use crate::EvalContext;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Constructor, PartialEq)]
|
||||
pub struct AttrSet<Ctx: EvalContext> {
|
||||
data: HashMap<String, Value<Ctx>>,
|
||||
pub struct AttrSet {
|
||||
data: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Debug for AttrSet<Ctx> {
|
||||
impl Debug for AttrSet {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use Value::*;
|
||||
write!(f, "{{ ")?;
|
||||
@@ -34,7 +34,7 @@ impl<Ctx: EvalContext> Debug for AttrSet<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Clone for AttrSet<Ctx> {
|
||||
impl Clone for AttrSet {
|
||||
fn clone(&self) -> Self {
|
||||
AttrSet {
|
||||
data: self.data.clone(),
|
||||
@@ -42,31 +42,31 @@ impl<Ctx: EvalContext> Clone for AttrSet<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> From<HashMap<String, Value<Ctx>>> for AttrSet<Ctx> {
|
||||
fn from(data: HashMap<String, Value<Ctx>>) -> Self {
|
||||
impl From<HashMap<String, Value>> for AttrSet {
|
||||
fn from(data: HashMap<String, Value>) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Deref for AttrSet<Ctx> {
|
||||
type Target = HashMap<String, Value<Ctx>>;
|
||||
impl Deref for AttrSet {
|
||||
type Target = HashMap<String, Value>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> AttrSet<Ctx> {
|
||||
impl AttrSet {
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
AttrSet {
|
||||
data: HashMap::with_capacity(cap),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_attr_force(&mut self, sym: String, val: Value<Ctx>) {
|
||||
pub fn push_attr_force(&mut self, sym: String, val: Value) {
|
||||
self.data.insert(sym, val);
|
||||
}
|
||||
|
||||
pub fn push_attr(&mut self, sym: String, val: Value<Ctx>) {
|
||||
pub fn push_attr(&mut self, sym: String, val: Value) {
|
||||
if self.data.get(&sym).is_some() {
|
||||
todo!()
|
||||
}
|
||||
@@ -76,7 +76,7 @@ impl<Ctx: EvalContext> AttrSet<Ctx> {
|
||||
pub fn select(
|
||||
&self,
|
||||
mut path: impl DoubleEndedIterator<Item = Result<String>>,
|
||||
) -> Result<Value<Ctx>> {
|
||||
) -> Result<Value> {
|
||||
let mut data = &self.data;
|
||||
let last = path.nth_back(0).unwrap();
|
||||
for item in path {
|
||||
@@ -116,15 +116,15 @@ impl<Ctx: EvalContext> AttrSet<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_inner(&self) -> &HashMap<String, Value<Ctx>> {
|
||||
pub fn as_inner(&self) -> &HashMap<String, Value> {
|
||||
&self.data
|
||||
}
|
||||
|
||||
pub fn into_inner(self: Rc<Self>) -> Rc<HashMap<String, Value<Ctx>>> {
|
||||
pub fn into_inner(self: Rc<Self>) -> Rc<HashMap<String, Value>> {
|
||||
unsafe { core::mem::transmute(self) }
|
||||
}
|
||||
|
||||
pub fn from_inner(data: HashMap<String, Value<Ctx>>) -> Self {
|
||||
pub fn from_inner(data: HashMap<String, Value>) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
|
||||
@@ -137,11 +137,11 @@ impl<Ctx: EvalContext> AttrSet<Ctx> {
|
||||
.all(|((k1, v1), (k2, v2))| k1 == k2 && v1.eq_impl(v2))
|
||||
}
|
||||
|
||||
pub fn to_public(&self, ctx: &Ctx, seen: &mut HashSet<Value<Ctx>>) -> p::Value {
|
||||
pub fn to_public(&self, seen: &mut HashSet<Value>) -> p::Value {
|
||||
p::Value::AttrSet(p::AttrSet::new(
|
||||
self.data
|
||||
.iter()
|
||||
.map(|(sym, value)| (sym.as_str().into(), value.to_public(ctx, seen)))
|
||||
.map(|(sym, value)| (sym.as_str().into(), value.to_public(seen)))
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -9,39 +9,59 @@ use super::Value;
|
||||
use crate::EvalContext;
|
||||
|
||||
#[derive(Debug, Constructor)]
|
||||
pub struct FuncApp<Ctx: EvalContext> {
|
||||
pub struct FuncApp {
|
||||
pub body: ExprId,
|
||||
pub args: Vec<Value<Ctx>>,
|
||||
pub frame: Vec<Value<Ctx>>,
|
||||
pub args: Vec<Value>,
|
||||
pub frame: Vec<Value>,
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Clone for FuncApp<Ctx> {
|
||||
impl Clone for FuncApp {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
body: self.body,
|
||||
body: unsafe { self.body.clone() },
|
||||
args: self.args.clone(),
|
||||
frame: self.frame.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> FuncApp<Ctx> {
|
||||
pub fn call(
|
||||
impl FuncApp {
|
||||
pub fn call<Ctx: EvalContext>(
|
||||
self: &mut Rc<Self>,
|
||||
new_args: Vec<Value<Ctx>>,
|
||||
mut iter: impl Iterator<Item = Result<Value>> + ExactSizeIterator,
|
||||
ctx: &mut Ctx,
|
||||
) -> Result<Value<Ctx>> {
|
||||
let FuncApp { body: expr, args, frame } = Rc::make_mut(self);
|
||||
args.extend(new_args);
|
||||
let (args, ret) = ctx.with_args_env(core::mem::take(args), |ctx| ctx.eval(*expr));
|
||||
let mut ret = ret?;
|
||||
if let Value::Func(expr) = ret {
|
||||
let frame = ctx.pop_frame();
|
||||
ret = Value::FuncApp(FuncApp::new(expr, args, frame).into());
|
||||
} else if let Value::FuncApp(func) = &mut ret {
|
||||
todo!();
|
||||
let func = Rc::make_mut(func);
|
||||
) -> Result<Value> {
|
||||
let FuncApp {
|
||||
body: expr,
|
||||
args,
|
||||
frame,
|
||||
} = Rc::make_mut(self);
|
||||
let mut val;
|
||||
let mut args = core::mem::take(args);
|
||||
args.push(iter.next().unwrap()?);
|
||||
let (ret_args, ret) = ctx.with_args_env(args, |ctx| ctx.eval(expr));
|
||||
args = ret_args;
|
||||
val = ret?;
|
||||
loop {
|
||||
if !matches!(val, Value::Func(_) | Value::FuncApp(_)) {
|
||||
break;
|
||||
}
|
||||
let Some(arg) = iter.next() else {
|
||||
break;
|
||||
};
|
||||
args.push(arg?);
|
||||
if let Value::Func(expr) = val {
|
||||
let (ret_args, ret) = ctx.with_args_env(args, |ctx| ctx.eval(&expr));
|
||||
args = ret_args;
|
||||
val = ret?;
|
||||
} else if let Value::FuncApp(func) = val {
|
||||
let mut func = Rc::unwrap_or_clone(func);
|
||||
func.args.push(args.pop().unwrap());
|
||||
let (ret_args, ret) = ctx.with_args_env(func.args, |ctx| ctx.eval(&func.body));
|
||||
args = ret_args;
|
||||
val = ret?;
|
||||
}
|
||||
}
|
||||
ret.ok()
|
||||
val.ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::ops::Deref;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
|
||||
@@ -10,11 +10,11 @@ use super::Value;
|
||||
use crate::EvalContext;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct List<Ctx: EvalContext> {
|
||||
data: Vec<Value<Ctx>>,
|
||||
pub struct List {
|
||||
data: Vec<Value>,
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Debug for List<Ctx> {
|
||||
impl Debug for List {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "[ ")?;
|
||||
for v in self.data.iter() {
|
||||
@@ -24,7 +24,7 @@ impl<Ctx: EvalContext> Debug for List<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Clone for List<Ctx> {
|
||||
impl Clone for List {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
data: self.data.clone(),
|
||||
@@ -32,20 +32,20 @@ impl<Ctx: EvalContext> Clone for List<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext, T: Into<Vec<Value<Ctx>>>> From<T> for List<Ctx> {
|
||||
impl<T: Into<Vec<Value>>> From<T> for List {
|
||||
fn from(value: T) -> Self {
|
||||
Self { data: value.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Deref for List<Ctx> {
|
||||
type Target = [Value<Ctx>];
|
||||
impl Deref for List {
|
||||
type Target = [Value];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> List<Ctx> {
|
||||
impl List {
|
||||
pub fn new() -> Self {
|
||||
List { data: Vec::new() }
|
||||
}
|
||||
@@ -56,7 +56,7 @@ impl<Ctx: EvalContext> List<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, elem: Value<Ctx>) {
|
||||
pub fn push(&mut self, elem: Value) {
|
||||
self.data.push(elem);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ impl<Ctx: EvalContext> List<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> Vec<Value<Ctx>> {
|
||||
pub fn into_inner(self) -> Vec<Value> {
|
||||
self.data
|
||||
}
|
||||
|
||||
@@ -75,11 +75,11 @@ impl<Ctx: EvalContext> List<Ctx> {
|
||||
&& core::iter::zip(self.iter(), other.iter()).all(|(a, b)| a.eq_impl(b))
|
||||
}
|
||||
|
||||
pub fn to_public(&self, engine: &Ctx, seen: &mut HashSet<Value<Ctx>>) -> PubValue {
|
||||
pub fn to_public(&self, seen: &mut HashSet<Value>) -> PubValue {
|
||||
PubValue::List(PubList::new(
|
||||
self.data
|
||||
.iter()
|
||||
.map(|value| value.clone().to_public(engine, seen))
|
||||
.map(|value| value.clone().to_public(seen))
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::process::abort;
|
||||
use std::rc::Rc;
|
||||
use std::fmt::{write, Debug};
|
||||
|
||||
use derive_more::TryUnwrap;
|
||||
use derive_more::{IsVariant, Unwrap};
|
||||
use func::FuncApp;
|
||||
use hashbrown::HashSet;
|
||||
use nixjit_ir::ExprId;
|
||||
use replace_with::{replace_with_and_return, replace_with_or_abort};
|
||||
use nixjit_ir::{ExprId, PrimOp};
|
||||
use replace_with::replace_with_and_return;
|
||||
|
||||
use nixjit_error::{Error, Result};
|
||||
use nixjit_value::Const;
|
||||
@@ -23,28 +22,29 @@ mod primop;
|
||||
mod string;
|
||||
|
||||
pub use attrset::*;
|
||||
pub use func::*;
|
||||
pub use list::List;
|
||||
pub use primop::*;
|
||||
|
||||
#[repr(C, u64)]
|
||||
#[derive(IsVariant, TryUnwrap, Unwrap)]
|
||||
pub enum Value<Ctx: EvalContext> {
|
||||
pub enum Value {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
String(String),
|
||||
Null,
|
||||
Thunk(usize),
|
||||
AttrSet(Rc<AttrSet<Ctx>>),
|
||||
List(Rc<List<Ctx>>),
|
||||
AttrSet(Rc<AttrSet>),
|
||||
List(Rc<List>),
|
||||
Catchable(String),
|
||||
PrimOp(Rc<PrimOp<Ctx>>),
|
||||
PrimOpApp(Rc<PrimOpApp<Ctx>>),
|
||||
PrimOp(PrimOp),
|
||||
PrimOpApp(Rc<PrimOpApp>),
|
||||
Func(ExprId),
|
||||
FuncApp(Rc<FuncApp<Ctx>>),
|
||||
FuncApp(Rc<FuncApp>),
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Debug for Value<Ctx> {
|
||||
impl Debug for Value {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use Value::*;
|
||||
match self {
|
||||
@@ -65,28 +65,28 @@ impl<Ctx: EvalContext> Debug for Value<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Clone for Value<Ctx> {
|
||||
impl Clone for Value {
|
||||
fn clone(&self) -> Self {
|
||||
use Value::*;
|
||||
match self {
|
||||
AttrSet(attrs) => AttrSet(attrs.clone()),
|
||||
List(list) => List(list.clone()),
|
||||
Catchable(catchable) => Catchable(catchable.clone()),
|
||||
Int(x) => Int(*x),
|
||||
Float(x) => Float(*x),
|
||||
Bool(x) => Bool(*x),
|
||||
&Int(x) => Int(x),
|
||||
&Float(x) => Float(x),
|
||||
&Bool(x) => Bool(x),
|
||||
String(x) => String(x.clone()),
|
||||
Null => Null,
|
||||
Thunk(expr) => Thunk(*expr),
|
||||
PrimOp(primop) => PrimOp(primop.clone()),
|
||||
&Thunk(expr) => Thunk(expr),
|
||||
&PrimOp(primop) => PrimOp(primop),
|
||||
PrimOpApp(primop) => PrimOpApp(primop.clone()),
|
||||
Func(expr) => Func(*expr),
|
||||
Func(expr) => Func(unsafe { expr.clone() }),
|
||||
FuncApp(func) => FuncApp(func.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Hash for Value<Ctx> {
|
||||
impl Hash for Value {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
use Value::*;
|
||||
std::mem::discriminant(self).hash(state);
|
||||
@@ -98,7 +98,7 @@ impl<Ctx: EvalContext> Hash for Value<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Value<Ctx> {
|
||||
impl Value {
|
||||
pub const INT: u64 = 0;
|
||||
pub const FLOAT: u64 = 1;
|
||||
pub const BOOL: u64 = 2;
|
||||
@@ -130,7 +130,7 @@ impl<Ctx: EvalContext> Value<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> PartialEq for Value<Ctx> {
|
||||
impl PartialEq for Value {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
use Value::*;
|
||||
match (self, other) {
|
||||
@@ -141,27 +141,27 @@ impl<Ctx: EvalContext> PartialEq for Value<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Eq for Value<Ctx> {}
|
||||
impl Eq for Value {}
|
||||
|
||||
#[derive(IsVariant, TryUnwrap, Unwrap, Clone)]
|
||||
pub enum ValueAsRef<'v, Ctx: EvalContext> {
|
||||
pub enum ValueAsRef<'v> {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
String(&'v String),
|
||||
Null,
|
||||
Thunk(usize),
|
||||
AttrSet(&'v AttrSet<Ctx>),
|
||||
List(&'v List<Ctx>),
|
||||
AttrSet(&'v AttrSet),
|
||||
List(&'v List),
|
||||
Catchable(&'v str),
|
||||
PrimOp(&'v PrimOp<Ctx>),
|
||||
PartialPrimOp(&'v PrimOpApp<Ctx>),
|
||||
Func(ExprId),
|
||||
PartialFunc(&'v FuncApp<Ctx>),
|
||||
PrimOp(&'v PrimOp),
|
||||
PartialPrimOp(&'v PrimOpApp),
|
||||
Func(&'v ExprId),
|
||||
PartialFunc(&'v FuncApp),
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Value<Ctx> {
|
||||
pub fn as_ref(&self) -> ValueAsRef<'_, Ctx> {
|
||||
impl Value {
|
||||
pub fn as_ref(&self) -> ValueAsRef<'_> {
|
||||
use Value::*;
|
||||
use ValueAsRef as R;
|
||||
match self {
|
||||
@@ -176,12 +176,12 @@ impl<Ctx: EvalContext> Value<Ctx> {
|
||||
Catchable(x) => R::Catchable(x),
|
||||
PrimOp(x) => R::PrimOp(x),
|
||||
PrimOpApp(x) => R::PartialPrimOp(x),
|
||||
Func(x) => R::Func(*x),
|
||||
Func(x) => R::Func(x),
|
||||
FuncApp(x) => R::PartialFunc(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Ctx: EvalContext> Value<Ctx> {
|
||||
impl Value {
|
||||
pub fn ok(self) -> Result<Self> {
|
||||
Ok(self)
|
||||
}
|
||||
@@ -213,32 +213,58 @@ impl<Ctx: EvalContext> Value<Ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(&mut self, args: Vec<Self>, ctx: &mut Ctx) -> Result<()> {
|
||||
pub fn call<Ctx: EvalContext>(&mut self, mut iter: impl Iterator<Item = Result<Value>> + ExactSizeIterator, ctx: &mut Ctx) -> Result<()> {
|
||||
use Value::*;
|
||||
for arg in args.iter() {
|
||||
if matches!(arg, Value::Catchable(_)) {
|
||||
*self = arg.clone();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
*self = match self {
|
||||
PrimOp(func) => func.call(args, ctx),
|
||||
PrimOpApp(func) => func.call(args, ctx),
|
||||
FuncApp(func) => func.call(args, ctx),
|
||||
&mut Func(expr) => {
|
||||
let (args, ret) = ctx.with_args_env(args, |ctx| ctx.eval(expr));
|
||||
let mut ret = ret?;
|
||||
if let Value::Func(expr) = ret {
|
||||
let frame = ctx.pop_frame();
|
||||
ret = Value::FuncApp(self::FuncApp::new(expr, args, frame).into());
|
||||
} else if let Value::FuncApp(func) = &mut ret {
|
||||
todo!();
|
||||
let func = Rc::make_mut(func);
|
||||
&mut PrimOp(func) => {
|
||||
if iter.len() > func.arity {
|
||||
todo!()
|
||||
}
|
||||
if func.arity > iter.len() {
|
||||
Value::PrimOpApp(Rc::new(self::PrimOpApp::new(
|
||||
func.name,
|
||||
func.arity - iter.len(),
|
||||
func.id,
|
||||
iter.collect::<Result<_>>()?,
|
||||
)))
|
||||
.ok()
|
||||
} else {
|
||||
ctx.call_primop(func.id, iter.collect::<Result<_>>()?)
|
||||
}
|
||||
ret.ok()
|
||||
}
|
||||
Func(expr) => {
|
||||
let mut val;
|
||||
let mut args = Vec::with_capacity(iter.len());
|
||||
args.push(iter.next().unwrap()?);
|
||||
let (ret_args, ret) = ctx.with_args_env(args, |ctx| ctx.eval(expr));
|
||||
args = ret_args;
|
||||
val = ret?;
|
||||
loop {
|
||||
if !matches!(val, Value::Func(_) | Value::FuncApp(_)) {
|
||||
break;
|
||||
}
|
||||
let Some(arg) = iter.next() else {
|
||||
break;
|
||||
};
|
||||
args.push(arg?);
|
||||
if let Value::Func(expr) = val {
|
||||
let (ret_args, ret) = ctx.with_args_env(args, |ctx| ctx.eval(&expr));
|
||||
args = ret_args;
|
||||
val = ret?;
|
||||
} else if let Value::FuncApp(func) = val {
|
||||
let mut func = Rc::unwrap_or_clone(func);
|
||||
func.args.push(args.pop().unwrap());
|
||||
let (ret_args, ret) = ctx.with_args_env(func.args, |ctx| ctx.eval(&func.body));
|
||||
args = ret_args;
|
||||
val = ret?;
|
||||
}
|
||||
}
|
||||
val.ok()
|
||||
}
|
||||
PrimOpApp(func) => func.call(iter.collect::<Result<_>>()?, ctx),
|
||||
FuncApp(func) => func.call(iter, ctx),
|
||||
Catchable(_) => return Ok(()),
|
||||
other => todo!("{}", other.typename()),
|
||||
_ => Err(Error::EvalError("attempt to call something which is not a function but ...".to_string()))
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -310,22 +336,26 @@ impl<Ctx: EvalContext> Value<Ctx> {
|
||||
|
||||
pub fn add(&mut self, other: Self) -> Result<()> {
|
||||
use Value::*;
|
||||
replace_with_and_return(self, || abort(), |a| {
|
||||
let val = match (a, other) {
|
||||
(Int(a), Int(b)) => Int(a + b),
|
||||
(Int(a), Float(b)) => Float(a as f64 + b),
|
||||
(Float(a), Int(b)) => Float(a + b as f64),
|
||||
(Float(a), Float(b)) => Float(a + b),
|
||||
(String(mut a), String(b)) => {
|
||||
a.push_str(&b);
|
||||
String(a)
|
||||
}
|
||||
(a @ Value::Catchable(_), _) => a,
|
||||
(_, x @ Value::Catchable(_)) => x,
|
||||
_ => return (Err(Error::EvalError(format!(""))), Value::Null),
|
||||
};
|
||||
(Ok(()), val)
|
||||
})
|
||||
replace_with_and_return(
|
||||
self,
|
||||
|| abort(),
|
||||
|a| {
|
||||
let val = match (a, other) {
|
||||
(Int(a), Int(b)) => Int(a + b),
|
||||
(Int(a), Float(b)) => Float(a as f64 + b),
|
||||
(Float(a), Int(b)) => Float(a + b as f64),
|
||||
(Float(a), Float(b)) => Float(a + b),
|
||||
(String(mut a), String(b)) => {
|
||||
a.push_str(&b);
|
||||
String(a)
|
||||
}
|
||||
(a @ Value::Catchable(_), _) => a,
|
||||
(_, x @ Value::Catchable(_)) => x,
|
||||
_ => return (Err(Error::EvalError(format!(""))), Value::Null),
|
||||
};
|
||||
(Ok(()), val)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn mul(&mut self, other: Self) {
|
||||
@@ -490,7 +520,7 @@ impl<Ctx: EvalContext> Value<Ctx> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn to_public(&self, ctx: &Ctx, seen: &mut HashSet<Value<Ctx>>) -> PubValue {
|
||||
pub fn to_public(&self, seen: &mut HashSet<Value>) -> PubValue {
|
||||
use Value::*;
|
||||
if seen.contains(self) {
|
||||
return PubValue::Repeated;
|
||||
@@ -498,11 +528,11 @@ impl<Ctx: EvalContext> Value<Ctx> {
|
||||
match self {
|
||||
AttrSet(attrs) => {
|
||||
seen.insert(self.clone());
|
||||
attrs.to_public(ctx, seen)
|
||||
attrs.to_public(seen)
|
||||
}
|
||||
List(list) => {
|
||||
seen.insert(self.clone());
|
||||
list.to_public(ctx, seen)
|
||||
list.to_public(seen)
|
||||
}
|
||||
Catchable(catchable) => PubValue::Catchable(catchable.clone().into()),
|
||||
Int(x) => PubValue::Const(Const::Int(*x)),
|
||||
|
||||
@@ -3,67 +3,34 @@ use std::rc::Rc;
|
||||
use derive_more::Constructor;
|
||||
|
||||
use nixjit_error::Result;
|
||||
use nixjit_ir::PrimOpId;
|
||||
|
||||
use super::Value;
|
||||
use crate::EvalContext;
|
||||
|
||||
#[derive(Debug, Clone, Constructor)]
|
||||
pub struct PrimOp<Ctx: EvalContext> {
|
||||
pub struct PrimOpApp {
|
||||
pub name: &'static str,
|
||||
arity: usize,
|
||||
func: fn(Vec<Value<Ctx>>, &Ctx) -> Result<Value<Ctx>>,
|
||||
id: PrimOpId,
|
||||
args: Vec<Value>,
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> PrimOp<Ctx> {
|
||||
pub fn call(&self, args: Vec<Value<Ctx>>, ctx: &Ctx) -> Result<Value<Ctx>> {
|
||||
if args.len() > self.arity {
|
||||
todo!()
|
||||
}
|
||||
if self.arity > args.len() {
|
||||
Value::PrimOpApp(Rc::new(PrimOpApp {
|
||||
name: self.name,
|
||||
arity: self.arity - args.len(),
|
||||
args,
|
||||
func: self.func,
|
||||
}))
|
||||
.ok()
|
||||
} else {
|
||||
(self.func)(args, ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PrimOpApp<Ctx: EvalContext> {
|
||||
pub name: &'static str,
|
||||
arity: usize,
|
||||
args: Vec<Value<Ctx>>,
|
||||
func: fn(Vec<Value<Ctx>>, &Ctx) -> Result<Value<Ctx>>,
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> Clone for PrimOpApp<Ctx> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
name: self.name,
|
||||
arity: self.arity,
|
||||
args: self.args.clone(),
|
||||
func: self.func,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: EvalContext> PrimOpApp<Ctx> {
|
||||
pub fn call(self: &mut Rc<Self>, args: Vec<Value<Ctx>>, ctx: &Ctx) -> Result<Value<Ctx>> {
|
||||
impl PrimOpApp {
|
||||
pub fn call(
|
||||
self: &mut Rc<Self>,
|
||||
args: Vec<Value>,
|
||||
ctx: &mut impl EvalContext,
|
||||
) -> Result<Value> {
|
||||
if self.arity < args.len() {
|
||||
todo!()
|
||||
}
|
||||
let func = self.func;
|
||||
let Some(ret) = ({
|
||||
let self_mut = Rc::make_mut(self);
|
||||
self_mut.arity -= args.len();
|
||||
self_mut.args.extend(args);
|
||||
if self_mut.arity == 0 {
|
||||
Some(func(std::mem::take(&mut self_mut.args), ctx))
|
||||
Some(ctx.call_primop(self_mut.id, std::mem::take(&mut self_mut.args)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user