chore: tidy

This commit is contained in:
2026-01-10 19:56:20 +08:00
parent fbf35ba4cd
commit e33770c1bf
23 changed files with 163 additions and 172 deletions

7
.lazy.lua Normal file
View File

@@ -0,0 +1,7 @@
vim.lsp.config("biome", {
root_dir = function (bufnr, on_dir)
on_dir(vim.fn.getcwd())
end
})
return {}

View File

@@ -17,6 +17,13 @@
"lineWidth": 110,
"lineEnding": "lf"
},
"linter": {
"rules": {
"style": {
"useNamingConvention": "warn"
}
}
},
"javascript": {
"formatter": {
"arrowParentheses": "always",

View File

@@ -3,33 +3,33 @@
*/
import type { NixBool, NixInt, NixNumber, NixValue } from "../types";
import { force_numeric, coerce_numeric, force_int } from "../type-assert";
import { forceNumeric, coerceNumeric, forceInt } from "../type-assert";
export const add =
(a: NixValue) =>
(b: NixValue): bigint | number => {
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) + (bv as any);
};
export const sub =
(a: NixValue) =>
(b: NixValue): bigint | number => {
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) - (bv as any);
};
export const mul =
(a: NixValue) =>
(b: NixValue): bigint | number => {
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) * (bv as any);
};
export const div =
(a: NixValue) =>
(b: NixValue): NixNumber => {
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
if (bv === 0 || bv === 0n) {
throw new RangeError("Division by zero");
@@ -42,28 +42,28 @@ export const div =
export const bitAnd =
(a: NixValue) =>
(b: NixValue): NixInt => {
const av = force_int(a);
const bv = force_int(b);
const av = forceInt(a);
const bv = forceInt(b);
return av & bv;
};
export const bitOr =
(a: NixValue) =>
(b: NixValue): NixInt => {
const av = force_int(a);
const bv = force_int(b);
const av = forceInt(a);
const bv = forceInt(b);
return av | bv;
};
export const bitXor =
(a: NixValue) =>
(b: NixValue): NixInt => {
const av = force_int(a);
const bv = force_int(b);
const av = forceInt(a);
const bv = forceInt(b);
return av ^ bv;
};
export const lessThan =
(a: NixValue) =>
(b: NixValue): NixBool =>
force_numeric(a) < force_numeric(b);
forceNumeric(a) < forceNumeric(b);

View File

@@ -3,30 +3,30 @@
*/
import type { NixValue, NixAttrs, NixList } from "../types";
import { force_attrs, force_string, force_function, force_list } from "../type-assert";
import { forceAttrs, forceString, forceFunction, forceList } from "../type-assert";
export const attrNames = (set: NixValue): string[] => Object.keys(force_attrs(set)).sort();
export const attrNames = (set: NixValue): string[] => Object.keys(forceAttrs(set)).sort();
export const attrValues = (set: NixValue): NixValue[] => Object.values(force_attrs(set));
export const attrValues = (set: NixValue): NixValue[] => Object.values(forceAttrs(set));
export const getAttr =
(s: NixValue) =>
(set: NixValue): NixValue =>
force_attrs(set)[force_string(s)];
forceAttrs(set)[forceString(s)];
export const hasAttr =
(s: NixValue) =>
(set: NixValue): boolean =>
Object.hasOwn(force_attrs(set), force_string(s));
Object.hasOwn(forceAttrs(set), forceString(s));
export const mapAttrs =
(f: NixValue) =>
(attrs: NixValue): NixAttrs => {
const new_attrs: NixAttrs = {};
const forced_attrs = force_attrs(attrs);
const forced_f = force_function(f);
const forced_attrs = forceAttrs(attrs);
const forced_f = forceFunction(f);
for (const key in forced_attrs) {
new_attrs[key] = forced_f(key)(forced_attrs[key]);
new_attrs[key] = forceFunction(forced_f(key))(forced_attrs[key]);
}
return new_attrs;
};
@@ -35,8 +35,8 @@ export const removeAttrs =
(attrs: NixValue) =>
(list: NixValue): NixAttrs => {
const new_attrs: NixAttrs = {};
const forced_attrs = force_attrs(attrs);
const forced_list = force_list(list);
const forced_attrs = forceAttrs(attrs);
const forced_list = forceList(list);
for (const key in forced_attrs) {
if (!(key in forced_list)) {
@@ -48,10 +48,10 @@ export const removeAttrs =
export const listToAttrs = (e: NixValue): NixAttrs => {
const attrs: NixAttrs = {};
const forced_e = [...force_list(e)].reverse();
const forced_e = [...forceList(e)].reverse();
for (const obj of forced_e) {
const item = force_attrs(obj);
attrs[force_string(item.name)] = item.value;
const item = forceAttrs(obj);
attrs[forceString(item.name)] = item.value;
}
return attrs;
};
@@ -59,8 +59,8 @@ export const listToAttrs = (e: NixValue): NixAttrs => {
export const intersectAttrs =
(e1: NixValue) =>
(e2: NixValue): NixAttrs => {
const f1 = force_attrs(e1);
const f2 = force_attrs(e2);
const f1 = forceAttrs(e1);
const f2 = forceAttrs(e2);
const attrs: NixAttrs = {};
for (const key of Object.keys(f2)) {
if (Object.hasOwn(f1, key)) {
@@ -73,9 +73,9 @@ export const intersectAttrs =
export const catAttrs =
(attr: NixValue) =>
(list: NixValue): NixList => {
const key = force_string(attr);
return force_list(list)
.map((set) => force_attrs(set)[key])
const key = forceString(attr);
return forceList(list)
.map((set) => forceAttrs(set)[key])
.filter((val) => val !== undefined);
};
@@ -83,10 +83,10 @@ export const groupBy =
(f: NixValue) =>
(list: NixValue): NixAttrs => {
const attrs: NixAttrs = {};
const forced_f = force_function(f);
const forced_list = force_list(list);
const forced_f = forceFunction(f);
const forced_list = forceList(list);
for (const elem of forced_list) {
const key = force_string(forced_f(elem));
const key = forceString(forced_f(elem));
if (!attrs[key]) attrs[key] = [];
(attrs[key] as NixList).push(elem);
}

View File

@@ -191,6 +191,6 @@ export const coerceToString = (
* @param value - The value to convert to a string
* @returns The string representation
*/
export const toString = (value: NixValue): string => {
export const toStringFunc = (value: NixValue): string => {
return coerceToString(value, StringCoercionMode.ToString, false);
};

View File

@@ -4,7 +4,7 @@
import { CatchableError, type NixValue } from "../types";
import { force } from "../thunk";
import { force_string } from "../type-assert";
import { forceString } from "../type-assert";
export const seq =
(e1: NixValue) =>
@@ -24,7 +24,7 @@ export const abort = (s: NixValue): never => {
};
export const throwFunc = (s: NixValue): never => {
throw new CatchableError(force_string(s));
throw new CatchableError(forceString(s));
};
export const trace = (e1: NixValue, e2: NixValue): NixValue => {

View File

@@ -211,7 +211,7 @@ export const builtins: any = {
fromTOML: mkPrimop(conversion.fromTOML, "fromTOML", 1),
toJSON: mkPrimop(conversion.toJSON, "toJSON", 1),
toXML: mkPrimop(conversion.toXML, "toXML", 1),
toString: mkPrimop(conversion.toString, "toString", 1),
toString: mkPrimop(conversion.toStringFunc, "toString", 1),
addErrorContext: mkPrimop(misc.addErrorContext, "addErrorContext", 1),
appendContext: mkPrimop(misc.appendContext, "appendContext", 1),

View File

@@ -3,23 +3,20 @@
* Implemented via Rust ops exposed through deno_core
*/
import { forceString } from "../type-assert";
import type { NixValue } from "../types";
import { force_string } from "../type-assert";
// Declare Deno.core.ops global (provided by deno_core runtime)
export const importFunc = (path: NixValue): NixValue => {
// For MVP: only support string paths
// TODO: After implementing path type, also accept path values
const pathStr = force_string(path);
const pathStr = forceString(path);
// Call Rust op - returns JS code string
const code = Deno.core.ops.op_import(pathStr);
// Eval in current context - returns V8 value directly!
// (0, eval) = indirect eval = global scope
// Wrap in parentheses to ensure object literals are parsed correctly
return (0, eval)(`(${code})`);
return Function(`return (${code})`)();
};
export const scopedImport =
@@ -61,7 +58,7 @@ export const readDir = (path: NixValue): never => {
};
export const readFile = (path: NixValue): string => {
const pathStr = force_string(path);
const pathStr = forceString(path);
return Deno.core.ops.op_read_file(pathStr);
};
@@ -70,7 +67,7 @@ export const readFileType = (path: NixValue): never => {
};
export const pathExists = (path: NixValue): boolean => {
const pathStr = force_string(path);
const pathStr = forceString(path);
return Deno.core.ops.op_path_exists(pathStr);
};

View File

@@ -5,38 +5,38 @@
import type { NixValue, NixList, NixAttrs } from "../types";
import { force } from "../thunk";
import { force_list, force_function, force_numeric, force_int } from "../type-assert";
import { forceList, forceFunction, forceInt } from "../type-assert";
export const map =
(f: NixValue) =>
(list: NixValue): NixList =>
force_list(list).map(force_function(f));
forceList(list).map(forceFunction(f));
export const filter =
(f: NixValue) =>
(list: NixValue): NixList =>
force_list(list).filter(force_function(f));
forceList(list).filter(forceFunction(f));
export const length = (e: NixValue): bigint => {
const forced = force(e);
if (typeof forced === "string") return BigInt(forced.length);
return BigInt(force_list(forced).length);
return BigInt(forceList(forced).length);
};
export const head = (list: NixValue): NixValue => force_list(list)[0];
export const head = (list: NixValue): NixValue => forceList(list)[0];
export const tail = (list: NixValue): NixList => force_list(list).slice(1);
export const tail = (list: NixValue): NixList => forceList(list).slice(1);
export const elem =
(x: NixValue) =>
(xs: NixValue): boolean =>
force_list(xs).includes(force(x));
forceList(xs).includes(force(x));
export const elemAt =
(xs: NixValue) =>
(n: NixValue): NixValue => {
const list = force_list(xs);
const idx = Number(force_int(n));
const list = forceList(xs);
const idx = Number(forceInt(n));
if (idx < 0 || idx >= list.length) {
throw new RangeError(`Index ${idx} out of bounds for list of length ${list.length}`);
@@ -46,16 +46,16 @@ export const elemAt =
};
export const concatLists = (lists: NixValue): NixList => {
return force_list(lists).reduce((acc: NixList, cur: NixValue) => {
return acc.concat(force_list(cur));
return forceList(lists).reduce((acc: NixList, cur: NixValue) => {
return acc.concat(forceList(cur));
}, []);
};
export const concatMap =
(f: NixValue) =>
(lists: NixValue): NixList => {
const fn = force_function(f);
return force_list(lists).reduce((acc: NixList, cur: NixValue) => {
const fn = forceFunction(f);
return forceList(lists).reduce((acc: NixList, cur: NixValue) => {
return acc.concat(force(fn(cur)) as NixList);
}, []);
};
@@ -64,20 +64,20 @@ export const foldlPrime =
(op_fn: NixValue) =>
(nul: NixValue) =>
(list: NixValue): NixValue => {
const forced_op = force_function(op_fn);
return force_list(list).reduce((acc: NixValue, cur: NixValue) => {
return forced_op(acc)(cur);
const forced_op = forceFunction(op_fn);
return forceList(list).reduce((acc: NixValue, cur: NixValue) => {
return forceFunction(forced_op(acc))(cur);
}, nul);
};
export const sort =
(cmp: NixValue) =>
(list: NixValue): NixList => {
const forced_list = [...force_list(list)];
const forced_cmp = force_function(cmp);
const forced_list = [...forceList(list)];
const forced_cmp = forceFunction(cmp);
return forced_list.sort((a, b) => {
if (force(forced_cmp(a)(b))) return -1;
if (force(forced_cmp(b)(a))) return 1;
if (force(forceFunction(forced_cmp(a))(b))) return -1;
if (force(forceFunction(forced_cmp(b))(a))) return 1;
return 0;
});
};
@@ -85,8 +85,8 @@ export const sort =
export const partition =
(pred: NixValue) =>
(list: NixValue): NixAttrs => {
const forced_list = force_list(list);
const forced_pred = force_function(pred);
const forced_list = forceList(list);
const forced_pred = forceFunction(pred);
const attrs: NixAttrs = {
right: [],
wrong: [],
@@ -104,8 +104,8 @@ export const partition =
export const genList =
(f: NixValue) =>
(len: NixValue): NixList => {
const func = force_function(f);
const length = force_int(len);
const func = forceFunction(f);
const length = forceInt(len);
if (length < 0) {
throw new TypeError(`genList length must be non-negative integer, got ${length}`);
@@ -117,9 +117,9 @@ export const genList =
export const all =
(pred: NixValue) =>
(list: NixValue): boolean =>
force_list(list).every(force_function(pred));
forceList(list).every(forceFunction(pred));
export const any =
(pred: NixValue) =>
(list: NixValue): boolean =>
force_list(list).some(force_function(pred));
forceList(list).some(forceFunction(pred));

View File

@@ -3,16 +3,16 @@
*/
import type { NixValue } from "../types";
import { force_numeric } from "../type-assert";
import { forceNumeric } from "../type-assert";
export const ceil = (x: NixValue): bigint => {
const val = force_numeric(x);
const val = forceNumeric(x);
if (typeof val === "bigint") return val; // Already an integer
return BigInt(Math.ceil(val)); // Convert to integer
};
export const floor = (x: NixValue): bigint => {
const val = force_numeric(x);
const val = forceNumeric(x);
if (typeof val === "bigint") return val; // Already an integer
return BigInt(Math.floor(val)); // Convert to integer
};

View File

@@ -3,27 +3,27 @@
*/
import type { NixValue } from "../types";
import { force_string, force_list, force_int } from "../type-assert";
import { forceString, forceList, forceInt } from "../type-assert";
export const stringLength = (e: NixValue): number => force_string(e).length;
export const stringLength = (e: NixValue): number => forceString(e).length;
export const substring =
(start: NixValue) =>
(len: NixValue) =>
(s: NixValue): string => {
const str = force_string(s);
const startPos = Number(force_int(start));
const length = Number(force_int(len));
const str = forceString(s);
const startPos = Number(forceInt(start));
const length = Number(forceInt(len));
return str.substring(startPos, startPos + length);
};
export const concatStringsSep =
(sep: NixValue) =>
(list: NixValue): string =>
force_list(list).join(force_string(sep));
forceList(list).join(forceString(sep));
export const baseNameOf = (x: NixValue): string => {
const str = force_string(x);
const str = forceString(x);
if (str.length === 0) return "";
let last = str.length - 1;

View File

@@ -3,7 +3,7 @@
*/
import type { NixValue, NixAttrs, NixBool } from "./types";
import { force_attrs, force_string } from "./type-assert";
import { forceAttrs, forceString } from "./type-assert";
import { isAttrs } from "./builtins/type-check";
/**
@@ -14,7 +14,7 @@ import { isAttrs } from "./builtins/type-check";
* @returns Absolute path string
*/
export const resolvePath = (path: NixValue): string => {
const path_str = force_string(path);
const path_str = forceString(path);
return Deno.core.ops.op_resolve_path(path_str);
};
@@ -28,8 +28,8 @@ export const resolvePath = (path: NixValue): string => {
* @throws Error if obj is null/undefined or key not found
*/
export const select = (obj: NixValue, key: NixValue): NixValue => {
const forced_obj = force_attrs(obj);
const forced_key = force_string(key);
const forced_obj = forceAttrs(obj);
const forced_key = forceString(key);
if (!(forced_key in forced_obj)) {
throw new Error(`Attribute '${forced_key}' not found`);
@@ -48,8 +48,8 @@ export const select = (obj: NixValue, key: NixValue): NixValue => {
* @returns obj[key] if exists, otherwise default_val
*/
export const selectWithDefault = (obj: NixValue, key: NixValue, default_val: NixValue): NixValue => {
const attrs = force_attrs(obj);
const forced_key = force_string(key);
const attrs = forceAttrs(obj);
const forced_key = forceString(key);
if (!(forced_key in attrs)) {
return default_val;
@@ -65,7 +65,7 @@ export const hasAttr = (obj: NixValue, attrpath: NixValue[]): NixBool => {
let attrs = obj;
for (const attr of attrpath.slice(0, -1)) {
const cur = attrs[force_string(attr)];
const cur = attrs[forceString(attr)];
if (!isAttrs(cur)) {
return false;
}
@@ -94,7 +94,7 @@ export const validateParams = (
required: string[] | null,
allowed: string[] | null,
): NixAttrs => {
const forced_arg = force_attrs(arg);
const forced_arg = forceAttrs(arg);
// Check required parameters
if (required) {

View File

@@ -4,7 +4,7 @@
* All functionality is exported via the global `Nix` object
*/
import { createThunk, force, is_thunk, IS_THUNK } from "./thunk";
import { createThunk, force, isThunk, IS_THUNK } from "./thunk";
import { select, selectWithDefault, validateParams, resolvePath, hasAttr } from "./helpers";
import { op } from "./operators";
import { builtins, PRIMOP_METADATA } from "./builtins";
@@ -18,7 +18,7 @@ export type NixRuntime = typeof Nix;
export const Nix = {
createThunk,
force,
is_thunk,
isThunk,
IS_THUNK,
hasAttr,

View File

@@ -5,7 +5,7 @@
import type { NixValue, NixList, NixAttrs } from "./types";
import { force } from "./thunk";
import { force_numeric, force_list, force_attrs, coerce_numeric } from "./type-assert";
import { forceNumeric, forceList, forceAttrs, coerceNumeric } from "./type-assert";
/**
* Operator object exported as Nix.op
@@ -15,22 +15,22 @@ export const op = {
// Arithmetic operators - preserve int/float distinction
add: (a: NixValue, b: NixValue): bigint | number => {
// FIXME: String & Path
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) + (bv as any);
},
sub: (a: NixValue, b: NixValue): bigint | number => {
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) - (bv as any);
},
mul: (a: NixValue, b: NixValue): bigint | number => {
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) * (bv as any);
},
div: (a: NixValue, b: NixValue): bigint | number => {
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
if (bv === 0 || bv === 0n) {
throw new RangeError("Division by zero");
@@ -54,22 +54,22 @@ export const op = {
},
lt: (a: NixValue, b: NixValue): boolean => {
// FIXME: Non-numeric
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) < (bv as any);
},
lte: (a: NixValue, b: NixValue): boolean => {
// FIXME: Non-numeric
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) <= (bv as any);
},
gt: (a: NixValue, b: NixValue): boolean => {
// FIXME: Non-numeric
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) > (bv as any);
},
gte: (a: NixValue, b: NixValue): boolean => {
// FIXME: Non-numeric
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b));
return (av as any) >= (bv as any);
},
@@ -81,11 +81,11 @@ export const op = {
// List concatenation
concat: (a: NixValue, b: NixValue): NixList => {
return Array.prototype.concat.call(force_list(a), force_list(b));
return Array.prototype.concat.call(forceList(a), forceList(b));
},
// Attribute set update (merge)
update: (a: NixValue, b: NixValue): NixAttrs => {
return { ...force_attrs(a), ...force_attrs(b) };
return { ...forceAttrs(a), ...forceAttrs(b) };
},
};

View File

@@ -34,7 +34,7 @@ export class NixThunk implements NixThunkInterface {
* @param value - Value to check
* @returns true if value is a NixThunk
*/
export const is_thunk = (value: unknown): value is NixThunkInterface => {
export const isThunk = (value: unknown): value is NixThunkInterface => {
return value !== null && typeof value === "object" && IS_THUNK in value && value[IS_THUNK] === true;
};
@@ -47,7 +47,7 @@ export const is_thunk = (value: unknown): value is NixThunkInterface => {
* @returns The forced/evaluated value
*/
export const force = (value: NixValue): NixStrictValue => {
if (!is_thunk(value)) {
if (!isThunk(value)) {
return value;
}

View File

@@ -5,7 +5,6 @@
import type { NixValue, NixList, NixAttrs, NixFunction, NixInt, NixFloat, NixNumber } from "./types";
import { force } from "./thunk";
import { isAttrs } from "./builtins/type-check";
const typeName = (value: NixValue): string => {
const val = force(value);
@@ -26,7 +25,7 @@ const typeName = (value: NixValue): string => {
* Force a value and assert it's a list
* @throws TypeError if value is not a list after forcing
*/
export const force_list = (value: NixValue): NixList => {
export const forceList = (value: NixValue): NixList => {
const forced = force(value);
if (!Array.isArray(forced)) {
throw new TypeError(`Expected list, got ${typeName(forced)}`);
@@ -38,7 +37,7 @@ export const force_list = (value: NixValue): NixList => {
* Force a value and assert it's a function
* @throws TypeError if value is not a function after forcing
*/
export const force_function = (value: NixValue): NixFunction => {
export const forceFunction = (value: NixValue): NixFunction => {
const forced = force(value);
if (typeof forced !== "function") {
throw new TypeError(`Expected function, got ${typeName(forced)}`);
@@ -50,7 +49,7 @@ export const force_function = (value: NixValue): NixFunction => {
* Force a value and assert it's an attribute set
* @throws TypeError if value is not an attribute set after forcing
*/
export const force_attrs = (value: NixValue): NixAttrs => {
export const forceAttrs = (value: NixValue): NixAttrs => {
const forced = force(value);
if (typeof forced !== "object" || Array.isArray(forced) || forced === null) {
throw new TypeError(`Expected attribute set, got ${typeName(forced)}`);
@@ -62,7 +61,7 @@ export const force_attrs = (value: NixValue): NixAttrs => {
* Force a value and assert it's a string
* @throws TypeError if value is not a string after forcing
*/
export const force_string = (value: NixValue): string => {
export const forceString = (value: NixValue): string => {
const forced = force(value);
if (typeof forced !== "string") {
throw new TypeError(`Expected string, got ${typeName(forced)}`);
@@ -74,7 +73,7 @@ export const force_string = (value: NixValue): string => {
* Force a value and assert it's a boolean
* @throws TypeError if value is not a boolean after forcing
*/
export const force_bool = (value: NixValue): boolean => {
export const forceBool = (value: NixValue): boolean => {
const forced = force(value);
if (typeof forced !== "boolean") {
throw new TypeError(`Expected boolean, got ${typeName(forced)}`);
@@ -86,7 +85,7 @@ export const force_bool = (value: NixValue): boolean => {
* Force a value and extract int value
* @throws TypeError if value is not an int
*/
export const force_int = (value: NixValue): NixInt => {
export const forceInt = (value: NixValue): NixInt => {
const forced = force(value);
if (typeof forced === "bigint") {
return forced;
@@ -98,7 +97,7 @@ export const force_int = (value: NixValue): NixInt => {
* Force a value and extract float value
* @throws TypeError if value is not a float
*/
export const force_float = (value: NixValue): NixFloat => {
export const forceFloat = (value: NixValue): NixFloat => {
const forced = force(value);
if (typeof forced === "number") {
return forced;
@@ -110,7 +109,7 @@ export const force_float = (value: NixValue): NixFloat => {
* Force a value and extract numeric value (int or float)
* @throws TypeError if value is not a numeric type
*/
export const force_numeric = (value: NixValue): NixNumber => {
export const forceNumeric = (value: NixValue): NixNumber => {
const forced = force(value);
if (typeof forced === "bigint" || typeof forced === "number") {
return forced;
@@ -123,7 +122,7 @@ export const force_numeric = (value: NixValue): NixNumber => {
* Rule: If either is float, convert both to float; otherwise keep as bigint
* @returns [a, b] tuple of coerced values
*/
export const coerce_numeric = (a: NixNumber, b: NixNumber): [NixFloat, NixFloat] | [NixInt, NixInt] => {
export const coerceNumeric = (a: NixNumber, b: NixNumber): [NixFloat, NixFloat] | [NixInt, NixInt] => {
const aIsInt = typeof a === "bigint";
const bIsInt = typeof b === "bigint";

View File

@@ -15,7 +15,7 @@ export type NixNull = null;
// Nix composite types
export type NixList = NixValue[];
export type NixAttrs = { [key: string]: NixValue };
export type NixFunction = (...args: any[]) => any;
export type NixFunction = (arg: NixValue) => NixValue;
/**
* Interface for lazy thunk values
@@ -42,11 +42,7 @@ export type NixStrictValue = Exclude<NixValue, NixThunkInterface>;
* CatchableError: Error type thrown by `builtins.throw`
* This can be caught by `builtins.tryEval`
*/
export class CatchableError extends Error {
constructor(msg: string) {
super(msg);
}
}
export class CatchableError extends Error {}
// Operator function signatures
export type BinaryOp<T = NixValue, U = NixValue, R = NixValue> = (a: T, b: U) => R;

View File

@@ -199,11 +199,7 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Let {
}
let body = ctx.get_ir(self.body).compile(ctx);
format!(
"(()=>{{{}; return {}}})()",
js_statements.join(";"),
body
)
format!("(()=>{{{}; return {}}})()", js_statements.join(";"), body)
}
}
@@ -293,7 +289,10 @@ impl<Ctx: CodegenContext> Compile<Ctx> for ConcatStrings {
.map(|part| {
let compiled = ctx.get_ir(*part).compile(ctx);
// TODO: copyToStore
format!("Nix.coerceToString({}, Nix.StringCoercionMode.Interpolation, false)", compiled)
format!(
"Nix.coerceToString({}, Nix.StringCoercionMode.Interpolation, false)",
compiled
)
})
.collect();

View File

@@ -77,7 +77,6 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Path {
path_str
} else {
let current_dir = ctx.get_current_dir();
dbg!(&current_dir);
current_dir
.join(&path_str)
@@ -172,29 +171,22 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::AttrSet {
// rec { a = 1; b = a; } => let a = 1; b = a; in { inherit a b; }
let entries: Vec<_> = self.entries().collect();
let (binding_sccs, body) =
downgrade_let_bindings(entries, ctx, |ctx, binding_keys| {
// Create plain attrset as body with inherit
let mut attrs = AttrSet {
stcs: HashMap::new(),
dyns: Vec::new(),
};
let (binding_sccs, body) = downgrade_let_bindings(entries, ctx, |ctx, binding_keys| {
// Create plain attrset as body with inherit
let mut attrs = AttrSet {
stcs: HashMap::new(),
dyns: Vec::new(),
};
for sym in binding_keys {
let expr = ctx.lookup(*sym)?;
attrs.stcs.insert(*sym, expr);
}
Ok(ctx.new_expr(attrs.to_ir()))
})?;
Ok(ctx.new_expr(
Let {
body,
binding_sccs,
for sym in binding_keys {
let expr = ctx.lookup(*sym)?;
attrs.stcs.insert(*sym, expr);
}
.to_ir(),
))
Ok(ctx.new_expr(attrs.to_ir()))
})?;
Ok(ctx.new_expr(Let { body, binding_sccs }.to_ir()))
}
}
@@ -299,13 +291,7 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::LetIn {
let (binding_sccs, body) =
downgrade_let_bindings(entries, ctx, |ctx, _binding_keys| body_expr.downgrade(ctx))?;
Ok(ctx.new_expr(
Let {
body,
binding_sccs,
}
.to_ir(),
))
Ok(ctx.new_expr(Let { body, binding_sccs }.to_ir()))
}
}

View File

@@ -323,7 +323,7 @@ where
body,
scc_info,
required_params: required,
allowed_params: allowed
allowed_params: allowed,
})
}
@@ -348,7 +348,11 @@ where
F: FnOnce(&mut Ctx, &[SymId]) -> Result<ExprId>,
{
let slots: Vec<_> = ctx.reserve_slots(binding_keys.len()).collect();
let let_bindings: HashMap<_, _> = binding_keys.iter().copied().zip(slots.iter().copied()).collect();
let let_bindings: HashMap<_, _> = binding_keys
.iter()
.copied()
.zip(slots.iter().copied())
.collect();
ctx.push_dep_tracker(&slots);

View File

@@ -77,10 +77,7 @@ fn nested_function_parameters() {
#[test]
fn pattern_param_simple_reference_in_default() {
assert_eq!(
eval("({ a, b ? a }: b) { a = 10; }"),
Value::Int(10)
);
assert_eq!(eval("({ a, b ? a }: b) { a = 10; }"), Value::Int(10));
}
#[test]

View File

@@ -90,8 +90,7 @@ fn import_with_complex_dependency_graph() {
std::fs::write(&utils_path, "{ double = x: x * 2; }").unwrap();
let math_path = temp_dir.path().join("math.nix");
let math_content =
r#"let utils = import ./utils.nix; in { triple = x: x + utils.double x; }"#;
let math_content = r#"let utils = import ./utils.nix; in { triple = x: x + utils.double x; }"#;
std::fs::write(&math_path, math_content).unwrap();
let main_path = temp_dir.path().join("main.nix");

View File

@@ -5,7 +5,10 @@ use utils::eval;
#[test]
fn string_returns_as_is() {
assert_eq!(eval(r#"toString "hello""#), Value::String("hello".to_string()));
assert_eq!(
eval(r#"toString "hello""#),
Value::String("hello".to_string())
);
}
#[test]
@@ -67,10 +70,7 @@ fn list_with_multiple_empty_lists() {
eval("toString [1 [] [] 2]"),
Value::String("1 2".to_string())
);
assert_eq!(
eval("toString [[] [] 1]"),
Value::String("1".to_string())
);
assert_eq!(eval("toString [[] [] 1]"), Value::String("1".to_string()));
}
#[test]
@@ -112,7 +112,9 @@ fn attrs_with_to_string_method() {
#[test]
fn attrs_to_string_self_reference() {
assert_eq!(
eval(r#"let obj = { x = 42; __toString = self: "x is ${toString self.x}"; }; in toString obj"#),
eval(
r#"let obj = { x = 42; __toString = self: "x is ${toString self.x}"; }; in toString obj"#
),
Value::String("x is 42".to_string())
);
}
@@ -120,9 +122,7 @@ fn attrs_to_string_self_reference() {
#[test]
fn attrs_to_string_priority() {
assert_eq!(
eval(
r#"toString { __toString = self: "custom"; outPath = "/nix/store/foo"; }"#
),
eval(r#"toString { __toString = self: "custom"; outPath = "/nix/store/foo"; }"#),
Value::String("custom".to_string())
);
}