feat: runtime error
This commit is contained in:
@@ -5,21 +5,21 @@
|
||||
import type { NixValue } from "../types";
|
||||
|
||||
export const fromJSON = (e: NixValue): never => {
|
||||
throw "Not implemented: fromJSON";
|
||||
throw new Error("Not implemented: fromJSON");
|
||||
};
|
||||
|
||||
export const fromTOML = (e: NixValue): never => {
|
||||
throw "Not implemented: fromTOML";
|
||||
throw new Error("Not implemented: fromTOML");
|
||||
};
|
||||
|
||||
export const toJSON = (e: NixValue): never => {
|
||||
throw "Not implemented: toJSON";
|
||||
throw new Error("Not implemented: toJSON");
|
||||
};
|
||||
|
||||
export const toXML = (e: NixValue): never => {
|
||||
throw "Not implemented: toXML";
|
||||
throw new Error("Not implemented: toXML");
|
||||
};
|
||||
|
||||
export const toString = (name: NixValue, s: NixValue): never => {
|
||||
throw "Not implemented: toString";
|
||||
throw new Error("Not implemented: toString");
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { NixValue } from "../types";
|
||||
|
||||
export const derivation = (args: NixValue) => {
|
||||
throw "Not implemented: derivation";
|
||||
throw new Error("Not implemented: derivation");
|
||||
};
|
||||
|
||||
export const derivationStrict = (args: NixValue) => {
|
||||
throw "Not implemented: derivationStrict";
|
||||
throw new Error("Not implemented: derivationStrict");
|
||||
};
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
* Functional programming builtin functions
|
||||
*/
|
||||
|
||||
import type { NixValue } from "../types";
|
||||
import { CatchableError, type NixValue } from "../types";
|
||||
import { force } from "../thunk";
|
||||
import { force_string } from "../type-assert";
|
||||
|
||||
export const seq =
|
||||
(e1: NixValue) =>
|
||||
@@ -15,15 +16,15 @@ export const seq =
|
||||
export const deepSeq =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): never => {
|
||||
throw "Not implemented: deepSeq";
|
||||
throw new Error("Not implemented: deepSeq");
|
||||
};
|
||||
|
||||
export const abort = (s: NixValue): never => {
|
||||
throw `evaluation aborted with the following error message: '${force(s)}'`;
|
||||
throw new Error(`evaluation aborted with the following error message: '${force(s)}'`);
|
||||
};
|
||||
|
||||
export const throwFunc = (s: NixValue): never => {
|
||||
throw force(s);
|
||||
throw new CatchableError(force_string(s));
|
||||
};
|
||||
|
||||
export const trace = (e1: NixValue, e2: NixValue): NixValue => {
|
||||
|
||||
@@ -249,7 +249,7 @@ export const builtins: any = {
|
||||
|
||||
builtins: create_thunk(() => builtins),
|
||||
currentSystem: create_thunk(() => {
|
||||
throw "Not implemented: currentSystem";
|
||||
throw new Error("Not implemented: currentSystem");
|
||||
}),
|
||||
currentTime: create_thunk(() => Date.now()),
|
||||
|
||||
|
||||
@@ -25,39 +25,39 @@ export const importFunc = (path: NixValue): NixValue => {
|
||||
export const scopedImport =
|
||||
(scope: NixValue) =>
|
||||
(path: NixValue): never => {
|
||||
throw "Not implemented: scopedImport";
|
||||
throw new Error("Not implemented: scopedImport");
|
||||
};
|
||||
|
||||
export const storePath = (args: NixValue): never => {
|
||||
throw "Not implemented: storePath";
|
||||
throw new Error("Not implemented: storePath");
|
||||
};
|
||||
|
||||
export const fetchClosure = (args: NixValue): never => {
|
||||
throw "Not implemented: fetchClosure";
|
||||
throw new Error("Not implemented: fetchClosure");
|
||||
};
|
||||
|
||||
export const fetchMercurial = (args: NixValue): never => {
|
||||
throw "Not implemented: fetchMercurial";
|
||||
throw new Error("Not implemented: fetchMercurial");
|
||||
};
|
||||
|
||||
export const fetchGit = (args: NixValue): never => {
|
||||
throw "Not implemented: fetchGit";
|
||||
throw new Error("Not implemented: fetchGit");
|
||||
};
|
||||
|
||||
export const fetchTarball = (args: NixValue): never => {
|
||||
throw "Not implemented: fetchTarball";
|
||||
throw new Error("Not implemented: fetchTarball");
|
||||
};
|
||||
|
||||
export const fetchTree = (args: NixValue): never => {
|
||||
throw "Not implemented: fetchTree";
|
||||
throw new Error("Not implemented: fetchTree");
|
||||
};
|
||||
|
||||
export const fetchurl = (args: NixValue): never => {
|
||||
throw "Not implemented: fetchurl";
|
||||
throw new Error("Not implemented: fetchurl");
|
||||
};
|
||||
|
||||
export const readDir = (path: NixValue): never => {
|
||||
throw "Not implemented: readDir";
|
||||
throw new Error("Not implemented: readDir");
|
||||
};
|
||||
|
||||
export const readFile = (path: NixValue): string => {
|
||||
@@ -66,7 +66,7 @@ export const readFile = (path: NixValue): string => {
|
||||
};
|
||||
|
||||
export const readFileType = (path: NixValue): never => {
|
||||
throw "Not implemented: readFileType";
|
||||
throw new Error("Not implemented: readFileType");
|
||||
};
|
||||
|
||||
export const pathExists = (path: NixValue): boolean => {
|
||||
@@ -75,27 +75,27 @@ export const pathExists = (path: NixValue): boolean => {
|
||||
};
|
||||
|
||||
export const path = (args: NixValue): never => {
|
||||
throw "Not implemented: path";
|
||||
throw new Error("Not implemented: path");
|
||||
};
|
||||
|
||||
export const toFile = (name: NixValue, s: NixValue): never => {
|
||||
throw "Not implemented: toFile";
|
||||
throw new Error("Not implemented: toFile");
|
||||
};
|
||||
|
||||
export const toPath = (name: NixValue, s: NixValue): never => {
|
||||
throw "Not implemented: toPath";
|
||||
throw new Error("Not implemented: toPath");
|
||||
};
|
||||
|
||||
export const filterSource = (args: NixValue): never => {
|
||||
throw "Not implemented: filterSource";
|
||||
throw new Error("Not implemented: filterSource");
|
||||
};
|
||||
|
||||
export const findFile =
|
||||
(search: NixValue) =>
|
||||
(lookup: NixValue): never => {
|
||||
throw "Not implemented: findFile";
|
||||
throw new Error("Not implemented: findFile");
|
||||
};
|
||||
|
||||
export const getEnv = (s: NixValue): never => {
|
||||
throw "Not implemented: getEnv";
|
||||
throw new Error("Not implemented: getEnv");
|
||||
};
|
||||
|
||||
@@ -2,141 +2,155 @@
|
||||
* Miscellaneous unimplemented builtin functions
|
||||
*/
|
||||
|
||||
import type { NixValue } from "../types";
|
||||
import { force } from "../thunk";
|
||||
import { CatchableError } from "../types";
|
||||
import type { NixBool, NixStrictValue, NixValue } from "../types";
|
||||
|
||||
export const addErrorContext =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): never => {
|
||||
throw "Not implemented: addErrorContext";
|
||||
throw new Error("Not implemented: addErrorContext");
|
||||
};
|
||||
|
||||
export const appendContext =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): never => {
|
||||
throw "Not implemented: appendContext";
|
||||
throw new Error("Not implemented: appendContext");
|
||||
};
|
||||
|
||||
export const getContext = (s: NixValue): never => {
|
||||
throw "Not implemented: getContext";
|
||||
throw new Error("Not implemented: getContext");
|
||||
};
|
||||
|
||||
export const hasContext = (s: NixValue): never => {
|
||||
throw "Not implemented: hasContext";
|
||||
throw new Error("Not implemented: hasContext");
|
||||
};
|
||||
|
||||
export const hashFile =
|
||||
(type: NixValue) =>
|
||||
(p: NixValue): never => {
|
||||
throw "Not implemented: hashFile";
|
||||
throw new Error("Not implemented: hashFile");
|
||||
};
|
||||
|
||||
export const hashString =
|
||||
(type: NixValue) =>
|
||||
(p: NixValue): never => {
|
||||
throw "Not implemented: hashString";
|
||||
throw new Error("Not implemented: hashString");
|
||||
};
|
||||
|
||||
export const convertHash = (args: NixValue): never => {
|
||||
throw "Not implemented: convertHash";
|
||||
throw new Error("Not implemented: convertHash");
|
||||
};
|
||||
|
||||
export const unsafeDiscardOutputDependency = (s: NixValue): never => {
|
||||
throw "Not implemented: unsafeDiscardOutputDependency";
|
||||
throw new Error("Not implemented: unsafeDiscardOutputDependency");
|
||||
};
|
||||
|
||||
export const unsafeDiscardStringContext = (s: NixValue): never => {
|
||||
throw "Not implemented: unsafeDiscardStringContext";
|
||||
throw new Error("Not implemented: unsafeDiscardStringContext");
|
||||
};
|
||||
|
||||
export const unsafeGetAttrPos = (s: NixValue): never => {
|
||||
throw "Not implemented: unsafeGetAttrPos";
|
||||
throw new Error("Not implemented: unsafeGetAttrPos");
|
||||
};
|
||||
|
||||
export const addDrvOutputDependencies = (s: NixValue): never => {
|
||||
throw "Not implemented: addDrvOutputDependencies";
|
||||
throw new Error("Not implemented: addDrvOutputDependencies");
|
||||
};
|
||||
|
||||
export const compareVersions =
|
||||
(s1: NixValue) =>
|
||||
(s2: NixValue): never => {
|
||||
throw "Not implemented: compareVersions";
|
||||
throw new Error("Not implemented: compareVersions");
|
||||
};
|
||||
|
||||
export const dirOf = (s: NixValue): never => {
|
||||
throw "Not implemented: dirOf";
|
||||
throw new Error("Not implemented: dirOf");
|
||||
};
|
||||
|
||||
export const flakeRefToString = (attrs: NixValue): never => {
|
||||
throw "Not implemented: flakeRefToString";
|
||||
throw new Error("Not implemented: flakeRefToString");
|
||||
};
|
||||
|
||||
export const functionArgs = (f: NixValue): never => {
|
||||
throw "Not implemented: functionArgs";
|
||||
throw new Error("Not implemented: functionArgs");
|
||||
};
|
||||
|
||||
export const genericClosure = (args: NixValue): never => {
|
||||
throw "Not implemented: genericClosure";
|
||||
throw new Error("Not implemented: genericClosure");
|
||||
};
|
||||
|
||||
export const getFlake = (attrs: NixValue): never => {
|
||||
throw "Not implemented: getFlake";
|
||||
throw new Error("Not implemented: getFlake");
|
||||
};
|
||||
|
||||
export const match =
|
||||
(regex: NixValue) =>
|
||||
(str: NixValue): never => {
|
||||
throw "Not implemented: match";
|
||||
throw new Error("Not implemented: match");
|
||||
};
|
||||
|
||||
export const outputOf =
|
||||
(drv: NixValue) =>
|
||||
(out: NixValue): never => {
|
||||
throw "Not implemented: outputOf";
|
||||
throw new Error("Not implemented: outputOf");
|
||||
};
|
||||
|
||||
export const parseDrvName = (s: NixValue): never => {
|
||||
throw "Not implemented: parseDrvName";
|
||||
throw new Error("Not implemented: parseDrvName");
|
||||
};
|
||||
|
||||
export const parseFlakeName = (s: NixValue): never => {
|
||||
throw "Not implemented: parseFlakeName";
|
||||
throw new Error("Not implemented: parseFlakeName");
|
||||
};
|
||||
|
||||
export const parseFlakeRef = (s: NixValue): never => {
|
||||
throw "Not implemented: parseFlakeRef";
|
||||
throw new Error("Not implemented: parseFlakeRef");
|
||||
};
|
||||
|
||||
export const placeholder = (output: NixValue): never => {
|
||||
throw "Not implemented: placeholder";
|
||||
throw new Error("Not implemented: placeholder");
|
||||
};
|
||||
|
||||
export const replaceStrings =
|
||||
(from: NixValue) =>
|
||||
(to: NixValue) =>
|
||||
(s: NixValue): never => {
|
||||
throw "Not implemented: replaceStrings";
|
||||
throw new Error("Not implemented: replaceStrings");
|
||||
};
|
||||
|
||||
export const split = (regex: NixValue, str: NixValue): never => {
|
||||
throw "Not implemented: split";
|
||||
throw new Error("Not implemented: split");
|
||||
};
|
||||
|
||||
export const splitVersion = (s: NixValue): never => {
|
||||
throw "Not implemented: splitVersion";
|
||||
throw new Error("Not implemented: splitVersion");
|
||||
};
|
||||
|
||||
export const traceVerbose = (e1: NixValue, e2: NixValue): never => {
|
||||
throw "Not implemented: traceVerbose";
|
||||
throw new Error("Not implemented: traceVerbose");
|
||||
};
|
||||
|
||||
export const tryEval =
|
||||
(e1: NixValue) =>
|
||||
(e2: NixValue): never => {
|
||||
throw "Not implemented: tryEval";
|
||||
export const tryEval = (e: NixValue): { success: NixBool; value: NixStrictValue } => {
|
||||
try {
|
||||
return {
|
||||
success: true,
|
||||
value: force(e),
|
||||
};
|
||||
} catch (err) {
|
||||
if (err instanceof CatchableError) {
|
||||
return {
|
||||
success: false,
|
||||
value: false,
|
||||
};
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const zipAttrsWith =
|
||||
(f: NixValue) =>
|
||||
(list: NixValue): never => {
|
||||
throw "Not implemented: zipAttrsWith";
|
||||
throw new Error("Not implemented: zipAttrsWith");
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
NixInt,
|
||||
NixList,
|
||||
NixNull,
|
||||
NixStrictValue,
|
||||
NixString,
|
||||
NixValue,
|
||||
} from "../types";
|
||||
@@ -39,7 +40,7 @@ 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 new Error("Not implemented: isPath");
|
||||
};
|
||||
|
||||
export const isString = (e: NixValue): e is NixString => typeof force(e) === "string";
|
||||
|
||||
@@ -60,7 +60,7 @@ export const select_with_default = (obj: NixValue, key: NixValue, default_val: N
|
||||
|
||||
export const has_attr = (obj: NixValue, attrpath: NixValue[]): NixBool => {
|
||||
if (!isAttrs(obj)) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
let attrs = obj;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Implements thunks for lazy evaluation of Nix expressions
|
||||
*/
|
||||
|
||||
import type { NixValue, NixThunkInterface } from "./types";
|
||||
import type { NixValue, NixThunkInterface, NixStrictValue } from "./types";
|
||||
|
||||
/**
|
||||
* Symbol used to mark objects as thunks
|
||||
@@ -20,12 +20,12 @@ export const IS_THUNK = Symbol("is_thunk");
|
||||
export class NixThunk implements NixThunkInterface {
|
||||
[key: symbol]: any;
|
||||
readonly [IS_THUNK] = true as const;
|
||||
func: (() => NixValue) | null;
|
||||
result: Exclude<NixValue, NixThunkInterface> | null;
|
||||
func: (() => NixValue) | undefined;
|
||||
result: NixStrictValue | undefined;
|
||||
|
||||
constructor(func: () => NixValue) {
|
||||
this.func = func;
|
||||
this.result = null;
|
||||
this.result = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,20 +46,20 @@ export const is_thunk = (value: unknown): value is NixThunkInterface => {
|
||||
* @param value - Value to force (may be a thunk)
|
||||
* @returns The forced/evaluated value
|
||||
*/
|
||||
export const force = (value: NixValue): Exclude<NixValue, NixThunkInterface> => {
|
||||
export const force = (value: NixValue): NixStrictValue => {
|
||||
if (!is_thunk(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// Already evaluated - return cached result
|
||||
if (value.func === null) {
|
||||
if (value.func === undefined) {
|
||||
return value.result!;
|
||||
}
|
||||
|
||||
// Evaluate and cache
|
||||
const result = force(value.func());
|
||||
value.result = result;
|
||||
value.func = null;
|
||||
value.func = undefined;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* Core TypeScript type definitions for nix-js runtime
|
||||
*/
|
||||
|
||||
import { IS_THUNK } from "./thunk";
|
||||
|
||||
// Nix primitive types
|
||||
export type NixInt = bigint;
|
||||
export type NixFloat = number;
|
||||
@@ -20,9 +22,9 @@ export type NixFunction = (...args: any[]) => any;
|
||||
* Thunks delay evaluation until forced
|
||||
*/
|
||||
export interface NixThunkInterface {
|
||||
readonly [key: symbol]: true; // IS_THUNK marker
|
||||
func: (() => NixValue) | null;
|
||||
result: Exclude<NixValue, NixThunkInterface> | null;
|
||||
readonly [IS_THUNK]: true;
|
||||
func: (() => NixValue) | undefined;
|
||||
result: NixStrictValue | undefined;
|
||||
}
|
||||
|
||||
// Union of all Nix primitive types
|
||||
@@ -34,6 +36,18 @@ export type NixPrimitive = NixNull | NixBool | NixInt | NixFloat | NixString;
|
||||
*/
|
||||
export type NixValue = NixPrimitive | NixList | NixAttrs | NixFunction | NixThunkInterface;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Operator function signatures
|
||||
export type BinaryOp<T = NixValue, U = NixValue, R = NixValue> = (a: T, b: U) => R;
|
||||
export type UnaryOp<T = NixValue, R = NixValue> = (a: T) => R;
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::pin::Pin;
|
||||
use std::sync::Once;
|
||||
|
||||
use deno_core::{Extension, ExtensionFileSource, JsRuntime, OpDecl, OpState, RuntimeOptions, v8};
|
||||
use deno_error::JsErrorClass;
|
||||
|
||||
use crate::codegen::{CodegenContext, Compile};
|
||||
use crate::context::{CtxPtr, PathDropGuard};
|
||||
@@ -44,12 +45,12 @@ mod private {
|
||||
pub struct SimpleErrorWrapper(pub(crate) String);
|
||||
impl std::fmt::Display for SimpleErrorWrapper {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self, f)
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
impl std::error::Error for SimpleErrorWrapper {}
|
||||
|
||||
js_error_wrapper!(SimpleErrorWrapper, NixError, "EvalError");
|
||||
js_error_wrapper!(SimpleErrorWrapper, NixError, "Error");
|
||||
|
||||
impl From<String> for NixError {
|
||||
fn from(value: String) -> Self {
|
||||
@@ -71,10 +72,13 @@ fn op_import(state: &mut OpState, #[string] path: String) -> std::result::Result
|
||||
let ctx = unsafe { ptr.as_mut() };
|
||||
|
||||
let current_dir = ctx.get_current_dir();
|
||||
let absolute_path = current_dir
|
||||
let mut absolute_path = current_dir
|
||||
.join(&path)
|
||||
.canonicalize()
|
||||
.map_err(|e| format!("Failed to resolve path {}: {}", path, e))?;
|
||||
if absolute_path.is_dir() {
|
||||
absolute_path.push("default.nix")
|
||||
}
|
||||
|
||||
let mut guard = PathDropGuard::new(absolute_path.clone(), ctx);
|
||||
let ctx = guard.as_ctx();
|
||||
@@ -175,7 +179,7 @@ impl Runtime {
|
||||
let global_value = self
|
||||
.js_runtime
|
||||
.execute_script("<eval>", script)
|
||||
.map_err(|e| Error::eval_error(format!("Execution error: {:?}", e)))?;
|
||||
.map_err(|e| Error::eval_error(format!("{}", e.get_message())))?;
|
||||
|
||||
// Retrieve scope from JsRuntime
|
||||
deno_core::scope!(scope, self.js_runtime);
|
||||
|
||||
Reference in New Issue
Block a user