Skip to content

Commit

Permalink
Error handling (#116)
Browse files Browse the repository at this point in the history
  • Loading branch information
arduano authored Apr 21, 2024
1 parent e5ad710 commit 7ee35a0
Show file tree
Hide file tree
Showing 28 changed files with 1,015 additions and 629 deletions.
80 changes: 46 additions & 34 deletions nixjs-rt/src/builtins/builtins.ts → nixjs-rt/src/builtins.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { err, errType, errTypes } from "./errors";
import { abortError } from "./errors/abort";
import { otherError } from "./errors/other";
import { typeMismatchError } from "./errors/typeError";
import {
Attrset,
EvalCtx,
Expand All @@ -10,27 +14,41 @@ import {
NixList,
NixString,
NixType,
NixTypeClass,
Path,
TRUE,
} from "../lib";
} from "./lib";

type BuiltinsRecord = Record<string, (param: NixType) => NixType>;

function builtinBasicTypeMismatchError(
fnName: string,
got: NixType,
expects: NixTypeClass | NixTypeClass[],
) {
if (!Array.isArray(expects)) {
expects = [expects];
}

return typeMismatchError(
got,
expects,
err`${fnName} expects ${errTypes(...expects)}, got ${errType(got)}.`,
);
}

export function getBuiltins() {
const builtins: BuiltinsRecord = {
abort: (message) => {
throw new EvalException(
`Evaluation aborted with the following error message: '${message.asString()}'`,
);
throw abortError(message.asString());
},

import: (path) => {
const pathStrict = path.toStrict();

if (!(pathStrict instanceof Path || pathStrict instanceof NixString)) {
throw new EvalException(
`Cannot import a value of type '${pathStrict.typeOf()}'.`,
);
const expected = [Path, NixString];
throw builtinBasicTypeMismatchError("import", pathStrict, expected);
}

const pathValue = pathStrict.toJs();
Expand All @@ -47,15 +65,13 @@ export function getBuiltins() {
return new Lambda((rhs) => {
let lhsStrict = lhs.toStrict();
if (!(lhsStrict instanceof NixInt || lhsStrict instanceof NixFloat)) {
throw new EvalException(
`value is of type '${lhs.typeOf()}' while a number was expected.`,
);
let expected = [NixInt, NixFloat];
throw builtinBasicTypeMismatchError("add", lhsStrict, expected);
}
let rhsStrict = rhs.toStrict();
if (!(rhsStrict instanceof NixInt || rhsStrict instanceof NixFloat)) {
throw new EvalException(
`value is of type '${rhs.typeOf()}' while a number was expected.`,
);
let expected = [NixInt, NixFloat];
throw builtinBasicTypeMismatchError("add", rhsStrict, expected);
}
return lhsStrict.add(rhsStrict);
});
Expand All @@ -64,32 +80,28 @@ export function getBuiltins() {
head: (list) => {
const listStrict = list.toStrict();
if (!(listStrict instanceof NixList)) {
throw new EvalException(
`Cannot apply the 'head' function on '${listStrict.typeOf()}'.`,
throw typeMismatchError(
listStrict,
NixList,
err`Cannot apply the 'head' function on '${errType(listStrict)}', expected ${errType(NixList)}.`,
);
}
if (listStrict.values.length === 0) {
throw new EvalException(
"Cannot fetch the first element in an empty list.",
);
throw otherError("Cannot fetch the first element in an empty list.");
}
return listStrict.values[0];
},

all: (pred) => {
const lambdaStrict = pred.toStrict();
if (!(lambdaStrict instanceof Lambda)) {
throw new EvalException(
`'all' function requires another function, but got '${lambdaStrict.typeOf()}' instead.`,
);
throw builtinBasicTypeMismatchError("all", lambdaStrict, Lambda);
}

return new Lambda((list) => {
const listStrict = list.toStrict();
if (!(listStrict instanceof NixList)) {
throw new EvalException(
`Cannot apply the 'all' function on '${listStrict.typeOf()}'.`,
);
throw builtinBasicTypeMismatchError("all", listStrict, NixList);
}

for (const element of listStrict.values) {
Expand All @@ -106,17 +118,13 @@ export function getBuiltins() {
any: (pred) => {
const lambdaStrict = pred.toStrict();
if (!(lambdaStrict instanceof Lambda)) {
throw new EvalException(
`'any' function requires another function, but got '${lambdaStrict.typeOf()}' instead.`,
);
throw builtinBasicTypeMismatchError("any", lambdaStrict, Lambda);
}

return new Lambda((list) => {
const listStrict = list.toStrict();
if (!(listStrict instanceof NixList)) {
throw new EvalException(
`Cannot apply the 'any' function on '${listStrict.typeOf()}'.`,
);
throw builtinBasicTypeMismatchError("any", listStrict, NixList);
}

for (const element of listStrict.values) {
Expand All @@ -133,8 +141,10 @@ export function getBuiltins() {
attrNames: (attrset) => {
const attrsetStrict = attrset.toStrict();
if (!(attrsetStrict instanceof Attrset)) {
throw new EvalException(
`Cannot apply the 'attrNames' function on '${attrsetStrict.typeOf()}'.`,
throw builtinBasicTypeMismatchError(
"attrNames",
attrsetStrict,
Attrset,
);
}

Expand All @@ -147,8 +157,10 @@ export function getBuiltins() {
attrValues: (attrset) => {
const attrsetStrict = attrset.toStrict();
if (!(attrsetStrict instanceof Attrset)) {
throw new EvalException(
`Cannot apply the 'attrValues' function on '${attrsetStrict.typeOf()}'.`,
throw builtinBasicTypeMismatchError(
"attrValues",
attrsetStrict,
Attrset,
);
}

Expand Down
40 changes: 0 additions & 40 deletions nixjs-rt/src/builtins/tests/abort.test.ts

This file was deleted.

42 changes: 0 additions & 42 deletions nixjs-rt/src/builtins/tests/add.test.ts

This file was deleted.

49 changes: 0 additions & 49 deletions nixjs-rt/src/builtins/tests/all.test.ts

This file was deleted.

49 changes: 0 additions & 49 deletions nixjs-rt/src/builtins/tests/any.test.ts

This file was deleted.

42 changes: 0 additions & 42 deletions nixjs-rt/src/builtins/tests/attrNames.test.ts

This file was deleted.

Loading

0 comments on commit 7ee35a0

Please sign in to comment.