nargs
[1/8] from: maarten::vrijheid::net at: 17-Oct-2003 11:53
Here is a nargs function that also counts the optional arguments if you
use refinements (e.g. nargs copy == 1 nargs copy/part == 2).
Enjoy it.
-----------------------------------
nargs: func
[
{Returns the total number of args of a function (with and without
refinements)}
f [word! lit-path!]
/local argc f-blk f-ref f-sig ref-pos next-ref-pos
]
[
;The total number or arguments
argc: 0
;We either have a path or a function
;If we have a path, we count the number
;of arguments of the supplied refinements first.
either path? f
[
;Translate the path to a block
f-blk: to-block f
;Is it a function?
if not any-function? get/any first f-blk
[throw make error! "Rugby error: invocation not on a function"]
bind f-blk 'do
;The refinements used
f-ref: next head f-blk
;the function signature
f-sig: first get first f-blk
;Now get the number of arguments foreach refinement
;and add them to argc
repeat ref f-ref
[
;Find the ref refinement
ref-pos: find/tail f-sig to-refinement ref
;If succeed in the find
if not none? ref-pos
[
;try to find the next one
next-ref-pos: find ref-pos refinement!
if not none? next-ref-pos
[
argc: argc + ((index? next-ref-pos) - (index? ref-pos))
];if not none next-ref-pos
];if not none? ref-pos
];foreach ref f-ref
];either path? f first clause
[
if not any-function? get/any f
[ throw make error! "Rugby error: invocation not on a function" ]
f-sig: first get f
];either path? f second clause
;Add the number of function arguments
argc: argc + -1 + index? any [ find f-sig refinement! tail f-sig ]
];nargs
[2/8] from: AJMartin:orcon at: 24-Dec-2003 22:41
Maarten wrote:
> Here is a nargs function that also counts the optional arguments if you
use refinements (e.g. nargs copy == 1 nargs copy/part == 2).
> [Snip large chunk of code.]
Ouch! That's a large amount of code.
Isn't this easier?
>> length? Arguments :copy
== 1
>> source Arguments
Arguments: func [
{Returns the arguments of the function as a block of word! values.}
F [any-function!] "The Function"
][
head clear any [
find first :F refinement!
tail first :F
]
]
And if one needs the length of a path:
>> length? 'copy/part
== 2
Or perhaps I've misunderstood something?
Andrew J Martin
Grail Jedi
ICQ: 26227169
http://www.rebol.it/Valley/
http://valley.orcon.net.nz/
http://Valley.150m.com/
[3/8] from: cyphre:seznam:cz at: 17-Oct-2003 13:02
Hi Maarten,
Not sure if this is better/complete solution version but I just hacked for
fun simmilar function with the same functionality and it also proper counts
the /local words ;-)
example:
>> nargs 'copy
== 1
>> nargs 'copy/deep
== 0
>> nargs 'copy/part
== 1
>> nargs 'copy/local
== 0
>>
--------------------start of code--------------------------
nargs: func [f [word! path!] /local loc? ref? args refs fn rf][
fn: either word? f [
get f
][
rf: to-refinement first next to-block f
get first f
]
args: copy []
refs: copy []
parse third :fn [
any [
set w word! (
either ref? [
insert tail last refs w
][
insert tail args w
]
)
| m: refinement! (
ref?: true
insert tail refs reduce [m/1 copy []]
)
| skip
]
to end
]
return either rf [
length? any reduce [select refs rf []]
][
length? args
]
]
-------------------end of code--------------------------------
enjoy it,
Cyphre
[4/8] from: maarten:vrijheid at: 17-Oct-2003 13:18
Nargs returns the actual number of arguments depending upon your
invocation:
e.g. nargs 'open/lines
or nargs 'open/lines/binary
etc. with "object" detection. As you can see it is a Rugby excerpt.
--Maarten
[5/8] from: maarten:vrijheid at: 17-Oct-2003 14:41
> >> nargs 'copy/deep
> == 0
??
--Maarten
[6/8] from: cyphre:seznam:cz at: 17-Oct-2003 16:04
Ups, posting in hurry brings always bugs ;) Here is the fixed version:
example:
>> nargs 'open
== 1
>> nargs 'open/binary
== 1
>> nargs 'open/binary/mode
== 2
>> nargs 'open/binary/mode/with
== 3
>>
etc.
------------------start of code--------------------
nargs: func [f [word! path!] /local rslt loc? ref? args refs fn rf][
fn: either word? f [
get f
][
rf: copy next to-block f
get first f
]
args: copy []
refs: copy []
parse third :fn [
any [
set w word! (
either ref? [
insert tail last refs w
][
insert tail args w
]
)
| m: refinement! (
ref?: true
insert tail refs reduce [m/1 copy []]
)
| skip
]
to end
]
return either rf [
rslt: 0
(length? args) + foreach a rf [
rslt: rslt + length? any reduce [select refs to-refinement a []]
]
][
length? args
]
]
------------------------------end of code----------------------------------
[7/8] from: maarten:vrijheid at: 17-Oct-2003 16:25
But what if I pass in an object with a function?
--Maarten
[8/8] from: cyphre:seznam:cz at: 19-Oct-2003 22:37
ok here you are a newer version which also takes objects with functions ;)
--------------------------------------------start of
code---------------------------------
nargs: func [f [word! path!] /local rslt ref? args refs fn rf obj][
rf: copy []
fn: either word? f [
get f
][
rf: get first f
either any [block? :rf object? :rf][
rf: copy to-block f
repeat n length? rf [
if error? try [do reduce [to-path copy/part rf n]][
obj: do reduce [to-path copy/part rf n - 1]
rf: at rf n + 1
break/return get in obj first back rf
]
]
][
rf: copy next to-block f
get first f
]
]
args: copy []
refs: copy []
parse third :fn [
any [
set w word! (
either ref? [
insert tail last refs w
][
insert tail args w
]
)
| m: refinement! (
ref?: true
insert tail refs reduce [m/1 copy []]
)
| skip
]
to end
]
return either empty? rf [
length? args
][
rslt: 0
(length? args) + foreach a rf [
rslt: rslt + length? any reduce [select refs to-refinement a []]
]
]
]
----------------------------------------end of
code--------------------------------------
cheers,
Cyphre