diff --git a/nix-js/src/context.rs b/nix-js/src/context.rs index c687d96..0bba013 100644 --- a/nix-js/src/context.rs +++ b/nix-js/src/context.rs @@ -11,7 +11,7 @@ use crate::codegen::{CodegenContext, compile}; use crate::error::{Error, Result, Source}; use crate::ir::{ Arg, ArgId, Bool, Builtin, Downgrade as _, DowngradeContext, ExprId, ExprRef, Ir, Null, SymId, - ToIr as _, synthetic_span, + Thunk, ToIr as _, synthetic_span, }; use crate::runtime::{Runtime, RuntimeContext}; use crate::store::{StoreBackend, StoreConfig}; @@ -351,6 +351,34 @@ impl DowngradeContext for DowngradeCtx<'_> { ExprId(self.ctx.irs.len() + self.irs.len() - 1) } + fn maybe_thunk(&mut self, id: ExprId) -> ExprId { + let ir = if id.0 < self.ctx.irs.len() { + self.ctx.irs.get(id.0).expect("unreachable") + } else { + self.irs + .get(id.0 - self.ctx.irs.len()) + .expect("ExprId out of bounds") + .as_ref() + .expect("maybe_thunk called on an extracted expr") + }; + match ir { + Ir::Builtin(_) + | Ir::Builtins(_) + | Ir::Int(_) + | Ir::Float(_) + | Ir::Bool(_) + | Ir::Null(_) + | Ir::Str(_) => id, + _ => self.new_expr( + Thunk { + inner: id, + span: ir.span(), + } + .to_ir(), + ), + } + } + fn new_sym(&mut self, sym: String) -> SymId { self.ctx.symbols.get_or_intern(sym) } diff --git a/nix-js/src/ir.rs b/nix-js/src/ir.rs index 227a223..9f021b2 100644 --- a/nix-js/src/ir.rs +++ b/nix-js/src/ir.rs @@ -22,6 +22,7 @@ pub trait DowngradeContext { fn new_expr(&mut self, expr: Ir) -> ExprId; fn new_arg(&mut self, span: TextRange) -> ExprId; + fn maybe_thunk(&mut self, id: ExprId) -> ExprId; fn new_sym(&mut self, sym: String) -> SymId; fn get_sym(&self, id: SymId) -> &str; diff --git a/nix-js/src/ir/downgrade.rs b/nix-js/src/ir/downgrade.rs index 10c041a..160c4ad 100644 --- a/nix-js/src/ir/downgrade.rs +++ b/nix-js/src/ir/downgrade.rs @@ -121,7 +121,8 @@ impl Downgrade for ast::Str { .map(|part| match part { ast::InterpolPart::Literal(lit) => Ok(ctx.new_expr(Str { val: lit, span }.to_ir())), ast::InterpolPart::Interpolation(interpol) => { - interpol.expr().unwrap().downgrade(ctx) + let inner = interpol.expr().unwrap().downgrade(ctx)?; + Ok(ctx.new_expr(Thunk { inner, span }.to_ir())) } }) .collect::>>()?; @@ -210,7 +211,10 @@ impl Downgrade for ast::List { fn downgrade(self, ctx: &mut Ctx) -> Result { let items = self .items() - .map(|item| maybe_thunk(item, ctx)) + .map(|item| { + let id = item.downgrade(ctx)?; + Ok(ctx.maybe_thunk(id)) + }) .collect::>()?; let span = self.syntax().text_range(); Ok(ctx.new_expr(List { items, span }.to_ir())) @@ -439,7 +443,8 @@ impl Downgrade for ast::Lambda { impl Downgrade for ast::Apply { fn downgrade(self, ctx: &mut Ctx) -> Result { let func = self.lambda().unwrap().downgrade(ctx)?; - let arg = maybe_thunk(self.argument().unwrap(), ctx)?; + let arg = self.argument().unwrap().downgrade(ctx)?; + let arg = ctx.maybe_thunk(arg); let span = self.syntax().text_range(); Ok(ctx.new_expr(Call { func, arg, span }.to_ir())) } diff --git a/nix-js/src/ir/utils.rs b/nix-js/src/ir/utils.rs index 3ca0b68..5d9e150 100644 --- a/nix-js/src/ir/utils.rs +++ b/nix-js/src/ir/utils.rs @@ -13,57 +13,6 @@ use crate::value::format_symbol; use super::*; -pub fn maybe_thunk(mut expr: ast::Expr, ctx: &mut impl DowngradeContext) -> Result { - use ast::Expr::*; - let expr = loop { - expr = match expr { - Paren(paren) => paren.expr().unwrap(), - Root(root) => root.expr().unwrap(), - expr => break expr, - } - }; - match expr { - Error(error) => { - let span = error.syntax().text_range(); - return Err(self::Error::downgrade_error(error.to_string()) - .with_span(span) - .with_source(ctx.get_current_source())); - } - Ident(ident) => return ident.downgrade(ctx), - Literal(lit) => return lit.downgrade(ctx), - Str(str) => return str.downgrade(ctx), - Path(path) => return path.downgrade(ctx), - - _ => (), - } - let id = match expr { - Apply(apply) => apply.downgrade(ctx), - Assert(assert) => assert.downgrade(ctx), - IfElse(ifelse) => ifelse.downgrade(ctx), - Select(select) => select.downgrade(ctx), - Lambda(lambda) => lambda.downgrade(ctx), - LegacyLet(let_) => let_.downgrade(ctx), - LetIn(letin) => letin.downgrade(ctx), - List(list) => list.downgrade(ctx), - BinOp(op) => op.downgrade(ctx), - AttrSet(attrs) => attrs.downgrade(ctx), - UnaryOp(op) => op.downgrade(ctx), - With(with) => with.downgrade(ctx), - HasAttr(has) => has.downgrade(ctx), - - _ => unreachable!(), - }?; - Ok(ctx.new_expr( - Thunk { - inner: id, - // span: ctx.get_span(id), - // FIXME: span - span: synthetic_span(), - } - .to_ir(), - )) -} - /// Downgrades the entries of an attribute set. /// This handles `inherit` and `attrpath = value;` entries. pub fn downgrade_attrs( @@ -231,7 +180,8 @@ pub fn downgrade_attrpathvalue( ctx: &mut impl DowngradeContext, ) -> Result<()> { let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?; - let value = maybe_thunk(value.value().unwrap(), ctx)?; + let value = value.value().unwrap().downgrade(ctx)?; + let value = ctx.maybe_thunk(value); attrs.insert(path, value, ctx) }