Skip to content

Instantly share code, notes, and snippets.

@ne1uno
Last active June 7, 2025 13:20
Show Gist options
  • Save ne1uno/44b942855d36c5317a095c59ebd76681 to your computer and use it in GitHub Desktop.
Save ne1uno/44b942855d36c5317a095c59ebd76681 to your computer and use it in GitHub Desktop.
parse/trace call back example gui demo in red-lang
get red-lang from red-lang.org
takeoff on a red-lang gitter post from 2018 about parse-?? custom tracing
un-comment at do-parse to see the demo parse-trace and parse/trace :callback
gui is from a simplified parse tab in my unpublished ne1 clean-script tool
cGPT suggested some utf color markers for succeed/fail that improve readability
difficult to imagine how to make trace debug parse rules without showing everything
;credits,
; 2018 post in gitter/red/parse @endo64, @gltewalt, @gltewalt & others for parse ideas
; splitters I think from live code enhanced on gist or @toomasv dx2 demo?
the examples are really to demo the custom trace and maybe not great parse examples
the sliders and area size calculations are a bit sloppy, please don't blame the sources
they need a limit so they can't be dropped in the wrong place
resizing doesn't account for scroll bars propeely so it's a bit of an adventure
Red [
Title: "parse tracing"
File: %parse-??.red
Version: 0.1
Needs: 'View
]
; system/view/debug?: on ; does step by step print of layout
line-end: "^/" ; crlf in area in windows seems to work better? otherwise ^M or ^/
random/seed now/time/precise
;parse gui is setup to run a function live to demonstrate the parse trace
; a top row of buttons to clear areas, parse and quit
; p1..p4 area/text with 3 horizontal splitters between them
; there is no error reporting in the virtual function used in the demo
; they may just silently fail with typo or syntax errors, be warned.
P-def: random 4
; select 1st 2nd 3rd nth example, drop-list to choose in ui however many
; each block of P-drop is 3 strings.
; [[{title}{function}{data}]...] , output of function will be to p3. trace to p4
; <1> message for p3 <2> function spec & body for p1 <3> data to parse
; form gets rendered and errors on some char literal is why charset reduce works
; there few no error checks on the function syntax in this demo
; if you see nothing happening when you click parse that may be one reason why
; p1 area is not a full editor so has the normal area editing, it's a demo...
; p2 area data needs to be loadable as string or block
; the examples don't have to use parse, it is normal red language code
; it might've been simpler to read/write example scripts to/from disk
P-drop: [
[{parse-block-demo} ;<P-d1> simpler test,
{["function spec & body body to parse data from P2 area"
data [series! block!] "from P2 area"
/local out spc rule et ;tag val not sure how parse words propagate
][ ;could be dangerous, don't do anything stupid
out: clear []
print ['data mold data]
rule: [
some [
copy tag set-word!
copy val [integer! | string! | set-word! | word!]
(append/only out reduce [tag val])
]
]
; et: parse-trace data rule ;default-trace prints to console
; et: parse data rule ;no-trace
et: parse-?? data rule 45 ;n=depth custom trace redirect enabled
reduce [et out]
]}
{[name: "Alice" age: 30 logged-in: true]}
]
; converts string like "2 +3 -4 'cmt" to [2 + 3 - 4] ignoring 'cmt not much error checking
[{parse-mlstring-code} ;<P-d2>
{["function spec & body body to parse data from P2 area"
data [series! block!] "from P2 area"
/local out rule spcs et lf digit sign ncmt v vars i x
][ ;could be dangerous, don't do anything stupid
out: clear []
;data: "1 +3 'cmt"
print ['data mold data]
;crlf? area renders char literal
;note: ^^+- as tab, ^^+/ will embed a newline string or comment
spcs: charset reduce [space tab newline]
lf: charset reduce [newline]
digit: charset "0123456789."
sign: charset "+-"
ncmt: complement charset reduce ["'" newline]
rule: [
some [
some [spcs | end]
| [copy v [some [sign]] (append out v)]
| [copy v [some [digit]] (append out v)]
| ["'" any ncmt any [lf | end]] ; skip comment to end of line
]
]
; et: parse-trace data rule ;default-trace prints to console
; et: parse data rule ;no-trace
et: parse-?? data rule 45 ;n=depth custom trace redirect enabled
;rework the strings
print ["math ans=" attempt [math probe vars: collect [
foreach [i x] probe out [
keep reduce [to-float i]
keep either x [first to-block x][continue]
]
]]]
print reduce [";ans=" do vars]
append p3/text " p3/text output functest " ;don't try to embed ^-^/
reduce [et out]
]}
{{5 +8 'cmt}} ;not a math replacement, only sums signed numbers as a demo
]
[{parse-string-char-counter} ;<P-d4> ; show skip if not a letter
{["function spec & body body to parse data from P2 area"
data [series!] "from P2 area"
/local out spc rule et letters counts ;ch cur
][ ;could be dangerous, don't do anything stupid
out: clear []
print ['data mold trim data]
letters: charset "abcdefghijklmnopqrstuvwxyz"
counts: make map! []
rule: [
some [
copy ch [letters | skip]
(
either all [ch curr: counts/:ch] [counts/:ch: curr + 1][counts/:ch: 1]
)
;end
]
]
et: parse-?? data rule 45 ;n=depth custom trace redirect enabled
probe append out counts
reduce [et out]
]}
{"all 5"}
]
[{parse-string-block-code} ;<P-d4> empty template
{["function spec & body body to parse data from P2 area"
data [string! block!] "from P2 area"
/local out spc rule et ;var
][ ;could be dangerous, don't do anything stupid
out: clear []
print ['data mold trim data]
spc: charset reduce [space tab]
rule: [
some [copy var [word! | string! | end] (append out var)]
] ;
et: parse-?? data rule 45 ;n=depth custom trace redirect enabled
reduce [et out]
]}
{[data block "data string"]
}
]
]
;for cli use bypass gui area/text
p4a: none
to-area: no
init-areas: func [
P-def "integer block of P-drop to use"
][
p1/text: P-drop/:P-def/2
p2/text: P-drop/:P-def/3
p3/text: rejoin ["parsed results ^M^/^-"
P-drop/:P-def/1
]
p4/text: {parse trace ^M^/}
]
p-indent: make string! 30
parse-skips: 0 ;0: all 1: fails 2: etc TBD
; can override while testing print also to console
;line endings tricky in windows area sometimes
print-et: function ["mimic print echo to etrace area, caller should reduce blk?"
blk [string! block!] ;
/local x
][
; if block? blk [
; repeat x length? blk [
; blk/x: mold blk/x
; ]
; blk: join/with blk "^/"
; ]
print blk ;option to echo to console or not (only if don't redirect print)
;etrace/text: rejoin [etrace/text mold blk line-end] ;included brackets & quotes
if to-area [ ;area on windows needs crnl?
;p4a/text: rejoin [p4a/text replace/all blk "^/" "^M^/"]
;p4a/text: rejoin [p4a/text mold blk]
p4a/text: rejoin [p4a/text to-string blk newline]
] ;newline, trace adds newline between match & input
]
on-parse-compact: function [
"Compact and clear parse/trace event printer"
event [word!]
match? [logic!]
rule [block!]
input [series!]
stack [block!]
][
switch event [
push [
; print-et [p-indent] ;"-->" ;need no nl option print-et
append p-indent " "
]
pop [
clear back back tail p-indent
; print-et [p-indent "<--"] ;is on line by itself, just adds noise really
]
fetch [
print-et rejoin [
p-indent "R: " mold/flat/part rule 40 line-end ; newline added by caller
p-indent "I: " either parse-skips = 0 [" At: " mold/flat/part input 30][""]
]
]
match [
print-et rejoin [
p-indent either match? ["✅"] ["❌"] ;green & red on console, newline added
;not sure why need to repeat rule, is 2 lines above
; either parse-skips = 0 [mold/flat/part rule 60][""] ; newline caller added, skip detail
]
]
end [
print-et reduce ["Done: " mold match?]
]
]
true
]
;\gist\repos\repo-red\Oldes\Red-master\environment\functions.red
;the default callback in parse-trace I think
on-parse-event: func [
event [word!] "Trace events: push, pop, fetch, match, iterate, paren, end"
match? [logic!] "Result of last matching operation"
rule [block!] "Current rule at current position"
input [series!] "Input series at next position to match"
stack [block!] "Internal parse rules stack"
return: [logic!] "TRUE: continue parsing, FALSE: stop and exit parsing"
][
switch event [
push [
print [p-indent "-->"]
append p-indent " "
]
pop [
clear back back tail p-indent
print [p-indent "<--"]
]
fetch [
print [
p-indent "match:" mold/flat/part rule 50 line-end
p-indent "input:" mold/flat/part input 50 p-indent
]
]
match [print [p-indent "==>" pick ["matched" "not matched"] match?]]
end [print ["return:" match?]]
]
true
]
parse-??: function [{Wrapper for parse/trace using ?? hook w/o the ?? hook}
input [series!]
rules [block!]
/case
/part
/skips sps
limit [integer!]
;return: [logic! block!]
][
parse-skips: any [sps 1] ;0 all, 1 less detail, RSN
clear p-indent ;no longer works to indent red 22B
parse-event: :on-parse-compact ; :on-parse-event-mod ;on-parse-?? option TBD
either case [
print ["parse/case/trace input rules :on-parse-??"]
parse/case/trace input rules :parse-event
][
either part [
print ["parse/part/trace input rules :on-parse-??"]
parse/part/trace input rules limit :parse-event
][
print-et reduce ["parse/trace input rules :on-parse-??"]
parse/trace input rules :parse-event
]
]
]
;; June, 2018 https://rebol.tech/gitter.im/red/parse/2018/#msg5b164af7edd06f7d150e7faa
;; endo64> I saw "??" usage in Respectech's http://video.respectech.com:8080/tutorial/r3/index.r3 tutorial
;; We don't have ?? in Red/Parse, is it handy?
;; Should we consider to add it, or parse-trace is already do what ?? does?
;; gltewalt> Looks like [pindent] was a todo, to put in non-global?
;; greggirwin> Thanks @gltewalt
;; parse-?? "dog" [ ?? "d" ?? [ "i" | "o" ] ?? "g" ?? ]
;?? FIXME, I think the idea was ?? would be replaced in the rules or trigger more info?
; @gltewalt went on to work on parse caddy but it didn't show traces or have ??
do-parse: does [
rule: [["d" | "c"] [ "o" | "a" ] [ "g" | "t" ]]
parse-trace "dog" rule
parse-?? "cat" rule
]
; do-parse ; un-comment to show compact trace to console
; halt
; cfg stuff lifted from larger multi panel layout
; not all of it was needed for this parse trace demo
; not sure of the utility of this allocation, lifted from a red editor script
; I've also heard there's a 32k area/text limit, they seem to work ok for small demo's
p1script: make string! 30000
p2script: make string! 60000
p3script: make string! 40000
p4script: make string! 90000
out: copy "" ;replaced later but here incase of compiler confusion
f: func [][] ;replaced later
fs: func [][] ;replaced later
init-pos: 50x5 ;offset upper left of screen
window-size: 760x560 ;x650 was too close for some laptop x700 & taskbar
T-size: window-size - 5x30 ;room for status with n rows of buttons
H-size: as-pair (T-size/x - 12) (7) ;hoiz splitter init
;parse area inits. not sure how <>100% works
P1-size: as-pair (T-size/x - 12) to-integer (T-size/y * 30%)
P2-size: as-pair (T-size/x - 12) to-integer (T-size/y * 10%)
P3-size: as-pair (T-size/x - 12) to-integer (T-size/y * 25%)
P4-size: as-pair (T-size/x - 12) to-integer (T-size/y * 25%)
a_color: 240.240.240
hvs_coloron: gray
hvs_coloroff: blue
afont: make font! [ ;ui area
name: "Consolas" ;
size: 11
color: coal
]
ifont: make font! [ ;ui buttons
name: "Consolas" ;
size: 9
color: coal
]
gview: layout [
title "parse Text quad Pane"
size window-size
backdrop ivory
style btn: button 92x17 center font ifont pewter ;~9 char
style text: text font afont snow pewter
style drop-list: drop-list font afont snow pewter ;~9 char
style area: area a_color font afont
style splitter: base 5x5 hvs_coloron loose ;make I-beam cursor
across
pad -2x-4
btn "cls P2-data" [
clear p1/text
]
btn "cls P3-results" [
clear p3/text
]
btn "cls P4-trace" [
clear p4/text
]
pad 20x0
text 90x16 "examples:"
drop-list 30x16 data [] [
;print [face/selected]
]
on-created [ ;wonder can this fail if areas not created yet?
repeat ix length? P-drop [append face/data form ix]
face/selected: P-def
init-areas face/selected
]
on-change [
init-areas face/selected
]
btn "Parse" [ ; p1 func rule p2 data p3 results p4 trace
;build dynamic function and run it
;need a way to trap error,
; just as likely to get syntax error that won't point to users function or data
; could check structure & open/close balance but way beyond trace demo already
either
;all [attempt [load to-string first blk] attempt [load to-string second blk]]
all [attempt [blk: to-block p1/text] attempt [first blk] attempt [second blk]]
[
f: function first blk second blk
][
print "p1 function has malformed blocks?" ;FIXME
blk: to-block p1/text
print [mold first blk newline mold second blk]
]
; probe spec-of :f
; probe reflect :f 'body
; ? f
; ?? f
; probe find spec-of :f 'local ; check all setwords if use function
;check debug cb or don't bother echo
if no [
append p3/text rejoin [ newline "******" newline
'f-s mold spec-of :f newline 'f-b mold body-of :f newline
'data mold p2/text
newline newline
]]
px: copy ";in case attempt fails"
append p3/text rejoin [
newline "------- mold" newline
;ok for string or block litteral in data
mold attempt [px: f attempt [load p2/text]]
newline "-------form " newline
form px
newline newline ;last line in area sometimes truncated
]
]
;add cd no-trace or spinbox verbose
;add cb string/block
pad 24x0
btn "QuitAll" [quit] ;same compiled?
btn 38x15 "Exit" [print [";do system/options/script"] unview] ;prints to history
return
pad -2x-4
below
p1: area P1-size p1script react [
face/size/x: face/parent/size/x - 10
]
splitter-hp1: splitter H-size react [
face/size/x: face/parent/size/x - 10
]
on-down [ofsx1: face/offset/x system/view/auto-sync?: off]
on-up [system/view/auto-sync?: on]
on-drag [
face/offset/x: ofsx1
p1/size/y: face/offset/y - 10
p2/offset/y: face/offset/y + 10
p2/size/y: face/parent/size/y - face/offset/y - 2 ;20
show [p1 p2 face]
] on-over [face/color: either event/away? [hvs_coloron][hvs_coloroff]]
p2: area P2-size p2script react [
face/size/x: face/parent/size/x
]
splitter-hp2: splitter H-size react [
face/size/x: face/parent/size/x - 10
]
on-down [ofsx2: face/offset/x system/view/auto-sync?: off]
on-up [system/view/auto-sync?: on]
on-drag [
face/offset/x: ofsx2
p2/size/y: face/offset/y - 10
p3/offset/y: face/offset/y + 10
p3/size/y: face/parent/size/y - face/offset/y - 2 ;20
show [p2 p3 face]
] on-over [face/color: either event/away? [hvs_coloron][hvs_coloroff]]
p3: area P3-size p3script react [
face/size/x: face/parent/size/x - 10
]
splitter-hp3: splitter H-size react [
face/size/x: face/parent/size/x
]
on-down [ofsx3: face/offset/x system/view/auto-sync?: off]
on-up [system/view/auto-sync?: on]
on-drag [
face/offset/x: ofsx3
p3/size/y: face/offset/y - 10
p4/offset/y: face/offset/y + 10
p4/size/y: face/parent/size/y - face/offset/y - 2 ;20
show [p3 p4 face]
] on-over [face/color: either event/away? [hvs_coloron][hvs_coloroff]]
p4: area P4-size p4script react [
face/size/x: face/parent/size/x - 10
]
]
; copy to above print-et if compiling
p4a: p4 ;trace area object
to-area: on ; set toarea to do print-et redirect
;don't use /no-wait compiled or w/o opening console first
probe init-pos ;open console interpreted
view/no-wait/flags/options gview ['resize][offset: init-pos]
comment { don't debug the comments
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment