This commit is contained in:
2026-02-18 19:27:20 +08:00
parent c3c39bda0c
commit 04dcadfd61
4 changed files with 50 additions and 45 deletions

View File

@@ -144,17 +144,20 @@ export const resolvePath = (currentDir: string, path: NixValue): NixPath => {
export const select = (obj: NixValue, attrpath: NixValue[], span?: string): NixValue => {
if (span) {
const pathStrings = attrpath.map((a) => forceStringValue(a));
const path = pathStrings.join(".");
const message = path ? `while selecting attribute [${path}]` : "while selecting attribute";
if (callStack.length >= MAX_STACK_DEPTH) {
callStack.shift();
}
callStack.push({ span, message });
const frame: StackFrame = { span, message: "while selecting attribute" };
callStack.push(frame);
try {
return selectImpl(obj, attrpath);
} catch (error) {
try {
const path = attrpath.map((a) => forceStringValue(a)).join(".");
if (path) frame.message = `while selecting attribute [${path}]`;
} catch {
throw enrichError(error);
}
throw enrichError(error);
} finally {
callStack.pop();
@@ -167,8 +170,8 @@ export const select = (obj: NixValue, attrpath: NixValue[], span?: string): NixV
function selectImpl(obj: NixValue, attrpath: NixValue[]): NixValue {
let attrs = forceAttrs(obj);
for (const attr of attrpath.slice(0, -1)) {
const key = forceStringValue(attr);
for (let i = 0; i < attrpath.length - 1; i++) {
const key = forceStringValue(attrpath[i]);
if (!attrs.has(key)) {
throw new Error(`Attribute '${key}' not found`);
}
@@ -190,17 +193,20 @@ export const selectWithDefault = (
span?: string,
): NixValue => {
if (span) {
const pathStrings = attrpath.map((a) => forceStringValue(a));
const path = pathStrings.join(".");
const message = path ? `while selecting attribute [${path}]` : "while selecting attribute";
if (callStack.length >= MAX_STACK_DEPTH) {
callStack.shift();
}
callStack.push({ span, message });
const frame: StackFrame = { span, message: "while selecting attribute" };
callStack.push(frame);
try {
return selectWithDefaultImpl(obj, attrpath, defaultVal);
} catch (error) {
try {
const path = attrpath.map((a) => forceStringValue(a)).join(".");
if (path) frame.message = `while selecting attribute [${path}]`;
} catch {
throw enrichError(error);
}
throw enrichError(error);
} finally {
callStack.pop();
@@ -216,8 +222,8 @@ function selectWithDefaultImpl(obj: NixValue, attrpath: NixValue[], defaultVal:
return defaultVal;
}
for (const attr of attrpath.slice(0, -1)) {
const key = forceStringValue(attr);
for (let i = 0; i < attrpath.length - 1; i++) {
const key = forceStringValue(attrpath[i]);
if (!attrs.has(key)) {
return defaultVal;
}
@@ -242,8 +248,8 @@ export const hasAttr = (obj: NixValue, attrpath: NixValue[]): NixBool => {
}
let attrs = forced;
for (const attr of attrpath.slice(0, -1)) {
const key = forceStringNoCtx(attr);
for (let i = 0; i < attrpath.length - 1; i++) {
const key = forceStringNoCtx(attrpath[i]);
if (!attrs.has(key)) {
return false;
}

View File

@@ -49,11 +49,12 @@ export const getStringValue = (s: string | StringWithContext): string => {
return s;
};
const emptyContext: NixStringContext = new Set();
export const getStringContext = (s: string | StringWithContext): NixStringContext => {
if (isStringWithContext(s)) {
return s.context;
}
return new Set();
return emptyContext;
};
export const mergeContexts = (...contexts: NixStringContext[]): NixStringContext => {

View File

@@ -35,10 +35,10 @@ export class NixArgs {
allowed: Set<string>;
ellipsis: boolean;
positions: Map<string, string>;
constructor(required: string[], optional: string[], positions: Record<string, string>, ellipsis: boolean) {
constructor(required: string[], optional: string[], positions: Map<string, string>, ellipsis: boolean) {
this.required = required;
this.optional = optional;
this.positions = new Map(Object.entries(positions));
this.positions = positions;
this.ellipsis = ellipsis;
this.allowed = new Set(required.concat(optional));
}
@@ -64,7 +64,7 @@ export const mkFunction = (
f: (arg: NixValue) => NixValue,
required: string[],
optional: string[],
positions: Record<string, string>,
positions: Map<string, string>,
ellipsis: boolean,
): NixFunction => {
const func: NixFunction = f;
@@ -86,12 +86,10 @@ export const mkAttrs = (attrs: NixAttrs, keys: NixValue[], values: NixValue[]):
};
export const mkAttrsWithPos = (
obj: Record<string, NixValue>,
positions: Record<string, string>,
attrs: NixAttrs,
positions: Map<string, string>,
dyns?: { dynKeys: NixValue[]; dynVals: NixValue[]; dynSpans: string[] },
): NixAttrs => {
const attrs: NixAttrs = new Map(Object.entries(obj));
if (dyns) {
const len = dyns.dynKeys.length;
for (let i = 0; i < len; i++) {
@@ -101,12 +99,12 @@ export const mkAttrsWithPos = (
}
const str = forceStringNoCtx(key);
attrs.set(str, dyns.dynVals[i]);
positions[str] = dyns.dynSpans[i];
positions.set(str, dyns.dynSpans[i]);
}
}
if (Object.keys(positions).length > 0) {
attrs[ATTR_POSITIONS] = new Map(Object.entries(positions));
if (positions.size > 0) {
attrs[ATTR_POSITIONS] = positions;
}
return attrs;

View File

@@ -458,11 +458,11 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Func {
joined(optional.iter(), ",", |ctx: &Ctx, buf, &(sym, _)| {
code!(buf, ctx; ctx.get_sym(sym));
})
"],{"
joined(required.iter().chain(optional.iter()), ",", |ctx: &Ctx, buf, &(sym, span)| {
code!(buf, ctx; ctx.get_sym(sym) ":" span);
"],new Map()"
joined(required.iter().chain(optional.iter()), "", |ctx: &Ctx, buf, &(sym, span)| {
code!(buf, ctx; ".set(" ctx.get_sym(sym) "," span ")");
})
"},"
","
ellipsis
")"
);
@@ -574,21 +574,21 @@ impl<Ctx: CodegenContext> Compile<Ctx> for AttrSet {
fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) {
if !self.dyns.is_empty() {
code!(buf, ctx;
"Nix.mkAttrsWithPos({"
joined(self.stcs.iter(), ",", |ctx: &Ctx, buf, (&sym, &(expr, _))| {
"Nix.mkAttrsWithPos(new Map()"
joined(self.stcs.iter(), "", |ctx: &Ctx, buf, (&sym, &(expr, _))| {
let key = ctx.get_sym(sym);
let val = ctx.get_ir(expr);
code!(
buf, ctx;
key ":Nix.withContext(\"while evaluating the attribute '" escaped(&key) "'\"," val.span() ",()=>(" val "))"
".set(" key ",Nix.withContext(\"while evaluating the attribute '" escaped(&key) "'\"," val.span() ",()=>(" val ")))"
);
})
"},{"
joined(self.stcs.iter(), ",", |ctx: &Ctx, buf, (&sym, &(_, span))| {
code!(buf, ctx; ctx.get_sym(sym) ":" span);
",new Map()"
joined(self.stcs.iter(), "", |ctx: &Ctx, buf, (&sym, &(_, span))| {
code!(buf, ctx; ".set(" ctx.get_sym(sym) "," span ")");
})
"},{dynKeys:["
",{dynKeys:["
joined(self.dyns.iter(), ",", |ctx: &Ctx, buf, (key, _, _)| {
code!(buf, ctx; ctx.get_ir(*key));
})
@@ -608,21 +608,21 @@ impl<Ctx: CodegenContext> Compile<Ctx> for AttrSet {
);
} else if !self.stcs.is_empty() {
code!(buf, ctx;
"Nix.mkAttrsWithPos({"
joined(self.stcs.iter(), ",", |ctx: &Ctx, buf, (&sym, &(expr, _))| {
"Nix.mkAttrsWithPos(new Map()"
joined(self.stcs.iter(), "", |ctx: &Ctx, buf, (&sym, &(expr, _))| {
let key = ctx.get_sym(sym);
let val = ctx.get_ir(expr);
code!(
buf, ctx;
key ":Nix.withContext(\"while evaluating the attribute '" escaped(&key) "'\"," val.span() ",()=>(" val "))"
".set(" key ",Nix.withContext(\"while evaluating the attribute '" escaped(&key) "'\"," val.span() ",()=>(" val ")))"
);
})
"},{"
joined(self.stcs.iter(), ",", |ctx: &Ctx, buf, (&sym, &(_, span))| {
code!(buf, ctx; ctx.get_sym(sym) ":" span);
",new Map()"
joined(self.stcs.iter(), "", |ctx: &Ctx, buf, (&sym, &(_, span))| {
code!(buf, ctx; ".set(" ctx.get_sym(sym) "," span ")");
})
"})"
")"
);
} else {
code!(buf, ctx; "new Map()");