Skip to content

Commit

Permalink
Remove FILE! from the ANY-STRING! Category
Browse files Browse the repository at this point in the history
This makes the rather big change of removing FILE! from the ANY-STRING!
category.  This is in order to allow FILE! to act as a placeholder for
the PORT! that would be opened from that file, e.g.

    >> append %foo.txt "abc"

That would act as a write to the file, instead of giving you a
string operation like %foo.txtabc.

The JOIN operation remains operable for putting together parts of
filenames.

There are several rough edges to this change, but it's at the point of
being certain enough that pushing it through will provide more
information on the correct design vs. trying to design it perfectly
up front.
  • Loading branch information
hostilefork committed Sep 2, 2021
1 parent 5ccfce6 commit 249784c
Show file tree
Hide file tree
Showing 19 changed files with 122 additions and 84 deletions.
2 changes: 1 addition & 1 deletion extensions/filesystem/mod-filesystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ REBNATIVE(what_dir)
fail (current_path);
}

return rebValue(Lib(COPY), Lib(TRY), current_path); // caller mutates, copy
RETURN (current_path);
}


Expand Down
5 changes: 3 additions & 2 deletions scripts/make-file.r
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ make-file-path-parts: func [
]
text!
file! [ ; GROUP!-only (couldn't be literally in PATH!)
item: as text! item
all [
not last? path
#"/" <> last item
Expand Down Expand Up @@ -249,7 +250,7 @@ make-file: func [
; paths, and no support for generic tuples. It only offers the BLOCK!
; dialect form.

result: as file! try unspaced do [
result: unspaced do [
def: switch type of def [ ; consolidate to BLOCK!-oriented file spec
word! [to text! predicate def]
path! [make-file-path-parts def :predicate]
Expand Down Expand Up @@ -283,5 +284,5 @@ make-file: func [
remove skip result 2 ; remove ":"
]

return result
return as file! result
]
2 changes: 1 addition & 1 deletion scripts/shell.r
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ shell: func [
let needs-quotes?: func [return: [logic!] item] [
if match [word! issue!] item [return false] ; never quoted
if file? item [
return did find item space ; !!! should check other escapes
return did find as text! item space ; !!! check other escapes!
]
if splice = false [return true]
if splice = true [return false] ; e.g. even TEXT! has no quotes
Expand Down
4 changes: 2 additions & 2 deletions scripts/unzip.reb
Original file line number Diff line number Diff line change
Expand Up @@ -561,12 +561,12 @@ unzip: function [
either any-array? where [
where: insert where name
where: insert where all [
#"/" = last name
dir? name
empty? uncompressed-data
] then [blank] else [uncompressed-data]
][
; make directory and/or write file
either #"/" = last name [
either dir? name [
if not exists? %% (where)/(name) [
make-dir/deep %%(where)/(name)
]
Expand Down
2 changes: 1 addition & 1 deletion src/boot/generics.r
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ append: generic [

return: [any-series! port! map! object! module! bitset!]
series "Any position (modified)"
[any-series! port! map! object! module! bitset!]
[any-series! port! map! object! module! bitset! file! url!]
value "What to append (BLANK!s opt out)"
[any-value!]
/part "Limits to a given length or position"
Expand Down
13 changes: 7 additions & 6 deletions src/boot/types.r
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,16 @@ event "user interface event" ; %extensions/event/README.md
? ? ? ? []


; URL! has a HEART-BYTE! that is a string, but is not itself in the ANY-STRING!
; category.
; URL! and FILE! have a HEART-BYTE! that is REB_TEXT, but they are not
; themselves in the ANY-SERIES! category. It may be that they are ANY-STRING!
; unless that is decided to imply ANY-SERIES. (Should you believe that you
; can APPEND to an ANY-STRING! or merely form it?)
;
url "uniform resource locator or identifier"
url string string string []
file-or-url string string string []

file "file name or path"
file-or-url string string string []


; <BINARY>
Expand All @@ -169,9 +173,6 @@ binary "series of bytes"
text "text string series of characters"
string * * * [series string]

file "file name or path"
string * * * [series string]

email "email address"
string * * * [series string]

Expand Down
1 change: 1 addition & 0 deletions src/core/d-gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ void Assert_Cell_Marked_Correctly(const RELVAL *v)
}
break; }

case REB_FILE:
case REB_URL:
assert(heart == REB_TEXT);
break;
Expand Down
10 changes: 5 additions & 5 deletions src/core/n-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -1196,11 +1196,11 @@ bool Try_As_String(
Freeze_Series(str);
Init_Any_String(out, new_kind, str);
}
else if (ANY_STRING(v) or IS_URL(v)) {
else if (ANY_STRING(v) or IS_URL(v) or IS_FILE(v)) {
any_string:
Copy_Cell(out, v);
mutable_KIND3Q_BYTE(out) = new_kind;
if (new_kind == REB_URL)
if (new_kind == REB_URL or new_kind == REB_FILE)
mutable_HEART_BYTE(out) = REB_TEXT;
else
mutable_HEART_BYTE(out) = new_kind;
Expand All @@ -1220,15 +1220,15 @@ bool Try_As_String(
//
// return: [
// <opt> integer!
// issue! url!
// issue! url! file!
// any-sequence! any-series! any-word!
// frame! action!
// ]
// type [datatype!]
// value [
// <blank>
// integer!
// issue! url!
// issue! url! file!
// any-sequence! any-series! any-word! frame! action!
// ]
// ]
Expand Down Expand Up @@ -1345,7 +1345,7 @@ REBNATIVE(as)
if (IS_INTEGER(v))
return Init_Char_May_Fail(D_OUT, VAL_UINT32(v));

if (ANY_STRING(v)) {
if (ANY_STRING(v) or IS_URL(v) or IS_FILE(v)) {
REBLEN len;
REBSIZ utf8_size = VAL_SIZE_LIMIT_AT(&len, v, UNLIMITED);

Expand Down
9 changes: 8 additions & 1 deletion src/core/n-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,14 @@ REBINT Compare_Modify_Values(RELVAL *a, RELVAL *b, bool strict)
// the same comparison dispatcher. They might not be *exactly* equal.
//
COMPARE_HOOK *hook = Compare_Hook_For_Type_Of(a);
assert(Compare_Hook_For_Type_Of(b) == hook);
assert(
Compare_Hook_For_Type_Of(b) == hook
//
// !!! One of many grievous hacks to move forward on the "FILE! and
// URL! are not ANY-STRING!, pending a more elegant way of doing it.
//
or IS_FILE(b) or IS_URL(b) or IS_FILE(a) or IS_URL(a)
);

REBINT diff = hook(a, b, strict);
assert(diff == 0 or diff == 1 or diff == -1);
Expand Down
31 changes: 24 additions & 7 deletions src/core/t-port.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,9 @@ REBTYPE(Port)


//
// CT_Url: C
// CT_File_or_url: C
//
REBINT CT_Url(REBCEL(const*) a, REBCEL(const*) b, bool strict)
REBINT CT_File_or_url(REBCEL(const*) a, REBCEL(const*) b, bool strict)
{
return CT_String(a, b, strict);
}
Expand All @@ -168,12 +168,29 @@ REBINT CT_Url(REBCEL(const*) a, REBCEL(const*) b, bool strict)
// So it translates the request to open the port, then retriggers the action
// on that port, then closes the port.
//
REBTYPE(Url)
REBTYPE(File_or_url)
{
REBVAL *url = D_ARG(1);
REBVAL *file_or_url = D_ARG(1);

OPT_SYMID id = VAL_WORD_ID(verb);
if (GET_CELL_FLAG(url, UNEVALUATED)) {
if (id == SYM_COPY) {
//
// !!! Originally COPY on a PORT! was the way that an asynchronous
// request could get at the internal buffer for the port after a READ
// event had finished. But to synchronous requests this just seemed
// like a synonym for READ. Having COPY not mean "provide a copy of
// the value of the same type" but come back with a BINARY! is
// a surprising response for any type, and should be reviewed:
//
// https://forum.rebol.info/t/copy-and-port/1699
//
// For now we just have FILE! and URL! return themselves (presuming
// immutability, which is where this is heading).
//
RETURN (file_or_url);
}

if (GET_CELL_FLAG(file_or_url, UNEVALUATED)) {
//
// There are risks associated when common terms like APPEND can too
// carelessly be interpreted as IO. Because what was intended as a
Expand Down Expand Up @@ -204,10 +221,10 @@ REBTYPE(Url)
break;

default:
fail ("URL! must be used with IO annotation if intentional");
fail ("URL! or FILE! must be used with IO annotation if intentional");
}

REBVAL *port = rebValue("make port!", url);
REBVAL *port = rebValue("make port!", file_or_url);
assert(IS_PORT(port));

// The frame was built for the verb we want to apply, so tweak it so that
Expand Down
2 changes: 2 additions & 0 deletions src/core/t-string.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ REBINT CT_String(REBCEL(const*) a, REBCEL(const*) b, bool strict)
ANY_STRING_KIND(CELL_KIND(a))
or REB_ISSUE == CELL_KIND(a)
or REB_URL == CELL_KIND(a)
or REB_FILE == CELL_KIND(a)
);
assert(
ANY_STRING_KIND(CELL_KIND(b))
or REB_ISSUE == CELL_KIND(b)
or REB_URL == CELL_KIND(a)
or REB_FILE == CELL_KIND(a)
);

REBLEN l1;
Expand Down
6 changes: 5 additions & 1 deletion src/include/datatypes/sys-series.h
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ inline static REBVAL *Init_Any_Series_At_Core(
REBARR *specifier
){
#if !defined(NDEBUG)
assert(ANY_SERIES_KIND(type) or type == REB_URL);
assert(ANY_SERIES_KIND(type) or type == REB_URL or type == REB_FILE);
assert(GET_SERIES_FLAG(s, MANAGED));

// Note: a R3-Alpha Make_Binary() comment said:
Expand All @@ -1083,6 +1083,10 @@ inline static REBVAL *Init_Any_Series_At_Core(
#endif

RESET_CELL(out, type, CELL_FLAG_FIRST_IS_NODE);

if (type == REB_URL or type == REB_FILE)
mutable_HEART_BYTE(out) = REB_TEXT; // !!! hack for now

INIT_VAL_NODE1(out, s);
VAL_INDEX_RAW(out) = index;
INIT_SPECIFIER(out, specifier); // asserts if unbindable type tries to bind
Expand Down
2 changes: 0 additions & 2 deletions src/include/datatypes/sys-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,6 @@ inline static REBVAL *Init_Any_String_At(
index,
UNBOUND
);
if (kind == REB_URL)
mutable_HEART_BYTE(out) = REB_TEXT;
return SPECIFIC(out);
}

Expand Down
2 changes: 1 addition & 1 deletion src/include/sys-ordered.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ inline static enum Reb_Kind BLOCKIFY_KIND(REBYTE k) {

inline static bool ANY_UTF8_KIND(REBYTE k) {
return ANY_STRING_KIND(k) or ANY_WORD_KIND(k)
or k == REB_ISSUE or k == REB_URL;
or k == REB_ISSUE or k == REB_URL or k == REB_FILE;
}

#define ANY_UTF8(v) \
Expand Down
4 changes: 2 additions & 2 deletions src/main/main-startup.reb
Original file line number Diff line number Diff line change
Expand Up @@ -688,10 +688,10 @@ main-startup: func [
if file? o.script [ ; Get the path
let script-path: split-path o.script
case [
slash = first first script-path [] ; absolute
slash = first as text! first script-path [] ; absolute
%./ = first script-path [script-path.1: o.path] ; curr dir
] else [
insert first script-path o.path ; relative
script-path: join o.path script-path ; relative
]
]

Expand Down
40 changes: 23 additions & 17 deletions src/mezz/base-files.r
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,18 @@ dir?: func [
return: [logic!]
target [file! url!]
][
return did find "/\" last target
return #"/" = last as text! target ; Note: FILE! should not have \ in it
]

dirize: func [
{Returns a copy (always) of the path as a directory (ending slash).}
path [file! text! url!]
][
path: copy path
if slash <> last path [append path slash]
path
if #"/" = last as text! path [
if text? path [return copy path]
return path ; immutable, so no copy needed
]
return join path #"/"
]

make-dir: func [
Expand All @@ -125,12 +127,12 @@ make-dir: func [
]

; Scan reverse looking for first existing dir:
path: copy path
path: copy as text! path
dirs: copy []
loop [
all [
not empty? path
not exists? path
not exists? as file! path
remove back tail of path ; trailing slash
]
][
Expand All @@ -147,13 +149,13 @@ make-dir: func [
for-each dir dirs [
path: if empty? path [dir] else [join path dir]
append path slash
trap [make-dir path] then (lambda e [
for-each dir created [attempt [delete dir]]
trap [make-dir to file! path] then (lambda e [
for-each dir created [attempt [delete to file! dir]]
fail e
])
insert created path
]
return path
return as file! path
]

delete-dir: func [
Expand Down Expand Up @@ -198,19 +200,23 @@ split-path: func [
"Splits and returns directory path and file as a block."
return: [block!]
target [file! url! text!]
<local> dir pos
<local> dir pos type
][
pos: _
type: type of target
target: as text! target
parse target [
[#"/" | #"." opt #"." opt #"/"] end (dir: dirize target) |
pos: here, while [thru #"/" [end | pos: here]] (
all [
empty? dir: copy/part target (at head of target index of pos),
["/" | [".." | "."] opt "/"] end ; Subtlety: must match ".." before "."
(dir: dirize target)
|
pos: here, while [thru "/" [end | pos: here]] (
if empty? dir: copy/part target (at head of target index of pos) [
dir: %./
]
all [find [%. %..] pos: to file! pos insert tail of pos #"/"]
if find [{.} {..}] pos [
insert tail of pos "/"
]
)
end
]
return reduce [dir pos]
return reduce [as type dir, try as file! pos]
]
6 changes: 3 additions & 3 deletions src/mezz/base-series.r
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ join: function [
{Concatenates values to the end of a copy of a value}

return:
[any-series! issue! url! any-sequence! port!
[any-series! issue! url! file! any-sequence! port!
map! object! module! bitset!]
base [
datatype!
any-series! issue! url!
any-series! issue! url! file!
any-sequence!
port! map! object! module! bitset!
]
Expand All @@ -106,7 +106,7 @@ join: function [
]
]
find any-sequence! type [base: to block! base]
find :[issue! url!] type [base: to text! base]
find :[issue! url! file!] type [base: to text! base]
] else [
base: copy base
type: _ ; don't apply any conversion at end
Expand Down
Loading

0 comments on commit 249784c

Please sign in to comment.