Skip to content

Commit

Permalink
Merge 13e6ff9 into sapling-pr-archive-arduano
Browse files Browse the repository at this point in the history
  • Loading branch information
arduano authored May 20, 2024
2 parents a34e1cb + 13e6ff9 commit 80f122c
Show file tree
Hide file tree
Showing 15 changed files with 161 additions and 64 deletions.
24 changes: 16 additions & 8 deletions nixjs-rt/src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import {
NixTypeClass,
Path,
TRUE,
toPath,
} from "./lib";
import { dirOf, isAbsolutePath, normalizePath } from "./utils";

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

function builtinBasicTypeMismatchError(
fnName: string,
Expand Down Expand Up @@ -71,7 +72,7 @@ export function getBuiltins() {
throw new Error("unimplemented");
},

all: (pred) => {
all: (pred, ctx) => {
const lambdaStrict = pred.toStrict();
if (!(lambdaStrict instanceof Lambda)) {
throw builtinBasicTypeMismatchError("all", lambdaStrict, Lambda);
Expand All @@ -84,7 +85,7 @@ export function getBuiltins() {
}

for (const element of listStrict.values) {
const result = lambdaStrict.apply(element);
const result = lambdaStrict.apply(element, ctx);
if (!result.asBoolean()) {
return FALSE;
}
Expand All @@ -94,7 +95,7 @@ export function getBuiltins() {
});
},

any: (pred) => {
any: (pred, ctx) => {
const lambdaStrict = pred.toStrict();
if (!(lambdaStrict instanceof Lambda)) {
throw builtinBasicTypeMismatchError("any", lambdaStrict, Lambda);
Expand All @@ -107,7 +108,7 @@ export function getBuiltins() {
}

for (const element of listStrict.values) {
const result = lambdaStrict.apply(element);
const result = lambdaStrict.apply(element, ctx);
if (result.asBoolean()) {
return TRUE;
}
Expand Down Expand Up @@ -216,7 +217,7 @@ export function getBuiltins() {
throw new Error("unimplemented");
},

dirOf: (arg) => {
dirOf: (path) => {
throw new Error("unimplemented");
},

Expand Down Expand Up @@ -350,7 +351,7 @@ export function getBuiltins() {
return listStrict.values[0];
},

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

if (!(pathStrict instanceof Path || pathStrict instanceof NixString)) {
Expand Down Expand Up @@ -548,7 +549,14 @@ export function getBuiltins() {
throw new Error("unimplemented");
},

toString: (arg) => {
toString: (arg: NixType) => {
if (arg instanceof NixString) {
return arg;
} else if (arg instanceof Path) {
return new NixString(arg.path);
}

// TODO: Expand on this
throw new Error("unimplemented");
},

Expand Down
8 changes: 4 additions & 4 deletions nixjs-rt/src/legacyTests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import { evalCtx, keyVals, toAttrpath } from "./testUtils";

// Apply:
test("calling a lambda should return its value", () => {
expect(new Lambda((_) => new NixInt(1n)).apply(EMPTY_ATTRSET)).toStrictEqual(
new NixInt(1n),
);
expect(
new Lambda((_) => new NixInt(1n)).apply(EMPTY_ATTRSET, evalCtx()),
).toStrictEqual(new NixInt(1n));
});

// Arithmetic:
Expand Down Expand Up @@ -496,7 +496,7 @@ test("parameter lambda", () => {
expect(
n
.paramLambda(evalCtx(), "foo", (evalCtx) => evalCtx.lookup("foo"))
.apply(n.TRUE),
.apply(n.TRUE, evalCtx()),
).toBe(n.TRUE);
});

Expand Down
14 changes: 7 additions & 7 deletions nixjs-rt/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export abstract class NixType {
return _nixBoolFromJs(this.asBoolean() && rhs.asBoolean());
}

apply(param: NixType): NixType {
apply(param: NixType, ctx: EvalCtx): NixType {
throw invalidTypeError(
this,
err`Attempt to call something which is not a function but is ${errType(this)}`,
Expand Down Expand Up @@ -1063,8 +1063,8 @@ export class Lazy extends NixType {
return this.toStrict().and(rhs);
}

override apply(param: NixType): NixType {
return this.toStrict().apply(param);
override apply(param: NixType, ctx: EvalCtx): NixType {
return this.toStrict().apply(param, ctx);
}

override asBoolean(): boolean {
Expand Down Expand Up @@ -1176,15 +1176,15 @@ export class Lazy extends NixType {
}

export class Lambda extends NixType {
body: (param: NixType) => NixType;
body: (param: NixType, ctx: EvalCtx) => NixType;

constructor(body: (param: NixType) => NixType) {
constructor(body: (param: NixType, ctx: EvalCtx) => NixType) {
super();
this.body = body;
}

override apply(param: NixType): NixType {
return this.body(param);
override apply(param: NixType, ctx: EvalCtx): NixType {
return this.body(param, ctx);
}

toJs(): any {
Expand Down
5 changes: 4 additions & 1 deletion src/cmd/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ pub fn handle_cmd(parsed_args: &ArgMatches) -> Result<(), NixError> {
let expr = parsed_args
.get_one::<String>("expr")
.ok_or("You must use the '--expr' option. Nothing else is implemented :)")?;
print_value(&execution::evaluate(expr)?);

let current_dir = std::env::current_dir().map_err(|_| "Couldn't get the current directory")?;

print_value(&execution::evaluate(expr, &current_dir)?);
println!();
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion src/eval/emit_js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn emit_apply(apply: &ast::Apply, out_src: &mut String) -> Result<(), String> {
.expect("Unexpected lambda application without arguments."),
out_src,
)?;
out_src.push(')');
out_src.push_str(", ctx)");
Ok(())
}

Expand Down
20 changes: 7 additions & 13 deletions src/eval/execution.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::env::current_dir;
use std::path::Path;
use std::sync::Once;

Expand All @@ -13,7 +12,7 @@ use super::types::js_value_to_nix;

static INIT_V8: Once = Once::new();

pub fn evaluate(nix_expr: &str) -> EvalResult {
pub fn evaluate(nix_expr: &str, workdir: &Path) -> EvalResult {
initialize_v8();
// Declare the V8 execution context
let isolate = &mut v8::Isolate::new(Default::default());
Expand Down Expand Up @@ -53,7 +52,7 @@ pub fn evaluate(nix_expr: &str) -> EvalResult {

let root_nix_fn = nix_expr_to_js_function(scope, nix_expr)?;

nix_value_from_module(scope, root_nix_fn, nixjs_rt_obj)
nix_value_from_module(scope, root_nix_fn, nixjs_rt_obj, workdir)
}

fn nix_expr_to_js_function<'s>(
Expand Down Expand Up @@ -170,20 +169,15 @@ fn initialize_v8() {

fn nix_value_from_module(
scope: &mut v8::ContextScope<v8::HandleScope>,
nix_value: v8::Local<v8::Function>,
nix_module_fn: v8::Local<v8::Function>,
nixjs_rt_obj: v8::Local<v8::Object>,
workdir: &Path,
) -> EvalResult {
let nixrt: v8::Local<v8::Value> = nixjs_rt_obj.into();

let eval_ctx = create_eval_ctx(
scope,
&nixrt,
&current_dir().map_err(|err| {
format!("Failed to determine the current working directory. Error: {err}")
})?,
)?;
let eval_ctx = create_eval_ctx(scope, &nixrt, workdir)?;

let nix_value = call_js_function(scope, &nix_value, nixjs_rt_obj, &[eval_ctx.into()])?;
let nix_value = call_js_function(scope, &nix_module_fn, nixjs_rt_obj, &[eval_ctx.into()])?;

let to_strict_fn: v8::Local<v8::Function> =
try_get_js_object_key(scope, &nixrt, "recursiveStrict")?
Expand All @@ -192,7 +186,7 @@ fn nix_value_from_module(
.expect("`n.recursiveStrict` is not a function.");
let strict_nix_value = call_js_function(scope, &to_strict_fn, nixjs_rt_obj, &[nix_value])?;

js_value_to_nix(scope, &nixrt, &strict_nix_value)
js_value_to_nix(scope, &nixjs_rt_obj, &strict_nix_value)
}

fn create_eval_ctx<'s>(
Expand Down
41 changes: 32 additions & 9 deletions src/eval/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,38 @@ pub fn call_js_function<'s>(
args: &[v8::Local<v8::Value>],
) -> Result<v8::Local<'s, v8::Value>, NixError> {
let try_scope = &mut v8::TryCatch::new(scope);
let recv = v8::undefined(try_scope).into();
let Some(strict_nix_value) = js_function.call(try_scope, recv, args) else {
// TODO: Again, the stack trace needs to be source-mapped.
if let Some(error) = try_scope.exception() {
let error = js_error_to_rust(try_scope, nixrt, error);
return Err(error);
} else {
return Err("Unknown evaluation error.".into());
}
let this = v8::undefined(try_scope).into();
let Some(strict_nix_value) = js_function.call(try_scope, this, args) else {
let exception = try_scope.exception();
return Err(map_js_exception_value_to_rust(try_scope, nixrt, exception));
};
Ok(strict_nix_value)
}

pub fn call_js_instance_mehod<'s>(
scope: &mut v8::HandleScope<'s>,
js_function: &v8::Local<v8::Function>,
this: v8::Local<v8::Value>,
nixrt: v8::Local<v8::Object>,
args: &[v8::Local<v8::Value>],
) -> Result<v8::Local<'s, v8::Value>, NixError> {
let try_scope = &mut v8::TryCatch::new(scope);
let Some(strict_nix_value) = js_function.call(try_scope, this, args) else {
let exception = try_scope.exception();
return Err(map_js_exception_value_to_rust(try_scope, nixrt, exception));
};
Ok(strict_nix_value)
}

pub fn map_js_exception_value_to_rust<'s>(
scope: &mut v8::HandleScope<'s>,
nixrt: v8::Local<v8::Object>,
exception: Option<v8::Local<'s, v8::Value>>,
) -> NixError {
// TODO: Again, the stack trace needs to be source-mapped.
if let Some(error) = exception {
js_error_to_rust(scope, nixrt, error)
} else {
"Unknown evaluation error.".into()
}
}
Loading

0 comments on commit 80f122c

Please sign in to comment.