fmt: biome & editorconfig
This commit is contained in:
11
.editorconfig
Normal file
11
.editorconfig
Normal file
@@ -0,0 +1,11 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{rs,toml}]
|
||||
indent_size = 4
|
||||
36
biome.json
Normal file
36
biome.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.3.6/schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true
|
||||
},
|
||||
"files": {
|
||||
"includes": ["**", "!!**/dist"]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": true,
|
||||
"attributePosition": "auto",
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 110,
|
||||
"lineEnding": "lf"
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"arrowParentheses": "always",
|
||||
"bracketSameLine": false,
|
||||
"bracketSpacing": true,
|
||||
"jsxQuoteStyle": "double",
|
||||
"quoteProperties": "asNeeded",
|
||||
"semicolons": "always",
|
||||
"trailingCommas": "all"
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"formatter": {
|
||||
"trailingCommas": "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,9 @@
|
||||
valgrind
|
||||
claude-code
|
||||
|
||||
# Node.js tooling for TypeScript build
|
||||
nodejs
|
||||
nodePackages.npm
|
||||
biome
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,52 +2,68 @@
|
||||
* Arithmetic builtin functions
|
||||
*/
|
||||
|
||||
import type { NixBool, NixInt, NixNumber, NixValue } from '../types';
|
||||
import { force_numeric, coerce_numeric, force_int } from '../type-assert';
|
||||
import type { NixBool, NixInt, NixNumber, NixValue } from "../types";
|
||||
import { force_numeric, coerce_numeric, force_int } from "../type-assert";
|
||||
|
||||
export const add = (a: NixValue) => (b: NixValue): bigint | number => {
|
||||
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
|
||||
return (av as any) + (bv as any);
|
||||
};
|
||||
export const add =
|
||||
(a: NixValue) =>
|
||||
(b: NixValue): bigint | number => {
|
||||
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(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));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
export const div =
|
||||
(a: NixValue) =>
|
||||
(b: NixValue): NixNumber => {
|
||||
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
|
||||
|
||||
if (bv === 0 || bv === 0n) {
|
||||
throw new RangeError('Division by zero');
|
||||
}
|
||||
if (bv === 0 || bv === 0n) {
|
||||
throw new RangeError("Division by zero");
|
||||
}
|
||||
|
||||
return (av as any) / (bv as any)
|
||||
};
|
||||
return (av as any) / (bv as any);
|
||||
};
|
||||
|
||||
// Bitwise operations - only for integers
|
||||
export const bitAnd = (a: NixValue) => (b: NixValue): NixInt => {
|
||||
const av = force_int(a);
|
||||
const bv = force_int(b);
|
||||
return av & bv;
|
||||
};
|
||||
export const bitAnd =
|
||||
(a: NixValue) =>
|
||||
(b: NixValue): NixInt => {
|
||||
const av = force_int(a);
|
||||
const bv = force_int(b);
|
||||
return av & bv;
|
||||
};
|
||||
|
||||
export const bitOr = (a: NixValue) => (b: NixValue): NixInt => {
|
||||
const av = force_int(a);
|
||||
const bv = force_int(b);
|
||||
return av | bv;
|
||||
};
|
||||
export const bitOr =
|
||||
(a: NixValue) =>
|
||||
(b: NixValue): NixInt => {
|
||||
const av = force_int(a);
|
||||
const bv = force_int(b);
|
||||
return av | bv;
|
||||
};
|
||||
|
||||
export const bitXor = (a: NixValue) => (b: NixValue): NixInt => {
|
||||
const av = force_int(a);
|
||||
const bv = force_int(b);
|
||||
return av ^ bv;
|
||||
};
|
||||
export const bitXor =
|
||||
(a: NixValue) =>
|
||||
(b: NixValue): NixInt => {
|
||||
const av = force_int(a);
|
||||
const bv = force_int(b);
|
||||
return av ^ bv;
|
||||
};
|
||||
|
||||
export const lessThan = (a: NixValue) => (b: NixValue): NixBool =>
|
||||
force_numeric(a) < force_numeric(b);
|
||||
export const lessThan =
|
||||
(a: NixValue) =>
|
||||
(b: NixValue): NixBool =>
|
||||
force_numeric(a) < force_numeric(b);
|
||||
|
||||
@@ -2,28 +2,34 @@
|
||||
* Attribute set operation builtin functions
|
||||
*/
|
||||
|
||||
import type { NixValue, NixAttrs, NixList } from '../types';
|
||||
import { force_attrs, force_string, force_function, force_list } from '../type-assert';
|
||||
import type { NixValue, NixAttrs, NixList } from "../types";
|
||||
import { force_attrs, force_string, force_function, force_list } from "../type-assert";
|
||||
|
||||
export const attrNames = (set: NixValue): string[] => Object.keys(force_attrs(set));
|
||||
|
||||
export const attrValues = (set: NixValue): NixValue[] => Object.values(force_attrs(set));
|
||||
|
||||
export const getAttr = (s: NixValue) => (set: NixValue): NixValue =>
|
||||
force_attrs(set)[force_string(s)];
|
||||
export const getAttr =
|
||||
(s: NixValue) =>
|
||||
(set: NixValue): NixValue =>
|
||||
force_attrs(set)[force_string(s)];
|
||||
|
||||
export const hasAttr = (s: NixValue) => (set: NixValue): boolean =>
|
||||
Object.prototype.hasOwnProperty.call(force_attrs(set), force_string(s));
|
||||
export const hasAttr =
|
||||
(s: NixValue) =>
|
||||
(set: NixValue): boolean =>
|
||||
Object.prototype.hasOwnProperty.call(force_attrs(set), force_string(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);
|
||||
for (const key in forced_attrs) {
|
||||
new_attrs[key] = forced_f(key)(forced_attrs[key]);
|
||||
}
|
||||
return new_attrs;
|
||||
};
|
||||
export const mapAttrs =
|
||||
(f: NixValue) =>
|
||||
(attrs: NixValue): NixAttrs => {
|
||||
const new_attrs: NixAttrs = {};
|
||||
const forced_attrs = force_attrs(attrs);
|
||||
const forced_f = force_function(f);
|
||||
for (const key in forced_attrs) {
|
||||
new_attrs[key] = forced_f(key)(forced_attrs[key]);
|
||||
}
|
||||
return new_attrs;
|
||||
};
|
||||
|
||||
export const listToAttrs = (e: NixValue): NixAttrs => {
|
||||
const attrs: NixAttrs = {};
|
||||
@@ -35,33 +41,39 @@ export const listToAttrs = (e: NixValue): NixAttrs => {
|
||||
return attrs;
|
||||
};
|
||||
|
||||
export const intersectAttrs = (e1: NixValue) => (e2: NixValue): NixAttrs => {
|
||||
const f1 = force_attrs(e1);
|
||||
const f2 = force_attrs(e2);
|
||||
const attrs: NixAttrs = {};
|
||||
for (const key of Object.keys(f2)) {
|
||||
if (Object.prototype.hasOwnProperty.call(f1, key)) {
|
||||
attrs[key] = f2[key];
|
||||
export const intersectAttrs =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): NixAttrs => {
|
||||
const f1 = force_attrs(e1);
|
||||
const f2 = force_attrs(e2);
|
||||
const attrs: NixAttrs = {};
|
||||
for (const key of Object.keys(f2)) {
|
||||
if (Object.prototype.hasOwnProperty.call(f1, key)) {
|
||||
attrs[key] = f2[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return attrs;
|
||||
};
|
||||
return attrs;
|
||||
};
|
||||
|
||||
export const catAttrs = (attr: NixValue) => (list: NixValue): NixList => {
|
||||
const key = force_string(attr);
|
||||
return force_list(list)
|
||||
.map((set) => force_attrs(set)[key])
|
||||
.filter((val) => val !== undefined);
|
||||
};
|
||||
export const catAttrs =
|
||||
(attr: NixValue) =>
|
||||
(list: NixValue): NixList => {
|
||||
const key = force_string(attr);
|
||||
return force_list(list)
|
||||
.map((set) => force_attrs(set)[key])
|
||||
.filter((val) => val !== undefined);
|
||||
};
|
||||
|
||||
export const groupBy = (f: NixValue) => (list: NixValue): NixAttrs => {
|
||||
const attrs: NixAttrs = {};
|
||||
const forced_f = force_function(f);
|
||||
const forced_list = force_list(list);
|
||||
for (const elem of forced_list) {
|
||||
const key = force_string(forced_f(elem));
|
||||
if (!attrs[key]) attrs[key] = [];
|
||||
(attrs[key] as NixList).push(elem);
|
||||
}
|
||||
return attrs;
|
||||
};
|
||||
export const groupBy =
|
||||
(f: NixValue) =>
|
||||
(list: NixValue): NixAttrs => {
|
||||
const attrs: NixAttrs = {};
|
||||
const forced_f = force_function(f);
|
||||
const forced_list = force_list(list);
|
||||
for (const elem of forced_list) {
|
||||
const key = force_string(forced_f(elem));
|
||||
if (!attrs[key]) attrs[key] = [];
|
||||
(attrs[key] as NixList).push(elem);
|
||||
}
|
||||
return attrs;
|
||||
};
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
* Conversion and serialization builtin functions (unimplemented)
|
||||
*/
|
||||
|
||||
import type { NixValue } from '../types';
|
||||
import type { NixValue } from "../types";
|
||||
|
||||
export const fromJSON = (e: NixValue): never => {
|
||||
throw 'Not implemented: fromJSON';
|
||||
throw "Not implemented: fromJSON";
|
||||
};
|
||||
|
||||
export const fromTOML = (e: NixValue): never => {
|
||||
throw 'Not implemented: fromTOML';
|
||||
throw "Not implemented: fromTOML";
|
||||
};
|
||||
|
||||
export const toJSON = (e: NixValue): never => {
|
||||
throw 'Not implemented: toJSON';
|
||||
throw "Not implemented: toJSON";
|
||||
};
|
||||
|
||||
export const toXML = (e: NixValue): never => {
|
||||
throw 'Not implemented: toXML';
|
||||
throw "Not implemented: toXML";
|
||||
};
|
||||
|
||||
export const toString = (name: NixValue, s: NixValue): never => {
|
||||
throw 'Not implemented: toString';
|
||||
throw "Not implemented: toString";
|
||||
};
|
||||
|
||||
@@ -2,17 +2,21 @@
|
||||
* Functional programming builtin functions
|
||||
*/
|
||||
|
||||
import type { NixValue } from '../types';
|
||||
import { force } from '../thunk';
|
||||
import type { NixValue } from "../types";
|
||||
import { force } from "../thunk";
|
||||
|
||||
export const seq = (e1: NixValue) => (e2: NixValue): NixValue => {
|
||||
force(e1); // Force evaluation of e1
|
||||
return e2;
|
||||
};
|
||||
export const seq =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): NixValue => {
|
||||
force(e1); // Force evaluation of e1
|
||||
return e2;
|
||||
};
|
||||
|
||||
export const deepSeq = (e1: NixValue) => (e2: NixValue): never => {
|
||||
throw 'Not implemented: deepSeq';
|
||||
};
|
||||
export const deepSeq =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): never => {
|
||||
throw "Not implemented: deepSeq";
|
||||
};
|
||||
|
||||
export const abort = (s: NixValue): never => {
|
||||
throw `evaluation aborted with the following error message: '${force(s)}'`;
|
||||
@@ -27,9 +31,11 @@ export const trace = (e1: NixValue, e2: NixValue): NixValue => {
|
||||
return e2;
|
||||
};
|
||||
|
||||
export const warn = (e1: NixValue) => (e2: NixValue): NixValue => {
|
||||
console.log(`evaluation warning: ${force(e1)}`);
|
||||
return e2;
|
||||
};
|
||||
export const warn =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): NixValue => {
|
||||
console.log(`evaluation warning: ${force(e1)}`);
|
||||
return e2;
|
||||
};
|
||||
|
||||
export const breakFunc = (v: NixValue): NixValue => v;
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
* Combines all builtin function categories into the global `builtins` object
|
||||
*/
|
||||
|
||||
import { create_thunk } from '../thunk';
|
||||
import { create_thunk } from "../thunk";
|
||||
|
||||
/**
|
||||
* Symbol used to mark functions as primops (primitive operations)
|
||||
* This is similar to IS_THUNK but for builtin functions
|
||||
*/
|
||||
export const IS_PRIMOP = Symbol('is_primop');
|
||||
export const IS_PRIMOP = Symbol("is_primop");
|
||||
|
||||
/**
|
||||
* Metadata interface for primop functions
|
||||
@@ -37,7 +37,7 @@ export const markPrimop = <T extends Function>(
|
||||
func: T,
|
||||
name: string,
|
||||
arity: number,
|
||||
applied: number = 0
|
||||
applied: number = 0,
|
||||
): T => {
|
||||
// Mark this function as a primop
|
||||
(func as any)[IS_PRIMOP] = {
|
||||
@@ -52,7 +52,7 @@ export const markPrimop = <T extends Function>(
|
||||
const wrappedFunc = ((...args: any[]) => {
|
||||
const result = func(...args);
|
||||
// If result is a function, mark it as the next layer
|
||||
if (typeof result === 'function') {
|
||||
if (typeof result === "function") {
|
||||
return markPrimop(result, name, arity, applied + args.length);
|
||||
}
|
||||
return result;
|
||||
@@ -78,9 +78,9 @@ export const markPrimop = <T extends Function>(
|
||||
*/
|
||||
export const is_primop = (value: unknown): value is Function & { [IS_PRIMOP]: PrimopMetadata } => {
|
||||
return (
|
||||
typeof value === 'function' &&
|
||||
typeof value === "function" &&
|
||||
IS_PRIMOP in value &&
|
||||
typeof value[IS_PRIMOP] === 'object' &&
|
||||
typeof value[IS_PRIMOP] === "object" &&
|
||||
value[IS_PRIMOP] !== null
|
||||
);
|
||||
};
|
||||
@@ -98,16 +98,16 @@ export const get_primop_metadata = (func: unknown): PrimopMetadata | undefined =
|
||||
};
|
||||
|
||||
// Import all builtin categories
|
||||
import * as arithmetic from './arithmetic';
|
||||
import * as math from './math';
|
||||
import * as typeCheck from './type-check';
|
||||
import * as list from './list';
|
||||
import * as attrs from './attrs';
|
||||
import * as string from './string';
|
||||
import * as functional from './functional';
|
||||
import * as io from './io';
|
||||
import * as conversion from './conversion';
|
||||
import * as misc from './misc';
|
||||
import * as arithmetic from "./arithmetic";
|
||||
import * as math from "./math";
|
||||
import * as typeCheck from "./type-check";
|
||||
import * as list from "./list";
|
||||
import * as attrs from "./attrs";
|
||||
import * as string from "./string";
|
||||
import * as functional from "./functional";
|
||||
import * as io from "./io";
|
||||
import * as conversion from "./conversion";
|
||||
import * as misc from "./misc";
|
||||
|
||||
/**
|
||||
* The global builtins object
|
||||
@@ -120,122 +120,126 @@ import * as misc from './misc';
|
||||
* All primop functions are marked with IS_PRIMOP symbol for runtime introspection
|
||||
*/
|
||||
export const builtins: any = {
|
||||
add: markPrimop(arithmetic.add, 'add', 2),
|
||||
sub: markPrimop(arithmetic.sub, 'sub', 2),
|
||||
mul: markPrimop(arithmetic.mul, 'mul', 2),
|
||||
div: markPrimop(arithmetic.div, 'div', 2),
|
||||
bitAnd: markPrimop(arithmetic.bitAnd, 'bitAnd', 2),
|
||||
bitOr: markPrimop(arithmetic.bitOr, 'bitOr', 2),
|
||||
bitXor: markPrimop(arithmetic.bitXor, 'bitXor', 2),
|
||||
lessThan: markPrimop(arithmetic.lessThan, 'lessThan', 2),
|
||||
add: markPrimop(arithmetic.add, "add", 2),
|
||||
sub: markPrimop(arithmetic.sub, "sub", 2),
|
||||
mul: markPrimop(arithmetic.mul, "mul", 2),
|
||||
div: markPrimop(arithmetic.div, "div", 2),
|
||||
bitAnd: markPrimop(arithmetic.bitAnd, "bitAnd", 2),
|
||||
bitOr: markPrimop(arithmetic.bitOr, "bitOr", 2),
|
||||
bitXor: markPrimop(arithmetic.bitXor, "bitXor", 2),
|
||||
lessThan: markPrimop(arithmetic.lessThan, "lessThan", 2),
|
||||
|
||||
ceil: markPrimop(math.ceil, 'ceil', 1),
|
||||
floor: markPrimop(math.floor, 'floor', 1),
|
||||
ceil: markPrimop(math.ceil, "ceil", 1),
|
||||
floor: markPrimop(math.floor, "floor", 1),
|
||||
|
||||
isAttrs: markPrimop(typeCheck.isAttrs, 'isAttrs', 1),
|
||||
isBool: markPrimop(typeCheck.isBool, 'isBool', 1),
|
||||
isFloat: markPrimop(typeCheck.isFloat, 'isFloat', 1),
|
||||
isFunction: markPrimop(typeCheck.isFunction, 'isFunction', 1),
|
||||
isInt: markPrimop(typeCheck.isInt, 'isInt', 1),
|
||||
isList: markPrimop(typeCheck.isList, 'isList', 1),
|
||||
isNull: markPrimop(typeCheck.isNull, 'isNull', 1),
|
||||
isPath: markPrimop(typeCheck.isPath, 'isPath', 1),
|
||||
isString: markPrimop(typeCheck.isString, 'isString', 1),
|
||||
typeOf: markPrimop(typeCheck.typeOf, 'typeOf', 1),
|
||||
isAttrs: markPrimop(typeCheck.isAttrs, "isAttrs", 1),
|
||||
isBool: markPrimop(typeCheck.isBool, "isBool", 1),
|
||||
isFloat: markPrimop(typeCheck.isFloat, "isFloat", 1),
|
||||
isFunction: markPrimop(typeCheck.isFunction, "isFunction", 1),
|
||||
isInt: markPrimop(typeCheck.isInt, "isInt", 1),
|
||||
isList: markPrimop(typeCheck.isList, "isList", 1),
|
||||
isNull: markPrimop(typeCheck.isNull, "isNull", 1),
|
||||
isPath: markPrimop(typeCheck.isPath, "isPath", 1),
|
||||
isString: markPrimop(typeCheck.isString, "isString", 1),
|
||||
typeOf: markPrimop(typeCheck.typeOf, "typeOf", 1),
|
||||
|
||||
map: markPrimop(list.map, 'map', 2),
|
||||
filter: markPrimop(list.filter, 'filter', 2),
|
||||
length: markPrimop(list.length, 'length', 1),
|
||||
head: markPrimop(list.head, 'head', 1),
|
||||
tail: markPrimop(list.tail, 'tail', 1),
|
||||
elem: markPrimop(list.elem, 'elem', 2),
|
||||
elemAt: markPrimop(list.elemAt, 'elemAt', 2),
|
||||
concatLists: markPrimop(list.concatLists, 'concatLists', 1),
|
||||
concatMap: markPrimop(list.concatMap, 'concatMap', 2),
|
||||
'foldl\'': markPrimop(list.foldlPrime, 'foldl\'', 3),
|
||||
sort: markPrimop(list.sort, 'sort', 2),
|
||||
partition: markPrimop(list.partition, 'partition', 2),
|
||||
genList: markPrimop(list.genList, 'genList', 2),
|
||||
all: markPrimop(list.all, 'all', 2),
|
||||
any: markPrimop(list.any, 'any', 2),
|
||||
map: markPrimop(list.map, "map", 2),
|
||||
filter: markPrimop(list.filter, "filter", 2),
|
||||
length: markPrimop(list.length, "length", 1),
|
||||
head: markPrimop(list.head, "head", 1),
|
||||
tail: markPrimop(list.tail, "tail", 1),
|
||||
elem: markPrimop(list.elem, "elem", 2),
|
||||
elemAt: markPrimop(list.elemAt, "elemAt", 2),
|
||||
concatLists: markPrimop(list.concatLists, "concatLists", 1),
|
||||
concatMap: markPrimop(list.concatMap, "concatMap", 2),
|
||||
"foldl'": markPrimop(list.foldlPrime, "foldl'", 3),
|
||||
sort: markPrimop(list.sort, "sort", 2),
|
||||
partition: markPrimop(list.partition, "partition", 2),
|
||||
genList: markPrimop(list.genList, "genList", 2),
|
||||
all: markPrimop(list.all, "all", 2),
|
||||
any: markPrimop(list.any, "any", 2),
|
||||
|
||||
attrNames: markPrimop(attrs.attrNames, 'attrNames', 1),
|
||||
attrValues: markPrimop(attrs.attrValues, 'attrValues', 1),
|
||||
getAttr: markPrimop(attrs.getAttr, 'getAttr', 2),
|
||||
hasAttr: markPrimop(attrs.hasAttr, 'hasAttr', 2),
|
||||
mapAttrs: markPrimop(attrs.mapAttrs, 'mapAttrs', 2),
|
||||
listToAttrs: markPrimop(attrs.listToAttrs, 'listToAttrs', 1),
|
||||
intersectAttrs: markPrimop(attrs.intersectAttrs, 'intersectAttrs', 2),
|
||||
catAttrs: markPrimop(attrs.catAttrs, 'catAttrs', 2),
|
||||
groupBy: markPrimop(attrs.groupBy, 'groupBy', 2),
|
||||
attrNames: markPrimop(attrs.attrNames, "attrNames", 1),
|
||||
attrValues: markPrimop(attrs.attrValues, "attrValues", 1),
|
||||
getAttr: markPrimop(attrs.getAttr, "getAttr", 2),
|
||||
hasAttr: markPrimop(attrs.hasAttr, "hasAttr", 2),
|
||||
mapAttrs: markPrimop(attrs.mapAttrs, "mapAttrs", 2),
|
||||
listToAttrs: markPrimop(attrs.listToAttrs, "listToAttrs", 1),
|
||||
intersectAttrs: markPrimop(attrs.intersectAttrs, "intersectAttrs", 2),
|
||||
catAttrs: markPrimop(attrs.catAttrs, "catAttrs", 2),
|
||||
groupBy: markPrimop(attrs.groupBy, "groupBy", 2),
|
||||
|
||||
stringLength: markPrimop(string.stringLength, 'stringLength', 1),
|
||||
substring: markPrimop(string.substring, 'substring', 3),
|
||||
concatStringsSep: markPrimop(string.concatStringsSep, 'concatStringsSep', 2),
|
||||
baseNameOf: markPrimop(string.baseNameOf, 'baseNameOf', 1),
|
||||
stringLength: markPrimop(string.stringLength, "stringLength", 1),
|
||||
substring: markPrimop(string.substring, "substring", 3),
|
||||
concatStringsSep: markPrimop(string.concatStringsSep, "concatStringsSep", 2),
|
||||
baseNameOf: markPrimop(string.baseNameOf, "baseNameOf", 1),
|
||||
|
||||
seq: markPrimop(functional.seq, 'seq', 2),
|
||||
deepSeq: markPrimop(functional.deepSeq, 'deepSeq', 2),
|
||||
abort: markPrimop(functional.abort, 'abort', 1),
|
||||
throw: markPrimop(functional.throwFunc, 'throw', 1),
|
||||
trace: markPrimop(functional.trace, 'trace', 2),
|
||||
warn: markPrimop(functional.warn, 'warn', 2),
|
||||
break: markPrimop(functional.breakFunc, 'break', 1),
|
||||
seq: markPrimop(functional.seq, "seq", 2),
|
||||
deepSeq: markPrimop(functional.deepSeq, "deepSeq", 2),
|
||||
abort: markPrimop(functional.abort, "abort", 1),
|
||||
throw: markPrimop(functional.throwFunc, "throw", 1),
|
||||
trace: markPrimop(functional.trace, "trace", 2),
|
||||
warn: markPrimop(functional.warn, "warn", 2),
|
||||
break: markPrimop(functional.breakFunc, "break", 1),
|
||||
|
||||
import: markPrimop(io.importFunc, 'import', 1),
|
||||
scopedImport: markPrimop(io.scopedImport, 'scopedImport', 2),
|
||||
fetchClosure: markPrimop(io.fetchClosure, 'fetchClosure', 1),
|
||||
fetchGit: markPrimop(io.fetchGit, 'fetchGit', 1),
|
||||
fetchTarball: markPrimop(io.fetchTarball, 'fetchTarball', 1),
|
||||
fetchTree: markPrimop(io.fetchTree, 'fetchTree', 1),
|
||||
fetchurl: markPrimop(io.fetchurl, 'fetchurl', 1),
|
||||
readDir: markPrimop(io.readDir, 'readDir', 1),
|
||||
readFile: markPrimop(io.readFile, 'readFile', 1),
|
||||
readFileType: markPrimop(io.readFileType, 'readFileType', 1),
|
||||
pathExists: markPrimop(io.pathExists, 'pathExists', 1),
|
||||
path: markPrimop(io.path, 'path', 1),
|
||||
toFile: markPrimop(io.toFile, 'toFile', 2),
|
||||
toPath: markPrimop(io.toPath, 'toPath', 1),
|
||||
filterSource: markPrimop(io.filterSource, 'filterSource', 2),
|
||||
findFile: markPrimop(io.findFile, 'findFile', 2),
|
||||
getEnv: markPrimop(io.getEnv, 'getEnv', 1),
|
||||
import: markPrimop(io.importFunc, "import", 1),
|
||||
scopedImport: markPrimop(io.scopedImport, "scopedImport", 2),
|
||||
fetchClosure: markPrimop(io.fetchClosure, "fetchClosure", 1),
|
||||
fetchGit: markPrimop(io.fetchGit, "fetchGit", 1),
|
||||
fetchTarball: markPrimop(io.fetchTarball, "fetchTarball", 1),
|
||||
fetchTree: markPrimop(io.fetchTree, "fetchTree", 1),
|
||||
fetchurl: markPrimop(io.fetchurl, "fetchurl", 1),
|
||||
readDir: markPrimop(io.readDir, "readDir", 1),
|
||||
readFile: markPrimop(io.readFile, "readFile", 1),
|
||||
readFileType: markPrimop(io.readFileType, "readFileType", 1),
|
||||
pathExists: markPrimop(io.pathExists, "pathExists", 1),
|
||||
path: markPrimop(io.path, "path", 1),
|
||||
toFile: markPrimop(io.toFile, "toFile", 2),
|
||||
toPath: markPrimop(io.toPath, "toPath", 1),
|
||||
filterSource: markPrimop(io.filterSource, "filterSource", 2),
|
||||
findFile: markPrimop(io.findFile, "findFile", 2),
|
||||
getEnv: markPrimop(io.getEnv, "getEnv", 1),
|
||||
|
||||
fromJSON: markPrimop(conversion.fromJSON, 'fromJSON', 1),
|
||||
fromTOML: markPrimop(conversion.fromTOML, 'fromTOML', 1),
|
||||
toJSON: markPrimop(conversion.toJSON, 'toJSON', 1),
|
||||
toXML: markPrimop(conversion.toXML, 'toXML', 1),
|
||||
toString: markPrimop(conversion.toString, 'toString', 1),
|
||||
fromJSON: markPrimop(conversion.fromJSON, "fromJSON", 1),
|
||||
fromTOML: markPrimop(conversion.fromTOML, "fromTOML", 1),
|
||||
toJSON: markPrimop(conversion.toJSON, "toJSON", 1),
|
||||
toXML: markPrimop(conversion.toXML, "toXML", 1),
|
||||
toString: markPrimop(conversion.toString, "toString", 1),
|
||||
|
||||
getContext: markPrimop(misc.getContext, 'getContext', 1),
|
||||
hasContext: markPrimop(misc.hasContext, 'hasContext', 1),
|
||||
hashFile: markPrimop(misc.hashFile, 'hashFile', 2),
|
||||
hashString: markPrimop(misc.hashString, 'hashString', 2),
|
||||
convertHash: markPrimop(misc.convertHash, 'convertHash', 2),
|
||||
unsafeDiscardOutputDependency: markPrimop(misc.unsafeDiscardOutputDependency, 'unsafeDiscardOutputDependency', 1),
|
||||
unsafeDiscardStringContext: markPrimop(misc.unsafeDiscardStringContext, 'unsafeDiscardStringContext', 1),
|
||||
unsafeGetAttrPos: markPrimop(misc.unsafeGetAttrPos, 'unsafeGetAttrPos', 2),
|
||||
addDrvOutputDependencies: markPrimop(misc.addDrvOutputDependencies, 'addDrvOutputDependencies', 2),
|
||||
compareVersions: markPrimop(misc.compareVersions, 'compareVersions', 2),
|
||||
dirOf: markPrimop(misc.dirOf, 'dirOf', 1),
|
||||
flakeRefToString: markPrimop(misc.flakeRefToString, 'flakeRefToString', 1),
|
||||
functionArgs: markPrimop(misc.functionArgs, 'functionArgs', 1),
|
||||
genericClosure: markPrimop(misc.genericClosure, 'genericClosure', 1),
|
||||
getFlake: markPrimop(misc.getFlake, 'getFlake', 1),
|
||||
match: markPrimop(misc.match, 'match', 2),
|
||||
outputOf: markPrimop(misc.outputOf, 'outputOf', 2),
|
||||
parseDrvName: markPrimop(misc.parseDrvName, 'parseDrvName', 1),
|
||||
parseFlakeName: markPrimop(misc.parseFlakeName, 'parseFlakeName', 1),
|
||||
placeholder: markPrimop(misc.placeholder, 'placeholder', 1),
|
||||
replaceStrings: markPrimop(misc.replaceStrings, 'replaceStrings', 3),
|
||||
split: markPrimop(misc.split, 'split', 2),
|
||||
splitVersion: markPrimop(misc.splitVersion, 'splitVersion', 1),
|
||||
traceVerbose: markPrimop(misc.traceVerbose, 'traceVerbose', 2),
|
||||
tryEval: markPrimop(misc.tryEval, 'tryEval', 1),
|
||||
zipAttrsWith: markPrimop(misc.zipAttrsWith, 'zipAttrsWith', 2),
|
||||
getContext: markPrimop(misc.getContext, "getContext", 1),
|
||||
hasContext: markPrimop(misc.hasContext, "hasContext", 1),
|
||||
hashFile: markPrimop(misc.hashFile, "hashFile", 2),
|
||||
hashString: markPrimop(misc.hashString, "hashString", 2),
|
||||
convertHash: markPrimop(misc.convertHash, "convertHash", 2),
|
||||
unsafeDiscardOutputDependency: markPrimop(
|
||||
misc.unsafeDiscardOutputDependency,
|
||||
"unsafeDiscardOutputDependency",
|
||||
1,
|
||||
),
|
||||
unsafeDiscardStringContext: markPrimop(misc.unsafeDiscardStringContext, "unsafeDiscardStringContext", 1),
|
||||
unsafeGetAttrPos: markPrimop(misc.unsafeGetAttrPos, "unsafeGetAttrPos", 2),
|
||||
addDrvOutputDependencies: markPrimop(misc.addDrvOutputDependencies, "addDrvOutputDependencies", 2),
|
||||
compareVersions: markPrimop(misc.compareVersions, "compareVersions", 2),
|
||||
dirOf: markPrimop(misc.dirOf, "dirOf", 1),
|
||||
flakeRefToString: markPrimop(misc.flakeRefToString, "flakeRefToString", 1),
|
||||
functionArgs: markPrimop(misc.functionArgs, "functionArgs", 1),
|
||||
genericClosure: markPrimop(misc.genericClosure, "genericClosure", 1),
|
||||
getFlake: markPrimop(misc.getFlake, "getFlake", 1),
|
||||
match: markPrimop(misc.match, "match", 2),
|
||||
outputOf: markPrimop(misc.outputOf, "outputOf", 2),
|
||||
parseDrvName: markPrimop(misc.parseDrvName, "parseDrvName", 1),
|
||||
parseFlakeName: markPrimop(misc.parseFlakeName, "parseFlakeName", 1),
|
||||
placeholder: markPrimop(misc.placeholder, "placeholder", 1),
|
||||
replaceStrings: markPrimop(misc.replaceStrings, "replaceStrings", 3),
|
||||
split: markPrimop(misc.split, "split", 2),
|
||||
splitVersion: markPrimop(misc.splitVersion, "splitVersion", 1),
|
||||
traceVerbose: markPrimop(misc.traceVerbose, "traceVerbose", 2),
|
||||
tryEval: markPrimop(misc.tryEval, "tryEval", 1),
|
||||
zipAttrsWith: markPrimop(misc.zipAttrsWith, "zipAttrsWith", 2),
|
||||
|
||||
builtins: create_thunk(() => builtins),
|
||||
currentSystem: create_thunk(() => {
|
||||
throw 'Not implemented: currentSystem';
|
||||
throw "Not implemented: currentSystem";
|
||||
}),
|
||||
currentTime: create_thunk(() => Date.now()),
|
||||
|
||||
@@ -245,6 +249,6 @@ export const builtins: any = {
|
||||
|
||||
langVersion: 6,
|
||||
nixPath: [],
|
||||
nixVersion: 'NIX_JS_VERSION',
|
||||
storeDir: '/nix/store',
|
||||
nixVersion: "NIX_JS_VERSION",
|
||||
storeDir: "/nix/store",
|
||||
};
|
||||
|
||||
@@ -3,72 +3,76 @@
|
||||
* These functions require Node.js/Deno APIs not available in V8
|
||||
*/
|
||||
|
||||
import type { NixValue } from '../types';
|
||||
import type { NixValue } from "../types";
|
||||
|
||||
export const importFunc = (path: NixValue): never => {
|
||||
throw 'Not implemented: import';
|
||||
throw "Not implemented: import";
|
||||
};
|
||||
|
||||
export const scopedImport = (scope: NixValue) => (path: NixValue): never => {
|
||||
throw 'Not implemented: scopedImport';
|
||||
};
|
||||
export const scopedImport =
|
||||
(scope: NixValue) =>
|
||||
(path: NixValue): never => {
|
||||
throw "Not implemented: scopedImport";
|
||||
};
|
||||
|
||||
export const fetchClosure = (args: NixValue): never => {
|
||||
throw 'Not implemented: fetchClosure';
|
||||
throw "Not implemented: fetchClosure";
|
||||
};
|
||||
|
||||
export const fetchGit = (args: NixValue): never => {
|
||||
throw 'Not implemented: fetchGit';
|
||||
throw "Not implemented: fetchGit";
|
||||
};
|
||||
|
||||
export const fetchTarball = (args: NixValue): never => {
|
||||
throw 'Not implemented: fetchTarball';
|
||||
throw "Not implemented: fetchTarball";
|
||||
};
|
||||
|
||||
export const fetchTree = (args: NixValue): never => {
|
||||
throw 'Not implemented: fetchTree';
|
||||
throw "Not implemented: fetchTree";
|
||||
};
|
||||
|
||||
export const fetchurl = (args: NixValue): never => {
|
||||
throw 'Not implemented: fetchurl';
|
||||
throw "Not implemented: fetchurl";
|
||||
};
|
||||
|
||||
export const readDir = (path: NixValue): never => {
|
||||
throw 'Not implemented: readDir';
|
||||
throw "Not implemented: readDir";
|
||||
};
|
||||
|
||||
export const readFile = (path: NixValue): never => {
|
||||
throw 'Not implemented: readFile';
|
||||
throw "Not implemented: readFile";
|
||||
};
|
||||
|
||||
export const readFileType = (path: NixValue): never => {
|
||||
throw 'Not implemented: readFileType';
|
||||
throw "Not implemented: readFileType";
|
||||
};
|
||||
|
||||
export const pathExists = (path: NixValue): never => {
|
||||
throw 'Not implemented: pathExists';
|
||||
throw "Not implemented: pathExists";
|
||||
};
|
||||
|
||||
export const path = (args: NixValue): never => {
|
||||
throw 'Not implemented: path';
|
||||
throw "Not implemented: path";
|
||||
};
|
||||
|
||||
export const toFile = (name: NixValue, s: NixValue): never => {
|
||||
throw 'Not implemented: toFile';
|
||||
throw "Not implemented: toFile";
|
||||
};
|
||||
|
||||
export const toPath = (name: NixValue, s: NixValue): never => {
|
||||
throw 'Not implemented: toPath';
|
||||
throw "Not implemented: toPath";
|
||||
};
|
||||
|
||||
export const filterSource = (args: NixValue): never => {
|
||||
throw 'Not implemented: filterSource';
|
||||
throw "Not implemented: filterSource";
|
||||
};
|
||||
|
||||
export const findFile = (search: NixValue) => (lookup: NixValue): never => {
|
||||
throw 'Not implemented: findFile';
|
||||
};
|
||||
export const findFile =
|
||||
(search: NixValue) =>
|
||||
(lookup: NixValue): never => {
|
||||
throw "Not implemented: findFile";
|
||||
};
|
||||
|
||||
export const getEnv = (s: NixValue): never => {
|
||||
throw 'Not implemented: getEnv';
|
||||
throw "Not implemented: getEnv";
|
||||
};
|
||||
|
||||
@@ -3,19 +3,23 @@
|
||||
* All functions are properly curried
|
||||
*/
|
||||
|
||||
import type { NixValue, NixList, NixAttrs } from '../types';
|
||||
import { force } from '../thunk';
|
||||
import { force_list, force_function, force_numeric, force_int } from '../type-assert';
|
||||
import type { NixValue, NixList, NixAttrs } from "../types";
|
||||
import { force } from "../thunk";
|
||||
import { force_list, force_function, force_numeric, force_int } from "../type-assert";
|
||||
|
||||
export const map = (f: NixValue) => (list: NixValue): NixList =>
|
||||
force_list(list).map(force_function(f));
|
||||
export const map =
|
||||
(f: NixValue) =>
|
||||
(list: NixValue): NixList =>
|
||||
force_list(list).map(force_function(f));
|
||||
|
||||
export const filter = (f: NixValue) => (list: NixValue): NixList =>
|
||||
force_list(list).filter(force_function(f));
|
||||
export const filter =
|
||||
(f: NixValue) =>
|
||||
(list: NixValue): NixList =>
|
||||
force_list(list).filter(force_function(f));
|
||||
|
||||
export const length = (e: NixValue): bigint => {
|
||||
const forced = force(e);
|
||||
if (typeof forced === 'string') return BigInt(forced.length);
|
||||
if (typeof forced === "string") return BigInt(forced.length);
|
||||
return BigInt(force_list(forced).length);
|
||||
};
|
||||
|
||||
@@ -23,19 +27,23 @@ export const head = (list: NixValue): NixValue => force_list(list)[0];
|
||||
|
||||
export const tail = (list: NixValue): NixList => force_list(list).slice(1);
|
||||
|
||||
export const elem = (x: NixValue) => (xs: NixValue): boolean =>
|
||||
force_list(xs).includes(force(x));
|
||||
export const elem =
|
||||
(x: NixValue) =>
|
||||
(xs: NixValue): boolean =>
|
||||
force_list(xs).includes(force(x));
|
||||
|
||||
export const elemAt = (xs: NixValue) => (n: NixValue): NixValue => {
|
||||
const list = force_list(xs);
|
||||
const idx = Number(force_int(n));
|
||||
export const elemAt =
|
||||
(xs: NixValue) =>
|
||||
(n: NixValue): NixValue => {
|
||||
const list = force_list(xs);
|
||||
const idx = Number(force_int(n));
|
||||
|
||||
if (idx < 0 || idx >= list.length) {
|
||||
throw new RangeError(`Index ${idx} out of bounds for list of length ${list.length}`);
|
||||
}
|
||||
if (idx < 0 || idx >= list.length) {
|
||||
throw new RangeError(`Index ${idx} out of bounds for list of length ${list.length}`);
|
||||
}
|
||||
|
||||
return list[idx];
|
||||
};
|
||||
return list[idx];
|
||||
};
|
||||
|
||||
export const concatLists = (lists: NixValue): NixList => {
|
||||
return force_list(lists).reduce((acc: NixList, cur: NixValue) => {
|
||||
@@ -43,60 +51,75 @@ export const concatLists = (lists: NixValue): NixList => {
|
||||
}, []);
|
||||
};
|
||||
|
||||
export const concatMap = (f: NixValue) => (lists: NixValue): NixList => {
|
||||
const fn = force_function(f);
|
||||
return force_list(lists).reduce((acc: NixList, cur: NixValue) => {
|
||||
return acc.concat(force(fn(cur)) as NixList);
|
||||
}, []);
|
||||
};
|
||||
|
||||
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);
|
||||
}, nul);
|
||||
};
|
||||
|
||||
export const sort = (cmp: NixValue) => (list: NixValue): NixList => {
|
||||
const forced_list = [...force_list(list)];
|
||||
const forced_cmp = force_function(cmp);
|
||||
return forced_list.sort((a, b) => {
|
||||
if (force(forced_cmp(a)(b))) return -1;
|
||||
if (force(forced_cmp(b)(a))) return 1;
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
export const partition = (pred: NixValue) => (list: NixValue): NixAttrs => {
|
||||
const forced_list = force_list(list);
|
||||
const forced_pred = force_function(pred);
|
||||
const attrs: NixAttrs = {
|
||||
right: [],
|
||||
wrong: [],
|
||||
export const concatMap =
|
||||
(f: NixValue) =>
|
||||
(lists: NixValue): NixList => {
|
||||
const fn = force_function(f);
|
||||
return force_list(lists).reduce((acc: NixList, cur: NixValue) => {
|
||||
return acc.concat(force(fn(cur)) as NixList);
|
||||
}, []);
|
||||
};
|
||||
for (const elem of forced_list) {
|
||||
if (force(forced_pred(elem))) {
|
||||
(attrs.right as NixList).push(elem);
|
||||
} else {
|
||||
(attrs.wrong as NixList).push(elem);
|
||||
|
||||
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);
|
||||
}, nul);
|
||||
};
|
||||
|
||||
export const sort =
|
||||
(cmp: NixValue) =>
|
||||
(list: NixValue): NixList => {
|
||||
const forced_list = [...force_list(list)];
|
||||
const forced_cmp = force_function(cmp);
|
||||
return forced_list.sort((a, b) => {
|
||||
if (force(forced_cmp(a)(b))) return -1;
|
||||
if (force(forced_cmp(b)(a))) return 1;
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
export const partition =
|
||||
(pred: NixValue) =>
|
||||
(list: NixValue): NixAttrs => {
|
||||
const forced_list = force_list(list);
|
||||
const forced_pred = force_function(pred);
|
||||
const attrs: NixAttrs = {
|
||||
right: [],
|
||||
wrong: [],
|
||||
};
|
||||
for (const elem of forced_list) {
|
||||
if (force(forced_pred(elem))) {
|
||||
(attrs.right as NixList).push(elem);
|
||||
} else {
|
||||
(attrs.wrong as NixList).push(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return attrs;
|
||||
};
|
||||
return attrs;
|
||||
};
|
||||
|
||||
export const genList = (f: NixValue) => (len: NixValue): NixList => {
|
||||
const func = force_function(f);
|
||||
const length = force_int(len);
|
||||
export const genList =
|
||||
(f: NixValue) =>
|
||||
(len: NixValue): NixList => {
|
||||
const func = force_function(f);
|
||||
const length = force_int(len);
|
||||
|
||||
if (length < 0) {
|
||||
throw new TypeError(`genList length must be non-negative integer, got ${length}`);
|
||||
}
|
||||
if (length < 0) {
|
||||
throw new TypeError(`genList length must be non-negative integer, got ${length}`);
|
||||
}
|
||||
|
||||
return [...Array(Number(length)).keys()].map(i => func(BigInt(i)));
|
||||
};
|
||||
return [...Array(Number(length)).keys()].map((i) => func(BigInt(i)));
|
||||
};
|
||||
|
||||
export const all = (pred: NixValue) => (list: NixValue): boolean =>
|
||||
force_list(list).every(force_function(pred));
|
||||
export const all =
|
||||
(pred: NixValue) =>
|
||||
(list: NixValue): boolean =>
|
||||
force_list(list).every(force_function(pred));
|
||||
|
||||
export const any = (pred: NixValue) => (list: NixValue): boolean =>
|
||||
force_list(list).some(force_function(pred));
|
||||
export const any =
|
||||
(pred: NixValue) =>
|
||||
(list: NixValue): boolean =>
|
||||
force_list(list).some(force_function(pred));
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
* Math builtin functions
|
||||
*/
|
||||
|
||||
import type { NixValue } from '../types';
|
||||
import { force_numeric } from '../type-assert';
|
||||
import type { NixValue } from "../types";
|
||||
import { force_numeric } from "../type-assert";
|
||||
|
||||
export const ceil = (x: NixValue): bigint => {
|
||||
const val = force_numeric(x);
|
||||
if (typeof val === 'bigint') return val; // Already an integer
|
||||
return BigInt(Math.ceil(val)); // Convert to integer
|
||||
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);
|
||||
if (typeof val === 'bigint') return val; // Already an integer
|
||||
return BigInt(Math.floor(val)); // Convert to integer
|
||||
if (typeof val === "bigint") return val; // Already an integer
|
||||
return BigInt(Math.floor(val)); // Convert to integer
|
||||
};
|
||||
|
||||
@@ -2,108 +2,125 @@
|
||||
* Miscellaneous unimplemented builtin functions
|
||||
*/
|
||||
|
||||
import type { NixValue } from '../types';
|
||||
import type { NixValue } from "../types";
|
||||
|
||||
export const getContext = (s: NixValue): never => {
|
||||
throw 'Not implemented: getContext';
|
||||
throw "Not implemented: getContext";
|
||||
};
|
||||
|
||||
export const hasContext = (s: NixValue): never => {
|
||||
throw 'Not implemented: hasContext';
|
||||
throw "Not implemented: hasContext";
|
||||
};
|
||||
|
||||
export const hashFile = (type: NixValue) => (p: NixValue): never => {
|
||||
throw 'Not implemented: hashFile';
|
||||
};
|
||||
export const hashFile =
|
||||
(type: NixValue) =>
|
||||
(p: NixValue): never => {
|
||||
throw "Not implemented: hashFile";
|
||||
};
|
||||
|
||||
export const hashString = (type: NixValue) => (p: NixValue): never => {
|
||||
throw 'Not implemented: hashString';
|
||||
};
|
||||
export const hashString =
|
||||
(type: NixValue) =>
|
||||
(p: NixValue): never => {
|
||||
throw "Not implemented: hashString";
|
||||
};
|
||||
|
||||
export const convertHash = (args: NixValue): never => {
|
||||
throw 'Not implemented: convertHash';
|
||||
throw "Not implemented: convertHash";
|
||||
};
|
||||
|
||||
export const unsafeDiscardOutputDependency = (s: NixValue): never => {
|
||||
throw 'Not implemented: unsafeDiscardOutputDependency';
|
||||
throw "Not implemented: unsafeDiscardOutputDependency";
|
||||
};
|
||||
|
||||
export const unsafeDiscardStringContext = (s: NixValue): never => {
|
||||
throw 'Not implemented: unsafeDiscardStringContext';
|
||||
throw "Not implemented: unsafeDiscardStringContext";
|
||||
};
|
||||
|
||||
export const unsafeGetAttrPos = (s: NixValue): never => {
|
||||
throw 'Not implemented: unsafeGetAttrPos';
|
||||
throw "Not implemented: unsafeGetAttrPos";
|
||||
};
|
||||
|
||||
export const addDrvOutputDependencies = (s: NixValue): never => {
|
||||
throw 'Not implemented: addDrvOutputDependencies';
|
||||
throw "Not implemented: addDrvOutputDependencies";
|
||||
};
|
||||
|
||||
export const compareVersions = (s1: NixValue) => (s2: NixValue): never => {
|
||||
throw 'Not implemented: compareVersions';
|
||||
};
|
||||
export const compareVersions =
|
||||
(s1: NixValue) =>
|
||||
(s2: NixValue): never => {
|
||||
throw "Not implemented: compareVersions";
|
||||
};
|
||||
|
||||
export const dirOf = (s: NixValue): never => {
|
||||
throw 'Not implemented: dirOf';
|
||||
throw "Not implemented: dirOf";
|
||||
};
|
||||
|
||||
export const flakeRefToString = (attrs: NixValue): never => {
|
||||
throw 'Not implemented: flakeRefToString';
|
||||
throw "Not implemented: flakeRefToString";
|
||||
};
|
||||
|
||||
export const functionArgs = (f: NixValue): never => {
|
||||
throw 'Not implemented: functionArgs';
|
||||
throw "Not implemented: functionArgs";
|
||||
};
|
||||
|
||||
export const genericClosure = (args: NixValue): never => {
|
||||
throw 'Not implemented: genericClosure';
|
||||
throw "Not implemented: genericClosure";
|
||||
};
|
||||
|
||||
export const getFlake = (attrs: NixValue): never => {
|
||||
throw 'Not implemented: getFlake';
|
||||
throw "Not implemented: getFlake";
|
||||
};
|
||||
|
||||
export const match = (regex: NixValue) => (str: NixValue): never => {
|
||||
throw 'Not implemented: match';
|
||||
};
|
||||
export const match =
|
||||
(regex: NixValue) =>
|
||||
(str: NixValue): never => {
|
||||
throw "Not implemented: match";
|
||||
};
|
||||
|
||||
export const outputOf = (drv: NixValue) => (out: NixValue): never => {
|
||||
throw 'Not implemented: outputOf';
|
||||
};
|
||||
export const outputOf =
|
||||
(drv: NixValue) =>
|
||||
(out: NixValue): never => {
|
||||
throw "Not implemented: outputOf";
|
||||
};
|
||||
|
||||
export const parseDrvName = (s: NixValue): never => {
|
||||
throw 'Not implemented: parseDrvName';
|
||||
throw "Not implemented: parseDrvName";
|
||||
};
|
||||
|
||||
export const parseFlakeName = (s: NixValue): never => {
|
||||
throw 'Not implemented: parseFlakeName';
|
||||
throw "Not implemented: parseFlakeName";
|
||||
};
|
||||
|
||||
export const placeholder = (output: NixValue): never => {
|
||||
throw 'Not implemented: placeholder';
|
||||
throw "Not implemented: placeholder";
|
||||
};
|
||||
|
||||
export const replaceStrings = (from: NixValue) => (to: NixValue) => (s: NixValue): never => {
|
||||
throw 'Not implemented: replaceStrings';
|
||||
};
|
||||
export const replaceStrings =
|
||||
(from: NixValue) =>
|
||||
(to: NixValue) =>
|
||||
(s: NixValue): never => {
|
||||
throw "Not implemented: replaceStrings";
|
||||
};
|
||||
|
||||
export const split = (regex: NixValue, str: NixValue): never => {
|
||||
throw 'Not implemented: split';
|
||||
throw "Not implemented: split";
|
||||
};
|
||||
|
||||
export const splitVersion = (s: NixValue): never => {
|
||||
throw 'Not implemented: splitVersion';
|
||||
throw "Not implemented: splitVersion";
|
||||
};
|
||||
|
||||
export const traceVerbose = (e1: NixValue, e2: NixValue): never => {
|
||||
throw 'Not implemented: traceVerbose';
|
||||
throw "Not implemented: traceVerbose";
|
||||
};
|
||||
|
||||
export const tryEval = (e1: NixValue) => (e2: NixValue): never => {
|
||||
throw 'Not implemented: tryEval';
|
||||
};
|
||||
export const tryEval =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): never => {
|
||||
throw "Not implemented: tryEval";
|
||||
};
|
||||
|
||||
export const zipAttrsWith = (f: NixValue) => (list: NixValue): never => {
|
||||
throw 'Not implemented: zipAttrsWith';
|
||||
};
|
||||
export const zipAttrsWith =
|
||||
(f: NixValue) =>
|
||||
(list: NixValue): never => {
|
||||
throw "Not implemented: zipAttrsWith";
|
||||
};
|
||||
|
||||
@@ -2,32 +2,37 @@
|
||||
* String operation builtin functions
|
||||
*/
|
||||
|
||||
import type { NixValue } from '../types';
|
||||
import { force_string, force_list, force_int } from '../type-assert';
|
||||
import type { NixValue } from "../types";
|
||||
import { force_string, force_list, force_int } from "../type-assert";
|
||||
|
||||
export const stringLength = (e: NixValue): number => force_string(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));
|
||||
return str.substring(startPos, startPos + 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));
|
||||
return str.substring(startPos, startPos + length);
|
||||
};
|
||||
|
||||
export const concatStringsSep = (sep: NixValue) => (list: NixValue): string =>
|
||||
force_list(list).join(force_string(sep));
|
||||
export const concatStringsSep =
|
||||
(sep: NixValue) =>
|
||||
(list: NixValue): string =>
|
||||
force_list(list).join(force_string(sep));
|
||||
|
||||
export const baseNameOf = (x: NixValue): string => {
|
||||
const str = force_string(x);
|
||||
if (str.length === 0) return '';
|
||||
if (str.length === 0) return "";
|
||||
|
||||
let last = str.length - 1;
|
||||
if (str[last] === '/' && last > 0) last -= 1;
|
||||
if (str[last] === "/" && last > 0) last -= 1;
|
||||
|
||||
let pos = last;
|
||||
while (pos >= 0 && str[pos] !== '/') pos -= 1;
|
||||
while (pos >= 0 && str[pos] !== "/") pos -= 1;
|
||||
|
||||
if (pos !== 0 || (pos === 0 && str[pos] === '/')) {
|
||||
if (pos !== 0 || (pos === 0 && str[pos] === "/")) {
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,26 +2,36 @@
|
||||
* Type checking builtin functions
|
||||
*/
|
||||
|
||||
import type { NixAttrs, NixBool, NixFloat, NixFunction, NixInt, NixList, NixNull, NixString, NixValue } from '../types';
|
||||
import { force } from '../thunk';
|
||||
import type {
|
||||
NixAttrs,
|
||||
NixBool,
|
||||
NixFloat,
|
||||
NixFunction,
|
||||
NixInt,
|
||||
NixList,
|
||||
NixNull,
|
||||
NixString,
|
||||
NixValue,
|
||||
} from "../types";
|
||||
import { force } from "../thunk";
|
||||
|
||||
export const isAttrs = (e: NixValue): e is NixAttrs => {
|
||||
const val = force(e);
|
||||
return typeof val === 'object' && !Array.isArray(val) && val !== null;
|
||||
return typeof val === "object" && !Array.isArray(val) && val !== null;
|
||||
};
|
||||
|
||||
export const isBool = (e: NixValue): e is NixBool => typeof force(e) === 'boolean';
|
||||
export const isBool = (e: NixValue): e is NixBool => typeof force(e) === "boolean";
|
||||
|
||||
export const isFloat = (e: NixValue): e is NixFloat => {
|
||||
const val = force(e);
|
||||
return typeof val === 'number'; // Only number is float
|
||||
return typeof val === "number"; // Only number is float
|
||||
};
|
||||
|
||||
export const isFunction = (e: NixValue): e is NixFunction => typeof force(e) === 'function';
|
||||
export const isFunction = (e: NixValue): e is NixFunction => typeof force(e) === "function";
|
||||
|
||||
export const isInt = (e: NixValue): e is NixInt => {
|
||||
const val = force(e);
|
||||
return typeof val === 'bigint'; // Only bigint is int
|
||||
return typeof val === "bigint"; // Only bigint is int
|
||||
};
|
||||
|
||||
export const isList = (e: NixValue): e is NixList => Array.isArray(force(e));
|
||||
@@ -29,22 +39,22 @@ export const isList = (e: NixValue): e is NixList => Array.isArray(force(e));
|
||||
export const isNull = (e: NixValue): e is NixNull => force(e) === null;
|
||||
|
||||
export const isPath = (e: NixValue): never => {
|
||||
throw 'Not implemented: isPath';
|
||||
throw "Not implemented: isPath";
|
||||
};
|
||||
|
||||
export const isString = (e: NixValue): e is NixString => typeof force(e) === 'string';
|
||||
export const isString = (e: NixValue): e is NixString => typeof force(e) === "string";
|
||||
|
||||
export const typeOf = (e: NixValue): string => {
|
||||
const val = force(e);
|
||||
|
||||
if (typeof val === 'bigint') return 'int';
|
||||
if (typeof val === 'number') return 'float';
|
||||
if (typeof val === 'boolean') return 'bool';
|
||||
if (typeof val === 'string') return 'string';
|
||||
if (val === null) return 'null';
|
||||
if (Array.isArray(val)) return 'list';
|
||||
if (typeof val === 'function') return 'lambda';
|
||||
if (typeof val === 'object') return 'set';
|
||||
if (typeof val === "bigint") return "int";
|
||||
if (typeof val === "number") return "float";
|
||||
if (typeof val === "boolean") return "bool";
|
||||
if (typeof val === "string") return "string";
|
||||
if (val === null) return "null";
|
||||
if (Array.isArray(val)) return "list";
|
||||
if (typeof val === "function") return "lambda";
|
||||
if (typeof val === "object") return "set";
|
||||
|
||||
throw new TypeError(`Unknown Nix type: ${typeof val}`);
|
||||
};
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Implements attribute selection, parameter validation, and lazy sets
|
||||
*/
|
||||
|
||||
import type { NixValue, NixAttrs } from './types';
|
||||
import { force_attrs, force_string } from './type-assert';
|
||||
import type { NixValue, NixAttrs } from "./types";
|
||||
import { force_attrs, force_string } from "./type-assert";
|
||||
|
||||
/**
|
||||
* Select an attribute from an attribute set
|
||||
@@ -35,11 +35,7 @@ export const select = (obj: NixValue, key: NixValue): NixValue => {
|
||||
* @param default_val - Value to return if key not found
|
||||
* @returns obj[key] if exists, otherwise default_val
|
||||
*/
|
||||
export const select_with_default = (
|
||||
obj: NixValue,
|
||||
key: NixValue,
|
||||
default_val: NixValue
|
||||
): NixValue => {
|
||||
export const select_with_default = (obj: NixValue, key: NixValue, default_val: NixValue): NixValue => {
|
||||
const forced_obj = force_attrs(obj);
|
||||
const forced_key = force_string(key);
|
||||
|
||||
@@ -72,7 +68,7 @@ export const select_with_default = (
|
||||
export const validate_params = (
|
||||
arg: NixValue,
|
||||
required: string[] | null,
|
||||
allowed: string[] | null
|
||||
allowed: string[] | null,
|
||||
): NixAttrs => {
|
||||
const forced_arg = force_attrs(arg);
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* All functionality is exported via the global `Nix` object
|
||||
*/
|
||||
|
||||
import { create_thunk, force, is_thunk, IS_THUNK } from './thunk';
|
||||
import { select, select_with_default, validate_params } from './helpers';
|
||||
import { op } from './operators';
|
||||
import { builtins, IS_PRIMOP } from './builtins';
|
||||
import { create_thunk, force, is_thunk, IS_THUNK } from "./thunk";
|
||||
import { select, select_with_default, validate_params } from "./helpers";
|
||||
import { op } from "./operators";
|
||||
import { builtins, IS_PRIMOP } from "./builtins";
|
||||
|
||||
export type NixRuntime = typeof Nix;
|
||||
|
||||
@@ -31,5 +31,5 @@ export const Nix = {
|
||||
|
||||
globalThis.Nix = Nix;
|
||||
declare global {
|
||||
var Nix: NixRuntime
|
||||
var Nix: NixRuntime;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
* Implements all binary and unary operators used by codegen
|
||||
*/
|
||||
|
||||
import type { NixValue, NixList, NixAttrs } from './types';
|
||||
import { force } from './thunk';
|
||||
import { force_numeric, force_list, force_attrs, coerce_numeric } from './type-assert';
|
||||
import type { NixValue, NixList, NixAttrs } from "./types";
|
||||
import { force } from "./thunk";
|
||||
import { force_numeric, force_list, force_attrs, coerce_numeric } from "./type-assert";
|
||||
|
||||
/**
|
||||
* Operator object exported as Nix.op
|
||||
@@ -33,10 +33,10 @@ export const op = {
|
||||
const [av, bv] = coerce_numeric(force_numeric(a), force_numeric(b));
|
||||
|
||||
if (bv === 0 || bv === 0n) {
|
||||
throw new RangeError('Division by zero');
|
||||
throw new RangeError("Division by zero");
|
||||
}
|
||||
|
||||
return (av as any) / (bv as any)
|
||||
return (av as any) / (bv as any);
|
||||
},
|
||||
|
||||
// Comparison operators (JavaScript natively supports bigint/number mixed comparison)
|
||||
@@ -44,13 +44,13 @@ export const op = {
|
||||
// FIXME: Int and Float
|
||||
const av = force(a);
|
||||
const bv = force(b);
|
||||
return av === bv
|
||||
return av === bv;
|
||||
},
|
||||
neq: (a: NixValue, b: NixValue): boolean => {
|
||||
// FIXME: Int and Float
|
||||
const av = force(a);
|
||||
const bv = force(b);
|
||||
return av !== bv
|
||||
return av !== bv;
|
||||
},
|
||||
lt: (a: NixValue, b: NixValue): boolean => {
|
||||
// FIXME: Non-numeric
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
* Implements thunks for lazy evaluation of Nix expressions
|
||||
*/
|
||||
|
||||
import type { NixValue, NixThunkInterface } from './types';
|
||||
import type { NixValue, NixThunkInterface } from "./types";
|
||||
|
||||
/**
|
||||
* Symbol used to mark objects as thunks
|
||||
* This is exported to Rust via Nix.IS_THUNK
|
||||
*/
|
||||
export const IS_THUNK = Symbol('is_thunk');
|
||||
export const IS_THUNK = Symbol("is_thunk");
|
||||
|
||||
/**
|
||||
* NixThunk class - represents a lazy, unevaluated expression
|
||||
@@ -35,12 +35,7 @@ export class NixThunk implements NixThunkInterface {
|
||||
* @returns true if value is a NixThunk
|
||||
*/
|
||||
export const is_thunk = (value: unknown): value is NixThunkInterface => {
|
||||
return (
|
||||
value !== null &&
|
||||
typeof value === 'object' &&
|
||||
IS_THUNK in value &&
|
||||
value[IS_THUNK] === true
|
||||
);
|
||||
return value !== null && typeof value === "object" && IS_THUNK in value && value[IS_THUNK] === true;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* These functions force evaluation and verify the type, throwing errors on mismatch
|
||||
*/
|
||||
|
||||
import type { NixValue, NixList, NixAttrs, NixFunction, NixInt, NixFloat, NixNumber } from './types';
|
||||
import { force } from './thunk';
|
||||
import type { NixValue, NixList, NixAttrs, NixFunction, NixInt, NixFloat, NixNumber } from "./types";
|
||||
import { force } from "./thunk";
|
||||
|
||||
/**
|
||||
* Force a value and assert it's a list
|
||||
@@ -24,7 +24,7 @@ export const force_list = (value: NixValue): NixList => {
|
||||
*/
|
||||
export const force_function = (value: NixValue): NixFunction => {
|
||||
const forced = force(value);
|
||||
if (typeof forced !== 'function') {
|
||||
if (typeof forced !== "function") {
|
||||
throw new TypeError(`Expected function, got ${typeof forced}`);
|
||||
}
|
||||
return forced;
|
||||
@@ -36,7 +36,7 @@ export const force_function = (value: NixValue): NixFunction => {
|
||||
*/
|
||||
export const force_attrs = (value: NixValue): NixAttrs => {
|
||||
const forced = force(value);
|
||||
if (typeof forced !== 'object' || forced === null || Array.isArray(forced)) {
|
||||
if (typeof forced !== "object" || forced === null || Array.isArray(forced)) {
|
||||
throw new TypeError(`Expected attribute set, got ${typeof forced}`);
|
||||
}
|
||||
return forced as NixAttrs;
|
||||
@@ -48,7 +48,7 @@ export const force_attrs = (value: NixValue): NixAttrs => {
|
||||
*/
|
||||
export const force_string = (value: NixValue): string => {
|
||||
const forced = force(value);
|
||||
if (typeof forced !== 'string') {
|
||||
if (typeof forced !== "string") {
|
||||
throw new TypeError(`Expected string, got ${typeof forced}`);
|
||||
}
|
||||
return forced;
|
||||
@@ -60,7 +60,7 @@ export const force_string = (value: NixValue): string => {
|
||||
*/
|
||||
export const force_bool = (value: NixValue): boolean => {
|
||||
const forced = force(value);
|
||||
if (typeof forced !== 'boolean') {
|
||||
if (typeof forced !== "boolean") {
|
||||
throw new TypeError(`Expected boolean, got ${typeof forced}`);
|
||||
}
|
||||
return forced;
|
||||
@@ -72,7 +72,7 @@ export const force_bool = (value: NixValue): boolean => {
|
||||
*/
|
||||
export const force_int = (value: NixValue): NixInt => {
|
||||
const forced = force(value);
|
||||
if (typeof forced === 'bigint') {
|
||||
if (typeof forced === "bigint") {
|
||||
return forced;
|
||||
}
|
||||
throw new TypeError(`Expected int, got ${typeof forced}`);
|
||||
@@ -84,7 +84,7 @@ export const force_int = (value: NixValue): NixInt => {
|
||||
*/
|
||||
export const force_float = (value: NixValue): NixFloat => {
|
||||
const forced = force(value);
|
||||
if (typeof forced === 'number') {
|
||||
if (typeof forced === "number") {
|
||||
return forced;
|
||||
}
|
||||
throw new TypeError(`Expected float, got ${typeof forced}`);
|
||||
@@ -96,7 +96,7 @@ export const force_float = (value: NixValue): NixFloat => {
|
||||
*/
|
||||
export const force_numeric = (value: NixValue): NixNumber => {
|
||||
const forced = force(value);
|
||||
if (typeof forced === 'bigint' || typeof forced === 'number') {
|
||||
if (typeof forced === "bigint" || typeof forced === "number") {
|
||||
return forced;
|
||||
}
|
||||
throw new TypeError(`Expected numeric type, got ${typeof forced}`);
|
||||
@@ -107,19 +107,13 @@ 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] => {
|
||||
const aIsInt = typeof a === 'bigint';
|
||||
const bIsInt = typeof b === 'bigint';
|
||||
export const coerce_numeric = (a: NixNumber, b: NixNumber): [NixFloat, NixFloat] | [NixInt, NixInt] => {
|
||||
const aIsInt = typeof a === "bigint";
|
||||
const bIsInt = typeof b === "bigint";
|
||||
|
||||
// If either is float, convert both to float
|
||||
if (!aIsInt || !bIsInt) {
|
||||
return [
|
||||
aIsInt ? Number(a) : a,
|
||||
bIsInt ? Number(b) : b
|
||||
];
|
||||
return [aIsInt ? Number(a) : a, bIsInt ? Number(b) : b];
|
||||
}
|
||||
|
||||
// Both are integers
|
||||
|
||||
@@ -32,12 +32,7 @@ export type NixPrimitive = NixNull | NixBool | NixInt | NixFloat | NixString;
|
||||
* NixValue: Union type representing any possible Nix value
|
||||
* This is the core type used throughout the runtime
|
||||
*/
|
||||
export type NixValue =
|
||||
| NixPrimitive
|
||||
| NixList
|
||||
| NixAttrs
|
||||
| NixFunction
|
||||
| NixThunkInterface;
|
||||
export type NixValue = NixPrimitive | NixList | NixAttrs | NixFunction | NixThunkInterface;
|
||||
|
||||
// Operator function signatures
|
||||
export type BinaryOp<T = NixValue, U = NixValue, R = NixValue> = (a: T, b: U) => R;
|
||||
|
||||
Reference in New Issue
Block a user