Skip to content

Commit

Permalink
support recursive require
Browse files Browse the repository at this point in the history
  • Loading branch information
y21 committed Oct 20, 2023
1 parent 915890e commit a04f277
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 5 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/dash_node_impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ serde_json = "1.0.103"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.24.0", features = ["full"] }
dash_proc_macro = { path = "../dash_proc_macro" }
rustc-hash = "1.1.0"
42 changes: 38 additions & 4 deletions crates/dash_node_impl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::cell::RefCell;
use std::path::{Path, PathBuf};
use std::rc::Rc;

use anyhow::Context;
use anyhow::{anyhow, bail};
Expand All @@ -16,6 +18,7 @@ use dash_vm::value::object::PropertyValue;
use dash_vm::value::Value;
use dash_vm::{delegate, throw};
use package::Package;
use rustc_hash::FxHashMap;

mod package;

Expand Down Expand Up @@ -46,7 +49,16 @@ async fn run_inner_fallible(path: &str, opt: OptLevel, initial_gc_threshold: Opt

let mut rt = Runtime::new(initial_gc_threshold).await;
let scope = &mut rt.vm_mut().scope();
execute_node_module(scope, path, &entry, opt).map_err(|err| match err {

execute_node_module(
scope,
path,
path,
&entry,
opt,
Rc::new(RefCell::new(FxHashMap::default())),
)
.map_err(|err| match err {
(EvalError::Middle(errs), _) => anyhow!("{}", errs.formattable(&entry, true)),
(EvalError::Exception(err), _) => anyhow!("{}", format_value(err.root(scope), scope).unwrap()),
})?;
Expand All @@ -57,14 +69,17 @@ async fn run_inner_fallible(path: &str, opt: OptLevel, initial_gc_threshold: Opt
/// Returns the `module` object
fn execute_node_module(
scope: &mut LocalScope,
directory: &Path,
dir_path: &Path,
file_path: &Path,
source: &str,
opt: OptLevel,
ongoing_requires: Rc<RefCell<FxHashMap<PathBuf, Value>>>,
) -> Result<Value, (EvalError, StringInterner)> {
let exports = Value::Object(scope.register(NamedObject::new(scope)));
let module = Value::Object(scope.register(NamedObject::new(scope)));
let require = Value::Object(scope.register(RequireFunction {
dir: directory.to_owned(),
dir: dir_path.to_owned(),
ongoing_requires: ongoing_requires.clone(),
object: NamedObject::new(scope),
}));
module
Expand All @@ -83,6 +98,10 @@ fn execute_node_module(
.set_property(scope, "require".into(), PropertyValue::static_default(require))
.unwrap();

ongoing_requires
.borrow_mut()
.insert(file_path.to_owned(), module.clone());

scope.eval(source, opt)?;

Ok(module)
Expand All @@ -91,6 +110,7 @@ fn execute_node_module(
#[derive(Debug, Trace)]
struct RequireFunction {
dir: PathBuf,
ongoing_requires: Rc<RefCell<FxHashMap<PathBuf, Value>>>,
object: NamedObject,
}

Expand Down Expand Up @@ -120,16 +140,23 @@ impl Object for RequireFunction {
let Some(Value::String(arg)) = args.first() else {
throw!(scope, Error, "require() expects a string argument");
};

let is_path = matches!(arg.chars().next(), Some('.' | '/' | '~'));
if is_path {
let canonicalized_path = match self.dir.join(&**arg).canonicalize() {
Ok(v) => v,
Err(err) => throw!(scope, Error, err.to_string()),
};

if let Some(module) = self.ongoing_requires.borrow().get(&canonicalized_path) {
return Ok(module.clone());
}

let source = match std::fs::read_to_string(&canonicalized_path) {
Ok(v) => v,
Err(err) => throw!(scope, Error, err.to_string()),
};

let Some(parent_dir) = canonicalized_path.parent() else {
throw!(
scope,
Expand All @@ -139,7 +166,14 @@ impl Object for RequireFunction {
);
};

let module = match execute_node_module(scope, parent_dir, &source, OptLevel::default()) {
let module = match execute_node_module(
scope,
parent_dir,
&canonicalized_path,
&source,
OptLevel::default(),
self.ongoing_requires.clone(),
) {
Ok(v) => v,
Err((EvalError::Exception(value), _)) => return Err(value.root(scope)),
Err((EvalError::Middle(errs), _)) => {
Expand Down
3 changes: 2 additions & 1 deletion crates/dash_vm/src/gc/trace.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::cell::Cell;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::HashSet;
use std::path::PathBuf;
use std::rc::Rc;
Expand Down Expand Up @@ -58,7 +59,7 @@ unsafe impl<T: Trace> Trace for HashSet<T> {
}
}

unsafe impl<K: Trace, V: Trace> Trace for ahash::HashMap<K, V> {
unsafe impl<K: Trace, V: Trace, S> Trace for HashMap<K, V, S> {
fn trace(&self) {
for (k, v) in self.iter() {
k.trace();
Expand Down

0 comments on commit a04f277

Please sign in to comment.