refactor: RuntimeContext
This commit is contained in:
@@ -316,8 +316,8 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Select {
|
||||
.attrpath
|
||||
.iter()
|
||||
.map(|attr| match attr {
|
||||
Attr::Str(sym) => ctx.get_sym(*sym).escape_quote(),
|
||||
Attr::Dynamic(expr_id) => ctx.get_ir(*expr_id).compile(ctx),
|
||||
Attr::Str(sym, _) => ctx.get_sym(*sym).escape_quote(),
|
||||
Attr::Dynamic(expr_id, _) => ctx.get_ir(*expr_id).compile(ctx),
|
||||
})
|
||||
.join(",");
|
||||
let span_str = encode_span(self.span, ctx);
|
||||
@@ -431,8 +431,8 @@ impl<Ctx: CodegenContext> Compile<Ctx> for HasAttr {
|
||||
.rhs
|
||||
.iter()
|
||||
.map(|attr| match attr {
|
||||
Attr::Str(sym) => ctx.get_sym(*sym).escape_quote(),
|
||||
Attr::Dynamic(expr_id) => ctx.get_ir(*expr_id).compile(ctx),
|
||||
Attr::Str(sym, _) => ctx.get_sym(*sym).escape_quote(),
|
||||
Attr::Dynamic(expr_id, _) => ctx.get_ir(*expr_id).compile(ctx),
|
||||
})
|
||||
.join(",");
|
||||
format!("Nix.hasAttr({lhs},[{attrpath}])")
|
||||
|
||||
@@ -14,45 +14,8 @@ use crate::ir::{
|
||||
Thunk, ToIr as _, synthetic_span,
|
||||
};
|
||||
use crate::runtime::{Runtime, RuntimeContext};
|
||||
use crate::store::{StoreBackend, StoreConfig};
|
||||
use crate::store::{Store, StoreBackend, StoreConfig};
|
||||
use crate::value::Value;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod private {
|
||||
use super::*;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub struct CtxPtr(NonNull<Ctx>);
|
||||
impl CtxPtr {
|
||||
pub fn new(ctx: &mut Ctx) -> Self {
|
||||
unsafe { CtxPtr(NonNull::new_unchecked(ctx)) }
|
||||
}
|
||||
fn as_ref(&self) -> &Ctx {
|
||||
// SAFETY: This is safe since inner `NonNull<Ctx>` is obtained from `&mut Ctx`
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
fn as_mut(&mut self) -> &mut Ctx {
|
||||
// SAFETY: This is safe since inner `NonNull<Ctx>` is obtained from `&mut Ctx`
|
||||
unsafe { self.0.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeContext for CtxPtr {
|
||||
fn get_current_dir(&self) -> &Path {
|
||||
self.as_ref().get_current_dir()
|
||||
}
|
||||
fn add_source(&mut self, source: Source) {
|
||||
self.as_mut().sources.push(source);
|
||||
}
|
||||
fn compile_code(&mut self, source: Source) -> Result<String> {
|
||||
self.as_mut().compile_code(source)
|
||||
}
|
||||
fn get_source(&self, id: usize) -> Source {
|
||||
self.as_ref().get_source(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
use private::CtxPtr;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SccInfo {
|
||||
@@ -62,7 +25,7 @@ pub(crate) struct SccInfo {
|
||||
|
||||
pub struct Context {
|
||||
ctx: Ctx,
|
||||
runtime: Runtime<CtxPtr>,
|
||||
runtime: Runtime<Ctx>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@@ -79,14 +42,9 @@ impl Context {
|
||||
tracing::debug!("Compiling code");
|
||||
let code = self.compile_code(source)?;
|
||||
|
||||
self.runtime
|
||||
.op_state()
|
||||
.borrow_mut()
|
||||
.put(self.ctx.store.clone());
|
||||
|
||||
tracing::debug!("Executing JavaScript");
|
||||
self.runtime
|
||||
.eval(format!("Nix.force({code})"), CtxPtr::new(&mut self.ctx))
|
||||
.eval(format!("Nix.force({code})"), &mut self.ctx)
|
||||
}
|
||||
|
||||
pub fn compile_code(&mut self, source: Source) -> Result<String> {
|
||||
@@ -95,7 +53,7 @@ impl Context {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn eval_js(&mut self, code: String) -> Result<Value> {
|
||||
self.runtime.eval(code, CtxPtr::new(&mut self.ctx))
|
||||
self.runtime.eval(code, &mut self.ctx)
|
||||
}
|
||||
|
||||
pub fn get_store_dir(&self) -> &str {
|
||||
@@ -108,7 +66,7 @@ pub(crate) struct Ctx {
|
||||
symbols: DefaultStringInterner,
|
||||
global: NonNull<HashMap<SymId, ExprId>>,
|
||||
sources: Vec<Source>,
|
||||
store: Arc<StoreBackend>,
|
||||
store: StoreBackend,
|
||||
}
|
||||
|
||||
impl Ctx {
|
||||
@@ -197,7 +155,7 @@ impl Ctx {
|
||||
}
|
||||
|
||||
let config = StoreConfig::from_env();
|
||||
let store = Arc::new(StoreBackend::new(config)?);
|
||||
let store = StoreBackend::new(config)?;
|
||||
|
||||
Ok(Self {
|
||||
symbols,
|
||||
@@ -207,9 +165,7 @@ impl Ctx {
|
||||
store,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Ctx {
|
||||
pub(crate) fn downgrade_ctx<'a>(&'a mut self) -> DowngradeCtx<'a> {
|
||||
let global_ref = unsafe { self.global.as_ref() };
|
||||
DowngradeCtx::new(self, global_ref)
|
||||
@@ -279,6 +235,24 @@ impl CodegenContext for Ctx {
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeContext for Ctx {
|
||||
fn get_current_dir(&self) -> &Path {
|
||||
self.get_current_dir()
|
||||
}
|
||||
fn add_source(&mut self, source: Source) {
|
||||
self.sources.push(source);
|
||||
}
|
||||
fn compile_code(&mut self, source: Source) -> Result<String> {
|
||||
self.compile_code(source)
|
||||
}
|
||||
fn get_source(&self, id: usize) -> Source {
|
||||
self.get_source(id)
|
||||
}
|
||||
fn get_store(&self) -> &dyn Store {
|
||||
self.store.as_store()
|
||||
}
|
||||
}
|
||||
|
||||
struct DependencyTracker {
|
||||
graph: DiGraphMap<ExprId, ()>,
|
||||
current_binding: Option<ExprId>,
|
||||
@@ -460,16 +434,18 @@ impl DowngradeContext for DowngradeCtx<'_> {
|
||||
use crate::ir::{Attr, Select};
|
||||
let select = Select {
|
||||
expr: namespace,
|
||||
attrpath: vec![Attr::Str(sym)],
|
||||
attrpath: vec![Attr::Str(sym, synthetic_span())],
|
||||
default: result, // Link to outer With or None
|
||||
span,
|
||||
};
|
||||
result = Some(self.new_expr(select.to_ir()));
|
||||
}
|
||||
result.ok_or_else(|| {
|
||||
Error::downgrade_error(format!("'{}' not found", self.get_sym(sym)))
|
||||
.with_span(span)
|
||||
.with_source(self.get_current_source())
|
||||
Error::downgrade_error(
|
||||
format!("'{}' not found", self.get_sym(sym)),
|
||||
self.get_current_source(),
|
||||
span,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -134,10 +134,10 @@ impl Error {
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn downgrade_error(msg: String) -> Box<Self> {
|
||||
pub fn downgrade_error(msg: String, src: Source, span: rnix::TextRange) -> Box<Self> {
|
||||
Error::DowngradeError {
|
||||
src: None,
|
||||
span: None,
|
||||
src: Some(src.into()),
|
||||
span: Some(text_range_to_source_span(span)),
|
||||
message: msg,
|
||||
}
|
||||
.into()
|
||||
|
||||
@@ -3,6 +3,9 @@ use deno_core::op2;
|
||||
use serde::Serialize;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::runtime::OpStateExt;
|
||||
use crate::runtime::RuntimeContext;
|
||||
|
||||
mod archive;
|
||||
pub(crate) mod cache;
|
||||
mod download;
|
||||
@@ -53,16 +56,13 @@ pub struct FetchHgResult {
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_fetch_url(
|
||||
pub fn op_fetch_url<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] url: String,
|
||||
#[string] expected_hash: Option<String>,
|
||||
#[string] name: Option<String>,
|
||||
executable: bool,
|
||||
) -> Result<FetchUrlResult, NixError> {
|
||||
use crate::store::StoreBackend;
|
||||
use std::sync::Arc;
|
||||
|
||||
let _span = tracing::info_span!("op_fetch_url", url = %url).entered();
|
||||
info!("fetchurl started");
|
||||
|
||||
@@ -128,9 +128,9 @@ pub fn op_fetch_url(
|
||||
}
|
||||
}
|
||||
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
let store_path = store
|
||||
.as_store()
|
||||
.add_to_store(&file_name, &data, false, vec![])
|
||||
.map_err(|e| NixError::from(e.to_string()))?;
|
||||
|
||||
@@ -160,16 +160,13 @@ pub fn op_fetch_url(
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_fetch_tarball(
|
||||
pub fn op_fetch_tarball<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] url: String,
|
||||
#[string] expected_hash: Option<String>,
|
||||
#[string] expected_nar_hash: Option<String>,
|
||||
#[string] name: Option<String>,
|
||||
) -> Result<FetchTarballResult, NixError> {
|
||||
use crate::store::StoreBackend;
|
||||
use std::sync::Arc;
|
||||
|
||||
let _span = tracing::info_span!("op_fetch_tarball", url = %url).entered();
|
||||
info!("fetchTarball started");
|
||||
|
||||
@@ -264,9 +261,9 @@ pub fn op_fetch_tarball(
|
||||
}
|
||||
|
||||
info!("Adding to store");
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
let store_path = store
|
||||
.as_store()
|
||||
.add_to_store_from_path(&dir_name, &extracted_path, vec![])
|
||||
.map_err(|e| NixError::from(e.to_string()))?;
|
||||
|
||||
@@ -292,7 +289,7 @@ pub fn op_fetch_tarball(
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
pub fn op_fetch_git(
|
||||
pub fn op_fetch_git<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] url: String,
|
||||
#[string] git_ref: Option<String>,
|
||||
@@ -302,19 +299,17 @@ pub fn op_fetch_git(
|
||||
all_refs: bool,
|
||||
#[string] name: Option<String>,
|
||||
) -> Result<FetchGitResult, NixError> {
|
||||
use crate::store::StoreBackend;
|
||||
use std::sync::Arc;
|
||||
|
||||
let _span = tracing::info_span!("op_fetch_git", url = %url).entered();
|
||||
info!("fetchGit started");
|
||||
let cache = FetcherCache::new().map_err(|e| NixError::from(e.to_string()))?;
|
||||
let dir_name = name.unwrap_or_else(|| "source".to_string());
|
||||
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
|
||||
git::fetch_git(
|
||||
&cache,
|
||||
store.as_store(),
|
||||
store,
|
||||
&url,
|
||||
git_ref.as_deref(),
|
||||
rev.as_deref(),
|
||||
@@ -377,11 +372,11 @@ fn base64_decode(input: &str) -> Result<Vec<u8>, String> {
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn register_ops() -> Vec<deno_core::OpDecl> {
|
||||
pub fn register_ops<Ctx: RuntimeContext>() -> Vec<deno_core::OpDecl> {
|
||||
vec![
|
||||
op_fetch_url(),
|
||||
op_fetch_tarball(),
|
||||
op_fetch_git(),
|
||||
op_fetch_url::<Ctx>(),
|
||||
op_fetch_tarball::<Ctx>(),
|
||||
op_fetch_git::<Ctx>(),
|
||||
op_fetch_hg(),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ impl AttrSet {
|
||||
if let Some(attr) = path.next() {
|
||||
// If the path is not yet exhausted, we need to recurse deeper.
|
||||
match attr {
|
||||
Attr::Str(ident) => {
|
||||
Attr::Str(ident, span) => {
|
||||
// If the next attribute is a static string.
|
||||
if let Some(&id) = self.stcs.get(&ident) {
|
||||
// If a sub-attrset already exists, recurse into it.
|
||||
@@ -132,8 +132,11 @@ impl AttrSet {
|
||||
// This path segment exists but is not an attrset, which is an error.
|
||||
Error::downgrade_error(format!(
|
||||
"attribute '{}' already defined but is not an attribute set",
|
||||
format_symbol(ctx.get_sym(ident))
|
||||
))
|
||||
format_symbol(ctx.get_sym(ident)),
|
||||
),
|
||||
ctx.get_current_source(),
|
||||
span
|
||||
)
|
||||
})
|
||||
.and_then(|attrs| attrs._insert(path, name, value, ctx));
|
||||
ctx.replace_expr(id, ir);
|
||||
@@ -144,7 +147,7 @@ impl AttrSet {
|
||||
let mut attrs = AttrSet {
|
||||
stcs: Default::default(),
|
||||
dyns: Default::default(),
|
||||
span: synthetic_span(),
|
||||
span,
|
||||
};
|
||||
attrs._insert(path, name, value, ctx)?;
|
||||
let attrs = ctx.new_expr(attrs.to_ir());
|
||||
@@ -152,14 +155,14 @@ impl AttrSet {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Attr::Dynamic(dynamic) => {
|
||||
Attr::Dynamic(dynamic, span) => {
|
||||
// If the next attribute is a dynamic expression, we must create a new sub-attrset.
|
||||
// We cannot merge with existing dynamic attributes at this stage.
|
||||
// FIXME: span
|
||||
let mut attrs = AttrSet {
|
||||
stcs: Default::default(),
|
||||
dyns: Default::default(),
|
||||
span: synthetic_span(),
|
||||
span,
|
||||
};
|
||||
attrs._insert(path, name, value, ctx)?;
|
||||
self.dyns.push((dynamic, ctx.new_expr(attrs.to_ir())));
|
||||
@@ -169,15 +172,19 @@ impl AttrSet {
|
||||
} else {
|
||||
// This is the final attribute in the path, so insert the value here.
|
||||
match name {
|
||||
Attr::Str(ident) => {
|
||||
Attr::Str(ident, span) => {
|
||||
if self.stcs.insert(ident, value).is_some() {
|
||||
return Err(Error::downgrade_error(format!(
|
||||
return Err(Error::downgrade_error(
|
||||
format!(
|
||||
"attribute '{}' already defined",
|
||||
format_symbol(ctx.get_sym(ident))
|
||||
)));
|
||||
format_symbol(ctx.get_sym(ident)),
|
||||
),
|
||||
ctx.get_current_source(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
}
|
||||
Attr::Dynamic(dynamic) => {
|
||||
Attr::Dynamic(dynamic, _) => {
|
||||
self.dyns.push((dynamic, value));
|
||||
}
|
||||
}
|
||||
@@ -215,10 +222,10 @@ pub struct ArgId(pub usize);
|
||||
pub enum Attr {
|
||||
/// A dynamic attribute key, which is an expression that must evaluate to a string.
|
||||
/// Example: `attrs.${key}`
|
||||
Dynamic(ExprId),
|
||||
Dynamic(ExprId, TextRange),
|
||||
/// A static attribute key.
|
||||
/// Example: `attrs.key`
|
||||
Str(SymId),
|
||||
Str(SymId, TextRange),
|
||||
}
|
||||
|
||||
/// The kinds of binary operations supported in Nix.
|
||||
|
||||
@@ -19,9 +19,11 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for Expr {
|
||||
Assert(assert) => assert.downgrade(ctx),
|
||||
Error(error) => {
|
||||
let span = error.syntax().text_range();
|
||||
Err(self::Error::downgrade_error(error.to_string())
|
||||
.with_span(span)
|
||||
.with_source(ctx.get_current_source()))
|
||||
Err(self::Error::downgrade_error(
|
||||
error.to_string(),
|
||||
ctx.get_current_source(),
|
||||
span,
|
||||
))
|
||||
}
|
||||
IfElse(ifelse) => ifelse.downgrade(ctx),
|
||||
Select(select) => select.downgrade(ctx),
|
||||
@@ -320,7 +322,8 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::LegacyLet {
|
||||
let body_sym = ctx.new_sym("body".to_string());
|
||||
let select = Select {
|
||||
expr: attrset_expr,
|
||||
attrpath: vec![Attr::Str(body_sym)],
|
||||
// FIXME: span
|
||||
attrpath: vec![Attr::Str(body_sym, synthetic_span())],
|
||||
default: None,
|
||||
span,
|
||||
};
|
||||
@@ -397,13 +400,9 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Lambda {
|
||||
scc_info,
|
||||
required,
|
||||
optional,
|
||||
} = downgrade_pattern_bindings(
|
||||
pat_entries,
|
||||
alias,
|
||||
arg,
|
||||
ctx,
|
||||
|ctx, _| self.body().unwrap().downgrade(ctx),
|
||||
)?;
|
||||
} = downgrade_pattern_bindings(pat_entries, alias, arg, ctx, |ctx, _| {
|
||||
self.body().unwrap().downgrade(ctx)
|
||||
})?;
|
||||
|
||||
param = Some(Param {
|
||||
required,
|
||||
|
||||
@@ -79,21 +79,21 @@ pub fn downgrade_inherit(
|
||||
for attr in inherit.attrs() {
|
||||
let span = attr.syntax().text_range();
|
||||
let ident = match downgrade_attr(attr, ctx)? {
|
||||
Attr::Str(ident) => ident,
|
||||
Attr::Str(ident, _) => ident,
|
||||
_ => {
|
||||
// `inherit` does not allow dynamic attributes.
|
||||
return Err(Error::downgrade_error(
|
||||
"dynamic attributes not allowed in inherit".to_string(),
|
||||
)
|
||||
.with_span(span)
|
||||
.with_source(ctx.get_current_source()));
|
||||
ctx.get_current_source(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
};
|
||||
let expr = if let Some(expr) = from {
|
||||
let select_expr = ctx.new_expr(
|
||||
Select {
|
||||
expr,
|
||||
attrpath: vec![Attr::Str(ident)],
|
||||
attrpath: vec![Attr::Str(ident, span)],
|
||||
default: None,
|
||||
span,
|
||||
}
|
||||
@@ -111,10 +111,14 @@ pub fn downgrade_inherit(
|
||||
};
|
||||
match stcs.entry(ident) {
|
||||
Entry::Occupied(occupied) => {
|
||||
return Err(Error::downgrade_error(format!(
|
||||
return Err(Error::downgrade_error(
|
||||
format!(
|
||||
"attribute '{}' already defined",
|
||||
format_symbol(ctx.get_sym(*occupied.key()))
|
||||
))
|
||||
),
|
||||
ctx.get_current_source(),
|
||||
span,
|
||||
)
|
||||
.with_span(span)
|
||||
.with_source(ctx.get_current_source()));
|
||||
}
|
||||
@@ -129,20 +133,24 @@ pub fn downgrade_inherit(
|
||||
pub fn downgrade_attr(attr: ast::Attr, ctx: &mut impl DowngradeContext) -> Result<Attr> {
|
||||
use ast::Attr::*;
|
||||
use ast::InterpolPart::*;
|
||||
let span = attr.syntax().text_range();
|
||||
match attr {
|
||||
Ident(ident) => Ok(Attr::Str(ctx.new_sym(ident.to_string()))),
|
||||
Ident(ident) => Ok(Attr::Str(
|
||||
ctx.new_sym(ident.to_string()),
|
||||
ident.syntax().text_range(),
|
||||
)),
|
||||
Str(string) => {
|
||||
let parts = string.normalized_parts();
|
||||
let span = string.syntax().text_range();
|
||||
if parts.is_empty() {
|
||||
Ok(Attr::Str(ctx.new_sym("".to_string())))
|
||||
Ok(Attr::Str(ctx.new_sym("".to_string()), span))
|
||||
} else if parts.len() == 1 {
|
||||
// If the string has only one part, it's either a literal or a single interpolation.
|
||||
match parts.into_iter().next().unwrap() {
|
||||
Literal(ident) => Ok(Attr::Str(ctx.new_sym(ident))),
|
||||
Interpolation(interpol) => {
|
||||
Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx)?))
|
||||
}
|
||||
Literal(ident) => Ok(Attr::Str(ctx.new_sym(ident), span)),
|
||||
Interpolation(interpol) => Ok(Attr::Dynamic(
|
||||
interpol.expr().unwrap().downgrade(ctx)?,
|
||||
span,
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
// If the string has multiple parts, it's an interpolated string that must be concatenated.
|
||||
@@ -155,10 +163,14 @@ pub fn downgrade_attr(attr: ast::Attr, ctx: &mut impl DowngradeContext) -> Resul
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
Ok(Attr::Dynamic(
|
||||
ctx.new_expr(ConcatStrings { parts, span }.to_ir()),
|
||||
span,
|
||||
))
|
||||
}
|
||||
}
|
||||
Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(ctx)?)),
|
||||
Dynamic(dynamic) => Ok(Attr::Dynamic(
|
||||
dynamic.expr().unwrap().downgrade(ctx)?,
|
||||
dynamic.syntax().text_range(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,12 +206,14 @@ pub fn downgrade_static_attrpathvalue(
|
||||
) -> Result<()> {
|
||||
let attrpath_node = value.attrpath().unwrap();
|
||||
let path = downgrade_attrpath(attrpath_node.clone(), ctx)?;
|
||||
if path.iter().any(|attr| matches!(attr, Attr::Dynamic(_))) {
|
||||
if let Some(&Attr::Dynamic(_, span)) =
|
||||
path.iter().find(|attr| matches!(attr, Attr::Dynamic(..)))
|
||||
{
|
||||
return Err(Error::downgrade_error(
|
||||
"dynamic attributes not allowed in let bindings".to_string(),
|
||||
)
|
||||
.with_span(attrpath_node.syntax().text_range())
|
||||
.with_source(ctx.get_current_source()));
|
||||
ctx.get_current_source(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
let value = value.value().unwrap().downgrade(ctx)?;
|
||||
attrs.insert(path, value, ctx)
|
||||
@@ -231,40 +245,47 @@ pub fn downgrade_pattern_bindings<Ctx>(
|
||||
where
|
||||
Ctx: DowngradeContext,
|
||||
{
|
||||
let mut param_syms = Vec::new();
|
||||
let mut param_defaults = Vec::new();
|
||||
let mut param_spans = Vec::new();
|
||||
struct Param {
|
||||
sym: SymId,
|
||||
sym_span: TextRange,
|
||||
default: Option<ast::Expr>,
|
||||
span: TextRange,
|
||||
}
|
||||
let mut seen_params = HashSet::new();
|
||||
|
||||
for entry in pat_entries {
|
||||
let sym = ctx.new_sym(entry.ident().unwrap().to_string());
|
||||
let span = entry.ident().unwrap().syntax().text_range();
|
||||
let (params, mut binding_keys) = pat_entries
|
||||
.into_iter()
|
||||
.map(|entry| {
|
||||
let ident = entry.ident().unwrap();
|
||||
let sym_span = ident.syntax().text_range();
|
||||
let sym = ctx.new_sym(ident.syntax().text().to_string());
|
||||
let default = entry.default();
|
||||
let span = entry.syntax().text_range();
|
||||
|
||||
if !seen_params.insert(sym) {
|
||||
return Err(Error::downgrade_error(format!(
|
||||
"duplicate parameter '{}'",
|
||||
format_symbol(ctx.get_sym(sym))
|
||||
return Err(Error::downgrade_error(
|
||||
format!("duplicate parameter '{}'", format_symbol(ctx.get_sym(sym))),
|
||||
ctx.get_current_source(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
Ok((
|
||||
Param {
|
||||
sym,
|
||||
sym_span,
|
||||
default,
|
||||
span,
|
||||
},
|
||||
sym,
|
||||
))
|
||||
.with_span(span)
|
||||
.with_source(ctx.get_current_source()));
|
||||
}
|
||||
})
|
||||
.collect::<Result<(Vec<_>, Vec<_>)>>()?;
|
||||
|
||||
let default_ast = entry.default();
|
||||
param_syms.push(sym);
|
||||
param_defaults.push(default_ast);
|
||||
param_spans.push(span);
|
||||
}
|
||||
|
||||
let mut binding_keys: Vec<SymId> = param_syms.clone();
|
||||
if let Some(alias_sym) = alias {
|
||||
binding_keys.push(alias_sym);
|
||||
}
|
||||
|
||||
let (required, optional) =
|
||||
param_syms
|
||||
.iter()
|
||||
.zip(param_defaults.iter())
|
||||
.partition_map(|(&sym, default)| {
|
||||
let (required, optional) = params.iter().partition_map(|Param { sym, default, .. }| {
|
||||
use itertools::Either::*;
|
||||
if default.is_none() {
|
||||
Left(sym)
|
||||
@@ -282,16 +303,18 @@ where
|
||||
|ctx, sym_to_slot| {
|
||||
let mut bindings = HashMap::new();
|
||||
|
||||
for ((sym, default_ast), span) in param_syms
|
||||
.iter()
|
||||
.zip(param_defaults.iter())
|
||||
.zip(param_spans.iter())
|
||||
for Param {
|
||||
sym,
|
||||
sym_span,
|
||||
default,
|
||||
span,
|
||||
} in params
|
||||
{
|
||||
let slot = *sym_to_slot.get(sym).unwrap();
|
||||
let slot = *sym_to_slot.get(&sym).unwrap();
|
||||
ctx.set_current_binding(Some(slot));
|
||||
|
||||
let default = if let Some(default_expr) = default_ast {
|
||||
Some(default_expr.clone().downgrade(ctx)?)
|
||||
let default = if let Some(default) = default {
|
||||
Some(default.clone().downgrade(ctx)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -299,13 +322,13 @@ where
|
||||
let select_expr = ctx.new_expr(
|
||||
Select {
|
||||
expr: arg,
|
||||
attrpath: vec![Attr::Str(*sym)],
|
||||
attrpath: vec![Attr::Str(sym, sym_span)],
|
||||
default,
|
||||
span: *span,
|
||||
span,
|
||||
}
|
||||
.to_ir(),
|
||||
);
|
||||
bindings.insert(*sym, select_expr);
|
||||
bindings.insert(sym, select_expr);
|
||||
ctx.set_current_binding(None);
|
||||
}
|
||||
|
||||
@@ -393,12 +416,11 @@ where
|
||||
.to_ir(),
|
||||
);
|
||||
} else {
|
||||
return Err(Error::downgrade_error(format!(
|
||||
"binding '{}' not found",
|
||||
format_symbol(ctx.get_sym(sym))
|
||||
))
|
||||
.with_span(synthetic_span())
|
||||
.with_source(ctx.get_current_source()));
|
||||
return Err(Error::downgrade_error(
|
||||
format!("binding '{}' not found", format_symbol(ctx.get_sym(sym))),
|
||||
ctx.get_current_source(),
|
||||
synthetic_span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,12 +455,14 @@ where
|
||||
if let ast::Attr::Ident(ident) = attr {
|
||||
let sym = ctx.new_sym(ident.to_string());
|
||||
if !binding_syms.insert(sym) {
|
||||
return Err(Error::downgrade_error(format!(
|
||||
return Err(Error::downgrade_error(
|
||||
format!(
|
||||
"attribute '{}' already defined",
|
||||
format_symbol(ctx.get_sym(sym))
|
||||
))
|
||||
.with_span(ident.syntax().text_range())
|
||||
.with_source(ctx.get_current_source()));
|
||||
),
|
||||
ctx.get_current_source(),
|
||||
ident.syntax().text_range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -453,12 +477,14 @@ where
|
||||
if let Some(ast::Attr::Ident(ident)) = attrs_vec.first() {
|
||||
let sym = ctx.new_sym(ident.to_string());
|
||||
if !binding_syms.insert(sym) {
|
||||
return Err(Error::downgrade_error(format!(
|
||||
return Err(Error::downgrade_error(
|
||||
format!(
|
||||
"attribute '{}' already defined",
|
||||
format_symbol(ctx.get_sym(sym))
|
||||
))
|
||||
.with_span(ident.syntax().text_range())
|
||||
.with_source(ctx.get_current_source()));
|
||||
),
|
||||
ctx.get_current_source(),
|
||||
ident.syntax().text_range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if attrs_vec.len() > 1 {
|
||||
|
||||
@@ -8,6 +8,7 @@ use deno_error::JsErrorClass;
|
||||
use itertools::Itertools as _;
|
||||
|
||||
use crate::error::{Error, Result, Source};
|
||||
use crate::store::Store;
|
||||
use crate::value::{AttrSet, List, Symbol, Value};
|
||||
|
||||
type ScopeRef<'p, 's> = v8::PinnedRef<'p, v8::HandleScope<'s>>;
|
||||
@@ -19,6 +20,23 @@ pub(crate) trait RuntimeContext: 'static {
|
||||
fn add_source(&mut self, path: Source);
|
||||
fn compile_code(&mut self, source: Source) -> Result<String>;
|
||||
fn get_source(&self, id: usize) -> Source;
|
||||
fn get_store(&self) -> &dyn Store;
|
||||
}
|
||||
|
||||
pub(crate) trait OpStateExt<Ctx: RuntimeContext> {
|
||||
fn get_ctx(&self) -> &Ctx;
|
||||
fn get_ctx_mut(&mut self) -> &mut Ctx;
|
||||
}
|
||||
|
||||
impl<Ctx: RuntimeContext> OpStateExt<Ctx> for OpState {
|
||||
fn get_ctx(&self) -> &Ctx {
|
||||
self.try_borrow::<&'static mut Ctx>()
|
||||
.expect("RuntimeContext not set")
|
||||
}
|
||||
fn get_ctx_mut(&mut self) -> &mut Ctx {
|
||||
self.try_borrow_mut::<&'static mut Ctx>()
|
||||
.expect("RuntimeContext not set")
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_extension<Ctx: RuntimeContext>() -> Extension {
|
||||
@@ -30,16 +48,16 @@ fn runtime_extension<Ctx: RuntimeContext>() -> Extension {
|
||||
op_path_exists(),
|
||||
op_resolve_path(),
|
||||
op_sha256_hex(),
|
||||
op_make_store_path(),
|
||||
op_make_store_path::<Ctx>(),
|
||||
op_output_path_name(),
|
||||
op_make_fixed_output_path(),
|
||||
op_add_path(),
|
||||
op_store_path(),
|
||||
op_to_file(),
|
||||
op_copy_path_to_store(),
|
||||
op_make_fixed_output_path::<Ctx>(),
|
||||
op_add_path::<Ctx>(),
|
||||
op_store_path::<Ctx>(),
|
||||
op_to_file::<Ctx>(),
|
||||
op_copy_path_to_store::<Ctx>(),
|
||||
op_get_env(),
|
||||
];
|
||||
ops.extend(crate::fetcher::register_ops());
|
||||
ops.extend(crate::fetcher::register_ops::<Ctx>());
|
||||
|
||||
Extension {
|
||||
name: "nix_runtime",
|
||||
@@ -85,7 +103,7 @@ fn op_import<Ctx: RuntimeContext>(
|
||||
#[string] path: String,
|
||||
) -> std::result::Result<String, NixError> {
|
||||
let _span = tracing::info_span!("op_import", path = %path).entered();
|
||||
let ctx = state.borrow_mut::<Ctx>();
|
||||
let ctx: &mut Ctx = state.get_ctx_mut();
|
||||
|
||||
let current_dir = ctx.get_current_dir();
|
||||
let mut absolute_path = current_dir
|
||||
@@ -169,17 +187,15 @@ fn op_sha256_hex(#[string] data: String) -> String {
|
||||
|
||||
#[deno_core::op2]
|
||||
#[string]
|
||||
fn op_make_store_path(
|
||||
fn op_make_store_path<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] ty: String,
|
||||
#[string] hash_hex: String,
|
||||
#[string] name: String,
|
||||
) -> String {
|
||||
use crate::store::StoreBackend;
|
||||
use std::sync::Arc;
|
||||
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let store_dir = store.as_store().get_store_dir();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
let store_dir = store.get_store_dir();
|
||||
crate::nix_hash::make_store_path(store_dir, &ty, &hash_hex, &name)
|
||||
}
|
||||
|
||||
@@ -191,19 +207,18 @@ fn op_output_path_name(#[string] drv_name: String, #[string] output_name: String
|
||||
|
||||
#[deno_core::op2]
|
||||
#[string]
|
||||
fn op_make_fixed_output_path(
|
||||
fn op_make_fixed_output_path<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] hash_algo: String,
|
||||
#[string] hash: String,
|
||||
#[string] hash_mode: String,
|
||||
#[string] name: String,
|
||||
) -> String {
|
||||
use crate::store::StoreBackend;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::sync::Arc;
|
||||
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let store_dir = store.as_store().get_store_dir();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
let store_dir = store.get_store_dir();
|
||||
|
||||
if hash_algo == "sha256" && hash_mode == "recursive" {
|
||||
crate::nix_hash::make_store_path(store_dir, "source", &hash, &name)
|
||||
@@ -220,18 +235,16 @@ fn op_make_fixed_output_path(
|
||||
|
||||
#[deno_core::op2]
|
||||
#[string]
|
||||
fn op_add_path(
|
||||
fn op_add_path<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
#[string] name: Option<String>,
|
||||
recursive: bool,
|
||||
#[string] sha256: Option<String>,
|
||||
) -> std::result::Result<String, NixError> {
|
||||
use crate::store::StoreBackend;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
let path_obj = Path::new(&path);
|
||||
|
||||
@@ -272,10 +285,10 @@ fn op_add_path(
|
||||
)));
|
||||
}
|
||||
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
|
||||
let store_path = store
|
||||
.as_store()
|
||||
.add_to_store_from_path(&computed_name, path_obj, vec![])
|
||||
.map_err(|e| NixError::from(format!("failed to add path to store: {}", e)))?;
|
||||
|
||||
@@ -319,20 +332,19 @@ fn compute_nar_hash(path: &std::path::Path) -> std::result::Result<String, NixEr
|
||||
|
||||
#[deno_core::op2]
|
||||
#[string]
|
||||
fn op_store_path(
|
||||
fn op_store_path<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
) -> std::result::Result<String, NixError> {
|
||||
use crate::store::{StoreBackend, validate_store_path};
|
||||
use std::sync::Arc;
|
||||
use crate::store::validate_store_path;
|
||||
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let store_dir = store.as_store().get_store_dir();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
let store_dir = store.get_store_dir();
|
||||
|
||||
validate_store_path(store_dir, &path).map_err(|e| NixError::from(e.to_string()))?;
|
||||
|
||||
store
|
||||
.as_store()
|
||||
.ensure_path(&path)
|
||||
.map_err(|e| NixError::from(e.to_string()))?;
|
||||
|
||||
@@ -341,18 +353,15 @@ fn op_store_path(
|
||||
|
||||
#[deno_core::op2]
|
||||
#[string]
|
||||
fn op_to_file(
|
||||
fn op_to_file<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] name: String,
|
||||
#[string] contents: String,
|
||||
#[serde] references: Vec<String>,
|
||||
) -> std::result::Result<String, NixError> {
|
||||
use crate::store::StoreBackend;
|
||||
use std::sync::Arc;
|
||||
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
let store_path = store
|
||||
.as_store()
|
||||
.add_text_to_store(&name, &contents, references)
|
||||
.map_err(|e| NixError::from(format!("builtins.toFile failed: {}", e)))?;
|
||||
|
||||
@@ -361,13 +370,11 @@ fn op_to_file(
|
||||
|
||||
#[deno_core::op2]
|
||||
#[string]
|
||||
fn op_copy_path_to_store(
|
||||
fn op_copy_path_to_store<Ctx: RuntimeContext>(
|
||||
state: &mut OpState,
|
||||
#[string] path: String,
|
||||
) -> std::result::Result<String, NixError> {
|
||||
use crate::store::StoreBackend;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
let path_obj = Path::new(&path);
|
||||
|
||||
@@ -381,9 +388,9 @@ fn op_copy_path_to_store(
|
||||
.unwrap_or("source")
|
||||
.to_string();
|
||||
|
||||
let store = state.borrow::<Arc<StoreBackend>>();
|
||||
let ctx: &Ctx = state.get_ctx();
|
||||
let store = ctx.get_store();
|
||||
let store_path = store
|
||||
.as_store()
|
||||
.add_to_store_from_path(&name, path_obj, vec![])
|
||||
.map_err(|e| NixError::from(format!("failed to copy path to store: {}", e)))?;
|
||||
|
||||
@@ -436,11 +443,8 @@ impl<Ctx: RuntimeContext> Runtime<Ctx> {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn op_state(&mut self) -> std::rc::Rc<std::cell::RefCell<OpState>> {
|
||||
self.js_runtime.op_state()
|
||||
}
|
||||
|
||||
pub(crate) fn eval(&mut self, script: String, ctx: Ctx) -> Result<Value> {
|
||||
pub(crate) fn eval(&mut self, script: String, ctx: &mut Ctx) -> Result<Value> {
|
||||
let ctx: &'static mut Ctx = unsafe { &mut *(ctx as *mut Ctx) };
|
||||
self.js_runtime.op_state().borrow_mut().put(ctx);
|
||||
|
||||
let global_value = self
|
||||
@@ -450,7 +454,7 @@ impl<Ctx: RuntimeContext> Runtime<Ctx> {
|
||||
// Get current source from Context
|
||||
let op_state = self.js_runtime.op_state();
|
||||
let op_state_borrow = op_state.borrow();
|
||||
let ctx = op_state_borrow.borrow::<Ctx>();
|
||||
let ctx: &Ctx = op_state_borrow.get_ctx();
|
||||
|
||||
let msg = e.get_message().to_string();
|
||||
let mut span = None;
|
||||
|
||||
Reference in New Issue
Block a user