[REBOL] Re: More dialects than you think, validating function input.
From: joel:neely:fedex at: 13-Sep-2002 7:50
Hi, Dick,
You've given me an idea... (Thanks!)
[reffy--ulrich--net] wrote:
> Watching the thread on error handling ...
>
...
> As a developer, I would like to be able to place begin/end markers
> in my code. The purpose of the markers is to signal the language
> execution engine the type/degree of capturing trace information.
> I can imagine several fine/coarse grained levels. The coarseness of
> the tracing could be at the function level, the statement level,
> maybe even other levels.
>
> I like this approach because I probably don't want the execution
> engine burdened with something which might yield an overall
> performance hit. I/you can probably be the best judge of when/what
> we need information about. It would be up to us to cause the
> performance hit of tracing/tracking flow of control.
>
This is a *real* QAD, but the idea was to write something that would
let me "enclose" a block with a marker so that any error occurring
within that block would generate a display of all currently active
markers as well as the error message itself.
Again, this is a quick hack with much room for improvement...
Here's the error zone manager, in %errzone.r:
8<----------
errzone: make object! [
zones: []
init: func [] [zones: copy []]
new: func [/local newself] [
newself: make self []
newself/init
newself
]
nest: func [s [string!] b [block!] /local err] [
insert tail zones s
either error? set/any 'err try b [
print ["^/Error within"]
foreach zone zones [print ["^-" zone]]
print ["was^/" mold disarm err newline]
halt
][
remove back tail zones
]
]
]
8<----------
Here are some error-prone routines that use ERRZONE, either
recursively or in nested function evaluations:
8<----------
do %errzone.r
irecurrence: func [n [integer!] /local rzone _recurrence] [
rzone: errzone/new
do _recurrence: func [
p [integer!] n [integer!]
/local result
][
rzone/nest rejoin ["tracing: " p ", " n] [
result: _recurrence p / n n - 1
]
result
] 1000 n
]
nrecurrence: func [n [integer!] /local rzone _recurrence] [
rzone: errzone/new
do _recurrence: func [
p [number!] n [integer!]
/local result
][
rzone/nest rejoin ["tracing: " p ", " n] [
result: _recurrence p / n n - 1
]
result
] 1000 n
]
gzone: errzone/new
eenie: func [n [integer!]] [
gzone/nest "eenie" [
loop random 5 [print "blah "]
print 1 / n
loop random 5 [print "yak "]
]
]
meenie: func [n [integer!]] [
gzone/nest "meenie" [
loop random 5 [print "blah "]
eenie n
loop random 5 [print "yak "]
]
]
meinie: func [n [integer!]] [
gzone/nest "meinie" [
loop random 5 [print "blah "]
meenie n
loop random 5 [print "yak "]
]
]
moe: func [n [integer!]] [
gzone/nest "moe" [
loop random 5 [print "blah "]
meinie n
loop random 5 [print "yak "]
]
]
8<----------
Here are some annotated results of using the above "clients":
8<----------
>> irecurrence 5
Error within
tracing: 1000, 5
tracing: 200, 4
tracing: 50, 3
was
make object! [
code: 303
type: 'script
id: 'expect-arg
arg1: '_recurrence
arg2: 'p
arg3: [integer!]
near: [result: _recurrence p / n]
where: 'nest
]
8<----------
I included this one because it surprised me at first. (I didn't
read the error object carefully enough!) The value of 50 / 3 is
not integral, so the attempt to invoke _RECURRENCE failed because
of an argument type error.
8<----------
>> nrecurrence 5
Error within
tracing: 1000, 5
tracing: 200, 4
tracing: 50, 3
tracing: 16.6666666666667, 2
tracing: 8.33333333333333, 1
tracing: 8.33333333333333, 0
was
make object! [
code: 400
type: 'math
id: 'zero-divide
arg1: none
arg2: none
arg3: none
near: [result: _recurrence p / n]
where: 'nest
]
8<----------
Our classic poster-child error...
8<----------
>> moe 1
blah
blah
blah
blah
blah
blah
blah
blah
blah
blah
blah
blah
1
yak
yak
yak
yak
yak
yak
yak
yak
yak
yak
yak
yak
yak
yak
= []
>> moe 0
blah
blah
blah
blah
blah
blah
blah
blah
blah
blah
blah
blah
blah
Error within
moe
meinie
meenie
eenie
was
make object! [
code: 400
type: 'math
id: 'zero-divide
arg1: none
arg2: none
arg3: none
near: [print 1 / n
loop]
where: 'nest
]
8<----------
The first call to MOE succeeded (producing lots of simulated
work and output), but the second failed four levels of function
evaluation down.
As I said above, this is a bit kludged up, but serves as a proof
of concept. For example, we could define a new function-defining
word something like this
safe-foo: zonefunc zoneobj "FOO Zone" [...args...] [...body...]
in contrast with
foo: func [...args...] [...body...]
to wrap the body of the newly-defined function with an appropriate
use of the ERRZONE concept.
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]