implement Path type

This commit is contained in:
2026-05-08 19:01:13 +08:00
parent 3d07f89afe
commit 21899f7380
8 changed files with 209 additions and 26 deletions
+25 -13
View File
@@ -7,6 +7,7 @@ use gc_arena::{Gc, Mutation};
use hashbrown::HashSet;
use crate::bytecode_reader::BytecodeReader;
use crate::instructions::misc::canon_path_str;
use crate::value::*;
use crate::{Break, CallFrame, PendingLoad, PendingScope, Step, Vm, VmRuntimeCtx, VmRuntimeCtxExt};
@@ -19,11 +20,11 @@ impl<'gc> Vm<'gc> {
) -> Step {
// stack: [path]
let path_val = self.force_and_retry::<StrictValue>(reader, mc)?;
let path_str = match ctx.get_string(path_val) {
let path_str = match ctx.get_string_or_path(path_val) {
Some(s) => s.to_owned(),
None => {
return self.finish_err(Error::eval_error(format!(
"expected a path string, got {}",
"expected a path or string, got {}",
path_val.ty()
)));
}
@@ -93,11 +94,11 @@ impl<'gc> Vm<'gc> {
// stack: [scope, path]
let (scope_attrs, path_val) =
self.force_and_retry::<(Gc<AttrSet>, StrictValue)>(reader, mc)?;
let path_str = match ctx.get_string(path_val) {
let path_str = match ctx.get_string_or_path(path_val) {
Some(s) => s.to_owned(),
None => {
return self.finish_err(Error::eval_error(format!(
"expected a path string, got {}",
"expected a path or string, got {}",
path_val.ty()
)));
}
@@ -145,17 +146,28 @@ impl<'gc> Vm<'gc> {
mc: &Mutation<'gc>,
) -> Step {
let path_val = self.force_and_retry::<StrictValue>(reader, mc)?;
let path = match ctx.get_string(path_val) {
Some(s) => s.to_owned(),
None => {
return self.finish_err(Error::eval_error(format!(
"expected a path string, got {}",
path_val.ty()
)));
}
// CppNix: pathExists requires an absolute path. A `Path` value is
// always absolute; a string is accepted only if it starts with `/`.
let (path, is_path_value) = if let Some(p) = path_val.as_inline::<Path>() {
(ctx.resolve_string(p.0).to_owned(), true)
} else if let Some(s) = ctx.get_string(path_val) {
(s.to_owned(), false)
} else {
return self.finish_err(Error::eval_error(format!(
"expected a path or string, got {}",
path_val.ty()
)));
};
if !is_path_value && !path.starts_with('/') {
return self.finish_err(Error::eval_error(format!(
"string '{path}' doesn't represent an absolute path"
)));
}
// CppNix collapses consecutive slashes and resolves `.` / `..` lexically
// before checking. Trailing-slash / trailing-dot mean "must be a directory".
let must_be_dir = path.ends_with('/') || path.ends_with("/.");
let p = std::path::Path::new(&path);
let canon = canon_path_str(&path);
let p = std::path::Path::new(&canon);
let exists = if must_be_dir {
std::fs::metadata(p).map(|m| m.is_dir()).unwrap_or(false)
} else {