Rebol [
Title: "RSP Preprocessor"
Date: 12-Jun-2013
Author: "Christopher Ross-Gill"
Notes: "Extracted from QM"
Version: 0.4.1
File: %rsp.r
Type: 'module
Name: 'rsp
Exports: [sanitize load-rsp render render-each]
]
sanitize: use [ascii html* extended][
html*: exclude ascii: charset ["^/^-" #"^(20)" - #"^(7E)"] charset {&<>"}
extended: complement charset [#"^(00)" - #"^(7F)"]
func [text [any-string!] /local char][
parse/all form text [
copy text any [
text: some html*
| change #"<" "<" | change #">" ">" | change #"&" "&"
| change #"^"" """ | remove #"^M"
| remove copy char extended (char: rejoin ["&#" to integer! char/1 ";"]) insert char
| remove copy char skip (char: rejoin ["#(" to integer! char/1 ")"]) insert char
]
]
any [text copy ""]
]
]
load-rsp: use [prototype to-set-block][
prototype: context [
out*: "" prin: func [val][repend out* val]
print: func [val][prin val prin newline]
]
to-set-block: func [block [block! object!] /local word][
either object? block [block: body-of block][
parse copy block [
(block: copy [])
any [set word word! (repend block [to-set-word word get/any word])]
]
]
block
]
func [body [string!] /local code mk][
code: make string! length? body
append code "^/out*: make string! {}^/"
parse/all body [
any [
end (append code "out*") break
| "<%" [
"==" copy mk to "%>" (repend code ["prin sanitize form (" mk "^/)^/"])
| "=" copy mk to "%>" (repend code ["prin (" mk "^/)^/"])
| [#":" | #"!"] copy mk to "%>" (repend code ["prin build-tag [" mk "^/]^/"])
| copy mk to "%>" (repend code [mk newline])
| (throw make error! "Expected '%>'")
] 2 skip
| copy mk [to "<%" | to end] (repend code ["prin " mold mk "^/"])
]
]
func [args [block! object!]] compose/only [
args: make prototype to-set-block args
do bind/copy (load code) args
]
]
]
render: use [depth*][
depth*: 0 ;-- to break recursion
func [
rsp [file! url! string!]
/with locals [block! object!]
][
if depth* > 20 [return ""]
depth*: depth* + 1
rsp: case/all [
file? rsp [rsp: read rsp]
url? rsp [rsp: read rsp]
binary? rsp [rsp: to string! rsp]
string? rsp [
rsp: load-rsp rsp
rsp any [locals []]
]
]
depth*: depth* - 1
rsp
]
]
render-each: func [
'items [word! block!]
source [series!]
body [file! url! string!]
/with locals /local out
][
out: copy ""
locals: append any [locals []] items: compose [(items)]
foreach :items source compose/only [
append out render/with body (locals)
]
return out
]