View in color | License | Download script | History | Other scripts by: greggirwin · ladislav |
30-Apr 15:52 UTC
[0.045] 13.756k
[0.045] 13.756k
use-rule.rRebol [
Title: "Use-rule"
File: %use-rule.r
Author: ["Ladislav Mecir" "Gregg Irwin"]
Date: 31-Oct-2010/9:48:59+1:00
Purpose: {
Create a recursion and thread-safe parse rule with local variables.
R2/R3 compatible.
}
Notes: {
The USE-RULE function implements two USE variants as described in
http://www.rebol.net/wiki/Parse_Project.
The default, rebinding variant, rebinds the given rule every time
it is used for matching (that is why we call it "rebinding variant"),
while the /no-rebind variant binds the given rule just once.
The difference between the rebinding and the /no-rebind variant
is similar as the difference between closures and functions.
The WORDS block is expected to contain only words.
The implementation of the USE-RULE function does not use
the latest parse enhancements to remain compatible with R2
as well as with R3.
}
]
use-rule: func [
{
Create a recursion and thread-safe parse rule with local variables.
R2/R3 compatible.
}
words [block!] {Local variables to use}
rule [block!] {Parse rule}
/no-rebind {Do not rebind the given RULE every time it is reused}
] [
; we need some fresh local variables per every USE-RULE call
make object! either no-rebind [[
; We need the 'pos and 'success variables to transfer the parsing state
; between "inner" and "outer" PARSE calls.
pos: none
success: none
; The INNER-BODY function processes the given rule.
inner-body: func [rule] [
; If the parse of the given rule succeeds,
; we set the "outer parse position"
; to the point where the rule match ended,
; otherwise we use [end skip] for "parse failure"
; (for R2 compatibility).
success: either parse pos [rule pos: to end] [
[:pos]
] [
[end skip]
]
]
; Define CONTEXT-FN's context to contain words specified by the caller.
spec: copy []
unless empty? words [append spec to refinement! first words]
append spec next words
; The CONTEXT-FN function calls the INNER-BODY function,
; supplying the given rule bound to the CONTEXT-FN function's context
; as the RULE argument to it.
context-fn: func spec reduce [:inner-body rule]
; The result rule will be a "snapshot" of the block below,
; COPY/DEEP is needed to make sure the subsequent calls
; of the USE-RULE function do not modify the rule
set 'rule copy/deep [pos: (context-fn) success]
]] [[
; Define a new 'rebound-rule variable.
; (this block is processed by MAKE OBJECT! at the top)
rebound-rule: none
set 'rule reduce [
; The new rule contains a paren! evaluation at the start.
to paren! compose/only/deep [
; We compose a copy of the given WORDS block
; as a WORDS argument into the USE call,
; and a deep copy of the given RULE into the USE BODY.
; Whenever the new rule is matched, the rule in the
; USE BODY is rebound by the USE call and deep copied.
; (to not be influenced by subsequent USE calls)
rebound-rule: copy/deep use (copy words) [(copy/deep rule)]
]
; The rebound rule is used for matching by PARSE.
'rebound-rule
]
]]
rule
]
comment [
; tests
rule: [
"b" (print 1) |
a: "a" rule "a" b: (print subtract index? b index? a)
]
parse "aabaa" rule
rule: use-rule [a b] [
"b" (print 1) |
a: "a" rule "a" b: (print subtract index? b index? a)
]
parse "aabaa" rule
rule: use-rule/no-rebind [a b] [
"b" (print 1) |
a: "a" rule "a" b: (print subtract index? b index? a)
]
parse "aabaa" rule
] |