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

View File

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

View File

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

View File

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