use isStr more, include builtin name in bad path messages

This commit is contained in:
dzaima 2023-11-26 15:30:12 +02:00
parent 31e4b29115
commit 789064140b
10 changed files with 90 additions and 78 deletions

View File

@ -270,20 +270,13 @@ B show_c1(B t, B x) {
return x;
}
NOINLINE bool isStr(B x) {
if (isAtm(x) || RNK(x)!=1) return false;
if (elChr(TI(x,elType))) return true;
usz ia = IA(x); SGetU(x)
for (usz i = 0; i < ia; i++) if (!isC32(GetU(x,i))) return false;
return true;
}
NOINLINE B vfyStr(B x, char* name, char* arg) {
if (!isStr(x)) thrF("%U: %U must be a string", name, arg);
return x;
}
B cdPath;
static B args_path(B* fullpath, B w, char* name) { // consumes w, returns args, writes to fullpath
static NOINLINE B args_path(B* fullpath, B w, char* name) { // consumes w, returns args, writes to fullpath
if (!isArr(w) || RNK(w)!=1 || IA(w)>3) thrF("%U: 𝕨 must be a vector with at most 3 items, but had shape %H", name, w);
usz ia = IA(w);
SGet(w)
@ -721,28 +714,28 @@ B currentError_c1(B t, B x) { thrM("•CurrentError: No errors as error catching
static NFnDesc* fileAtDesc;
B fileAt_c1(B d, B x) {
return path_rel(nfn_objU(d), x);
return path_rel(nfn_objU(d), x, "•file.At");
}
B fileAt_c2(B d, B w, B x) {
vfyStr(w,"(file).At","𝕨");
B r = path_rel(w, x);
vfyStr(w,"•file.At","𝕨");
B r = path_rel(w, x, "•file.At");
dec(w);
return r;
}
static NFnDesc* fCharsDesc;
B fchars_c1(B d, B x) {
return path_chars(path_rel(nfn_objU(d), x));
return path_chars(path_rel(nfn_objU(d), x, "•file.Chars"));
}
B fchars_c2(B d, B w, B x) {
if (isAtm(x) || RNK(x)!=1) thrM("•file.Chars: 𝕩 must be a list of characters");
B p = path_rel(nfn_objU(d), w);
B p = path_rel(nfn_objU(d), w, "•file.Chars");
path_wChars(incG(p), x);
dec(x);
return p;
}
static NFnDesc* fBytesDesc;
B fbytes_c1(B d, B x) {
I8Arr* tf = path_bytes(path_rel(nfn_objU(d), x));
I8Arr* tf = path_bytes(path_rel(nfn_objU(d), x, "•file.Bytes"));
usz ia = PIA(tf);
u8* rp; B r = m_c8arrv(&rp, ia);
COPY_TO(rp, el_i8, 0, taga(tf), 0, ia);
@ -751,14 +744,14 @@ B fbytes_c1(B d, B x) {
}
B fbytes_c2(B d, B w, B x) {
if (isAtm(x) || RNK(x)!=1) thrM("•file.Bytes: 𝕩 must be a list");
B p = path_rel(nfn_objU(d), w);
B p = path_rel(nfn_objU(d), w, "•file.Bytes");
path_wBytes(incG(p), x);
dec(x);
return p;
}
static NFnDesc* fLinesDesc;
B flines_c1(B d, B x) {
return path_lines(path_rel(nfn_objU(d), x));
return path_lines(path_rel(nfn_objU(d), x, "•file.Lines"));
}
B flines_c2(B d, B w, B x) {
if (isAtm(x) || RNK(x)!=1) thrM("•file.Lines: 𝕩 must be a list");
@ -773,7 +766,7 @@ B flines_c2(B d, B w, B x) {
s = vec_addN(s, m_c32('\n'));
}
dec(x);
B p = path_rel(nfn_objU(d), w);
B p = path_rel(nfn_objU(d), w, "•file.Lines");
path_wChars(incG(p), s);
decG(s);
return p;
@ -783,7 +776,7 @@ static NFnDesc* importDesc;
B import_c2(B d, B w, B x) {
return bqn_execFile(path_rel(nfn_objU(d), x), w);
return bqn_execFile(path_rel(nfn_objU(d), x, "•Import"), w);
}
// defined in fns.c
@ -798,7 +791,7 @@ B import_c1(B d, B x) {
importKeyList = emptyHVec();
importValList = emptyHVec();
}
B path = path_abs(path_rel(nfn_objU(d), x));
B path = path_abs(path_rel(nfn_objU(d), x, "•Import"));
i32 prevIdx = getPrevImport(path);
if (prevIdx>=0) {
@ -847,56 +840,56 @@ static NFnDesc* renameDesc;
static NFnDesc* removeDesc;
B list_c1(B d, B x) {
return path_list(path_rel(nfn_objU(d), x));
return path_list(path_rel(nfn_objU(d), x, "•file.List"));
}
B createdir_c1(B d, B x) {
B p = path_rel(nfn_objU(d), x);
B p = path_rel(nfn_objU(d), x, "•file.CreateDir");
if (dir_create(p)) return p;
thrM("(file).CreateDir: Failed to create directory");
thrM("•file.CreateDir: Failed to create directory");
}
B realpath_c1(B d, B x) {
return path_abs(path_rel(nfn_objU(d), x));
return path_abs(path_rel(nfn_objU(d), x, "•file.RealPath"));
}
B rename_c2(B d, B w, B x) {
d = nfn_objU(d);
B p = path_rel(d, w);
if (path_rename(path_rel(d, x), p)) return p;
thrM("(file).Rename: Failed to rename file");
B p = path_rel(d, w, "•file.Rename");
if (path_rename(path_rel(d, x, "•file.Rename"), p)) return p;
thrM("•file.Rename: Failed to rename file");
}
B remove_c1(B d, B x) {
if (path_remove(path_rel(nfn_objU(d), x))) return m_i32(1);
thrM("(file).Remove: Failed to remove file");
if (path_remove(path_rel(nfn_objU(d), x, "•file.Remove"))) return m_i32(1);
thrM("•file.Remove: Failed to remove file");
}
B ftype_c1(B d, B x) {
char ty = path_type(path_rel(nfn_objU(d), x));
char ty = path_type(path_rel(nfn_objU(d), x, "•file.Type"));
if (ty==0) thrM("•file.Type: Error while accessing file");
return m_c32(ty);
}
B fcreated_c1 (B d, B x) { return path_info(path_rel(nfn_objU(d), x), 0); }
B faccessed_c1(B d, B x) { return path_info(path_rel(nfn_objU(d), x), 1); }
B fmodified_c1(B d, B x) { return path_info(path_rel(nfn_objU(d), x), 2); }
B fsize_c1 (B d, B x) { return path_info(path_rel(nfn_objU(d), x), 3); }
B fcreated_c1 (B d, B x) { return path_info(path_rel(nfn_objU(d), x, "•file.Created"), 0); }
B faccessed_c1(B d, B x) { return path_info(path_rel(nfn_objU(d), x, "•file.Accessed"), 1); }
B fmodified_c1(B d, B x) { return path_info(path_rel(nfn_objU(d), x, "•file.Modified"), 2); }
B fsize_c1 (B d, B x) { return path_info(path_rel(nfn_objU(d), x, "•file.Size"), 3); }
B fexists_c1(B d, B x) {
char ty = path_type(path_rel(nfn_objU(d), x));
char ty = path_type(path_rel(nfn_objU(d), x, "•file.Exists"));
return m_f64(ty!=0);
}
B fName_c1(B t, B x) {
if (isAtm(x) || RNK(x)!=1) thrM("•file.Name: Argument must be a string");
if (!isStr(x)) thrM("•file.Name: Argument must be a string");
return path_name(x);
}
B fParent_c1(B t, B x) {
if (isAtm(x) || RNK(x)!=1) thrM("•file.Parent: Argument must be a string");
if (!isStr(x)) thrM("•file.Parent: Argument must be a string");
return path_parent(x);
}
B mapBytes_c1(B d, B x) {
return mmap_file(path_rel(nfn_objU(d), x));
return mmap_file(path_rel(nfn_objU(d), x, "•file.MapBytes"));
}
B unixTime_c1(B t, B x) {

View File

@ -228,6 +228,7 @@ char* pm1_repr(u8 u);
char* pm2_repr(u8 u);
char* eltype_repr(u8 u);
bool isPureFn(B x); // doesn't consume
bool isStr(B x); // doesn't consume; returns if x is a rank 1 array of characters (includes any empty array)
B bqn_merge(B x, u32 type); // consumes
B any_squeeze(B x); // consumes; accepts any array, returns one with the smallest type (doesn't recurse!)

View File

@ -1011,7 +1011,7 @@ B ffiload_c2(B t, B w, B x) {
char* ws = NULL;
if (w.u != m_c32(0).u) {
w = path_rel(nfn_objU(t), w);
w = path_rel(nfn_objU(t), w, "•FFI");
ws = toCStr(w);
}
void* dl = dlopen(ws, RTLD_NOW);

View File

@ -235,7 +235,6 @@ B bqn_exec(B str, B path, B args) { // consumes all
return evalFunBlockConsume(bqn_comp(str, path, args));
}
bool isStr(B x);
B str_all, str_none;
void init_comp(B* new_re, B* prev_re, B prim, B sys) {
if (q_N(prim)) {

View File

@ -491,7 +491,7 @@ static NOINLINE i64 readInt(char** p) {
}
static NOINLINE B path_rel_dec(B base, B rel) {
B res = path_rel(base, rel);
B res = path_rel(base, rel, "main.c");
dec(base);
return res;
}

View File

@ -115,23 +115,14 @@ B path_lines(B path) { // consumes; TODO rewrite this, it's horrible
}
static NOINLINE void guaranteeStr(B x) { // assumes x is an array
if (elChr(TI(x,elType))) return;
usz xia = IA(x);
SGetU(x)
for (usz i = 0; i < xia; i++) if (!isC32(GetU(x, i))) thrM("Path wasn't a list of characters");
}
B path_rel(B base, B rel) { // consumes rel; assumes base is a char vector or bi_N
B path_rel(B base, B rel, char* name) {
assert(isArr(base) || q_N(base));
if (!isArr(rel) || RNK(rel)!=1) thrM("Path wasn't a list of characters");
SGetU(rel)
if (!isStr(rel)) thrF("%U: Path must be a list of characters", name);
usz ria = IA(rel);
if (RNK(rel)!=1) thrM("Path wasn't a list of characters");
guaranteeStr(rel);
if (ria>0 && isAbsolutePath(rel)) return rel;
if (q_N(base)) thrM("Using relative path with no absolute base path known");
if (q_N(base)) thrM("%U: Using relative path with no absolute base path known");
if (ria==0) { dec(rel); return incG(base); }
usz bia = IA(base);
if (bia==0) return rel;
@ -141,17 +132,17 @@ B path_rel(B base, B rel) { // consumes rel; assumes base is a char vector or bi
usz ri = 0;
for (usz i = 0; i < bia-(has?1:0); i++) rp[ri++] = o2cG(GetU(base, i));
rp[ri++] = PREFERRED_SEP;
SGetU(rel)
for (usz i = 0; i < ria; i++) rp[ri++] = o2cG(GetU(rel, i));
dec(rel);
return r;
}
B path_parent(B path) {
assert(isArr(path));
SGetU(path)
assert(isStr(path));
usz pia = IA(path);
if (pia==0) thrM("Empty file path");
guaranteeStr(path);
if (pia==0) thrM("•file.Parent: Path must be non-empty");
SGetU(path)
for (i64 i = (i64)pia-2; i >= 0; i--) {
if (isPathSep(o2cG(GetU(path, i)))) return taga(arr_shVec(TI(path,slice)(path, 0, i+1)));
}
@ -162,10 +153,9 @@ B path_parent(B path) {
}
B path_name(B path) {
assert(isArr(path));
SGetU(path)
usz pia = IA(path);
if (pia==0) thrM("Empty file path");
guaranteeStr(path);
if (pia==0) thrM("•file.Name: Path must be non-empty");
SGetU(path)
for (i64 i = (i64)pia-1; i >= 0; i--) {
if (isPathSep(o2cG(GetU(path, i)))) {
if (i == pia-1) thrF("File path ended with a slash: \"%R\"", path);
@ -176,6 +166,7 @@ B path_name(B path) {
}
B path_abs(B path) {
assert(isStr(path));
#if WASM
return path; // lazy
#else
@ -334,9 +325,7 @@ void mmap_init(void) {
// use default canStore
}
#else
B mmap_file(B path) {
thrM("CBQN was compiled without •file.MapBytes support");
}
B mmap_file(B path) { thrM("CBQN was compiled without •file.MapBytes support"); }
void mmap_init() { }
#endif

View File

@ -1,7 +1,8 @@
#pragma once
#include "utf.h"
// unless otherwise specified, these assume that paths are strings
B path_rel(B base, B rel); // consumes rel; assumes base is a char vector or bi_N
B path_rel(B base, B rel, char* name); // consumes rel; assumes base is a string or bi_N, throws if !isStr(rel)
B path_parent(B path); // consumes; returns the containing directory, with trailing slash
B path_name(B path); // consumes; returns filename from a path
B path_abs(B path); // consumes; returns absolute version of the path; propagates bi_N

View File

@ -1667,18 +1667,16 @@ void unwindCompiler() {
#endif
}
NOINLINE bool isStr(B x) {
if (isAtm(x) || RNK(x)!=1) return false;
if (elChr(TI(x,elType))) return true;
usz ia = IA(x); SGetU(x)
for (usz i = 0; i < ia; i++) if (!isC32(GetU(x,i))) return false;
return true;
}
NOINLINE void printErrMsg(B msg) {
if (isArr(msg)) {
if (!elChr(TI(msg,elType))) {
SGetU(msg)
usz msgLen = IA(msg);
for (usz i = 0; i < msgLen; i++) if (!isC32(GetU(msg,i))) goto base;
}
fprintsB(stderr, msg);
return;
}
base:
fprintI(stderr, msg);
if (isStr(msg)) fprintsB(stderr, msg);
else fprintI(stderr, msg);
}

View File

@ -5,6 +5,7 @@
# bad •FFI invocation
# generally weird
!"•FFI: Path must be a list of characters" % 12 •FFI """bqn_init"
"file that doesn't exist" •FFI'e' """abort" %% 'e'
@ •FFI'e' """bqn_this symbol doesn't exist" %% 'e'
!"FFI: Type must be a string" % @•FFI "hello"

View File

@ -86,6 +86,8 @@ f←•ReBQN{primitives⇐⋈'÷'‿- ⋄ system⇐⟨"primitives", "foo"‿⋈,
•file.Exists "/dev/file that doesn't exist" %% 0
!"Couldn't read file ""/dev/file that doesn't exist""" % •FChars "/dev/file that doesn't exist"
! (•path"/") •file.Parent •file.At "hi"
!"•file.Parent: Path must be non-empty" % •file.Parent ""
!"•file.Name: Path must be non-empty" % •file.Name ""
!"•file.Lines: 𝕩 must be a list" % "testfile.bqn" •FLines 22<"abcd"
!"•file.Lines: 𝕩 must be a list" % "testfile.bqn" •file.Lines <"abcd"
@ -96,8 +98,6 @@ f←•ReBQN{primitives⇐⋈'÷'‿- ⋄ system⇐⟨"primitives", "foo"‿⋈,
!"•file.Chars: 𝕩 must be a list of characters" % "testfile.bqn" •FChars <'a'
!"Expected character" % "testfile.bqn" •FBytes "abcd"
!"•file.Bytes: 𝕩 must be a list" % "testfile.bqn" •file.Bytes <'a'
!"Path wasn't a list of characters" % 'a' •FChars "hi"
!"Path wasn't a list of characters" % (42"testfile.bqn") •file.Chars "hi"
!"Expected character" % "badwrite"•FChars """"
!"Expected character" % "badwrite"•FLines "foo"
!"•file.Chars: 𝕩 must be a list of characters" % "badwrite"•FChars @
@ -116,11 +116,11 @@ f←•ReBQN{primitives⇐⋈'÷'‿- ⋄ system⇐⟨"primitives", "foo"‿⋈,
•FLines "testfile.bqn" %% "abc""def𝕩"
"testfile3B.bqn" •file.Rename "testfile3.bqn"
!"(file).Rename: Failed to rename file" % "testfile3B.bqn" •file.Rename "testfile.bqn"
!"•file.Rename: Failed to rename file" % "testfile3B.bqn" •file.Rename "testfile.bqn"
•file.Exists¨ "testfile.bqn""nontestfile.bqn""testfile3.bqn""testfile3B.bqn" %% 1001
¯22•file.Createdir "testdirNested" %% "/testDir/testdirNested"
¯8•file.RealPath "testdirNested/.././" %% "/testDir"
!"(file).CreateDir: Failed to create directory" % •file.Createdir "testdirNested"
!"•file.CreateDir: Failed to create directory" % •file.Createdir "testdirNested"
"testfile.bqn""testfile2.bqn""testfile3.bqn""testfile3B.bqn""testdirNested" •file.List "." %% 11011
"testfile.bqn""testfile2.bqn""testfile3.bqn""testfile3B.bqn""testdirNested" •file.List •file.path %% 11011
@ -132,6 +132,36 @@ f←•ReBQN{primitives⇐⋈'÷'‿- ⋄ system⇐⟨"primitives", "foo"‿⋈,
!"Failed to resolve ""/dev/file that doesn't exist"": No such file or directory" % •file.RealPath "/dev/file that doesn't exist"
!"Failed to resolve ""/dev/file that doesn't exist"": No such file or directory" % •Import "/dev/file that doesn't exist"
# bad paths
!"•file.At: Path must be a list of characters" % •file.At 12
!"•file.At: Path must be a list of characters" % •file.At 12
!"•file.At: Path must be a list of characters" % "foo" •file.At 12
!"•file.At: 𝕨 must be a string" % 12 •file.At "foo"
!"•file.List: Path must be a list of characters" % •file.List 12
!"•file.Bytes: Path must be a list of characters" % •file.Bytes 12
!"•file.Chars: Path must be a list of characters" % •file.Chars 12
!"•file.Lines: Path must be a list of characters" % •file.Lines 12
!"•file.Bytes: Path must be a list of characters" % 12 •FBytes "abc"
!"•file.Chars: Path must be a list of characters" % 12 •FChars "abc"
!"•file.Lines: Path must be a list of characters" % 12 •FLines "abc""def"
!"•file.Type: Path must be a list of characters" % •file.Type 12
!"•file.Exists: Path must be a list of characters" % •file.Exists 12
!"•file.Name: Argument must be a string" % •file.Name 12
!"•file.Parent: Argument must be a string" % •file.Parent 12
!"•file.MapBytes: Path must be a list of characters" % •file.MapBytes 12
!"•file.CreateDir: Path must be a list of characters" % •file.CreateDir 12
!"•file.RealPath: Path must be a list of characters" % •file.RealPath 12
!"•file.Rename: Path must be a list of characters" % "foo" •file.Rename 12
!"•file.Rename: Path must be a list of characters" % 12 •file.Rename "foo"
!"•file.Remove: Path must be a list of characters" % •file.Remove 12
!"•file.Created: Path must be a list of characters" % •file.Created 12
!"•file.Modified: Path must be a list of characters" % •file.Modified 12
!"•file.Accessed: Path must be a list of characters" % •file.Accessed 12
!"•file.Size: Path must be a list of characters" % •file.Size 12
!"•file.Size: Path must be a list of characters" % •file.Size 22"abcd"
# some of •term
!"Expected character" % •term.OutRaw 2{}
!"•term.ErrRaw: 𝕩 must be a list" % •term.ErrRaw 220