Skip to content

Commit

Permalink
Split REJOIN into JOIN-ALL and UNSPACED cases
Browse files Browse the repository at this point in the history
REJOIN in R3-Alpha was a construct which took a BLOCK! and was supposed
to "reduce and join" its values.  Its return type was cued by the
first series type that the reduced block contents contained, e.g.:

    `rejoin ["abc" "def"]` => STRING!
    `rejoin [#{} "abc" "def"]` => BINARY!
    `rejoin [() () http://hostilefork ".com"] => URL!

REJOIN was used in many applications where the expected result would
be a STRING!.  AJOIN was a more efficient function to call for the same
purpose, because it was a native and always assumed a STRING! result.
Yet the generality of REJOIN led people to be more familiar with it,
and additionally `REJOIN []` had a base case result of `[]`.

This commit substitutes calls to SPACED and UNSPACED as appropriate
for those REJOIN calls which have string intent.  It also introduces
JOIN-ALL as a nicer-named version which has a base case of returning
nothing (e.g. `join-all [() () ()]` is void), and which requires the
first reduced element to be a SERIES! to work.  (This is a requirement
of JOIN which is now like REPEND, and JOIN-OF which is like R3-Alpha's
JOIN.)

Includes some formatting of the extension bootstrap script in order to
make it more readable and fit in 80 columns.
  • Loading branch information
hostilefork committed Feb 9, 2017
1 parent 5fda0a7 commit 8494e7a
Show file tree
Hide file tree
Showing 35 changed files with 391 additions and 221 deletions.
4 changes: 3 additions & 1 deletion src/core/f-modify.c
Expand Up @@ -162,7 +162,9 @@ REBCNT Modify_String(
else
limit = -1;

if (limit == 0 || dups < 0) return (action == SYM_APPEND) ? 0 : dst_idx;
if (IS_VOID(src_val) || limit == 0 || dups < 0)
return (action == SYM_APPEND) ? 0 : dst_idx;

if (action == SYM_APPEND || dst_idx > tail) dst_idx = tail;

// If the src_val is not a string, then we need to create a string:
Expand Down
13 changes: 2 additions & 11 deletions src/mezz/base-series.r
Expand Up @@ -136,7 +136,7 @@ repend: redescribe [
; convenient, and not be beholden to the behavior that the name REPEND would
; seem to suggest.
;
join: func [ ;-- renamed to ADJOIN in %sys-start.r for user context, tempoary
join: func [ ;-- renamed to ADJOIN in %sys-start.r for user context, temporary
"Concatenates values to the end of a series."
series [any-series! port! map! gob! object! module! bitset!]
value [<opt> any-value!]
Expand All @@ -149,7 +149,7 @@ join: func [ ;-- renamed to ADJOIN in %sys-start.r for user context, tempoary
function? :value [
fail/where "Can't JOIN a FUNCTION! onto a series (use APPEND)."
]
'else [append/only series value] ;-- paths, words, not in block
'else [append/only series :value] ;-- paths, words, not in block
]
]

Expand All @@ -168,12 +168,3 @@ append-of: redescribe [
series: copy series
]
)

reform: redescribe [
"Forms a reduced block and returns a string."
;/with "separator"
](
adapt 'form [
value: reduce :value
]
)
4 changes: 2 additions & 2 deletions src/mezz/mezz-func.r
Expand Up @@ -128,9 +128,9 @@ body-of: function [

compose [
comment (
rejoin [
spaced [
{Specialization of}
space first spec-with-word space
first spec-with-word
{(this body is fake)}
]
)
Expand Down
18 changes: 9 additions & 9 deletions src/mezz/mezz-help.r
Expand Up @@ -31,16 +31,16 @@ dump-obj: function [

form-val: func [val [any-value!]] [
; Form a limited string from the value provided.
if any-block? :val [return reform ["length:" length val]]
if image? :val [return reform ["size:" val/size]]
if any-block? :val [return spaced ["length:" length val]]
if image? :val [return spaced ["size:" val/size]]
if datatype? :val [return get in spec-of val 'title]
if function? :val [
return clip-str any [title-of :val mold spec-of :val]
]
if object? :val [val: words-of val]
if typeset? :val [val: to-block val]
if port? :val [val: reduce [val/spec/title val/spec/ref]]
if gob? :val [return reform ["offset:" val/offset "size:" val/size]]
if gob? :val [return spaced ["offset:" val/offset "size:" val/size]]
clip-str mold :val
]

Expand All @@ -58,8 +58,8 @@ dump-obj: function [
for-each [word val] obj [
type: type-of :val

str: either any [function? :type object? :type] [
reform [word mold spec-of :val words-of :val]
str: either maybe [function! object!] :type [
spaced [word _ mold spec-of :val _ words-of :val]
][
form word
]
Expand All @@ -85,7 +85,7 @@ dump-obj: function [
str: form-pad word 15
append str #" "
append str form-pad type 10 - ((length str) - 15)
keep reform [
keep spaced [
" " str
if type [form-val :val]
newline
Expand Down Expand Up @@ -370,7 +370,7 @@ help: procedure [
; If it has refinements, strip them:
;if path? :word [word: first :word]

space4: rejoin [space space space space] ;-- use instead of tab
space4: unspaced [space space space space] ;-- use instead of tab

;-- Print info about function:
print "USAGE:"
Expand Down Expand Up @@ -538,7 +538,7 @@ source: make function! [[
]

integer? :arg [
name: rejoin ["backtrace-" arg]
name: unspaced ["backtrace-" arg]

; We add two here because we assume the caller meant to be
; using as point of reference what BACKTRACE would have told
Expand Down Expand Up @@ -583,7 +583,7 @@ source: make function! [[
]

either function? :f [
print rejoin [mold name ":" space mold :f]
print unspaced [mold name ":" space mold :f]
][
either integer? arg [
print ["Stack level" arg "does not exist in backtrace"]
Expand Down
25 changes: 24 additions & 1 deletion src/mezz/mezz-legacy.r
Expand Up @@ -260,9 +260,32 @@ dp: :delta-profile


; AJOIN is a kind of ugly name for making an unspaced string from a block.
; Ren-C has UNSPACED and SPACED.
; REFORM is nonsensical looking. Ren-C has UNSPACED and SPACED.
;
ajoin: :unspaced
reform: :spaced



; REJOIN in R3-Alpha meant "reduce and join"; the idea of cumulative joining
; in Ren-C already implies reduction of the appended data. JOIN-ALL is a
; friendlier name, suggesting joining with the atomic root type of the first
; reduced element.
;
; JOIN-ALL is not exactly the same as REJOIN; and it is not used as often
; because UNSPACED can be used for strings, with AS allowing aliasing of the
; data as other string types (`as tag! unspaced [...]` will not create a copy
; of the series data the way TO TAG! would). While REJOIN is tolerant of
; cases like `rejoin [() () ()]` producing an empty block, this makes a
; void in JOIN-ALL...but that is a common possibility.
;
rejoin: chain [
:join-all
|
func [v [<opt> any-series!]] [
either set? 'v [:v] [copy []]
]
]


; SET has a refinement called /ANY which doesn't communicate as well in the
Expand Down
4 changes: 3 additions & 1 deletion src/mezz/mezz-math.r
Expand Up @@ -273,7 +273,9 @@ math: function [
1 = length ret
any-number? ret/1
][
fail rejoin ["Cannot be REDUCED to a number(" mold ret ") :" mold res]
fail unspaced [
"Cannot be REDUCED to a number(" mold ret ") :" mold res
]
]
ret/1
]
Expand Down
28 changes: 16 additions & 12 deletions src/mezz/mezz-series.r
Expand Up @@ -43,21 +43,25 @@ extend: func [
:val
]

rejoin: function [
"Reduces and joins a block of values."
block [block!] "Values to reduce and join"
;/with "separator"
join-all: function [
"Reduces and appends a block of values together."
return: [<opt> any-series!]
"Will be the type of the first non-void series produced by evaluation"
block [block!]
"Values to join together"
<local> position
][
either void? base: do/next block 'position [
blank
][
either any-series? :base [
join-of base position
][
join form base position
]
forever [
if tail? block [return ()]
unless void? base: do/next block 'block [break]
]

; !!! It isn't especially compelling that `join-of 3 "hello"` gives you
; `3hello`; defaulting to a string doesn't make obviously more sense than
; `[3 "hello"]` when using a series operation. However, so long as
; JOIN-OF is willing to do so, it will be legal to do it here.
;
join-of base block
]

remold: func [
Expand Down
16 changes: 9 additions & 7 deletions src/mezz/prot-http.r
Expand Up @@ -211,13 +211,13 @@ make-http-request: func [
{Empty string not exactly like blank.}
/local result
] [
result: rejoin [
uppercase form method #" "
result: unspaced [
uppercase form method space
either file? target [next mold target] [target]
" HTTP/1.0" CRLF
space "HTTP/1.0" CRLF
]
for-each [word string] headers [
join result [mold word #" " string CRLF]
join result [mold word space string CRLF]
]
if content [
content: to binary! content
Expand All @@ -239,7 +239,7 @@ do-request: func [
Accept: "*/*"
Accept-Charset: "utf-8"
Host: either not find [80 443] spec/port-id [
rejoin [form spec/host #":" spec/port-id]
unspaced [form spec/host ":" spec/port-id]
] [
form spec/host
]
Expand Down Expand Up @@ -473,7 +473,9 @@ do-redirect: func [port [port!] new-uri [url! string! file!] /local spec state]
do-request port
false
] [
state/error: make-http-error/otherhost "Redirect to other host - requires custom handling" to-url rejoin [new-uri/scheme "://" new-uri/host new-uri/path]
state/error: make-http-error/otherhost
"Redirect to other host - requires custom handling"
as url! unspaced [new-uri/scheme "://" new-uri/host new-uri/path]
state/awake make event! [type: 'error port: port]
]
]
Expand Down Expand Up @@ -657,7 +659,7 @@ sys/make-scheme [
)
host: port/spec/host
port-id: port/spec/port-id
ref: rejoin [tcp:// host ":" port-id]
ref: join-all [tcp:// host ":" port-id]
]
conn/awake: :http-awake
conn/locals: port
Expand Down
37 changes: 22 additions & 15 deletions src/mezz/prot-tls.r
Expand Up @@ -251,7 +251,7 @@ client-hello: func [
random/seed now/time/precise
loop 28 [append ctx/client-random (random/secure 256) - 1]

cs-data: rejoin values-of cipher-suites
cs-data: join-all values-of cipher-suites

beg: length ctx/msg
emit ctx [
Expand Down Expand Up @@ -410,10 +410,10 @@ finished: func [
ctx [object!]
] [
ctx/seq-num-w: 0
return rejoin [
return join-all [
#{14} ; protocol message type (20=Finished)
#{00 00 0c} ; protocol message length (12 bytes)
prf ctx/master-secret either ctx/server? ["server finished"] ["client finished"] rejoin [
prf ctx/master-secret either ctx/server? ["server finished"] ["client finished"] join-all [
checksum/method ctx/handshake-messages 'md5 checksum/method ctx/handshake-messages 'sha1
] 12
]
Expand All @@ -427,11 +427,11 @@ encrypt-data: func [
/local
mac padding len
] [
data: rejoin [
data: join-all [
data
; MAC code
mac: checksum/method/key rejoin [
to-bin ctx/seq-num-w 8 ; sequence number (64-bit int in R3)
mac: checksum/method/key join-all [
to-bin ctx/seq-num-w 8 ; sequence number (64-bit int)
any [:msg-type #{17}] ; msg type
ctx/version ; version
to-bin length data 2 ; msg content length
Expand Down Expand Up @@ -773,7 +773,14 @@ parse-messages: func [
finished [
ctx/seq-num-r: 0
msg-content: copy/part at data 5 len
either msg-content <> prf ctx/master-secret either ctx/server? ["client finished"] ["server finished"] rejoin [checksum/method ctx/handshake-messages 'md5 checksum/method ctx/handshake-messages 'sha1] 12 [
either (msg-content <>
prf ctx/master-secret either ctx/server? ["client finished"] ["server finished"]
join-all [
checksum/method
ctx/handshake-messages 'md5
checksum/method ctx/handshake-messages 'sha1
] 12
) [
fail "Bad 'finished' MAC"
] [
debug "FINISHED MAC verify: OK"
Expand All @@ -791,7 +798,7 @@ parse-messages: func [
data: skip data len + either ctx/encrypted? [
; check the MAC
mac: copy/part skip data len + 4 ctx/hash-size
if mac <> checksum/method/key rejoin [
if mac <> checksum/method/key join-all [
to-bin ctx/seq-num-r 8 ; sequence number (64-bit int in R3)
#{16} ; msg type
ctx/version ; version
Expand Down Expand Up @@ -821,7 +828,7 @@ parse-messages: func [
len: length msg-obj/content
mac: copy/part skip data len ctx/hash-size
; check the MAC
if mac <> checksum/method/key rejoin [
if mac <> checksum/method/key join-all [
to-bin ctx/seq-num-r 8 ; sequence number (64-bit int in R3)
#{17} ; msg type
ctx/version ; version
Expand Down Expand Up @@ -873,21 +880,21 @@ prf: func [
s-1: copy/part secret mid
s-2: copy at secret mid + either odd? len [0] [1]

seed: rejoin [#{} label seed]
seed: join-all [#{} label seed]

p-md5: copy #{}
a: seed ; A(0)
while [output-length > length p-md5] [
a: checksum/method/key a 'md5 decode 'text s-1 ; A(n)
append p-md5 checksum/method/key rejoin [a seed] 'md5 decode 'text s-1
append p-md5 checksum/method/key join-all [a seed] 'md5 decode 'text s-1

]

p-sha1: copy #{}
a: seed ; A(0)
while [output-length > length p-sha1] [
a: checksum/method/key a 'sha1 decode 'text s-2 ; A(n)
append p-sha1 checksum/method/key rejoin [a seed] 'sha1 decode 'text s-2
append p-sha1 checksum/method/key join-all [a seed] 'sha1 decode 'text s-2
]
return ((copy/part p-md5 output-length) xor+ copy/part p-sha1 output-length)
]
Expand All @@ -898,7 +905,7 @@ make-key-block: func [
ctx/key-block: prf
ctx/master-secret
"key expansion"
rejoin [ctx/server-random ctx/client-random]
join-all [ctx/server-random ctx/client-random]
(
(ctx/hash-size + ctx/crypt-size)
+ (either ctx/block-size [ctx/iv-size] [0])
Expand All @@ -912,7 +919,7 @@ make-master-secret: func [
ctx/master-secret: prf
pre-master-secret
"master secret"
rejoin [ctx/client-random ctx/server-random]
join-all [ctx/client-random ctx/server-random]
48
]

Expand Down Expand Up @@ -1198,7 +1205,7 @@ sys/make-scheme [
scheme: 'tcp
host: port/spec/host
port-id: port/spec/port-id
ref: rejoin [tcp:// host ":" port-id]
ref: join-all [tcp:// host ":" port-id]
]

port/data: port/state/port-data
Expand Down
2 changes: 1 addition & 1 deletion src/os/generic/iso3166.r
Expand Up @@ -66,7 +66,7 @@ parse cnt [
some [
copy name to ";"
";" copy code-2 to "^/"
(emit rejoin [{^{"} code-2 {", "} binary-to-chex capitalize name {"^},^/}])
(emit join-all [{^{"} code-2 {", "} binary-to-chex capitalize name {"^},^/}])
"^/"
]
]
Expand Down

0 comments on commit 8494e7a

Please sign in to comment.