fix: infinite recursion on perl (WIP)
This commit is contained in:
@@ -31,7 +31,6 @@ export const hasAttr =
|
||||
(set: NixValue): boolean =>
|
||||
Object.hasOwn(forceAttrs(set), forceStringValue(s));
|
||||
|
||||
let counter = 0;
|
||||
export const mapAttrs =
|
||||
(f: NixValue) =>
|
||||
(attrs: NixValue): NixAttrs => {
|
||||
@@ -39,8 +38,7 @@ export const mapAttrs =
|
||||
const forcedF = forceFunction(f);
|
||||
const newAttrs: NixAttrs = {};
|
||||
for (const key in forcedAttrs) {
|
||||
newAttrs[key] = createThunk(() => forceFunction(forcedF(key))(forcedAttrs[key]), `created by mapAttrs (${counter})`);
|
||||
counter += 1;
|
||||
newAttrs[key] = createThunk(() => forceFunction(forcedF(key))(forcedAttrs[key]), "created by mapAttrs");
|
||||
}
|
||||
return newAttrs;
|
||||
};
|
||||
|
||||
@@ -351,6 +351,18 @@ export const derivationStrict = (args: NixValue): NixAttrs => {
|
||||
return result;
|
||||
};
|
||||
|
||||
const specialAttrs = new Set([
|
||||
"name",
|
||||
"builder",
|
||||
"system",
|
||||
"args",
|
||||
"outputs",
|
||||
"__structuredAttrs",
|
||||
"__ignoreNulls",
|
||||
"__contentAddressed",
|
||||
"impure",
|
||||
]);
|
||||
|
||||
export const derivation = (args: NixValue): NixAttrs => {
|
||||
const attrs = forceAttrs(args);
|
||||
const strict = derivationStrict(args);
|
||||
@@ -364,18 +376,6 @@ export const derivation = (args: NixValue): NixAttrs => {
|
||||
const ignoreNulls = "__ignoreNulls" in attrs ? force(attrs.__ignoreNulls) === true : false;
|
||||
const drvArgs = extractArgs(attrs, collectedContext);
|
||||
|
||||
const specialAttrs = new Set([
|
||||
"name",
|
||||
"builder",
|
||||
"system",
|
||||
"args",
|
||||
"outputs",
|
||||
"__structuredAttrs",
|
||||
"__ignoreNulls",
|
||||
"__contentAddressed",
|
||||
"impure",
|
||||
]);
|
||||
|
||||
const baseAttrs: NixAttrs = {
|
||||
type: "derivation",
|
||||
drvPath: strict.drvPath,
|
||||
|
||||
@@ -18,7 +18,8 @@ import * as misc from "./misc";
|
||||
import * as derivation from "./derivation";
|
||||
|
||||
import type { NixValue } from "../types";
|
||||
import { createThunk, force } from "../thunk";
|
||||
import { createThunk, force, isThunk } from "../thunk";
|
||||
import { getTos } from "../helpers";
|
||||
|
||||
/**
|
||||
* Symbol used to mark functions as primops (primitive operations)
|
||||
@@ -263,4 +264,9 @@ export const builtins: any = {
|
||||
nixPath: [],
|
||||
nixVersion: "2.31.2",
|
||||
storeDir: "INVALID_PATH",
|
||||
|
||||
__traceCaller: (e: NixValue) => {
|
||||
console.log(`traceCaller: ${getTos()}`)
|
||||
return e
|
||||
},
|
||||
};
|
||||
|
||||
@@ -12,7 +12,8 @@ import { getPathValue } from "../path";
|
||||
import type { NixStringContext, StringWithContext } from "../string-context";
|
||||
import { mkStringWithContext } from "../string-context";
|
||||
import { isPath } from "./type-check";
|
||||
import { getCorepkg } from "../corepkgs";
|
||||
|
||||
const importCache = new Map<string, NixValue>();
|
||||
|
||||
export const importFunc = (path: NixValue): NixValue => {
|
||||
const context: NixStringContext = new Set();
|
||||
@@ -30,9 +31,17 @@ Dependency tracking for imported derivations may be incomplete.`,
|
||||
);
|
||||
}
|
||||
|
||||
const cached = importCache.get(pathStr);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// Call Rust op - returns JS code string
|
||||
const code = Deno.core.ops.op_import(pathStr);
|
||||
return Function(`return (${code})`)();
|
||||
const result = Function(`return (${code})`)();
|
||||
|
||||
importCache.set(pathStr, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
export const scopedImport =
|
||||
@@ -452,13 +461,8 @@ export const findFile =
|
||||
}
|
||||
|
||||
if (lookupPathStr.startsWith("nix/")) {
|
||||
const corepkgName = lookupPathStr.substring(4);
|
||||
const corepkgContent = getCorepkg(corepkgName);
|
||||
|
||||
if (corepkgContent !== undefined) {
|
||||
// FIXME: special path type
|
||||
return { [IS_PATH]: true, value: `<nix/${corepkgName}>` };
|
||||
}
|
||||
// FIXME: special path type
|
||||
return { [IS_PATH]: true, value: `<${lookupPathStr}>` };
|
||||
}
|
||||
|
||||
throw new CatchableError(`file '${lookupPathStr}' was not found in the Nix search path`);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Miscellaneous builtin functions
|
||||
*/
|
||||
|
||||
import { createThunk, force } from "../thunk";
|
||||
import { force } from "../thunk";
|
||||
import { CatchableError } from "../types";
|
||||
import type { NixAttrs, NixBool, NixStrictValue, NixValue } from "../types";
|
||||
import { forceList, forceAttrs, forceFunction, forceStringValue, forceString, forceStringNoCtx } from "../type-assert";
|
||||
@@ -20,7 +20,8 @@ import {
|
||||
export const addErrorContext =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): NixValue => {
|
||||
console.log("[WARNING]: addErrorContext not implemented");
|
||||
// FIXME:
|
||||
// console.log("[WARNING]: addErrorContext not implemented");
|
||||
return e2;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
export const FETCHURL_NIX = `{
|
||||
system ? "", # obsolete
|
||||
url,
|
||||
hash ? "", # an SRI hash
|
||||
|
||||
# Legacy hash specification
|
||||
md5 ? "",
|
||||
sha1 ? "",
|
||||
sha256 ? "",
|
||||
sha512 ? "",
|
||||
outputHash ?
|
||||
if hash != "" then
|
||||
hash
|
||||
else if sha512 != "" then
|
||||
sha512
|
||||
else if sha1 != "" then
|
||||
sha1
|
||||
else if md5 != "" then
|
||||
md5
|
||||
else
|
||||
sha256,
|
||||
outputHashAlgo ?
|
||||
if hash != "" then
|
||||
""
|
||||
else if sha512 != "" then
|
||||
"sha512"
|
||||
else if sha1 != "" then
|
||||
"sha1"
|
||||
else if md5 != "" then
|
||||
"md5"
|
||||
else
|
||||
"sha256",
|
||||
|
||||
executable ? false,
|
||||
unpack ? false,
|
||||
name ? baseNameOf (toString url),
|
||||
impure ? false,
|
||||
}:
|
||||
|
||||
derivation (
|
||||
{
|
||||
builder = "builtin:fetchurl";
|
||||
|
||||
# New-style output content requirements.
|
||||
outputHashMode = if unpack || executable then "recursive" else "flat";
|
||||
|
||||
inherit
|
||||
name
|
||||
url
|
||||
executable
|
||||
unpack
|
||||
;
|
||||
|
||||
system = "builtin";
|
||||
|
||||
# No need to double the amount of network traffic
|
||||
preferLocalBuild = true;
|
||||
|
||||
# This attribute does nothing; it's here to avoid changing evaluation results.
|
||||
impureEnvVars = [
|
||||
"http_proxy"
|
||||
"https_proxy"
|
||||
"ftp_proxy"
|
||||
"all_proxy"
|
||||
"no_proxy"
|
||||
];
|
||||
|
||||
# To make "nix-prefetch-url" work.
|
||||
urls = [ url ];
|
||||
}
|
||||
// (if impure then { __impure = true; } else { inherit outputHashAlgo outputHash; })
|
||||
)
|
||||
`;
|
||||
@@ -1,9 +0,0 @@
|
||||
import { FETCHURL_NIX } from "./fetchurl.nix";
|
||||
|
||||
export const COREPKGS: Record<string, string> = {
|
||||
"fetchurl.nix": FETCHURL_NIX,
|
||||
};
|
||||
|
||||
export const getCorepkg = (name: string): string | undefined => {
|
||||
return COREPKGS[name];
|
||||
};
|
||||
@@ -19,12 +19,10 @@ interface StackFrame {
|
||||
const callStack: StackFrame[] = [];
|
||||
const MAX_STACK_DEPTH = 1000;
|
||||
|
||||
export const STACK_TRACE = { enabled: false };
|
||||
|
||||
function enrichError(error: unknown): Error {
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
|
||||
if (!STACK_TRACE.enabled || callStack.length === 0) {
|
||||
if (callStack.length === 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -38,13 +36,17 @@ function enrichError(error: unknown): Error {
|
||||
return err;
|
||||
}
|
||||
|
||||
export const getTos = (): string => {
|
||||
const tos = callStack[callStack.length - 2];
|
||||
const { file, line, column } = Deno.core.ops.op_decode_span(tos.span);
|
||||
return `${tos.message} at ${file}:${line}:${column}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an error context onto the stack
|
||||
* Used for tracking evaluation context (e.g., "while evaluating the condition")
|
||||
*/
|
||||
export const pushContext = (message: string, span: string): void => {
|
||||
if (!STACK_TRACE.enabled) return;
|
||||
|
||||
if (callStack.length >= MAX_STACK_DEPTH) {
|
||||
callStack.shift();
|
||||
}
|
||||
@@ -55,7 +57,6 @@ export const pushContext = (message: string, span: string): void => {
|
||||
* Pop an error context from the stack
|
||||
*/
|
||||
export const popContext = (): void => {
|
||||
if (!STACK_TRACE.enabled) return;
|
||||
callStack.pop();
|
||||
};
|
||||
|
||||
@@ -64,10 +65,6 @@ export const popContext = (): void => {
|
||||
* Automatically pushes context before execution and pops after
|
||||
*/
|
||||
export const withContext = <T>(message: string, span: string, fn: () => T): T => {
|
||||
if (!STACK_TRACE.enabled) {
|
||||
return fn();
|
||||
}
|
||||
|
||||
pushContext(message, span);
|
||||
try {
|
||||
return fn();
|
||||
@@ -183,7 +180,7 @@ export const resolvePath = (currentDir: string, path: NixValue): NixPath => {
|
||||
};
|
||||
|
||||
export const select = (obj: NixValue, attrpath: NixValue[], span?: string): NixValue => {
|
||||
if (STACK_TRACE.enabled && span) {
|
||||
if (span) {
|
||||
const pathStrings = attrpath.map((a) => forceStringValue(a));
|
||||
const path = pathStrings.join(".");
|
||||
const message = path ? `while selecting attribute [${path}]` : "while selecting attribute";
|
||||
@@ -229,7 +226,7 @@ export const selectWithDefault = (
|
||||
default_val: NixValue,
|
||||
span?: string,
|
||||
): NixValue => {
|
||||
if (STACK_TRACE.enabled && span) {
|
||||
if (span) {
|
||||
const pathStrings = attrpath.map((a) => forceStringValue(a));
|
||||
const path = pathStrings.join(".");
|
||||
const message = path ? `while selecting attribute [${path}]` : "while selecting attribute";
|
||||
@@ -337,7 +334,7 @@ export const validateParams = (
|
||||
};
|
||||
|
||||
export const call = (func: NixValue, arg: NixValue, span?: string): NixValue => {
|
||||
if (STACK_TRACE.enabled && span) {
|
||||
if (span) {
|
||||
if (callStack.length >= MAX_STACK_DEPTH) {
|
||||
callStack.shift();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
concatStringsWithContext,
|
||||
call,
|
||||
assert,
|
||||
STACK_TRACE,
|
||||
pushContext,
|
||||
popContext,
|
||||
withContext,
|
||||
@@ -41,7 +40,6 @@ export const Nix = {
|
||||
HAS_CONTEXT,
|
||||
IS_PATH,
|
||||
DEBUG_THUNKS,
|
||||
STACK_TRACE,
|
||||
|
||||
assert,
|
||||
call,
|
||||
|
||||
@@ -224,13 +224,15 @@ export const op = {
|
||||
const attrsA = av as NixAttrs;
|
||||
const attrsB = bv as NixAttrs;
|
||||
|
||||
// If both denote a derivation (type = "derivation"), compare their outPaths
|
||||
const isDerivationA = "type" in attrsA && force(attrsA.type) === "derivation";
|
||||
const isDerivationB = "type" in attrsB && force(attrsB.type) === "derivation";
|
||||
|
||||
if (isDerivationA && isDerivationB) {
|
||||
if ("outPath" in attrsA && "outPath" in attrsB) {
|
||||
return op.eq(attrsA.outPath, attrsB.outPath);
|
||||
// Derivation comparison: compare outPaths only
|
||||
// Safe to force 'type' because it's always a string literal, never a computed value
|
||||
if ("type" in attrsA && "type" in attrsB) {
|
||||
const typeValA = force(attrsA.type);
|
||||
const typeValB = force(attrsB.type);
|
||||
if (typeValA === "derivation" && typeValB === "derivation") {
|
||||
if ("outPath" in attrsA && "outPath" in attrsB) {
|
||||
return op.eq(attrsA.outPath, attrsB.outPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,9 @@ import type { NixValue, NixThunkInterface, NixStrictValue } from "./types";
|
||||
export const IS_THUNK = Symbol("is_thunk");
|
||||
|
||||
const forceStack: NixThunk[] = [];
|
||||
const MAX_FORCE_DEPTH = 1000;
|
||||
|
||||
export const DEBUG_THUNKS = { enabled: false };
|
||||
export const DEBUG_THUNKS = { enabled: true };
|
||||
|
||||
/**
|
||||
* NixThunk class - represents a lazy, unevaluated expression
|
||||
@@ -97,13 +98,28 @@ export const force = (value: NixValue): NixStrictValue => {
|
||||
|
||||
if (DEBUG_THUNKS.enabled) {
|
||||
forceStack.push(thunk);
|
||||
if (forceStack.length > MAX_FORCE_DEPTH) {
|
||||
let msg = `force depth exceeded ${MAX_FORCE_DEPTH} at ${thunk}\n`;
|
||||
msg += "Force chain (most recent first):\n";
|
||||
for (let i = forceStack.length - 1; i >= Math.max(0, forceStack.length - 20); i--) {
|
||||
const t = forceStack[i];
|
||||
msg += ` ${i + 1}. ${t}`;
|
||||
msg += "\n";
|
||||
}
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const result = force(func());
|
||||
thunk.result = result;
|
||||
return result;
|
||||
} catch (e) {
|
||||
thunk.func = func;
|
||||
throw e;
|
||||
} finally {
|
||||
forceStack.pop();
|
||||
if (DEBUG_THUNKS.enabled) {
|
||||
forceStack.pop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,9 +11,6 @@ pub(crate) fn compile(expr: &Ir, ctx: &impl CodegenContext) -> String {
|
||||
if std::env::var("NIX_JS_DEBUG_THUNKS").is_ok() {
|
||||
debug_flags.push("Nix.DEBUG_THUNKS.enabled=true");
|
||||
}
|
||||
if std::env::var("NIX_JS_STACK_TRACE").is_ok() {
|
||||
debug_flags.push("Nix.STACK_TRACE.enabled=true");
|
||||
}
|
||||
let debug_prefix = if debug_flags.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
@@ -97,17 +94,11 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Ir {
|
||||
let cond_code = ctx.get_ir(cond).compile(ctx);
|
||||
let consq = ctx.get_ir(consq).compile(ctx);
|
||||
let alter = ctx.get_ir(alter).compile(ctx);
|
||||
|
||||
// Only add context tracking if STACK_TRACE is enabled
|
||||
if std::env::var("NIX_JS_STACK_TRACE").is_ok() {
|
||||
let cond_span = encode_span(ctx.get_ir(cond).span(), ctx);
|
||||
format!(
|
||||
"(Nix.withContext(\"while evaluating a branch condition\",{},()=>Nix.forceBool({})))?({}):({})",
|
||||
cond_span, cond_code, consq, alter
|
||||
)
|
||||
} else {
|
||||
format!("Nix.forceBool({cond_code})?({consq}):({alter})")
|
||||
}
|
||||
let cond_span = encode_span(ctx.get_ir(cond).span(), ctx);
|
||||
format!(
|
||||
"(Nix.withContext(\"while evaluating a branch condition\",{},()=>Nix.forceBool({})))?({}):({})",
|
||||
cond_span, cond_code, consq, alter
|
||||
)
|
||||
}
|
||||
Ir::BinOp(x) => x.compile(ctx),
|
||||
Ir::UnOp(x) => x.compile(ctx),
|
||||
@@ -149,27 +140,16 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Ir {
|
||||
}) => {
|
||||
let assertion_code = ctx.get_ir(assertion).compile(ctx);
|
||||
let expr = ctx.get_ir(expr).compile(ctx);
|
||||
|
||||
// Only add context tracking if STACK_TRACE is enabled
|
||||
if std::env::var("NIX_JS_STACK_TRACE").is_ok() {
|
||||
let assertion_span = encode_span(ctx.get_ir(assertion).span(), ctx);
|
||||
let span = encode_span(span, ctx);
|
||||
format!(
|
||||
"Nix.assert(Nix.withContext(\"while evaluating the condition of the assert statement\",{},()=>({})),{},{},{})",
|
||||
assertion_span,
|
||||
assertion_code,
|
||||
expr,
|
||||
assertion_raw.escape_quote(),
|
||||
span
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Nix.assert({},{},{})",
|
||||
assertion_code,
|
||||
expr,
|
||||
assertion_raw.escape_quote()
|
||||
)
|
||||
}
|
||||
let assertion_span = encode_span(ctx.get_ir(assertion).span(), ctx);
|
||||
let span = encode_span(span, ctx);
|
||||
format!(
|
||||
"Nix.assert(Nix.withContext(\"while evaluating the condition of the assert statement\",{},()=>({})),{},{},{})",
|
||||
assertion_span,
|
||||
assertion_code,
|
||||
expr,
|
||||
assertion_raw.escape_quote(),
|
||||
span
|
||||
)
|
||||
}
|
||||
Ir::CurPos(cur_pos) => {
|
||||
let span_str = encode_span(cur_pos.span, ctx);
|
||||
@@ -186,20 +166,12 @@ impl<Ctx: CodegenContext> Compile<Ctx> for BinOp {
|
||||
let lhs = ctx.get_ir(self.lhs).compile(ctx);
|
||||
let rhs = ctx.get_ir(self.rhs).compile(ctx);
|
||||
|
||||
// Only add context tracking if STACK_TRACE is enabled
|
||||
let stack_trace_enabled = std::env::var("NIX_JS_STACK_TRACE").is_ok();
|
||||
|
||||
// Helper to wrap operation with context (only if enabled)
|
||||
let with_ctx = |op_name: &str, op_call: String| {
|
||||
if stack_trace_enabled {
|
||||
let span = encode_span(self.span, ctx);
|
||||
format!(
|
||||
"Nix.withContext(\"while evaluating the {} operator\",{},()=>({}))",
|
||||
op_name, span, op_call
|
||||
)
|
||||
} else {
|
||||
op_call
|
||||
}
|
||||
let span = encode_span(self.span, ctx);
|
||||
format!(
|
||||
"Nix.withContext(\"while evaluating the {} operator\",{},()=>({}))",
|
||||
op_name, span, op_call
|
||||
)
|
||||
};
|
||||
|
||||
match self.kind {
|
||||
@@ -284,7 +256,7 @@ fn should_keep_thunk(ir: &Ir) -> bool {
|
||||
Ir::Int(_) | Ir::Float(_) | Ir::Bool(_) | Ir::Null(_) | Ir::Str(_) => false,
|
||||
// Builtin references are safe to evaluate eagerly
|
||||
Ir::Builtin(_) | Ir::Builtins(_) => false,
|
||||
Ir::ExprRef(_) => false,
|
||||
Ir::ExprRef(_) => true,
|
||||
// Everything else should remain lazy:
|
||||
_ => true,
|
||||
}
|
||||
@@ -351,21 +323,16 @@ impl<Ctx: CodegenContext> Compile<Ctx> for AttrSet {
|
||||
fn compile(&self, ctx: &Ctx) -> String {
|
||||
let mut attrs = Vec::new();
|
||||
let mut attr_positions = Vec::new();
|
||||
let stack_trace_enabled = std::env::var("NIX_JS_STACK_TRACE").is_ok();
|
||||
|
||||
for (&sym, &(expr, attr_span)) in &self.stcs {
|
||||
let key = ctx.get_sym(sym);
|
||||
let value_code = ctx.get_ir(expr).compile(ctx);
|
||||
|
||||
let value = if stack_trace_enabled {
|
||||
let value_span = encode_span(ctx.get_ir(expr).span(), ctx);
|
||||
format!(
|
||||
"Nix.withContext(\"while evaluating the attribute '{}'\",{},()=>({}))",
|
||||
key, value_span, value_code
|
||||
)
|
||||
} else {
|
||||
value_code
|
||||
};
|
||||
let value_span = encode_span(ctx.get_ir(expr).span(), ctx);
|
||||
let value = format!(
|
||||
"Nix.withContext(\"while evaluating the attribute '{}'\",{},()=>({}))",
|
||||
key, value_span, value_code
|
||||
);
|
||||
attrs.push(format!("{}:{}", key.escape_quote(), value));
|
||||
|
||||
let attr_pos_str = encode_span(attr_span, ctx);
|
||||
@@ -381,15 +348,11 @@ impl<Ctx: CodegenContext> Compile<Ctx> for AttrSet {
|
||||
let val_expr = ctx.get_ir(*val);
|
||||
let val = val_expr.compile(ctx);
|
||||
let span = val_expr.span();
|
||||
let val = if stack_trace_enabled {
|
||||
let span = encode_span(span, ctx);
|
||||
format!(
|
||||
"Nix.withContext(\"while evaluating a dynamic attribute\",{},()=>({}))",
|
||||
span, val
|
||||
)
|
||||
} else {
|
||||
val
|
||||
};
|
||||
let span = encode_span(span, ctx);
|
||||
let val = format!(
|
||||
"Nix.withContext(\"while evaluating a dynamic attribute\",{},()=>({}))",
|
||||
span, val
|
||||
);
|
||||
let dyn_span_str = encode_span(*attr_span, ctx);
|
||||
(key, val, dyn_span_str)
|
||||
})
|
||||
@@ -416,23 +379,17 @@ impl<Ctx: CodegenContext> Compile<Ctx> for AttrSet {
|
||||
|
||||
impl<Ctx: CodegenContext> Compile<Ctx> for List {
|
||||
fn compile(&self, ctx: &Ctx) -> String {
|
||||
let stack_trace_enabled = std::env::var("NIX_JS_STACK_TRACE").is_ok();
|
||||
|
||||
let list = self
|
||||
.items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, item)| {
|
||||
let item_code = ctx.get_ir(*item).compile(ctx);
|
||||
if stack_trace_enabled {
|
||||
let item_span = encode_span(ctx.get_ir(*item).span(), ctx);
|
||||
format!(
|
||||
"Nix.withContext(\"while evaluating list element {}\",{},()=>({}))",
|
||||
idx, item_span, item_code
|
||||
)
|
||||
} else {
|
||||
item_code
|
||||
}
|
||||
let item_span = encode_span(ctx.get_ir(*item).span(), ctx);
|
||||
format!(
|
||||
"Nix.withContext(\"while evaluating list element {}\",{},()=>({}))",
|
||||
idx, item_span, item_code
|
||||
)
|
||||
})
|
||||
.join(",");
|
||||
format!("[{list}]")
|
||||
@@ -441,22 +398,16 @@ impl<Ctx: CodegenContext> Compile<Ctx> for List {
|
||||
|
||||
impl<Ctx: CodegenContext> Compile<Ctx> for ConcatStrings {
|
||||
fn compile(&self, ctx: &Ctx) -> String {
|
||||
let stack_trace_enabled = std::env::var("NIX_JS_STACK_TRACE").is_ok();
|
||||
|
||||
let parts: Vec<String> = self
|
||||
.parts
|
||||
.iter()
|
||||
.map(|part| {
|
||||
let part_code = ctx.get_ir(*part).compile(ctx);
|
||||
if stack_trace_enabled {
|
||||
let part_span = encode_span(ctx.get_ir(*part).span(), ctx);
|
||||
format!(
|
||||
"Nix.withContext(\"while evaluating a path segment\",{},()=>({}))",
|
||||
part_span, part_code
|
||||
)
|
||||
} else {
|
||||
part_code
|
||||
}
|
||||
let part_span = encode_span(ctx.get_ir(*part).span(), ctx);
|
||||
format!(
|
||||
"Nix.withContext(\"while evaluating a path segment\",{},()=>({}))",
|
||||
part_span, part_code
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
@@ -214,8 +214,8 @@ pub struct StackFrame {
|
||||
pub src: NamedSource<Arc<str>>,
|
||||
}
|
||||
|
||||
const MAX_STACK_FRAMES: usize = 10;
|
||||
const FRAMES_AT_START: usize = 5;
|
||||
const MAX_STACK_FRAMES: usize = 20;
|
||||
const FRAMES_AT_START: usize = 15;
|
||||
const FRAMES_AT_END: usize = 5;
|
||||
|
||||
pub(crate) fn parse_js_error(error: Box<JsError>, ctx: &impl RuntimeContext) -> Error {
|
||||
@@ -234,7 +234,11 @@ pub(crate) fn parse_js_error(error: Box<JsError>, ctx: &impl RuntimeContext) ->
|
||||
} else {
|
||||
(None, None, Vec::new())
|
||||
};
|
||||
let stack_trace = truncate_stack_trace(frames);
|
||||
let stack_trace = if std::env::var("NIX_JS_STACK_TRACE").is_ok() {
|
||||
truncate_stack_trace(frames)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let message = error.get_message().to_string();
|
||||
let js_backtrace = error.stack.map(|stack| {
|
||||
stack
|
||||
@@ -272,7 +276,7 @@ fn parse_frames(stack: &str, ctx: &impl RuntimeContext) -> Vec<NixStackFrame> {
|
||||
let mut frames = Vec::new();
|
||||
|
||||
for line in stack.lines() {
|
||||
// Format: NIX_STACK_FRAME:start:end[:extra_data]
|
||||
// Format: NIX_STACK_FRAME:source_id:start:end[:extra_data]
|
||||
let Some(rest) = line.strip_prefix("NIX_STACK_FRAME:") else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -314,7 +314,8 @@ where
|
||||
ctx.set_current_binding(Some(slot));
|
||||
|
||||
let default = if let Some(default) = default {
|
||||
Some(default.clone().downgrade(ctx)?)
|
||||
let default = default.clone().downgrade(ctx)?;
|
||||
Some(ctx.maybe_thunk(default))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -539,7 +539,11 @@ fn op_copy_path_to_store<Ctx: RuntimeContext>(
|
||||
#[deno_core::op2]
|
||||
#[string]
|
||||
fn op_get_env(#[string] key: String) -> std::result::Result<String, NixError> {
|
||||
Ok(std::env::var(key).map_err(|err| format!("Failed to read env var: {err}"))?)
|
||||
match std::env::var(key) {
|
||||
Ok(val) => Ok(val),
|
||||
Err(std::env::VarError::NotPresent) => Ok("".into()),
|
||||
Err(err) => Err(format!("Failed to read env var: {err}").into())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Runtime<Ctx: RuntimeContext> {
|
||||
|
||||
Reference in New Issue
Block a user