feat: graph (WIP)
This commit is contained in:
24
TODO.md
24
TODO.md
@@ -2,4 +2,26 @@
|
|||||||
- [ ] resolve stage
|
- [ ] resolve stage
|
||||||
- [ ] dynamic attr resolution
|
- [ ] dynamic attr resolution
|
||||||
- [ ] import resolution
|
- [ ] import resolution
|
||||||
- [ ] path resolution
|
- [ ] static path resolution
|
||||||
|
- [ ] eval stage
|
||||||
|
- [ ] dynamic path resolution
|
||||||
|
- [ ] graph update
|
||||||
|
- [ ] stack storage
|
||||||
|
|
||||||
|
阻拦变量解析的是 `with import` 而不是一般的 `with`
|
||||||
|
解析阶段可以解决除涉及非字符串常量拼接路径导入之外的问题
|
||||||
|
|
||||||
|
# 工作流程
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
Start --> CtxNew[Context::new]
|
||||||
|
CtxNew --> CtxEval[Context::eval]
|
||||||
|
CtxEval --> DCtxNew[DowngradeCtx::new]
|
||||||
|
DCtxNew --> DCtxDowngradeRoot[DowngradeCtx::downgrade_root]
|
||||||
|
DCtxDowngradeRoot --> RCtxNew[ResolveCtx::new]
|
||||||
|
RCtxNew --> RCtxResolveRoot[ResolveCtx::resolve_root]
|
||||||
|
RCtxResolveRoot --> ECtxNew[EvalCtx::new]
|
||||||
|
ECtxNew --> ECtxEvalRoot[EvalCtx::eval_root]
|
||||||
|
ECtxEvalRoot --> ECtxEvalDeps[EvalCtx::eval_deps]
|
||||||
|
ECtxEvalDeps --> ECtxEval[EvalCtx::eval]
|
||||||
|
```
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use nixjit_eval::{Args, EvalContext, Evaluate, StackFrame, Value};
|
|||||||
use nixjit_ir::ExprId;
|
use nixjit_ir::ExprId;
|
||||||
use nixjit_jit::JITContext;
|
use nixjit_jit::JITContext;
|
||||||
use nixjit_lir::Lir;
|
use nixjit_lir::Lir;
|
||||||
|
use petgraph::visit::{Topo, Walker};
|
||||||
|
|
||||||
use super::Context;
|
use super::Context;
|
||||||
|
|
||||||
@@ -40,10 +41,7 @@ impl<'ctx, 'bump> EvalCtx<'ctx, 'bump> {
|
|||||||
dbg!(&deps, &self.stack);
|
dbg!(&deps, &self.stack);
|
||||||
for (dep, idx) in deps {
|
for (dep, idx) in deps {
|
||||||
unsafe {
|
unsafe {
|
||||||
if matches!(
|
if matches!(&**self.ctx.lirs.get_unchecked(dep.raw()), Lir::Arg(_)) {
|
||||||
&**self.ctx.lirs.get_unchecked(dep.raw()),
|
|
||||||
Lir::Arg(_)
|
|
||||||
) {
|
|
||||||
*frame.get_unchecked_mut(idx.raw()) = arg.as_ref().unwrap().clone();
|
*frame.get_unchecked_mut(idx.raw()) = arg.as_ref().unwrap().clone();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -76,7 +74,7 @@ impl EvalContext for EvalCtx<'_, '_> {
|
|||||||
self.stack.push(frame);
|
self.stack.push(frame);
|
||||||
if let Err(err) = self.eval_deps(func, arg) {
|
if let Err(err) = self.eval_deps(func, arg) {
|
||||||
self.stack.pop();
|
self.stack.pop();
|
||||||
return Err(err)
|
return Err(err);
|
||||||
}
|
}
|
||||||
let ret = self.eval(func);
|
let ret = self.eval(func);
|
||||||
self.stack.pop();
|
self.stack.pop();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::{marker::PhantomPinned, ops::Deref};
|
use std::{marker::PhantomPinned, ops::{Deref, DerefMut}};
|
||||||
|
|
||||||
use bumpalo::{Bump, boxed::Box};
|
use bumpalo::{Bump, boxed::Box};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
@@ -32,6 +32,12 @@ struct Pin<'bump, T> {
|
|||||||
_marker: PhantomPinned,
|
_marker: PhantomPinned,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Pin<'_, T> {
|
||||||
|
fn into_inner(self) -> T {
|
||||||
|
Box::into_inner(self.ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Deref for Pin<'_, T> {
|
impl<T> Deref for Pin<'_, T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@@ -39,6 +45,12 @@ impl<T> Deref for Pin<'_, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Pin<'_, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.ptr.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'bump, T> Pin<'bump, T> {
|
impl<'bump, T> Pin<'bump, T> {
|
||||||
fn new_in(x: T, bump: &'bump Bump) -> Self {
|
fn new_in(x: T, bump: &'bump Bump) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::pin::Pin;
|
|
||||||
|
|
||||||
use bumpalo::boxed::Box;
|
|
||||||
use derive_more::Unwrap;
|
use derive_more::Unwrap;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
@@ -11,7 +9,7 @@ use nixjit_ir::{Const, ExprId, Param, StackIdx};
|
|||||||
use nixjit_lir::{Lir, LookupResult, Resolve, ResolveContext};
|
use nixjit_lir::{Lir, LookupResult, Resolve, ResolveContext};
|
||||||
use replace_with::replace_with_and_return;
|
use replace_with::replace_with_and_return;
|
||||||
|
|
||||||
use super::Context;
|
use super::{Context, Pin};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum Scope<'ctx> {
|
enum Scope<'ctx> {
|
||||||
@@ -20,7 +18,7 @@ enum Scope<'ctx> {
|
|||||||
/// A function argument scope. `Some` holds the name of the argument set if present.
|
/// A function argument scope. `Some` holds the name of the argument set if present.
|
||||||
Arg(Option<String>),
|
Arg(Option<String>),
|
||||||
Builtins(&'ctx HashMap<&'static str, ExprId>),
|
Builtins(&'ctx HashMap<&'static str, ExprId>),
|
||||||
Repl(&'ctx HashMap<String, ExprId>)
|
Repl(&'ctx HashMap<String, ExprId>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an expression at different stages of compilation.
|
/// Represents an expression at different stages of compilation.
|
||||||
@@ -44,7 +42,7 @@ impl Ir {
|
|||||||
|
|
||||||
pub struct ResolveCtx<'ctx, 'bump> {
|
pub struct ResolveCtx<'ctx, 'bump> {
|
||||||
ctx: &'ctx mut Context<'bump>,
|
ctx: &'ctx mut Context<'bump>,
|
||||||
irs: Vec<Pin<Box<'bump, RefCell<Ir>>>>,
|
irs: Vec<Pin<'bump, RefCell<Ir>>>,
|
||||||
scopes: Vec<Scope<'ctx>>,
|
scopes: Vec<Scope<'ctx>>,
|
||||||
has_with: bool,
|
has_with: bool,
|
||||||
with_used: bool,
|
with_used: bool,
|
||||||
@@ -58,15 +56,14 @@ impl<'ctx, 'bump> ResolveCtx<'ctx, 'bump> {
|
|||||||
Self {
|
Self {
|
||||||
scopes: vec![
|
scopes: vec![
|
||||||
Scope::Builtins(&ctx.global_scope),
|
Scope::Builtins(&ctx.global_scope),
|
||||||
Scope::Repl(&ctx.repl_scope)
|
Scope::Repl(&ctx.repl_scope),
|
||||||
],
|
],
|
||||||
has_with: false,
|
has_with: false,
|
||||||
with_used: false,
|
with_used: false,
|
||||||
irs: core::mem::take(&mut ctx.hirs)
|
irs: core::mem::take(&mut ctx.hirs)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|hir| Ir::Hir(hir).into())
|
.map(|hir| Ir::Hir(hir).into())
|
||||||
.map(|ir| Box::new_in(ir, ctx.bump))
|
.map(|ir| Pin::new_in(ir, ctx.bump))
|
||||||
.map(Pin::new)
|
|
||||||
.collect(),
|
.collect(),
|
||||||
ctx: ctx_mut,
|
ctx: ctx_mut,
|
||||||
closures: Vec::new(),
|
closures: Vec::new(),
|
||||||
@@ -105,10 +102,10 @@ impl<'ctx, 'bump> ResolveCtx<'ctx, 'bump> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_lir(&mut self, lir: Lir) -> ExprId {
|
fn new_lir(&mut self, lir: Lir) -> ExprId {
|
||||||
self.irs.push(Pin::new(Box::new_in(
|
self.irs.push(Pin::new_in(
|
||||||
RefCell::new(Ir::Lir(lir)),
|
RefCell::new(Ir::Lir(lir)),
|
||||||
self.ctx.bump,
|
self.ctx.bump,
|
||||||
)));
|
));
|
||||||
unsafe { ExprId::from_raw(self.ctx.lirs.len() + self.irs.len() - 1) }
|
unsafe { ExprId::from_raw(self.ctx.lirs.len() + self.irs.len() - 1) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,6 +141,10 @@ impl ResolveContext for ResolveCtx<'_, '_> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_call(&mut self, func: ExprId, arg: ExprId) -> Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_root(mut self, expr: ExprId) -> Result<()> {
|
fn resolve_root(mut self, expr: ExprId) -> Result<()> {
|
||||||
self.closures.push((expr, None, 0));
|
self.closures.push((expr, None, 0));
|
||||||
let ret = self.resolve(expr);
|
let ret = self.resolve(expr);
|
||||||
@@ -151,11 +152,10 @@ impl ResolveContext for ResolveCtx<'_, '_> {
|
|||||||
self.ctx.lirs.extend(
|
self.ctx.lirs.extend(
|
||||||
self.irs
|
self.irs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|pin| unsafe { core::mem::transmute::<Pin<_>, Box<_>>(pin) })
|
.map(Pin::into_inner)
|
||||||
.map(Box::into_inner)
|
|
||||||
.map(RefCell::into_inner)
|
.map(RefCell::into_inner)
|
||||||
.map(Ir::unwrap_lir)
|
.map(Ir::unwrap_lir)
|
||||||
.map(|lir| crate::Pin::new_in(lir, self.ctx.bump))
|
.map(|lir| crate::Pin::new_in(lir, self.ctx.bump)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
@@ -215,7 +215,9 @@ impl ResolveContext for ResolveCtx<'_, '_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_arg(&mut self) -> StackIdx {
|
fn lookup_arg(&mut self) -> StackIdx {
|
||||||
let Some((func, Some(arg), count)) = unsafe { &mut *(self as *mut Self) }.closures.last_mut() else {
|
let Some((func, Some(arg), count)) =
|
||||||
|
unsafe { &mut *(self as *mut Self) }.closures.last_mut()
|
||||||
|
else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
self.add_dep(*func, *arg, count)
|
self.add_dep(*func, *arg, count)
|
||||||
@@ -246,7 +248,7 @@ impl ResolveContext for ResolveCtx<'_, '_> {
|
|||||||
(core::mem::replace(&mut self.with_used, with_used), res)
|
(core::mem::replace(&mut self.with_used, with_used), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_param_env<T>(
|
fn with_closure_env<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: ExprId,
|
func: ExprId,
|
||||||
ident: Option<String>,
|
ident: Option<String>,
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ mod value;
|
|||||||
pub trait EvalContext {
|
pub trait EvalContext {
|
||||||
fn eval_root(self, expr: ExprId) -> Result<Value>;
|
fn eval_root(self, expr: ExprId) -> Result<Value>;
|
||||||
|
|
||||||
|
|
||||||
/// Evaluates an expression by its ID.
|
/// Evaluates an expression by its ID.
|
||||||
fn eval(&mut self, expr: ExprId) -> Result<Value>;
|
fn eval(&mut self, expr: ExprId) -> Result<Value>;
|
||||||
|
|
||||||
fn call(&mut self, func: ExprId, arg: Option<Value>, frame: StackFrame) -> Result<Value>;
|
fn call(&mut self, func: ExprId, arg: Option<Value>, frame: StackFrame) -> Result<Value>;
|
||||||
|
|
||||||
/// Enters a `with` scope for the duration of a closure's execution.
|
/// Enters a `with` scope for the duration of a closure's execution.
|
||||||
fn with_with_env<T>(
|
fn with_with_env<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -83,9 +83,15 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for lir::Lir {
|
|||||||
Str(x) => x.eval(ctx),
|
Str(x) => x.eval(ctx),
|
||||||
Var(x) => x.eval(ctx),
|
Var(x) => x.eval(ctx),
|
||||||
Path(x) => x.eval(ctx),
|
Path(x) => x.eval(ctx),
|
||||||
&StackRef(idx) => Ok(ctx.lookup_stack(idx).clone()),
|
&StackRef(idx) => {
|
||||||
|
let mut val = ctx.lookup_stack(idx).clone();
|
||||||
|
val.force(ctx)?;
|
||||||
|
Ok(val)
|
||||||
|
}
|
||||||
&ExprRef(expr) => ctx.eval(expr),
|
&ExprRef(expr) => ctx.eval(expr),
|
||||||
&FuncRef(body) => Ok(Value::Closure(Closure::new(body, ctx.capture_stack().clone()).into())),
|
&FuncRef(body) => Ok(Value::Closure(
|
||||||
|
Closure::new(body, ctx.capture_stack().clone()).into(),
|
||||||
|
)),
|
||||||
&Arg(_) => unreachable!(),
|
&Arg(_) => unreachable!(),
|
||||||
&PrimOp(primop) => Ok(Value::PrimOp(primop)),
|
&PrimOp(primop) => Ok(Value::PrimOp(primop)),
|
||||||
&Thunk(id) => Ok(Value::Thunk(id)),
|
&Thunk(id) => Ok(Value::Thunk(id)),
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ pub struct Closure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Closure {
|
impl Closure {
|
||||||
pub fn call<Ctx: EvalContext>(self: Rc<Self>, arg: Option<Value>, ctx: &mut Ctx) -> Result<Value> {
|
pub fn call<Ctx: EvalContext>(
|
||||||
|
self: Rc<Self>,
|
||||||
|
arg: Option<Value>,
|
||||||
|
ctx: &mut Ctx,
|
||||||
|
) -> Result<Value> {
|
||||||
let Self { body: func, frame } = Rc::unwrap_or_clone(self);
|
let Self { body: func, frame } = Rc::unwrap_or_clone(self);
|
||||||
ctx.call(func, arg, frame)
|
ctx.call(func, arg, frame)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ pub trait ResolveContext {
|
|||||||
/// Triggers the resolution of a given expression.
|
/// Triggers the resolution of a given expression.
|
||||||
fn resolve(&mut self, expr: ExprId) -> Result<()>;
|
fn resolve(&mut self, expr: ExprId) -> Result<()>;
|
||||||
|
|
||||||
|
fn resolve_call(&mut self, func: ExprId, arg: ExprId) -> Result<()>;
|
||||||
|
|
||||||
fn resolve_root(self, expr: ExprId) -> Result<()>;
|
fn resolve_root(self, expr: ExprId) -> Result<()>;
|
||||||
|
|
||||||
/// Looks up a variable by name in the current scope.
|
/// Looks up a variable by name in the current scope.
|
||||||
@@ -89,7 +91,7 @@ pub trait ResolveContext {
|
|||||||
) -> T;
|
) -> T;
|
||||||
|
|
||||||
/// Enters a function parameter scope for the duration of a closure.
|
/// Enters a function parameter scope for the duration of a closure.
|
||||||
fn with_param_env<T>(
|
fn with_closure_env<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: ExprId,
|
func: ExprId,
|
||||||
ident: Option<String>,
|
ident: Option<String>,
|
||||||
@@ -129,7 +131,7 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for hir::Hir {
|
|||||||
ctx.resolve(x)?;
|
ctx.resolve(x)?;
|
||||||
Ok(Lir::Thunk(x))
|
Ok(Lir::Thunk(x))
|
||||||
}
|
}
|
||||||
Arg(_) => Ok(Lir::StackRef(ctx.lookup_arg()))
|
Arg(_) => Ok(Lir::StackRef(ctx.lookup_arg())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,17 +221,19 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for If {
|
|||||||
/// It then registers the function with the context.
|
/// It then registers the function with the context.
|
||||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Func {
|
impl<Ctx: ResolveContext> Resolve<Ctx> for Func {
|
||||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||||
ctx.with_param_env(self.body, self.param.ident.clone(), |ctx| ctx.resolve(self.body))?;
|
ctx.with_closure_env(self.body, self.param.ident.clone(), |ctx| {
|
||||||
|
ctx.resolve(self.body)
|
||||||
|
})?;
|
||||||
ctx.new_func(self.body, self.param);
|
ctx.new_func(self.body, self.param);
|
||||||
Ok(Lir::FuncRef(self.body))
|
Ok(Lir::FuncRef(self.body))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves a `Call` by resolving the function and all of its arguments.
|
|
||||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Call {
|
impl<Ctx: ResolveContext> Resolve<Ctx> for Call {
|
||||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||||
ctx.resolve(self.func)?;
|
ctx.resolve(self.func)?;
|
||||||
ctx.resolve(self.arg)?;
|
ctx.resolve(self.arg)?;
|
||||||
|
ctx.resolve_call(self.func, self.arg)?;
|
||||||
Ok(self.to_lir())
|
Ok(self.to_lir())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user