Archived messages from: gitter.im/red/parse from year: 2022

cloutiy
20:04Is it possible to see how parse is implemented? Where can one see the implementation on github?
greggirwin
20:57https://github.com/red/red/blob/master/runtime/parse.reds
GiuseppeChillemi
20:59You can also Read This: http://www.codeconscious.com/rebol/parse-tutorial.html#Introduction
cloutiy
22:28@greggirwin thanks for the link gregg this is what i was looking for...

bubnenkoff
07:34Hi! I need a way to remove quotermark from string only if it's exists at start and it's end.
I decided that parse is best for it.
For example:
{"Hello World"}

Should become:
{Hello World}


But:
{Company name "Hello World"}

Should stay:
{Company name: "Hello World"}


I tried to write next code:
str: {"Hello World"}

parse str [remove {"} to end  ]

probe str

But how to deal with last quote mark?
GalenIvanov
07:52@bubnenkoff Something like that?
07:52
remove-quotes: function [str][
    parse dst: copy str [
		p-st: opt dbl-quote
		some [not dbl-quote skip]
		p-end: dbl-quote end
		(if p-st/1 = dbl-quote [remove p-end remove p-st])
	]
	dst
]
07:54
>> remove-quotes {"Hello World"}
== "Hello World"
>> remove-quotes {Company name "Hello World"}
== {Company name "Hello World"}
>> remove-quotes {"Hello World" Company name}
== {"Hello World" Company name}
bubnenkoff
08:27yeah! Big thanks!
Oldes
08:38
>> parse str: {"aa"bb"} [any [to #"^"" remove some #"^""]] str
== "aabb"
08:39Ah... sorry... it's not what you want... I should first read it:)
toomasv
08:42parse really not needed there:
rem: function [str][if all [#"^"" = first str   (index? find next str {"}) = length? str][replace/all str {"} ""] str]
rem {"Hello World"}
;== "Hello World"
rem {"Hello World" company}
;== {"Hello World" company}
rem {Company name "Hello World"}
;== {Company name "Hello World"}
Oldes
08:42
>> str: {"hello"} if all [#"^"" = first str #"^"" = last str][remove back tail remove str] str
== "hello"
toomasv
08:44
str: {"hello" wrong "world"} if all [#"^"" = first str #"^"" = last str][remove back tail remove str] str
== {hello" wrong "world}
Oldes
08:45hm:)
toomasv
08:46But [remove back tail remove str] is better, yes.
GalenIvanov
08:55Yes, parse is not needed here :)
bubnenkoff
11:16Thanks!
hiiamboris
11:39
>> parse s: {"hello" wrong "world"} [remove {"} to [{"} end] remove {"}] s
== {hello" wrong "world}
>> parse s: {"hello" wrong "world"} [remove {"} to [remove [{"} end]]] s
== {hello" wrong "world}

but parse will be much slower
toomasv
15:55Huh?
hiiamboris
16:05much slower than remove :)
gltewalt
18:13How can I account for parens with this?
Red ["24 Game"]

numbers: copy []
collect/into [loop 4 [keep random 9]] numbers
op: charset "*/+-"
valid-number: charset form numbers
valid-expression: [valid-number op valid-number op valid-number op valid-number]

explode: func [val /local c][
    c: copy []
    forall val [collect/into [keep val/1] c]
]

; allow spaces or no spaces in the expression with trim/all,
; but since Red throws invalid integer error without spaces, break the string
; back apart with explode, and then form it into a string with spaces.
; load that and feed it to math.
check-expression: does [
    either parse trim/all e: ask "Enter expression: " valid-expression [
        either 24 = math load form explode e ["You got it!"]["Not quite correct"]
    ][
        "Invalid expression"
    ]
]

print ["Using the following numbers, enter an expression that equals 24:" numbers]
check-expression
toomasv
18:30Hmm...
Using the following numbers, enter an expression that equals 24: 7 2 7 2
Enter expression: 7-2+7*2
== "Not quite correct"

Hey!
>> 7 - 2 + 7 * 2
== 24
hiiamboris
18:49why are you using collect/into?
gltewalt
18:51It's using math so follow order of operaations toomas
18:52Why not collect/into? append [] ... better?
hiiamboris
18:52why not just collect? it does the copy for you
18:52and you like no I don't need your copy I'll do that myself :)
18:53also
>> extract/into "1+2/3" 1 []
== [#"1" #"+" #"2" #"/" #"3"]
gltewalt
18:53Are you sure? I swear I did normal collect and it grew
19:04Oh, no, this is why I went to /into
19:04
>> x: "2*3/9-3"
== "2*3/9-3"
>> forall x [collect [keep x/1]]
== [#"3"]
19:04Because I iz smort
19:08There
op: charset "*/+-"
valid-expression: [valid-number op valid-number op valid-number op valid-number]

explode: func [val][
    extract/into val 1 c: copy []
]

check-expression: does [
    if "q" = e: ask "Enter expression: " [halt]
    either parse trim/all e valid-expression [
        either 24 = math load form explode e [print "You got it!"][print "Not quite correct"]
    ][
        print "Invalid expression"
    ]
]

main: does [
    numbers: collect [loop 4 [keep random 9]]
    valid-number: charset form numbers
    print [newline "Using the following numbers, enter an expression that equals 24:" numbers]
    check-expression
]

forever [main]
19:12Now for the parens, which I assume math obeys
toomasv
19:21OK, this follows Red order, but parens can be added:
numbers: collect [loop 4 [keep random 9]]
op: charset "*/+-"
n: charset form numbers
num: [keep n]
exp: [num some [op num]]
term: ["(" exp ")" | num]
formula: [collect [term any [op term]]]
explode: func [val][collect [forall val [keep val/1]]]
check-expression: does [
    either attempt [(sort numbers) = (sort load form parse trim/all e: ask "Enter expression: " formula)] [
        either 24 = do load form explode e ["You got it!"]["Not quite correct"]
    ][
        "Invalid expression"
    ]
]
print ["Using the following numbers, enter an expression that equals 24:" numbers]
check-expression

Using the following numbers, enter an expression that equals 24: 8 7 4 6
>> check-expression
Enter expression: 8-7*4*6
== "You got it!"
>> check-expression
Enter expression: (8-7)*4*6
== "You got it!"
>> check-expression
Enter expression: 4*6
== "Invalid expression"
>> check-expression
Enter expression: 2*2*2*3
== "Invalid expression"
gltewalt
19:55@toomasv "enter an arithmetic expression using just those, and all of those four digits, used exactly once each"
20:13Yeah, I guess that's it.
op: charset "*/+-"
num: [keep n]
exp: [num some [op num]]
term: ["(" exp ")" | num]
formula: [collect [term any [op term]]]

explode: func [val][
    extract/into val 1 c: copy []
]

check-expression: does [
    if "q" = e: ask "Enter expression: " [halt]
    either parse trim/all e formula [
        either 24 = math load form explode e [print "You got it!"][print "Not quite correct"]
    ][
        print "Invalid expression"
    ]
]

main: does [
    numbers: collect [loop 4 [keep random 9]]
    n: charset form numbers
    print [newline "Using the following numbers, enter an expression that equals 24 (pdmas):" numbers]
    check-expression
]

forever [main]
20:15Contrast with an entry that is already on rosetta.
https://rosettacode.org/wiki/24_game#Red
20:17Is there an "Easier to read to the non Red user" grammar for handling parens?
20:22Example without parens: [num op num op num op num] should be understandable to anybody

gltewalt
01:37@toomasv If collect is used, then an entry like "goodbye" will error. parse returns empty block if collect fails, instead of false
03:00Can I just ignore any "()"?
toomasv
06:01@gltewalt That's why I used attempt; and comparison - to ensure each number is used and only those numbers are used.
15:30Hmm.. actually to guarantee this n should be charset "123456789".
gltewalt
19:10To be bone-headedly declarative, this works.
numbers: collect [loop 4 [keep random 9]]
num: charset form numbers
op: charset "*/+-"
expr: [num some [op num] | num]
term: ["(" expr ")" | num]
p1: [term op term op term op term]  ; (7)*3+1-2
p2: [term op term op term]          ; (7*3)+1-2
p3: [term op term]                  ; 7*(3+1-2)
p4: [term]                          ; (7*3+1-2)

valid-expression: [p1 | p2 | p3 | p4]
19:11or could call it level1, level2, etc
19:11Not sure on the naming
19:12
>> numbers
== [7 2 7 2]

>> parse "7272" valid-expression
== false
>> parse "7+2+7+2" valid-expression
== true
>> parse "(7*2)+7+2" valid-expression
== true
>> parse "7*(2)+7+2" valid-expression
== true
>> parse "7*(2+7)+2" valid-expression
== true
>> parse "7*(2+7/2)" valid-expression
== true
>> parse "hello" valid-expression
== false
toomasv
19:31
>> parse "7+2+7+2" valid-expression
== true
>> parse "7+7+7+2" valid-expression
== true
>> parse "2+2+2+2" valid-expression
== true
>> parse "2+2" valid-expression
== true
>> parse "2" valid-expression
== true
>> parse "7" valid-expression
== true
>> parse "(7)" valid-expression
== true
greggirwin
19:45Bone-headedly declarative sounds like just my style. :^)
gltewalt
20:10Curses
20:14Wait.. no, it works when you generate the numbers. With my script:
Red [
    Title: "24 Game"
    Note: "Math precedence rules, PMDAS"
]

op: charset "*/+-"
expr: [num some [op num] | num]
term: ["(" expr ")" | num]

; naming? or recursive way?
p1: [term op term op term op term]  ; (7)*3+1-2
p2: [term op term op term]          ; (7*3)+1-2
p3: [term op term]                  ; 7*(3+1-2)
p4: [term]                          ; (7*3+1-2)
valid-expression: [p1 | p2 | p3 | p4]

explode: func [val][
    extract/into val 1 c: copy []
]

check-expression: does [
    if "q" = e: ask "Enter expression: " [halt]
    either parse trim/all e valid-expression [
        either 24 = math load form explode e [print "You got it!"][print "Not quite correct"]
    ][
        print "Invalid expression"
    ]
]

main: does [
    numbers: collect [loop 4 [keep random 9]]
    num: charset form numbers
    print [newline "Using the following numbers, enter an expression that equals 24: (pmdas)" numbers]
    check-expression
]

forever [main]

20:18The ; (7)*3+1-2 comments are just examples if the numbers generated were 7 3 1 2
20:54I swear "works on my machine!"

gltewalt
04:10Ok. This, as near as I can tell.
04:10
op: charset "*/+-"
expr: [num some [op num] | num]
term: [num | "(" expr ")"]

p1: [term op term op term op term]  
p2: [term op term op term]          
p3: [term op term]                 
valid-expression: [p1 | p2 | p3]

explode: func [val][
    extract/into val 1 c: copy []
]

check-expression: does [
    if "q" = e: ask "Enter expression: " [halt]
    either parse trim/all e valid-expression [
        either 24 = m: math to-block form explode e [
            print ["You got it!" m]
        ][
            print ["Not quite correct. That's" m]]
    ][
        print "Invalid expression"
    ]
]

main: does [
    numbers: collect [loop 4 [keep random 9]]
    num: charset form numbers
    print [newline "Using the following numbers, enter an expression that equals 24: (pmdas)" numbers]
    check-expression
]

forever [main]

04:11Bug with math and load form explode , so switched to to-block
04:13My flaw /bug.
toomasv
06:17But it accepts formulas with 2 and 3 numbers too:
Using the following numbers, enter an expression that equals 24: (pmdas) 8 7 4 6
Enter expression: 4*6
You got it! 24
gltewalt
07:14What I really want is:
[num op num op num op num], and "ignore any balanced paren along the way".
math will take care of obeying the parens.
toomasv
09:00Then probably the easiest you can do is, well, to ignore the parens in formula, e.g.:
term: [opt "(" num opt ")"]
valid-expression: [term op term op term op term]
Oldes
10:12But it will allow unbalanced parens.
toomasv
10:29Yes, and unbalanced parens will generate error. (Personally I would prefer to collect numbers from balaced expressions as shown above)
gltewalt
18:37I dontt want to. And im a stubborn jerk

gltewalt
18:40Error on unbalanced paren can be handled when calling check-expression
18:40
main: does [
    numbers: collect [loop 4 [keep random 9]]
    num: charset form numbers
    print [newline "Using the following numbers, enter an expression that equals 24: (pmdas)" numbers]
    if none? attempt [check-expression][print "Invalid expression"]
]

mikeyaunish
22:38
in the middle of the parse. The result I am looking
for is:
[btn: button]
which the parse gives
correctly. Just don't like leaving the parens as a loose
end.

res: parse [style btn: button "hello" 120x24] [
    collect any [
        'style 
            some [
                some [ ahead () keep set-word! ] | ;-- needs () to work??
                some [ ahead keep word! ]
            ]
        | skip 
    ]
]
? res
RES is a block! value.  length: 2  [btn: button]
>
greggirwin
22:42Will this work for you @mikeyaunish?
res: parse [style btn: button "hello" 120x24] [
	collect any [
		'style 
;		some [
		keep some set-word! 
		| keep some word!
;		]
		| skip 
	]
]
? res
22:44Bah, gitter formatting. :^\
hiiamboris
22:45I don't see any difference with or without ahead ()
greggirwin
22:46Nor I.
mikeyaunish
23:02@greggirwin Thanks - can't seem to get the 'some idea clear in my head.

gltewalt
04:11?
blk: [style b1: button "hello" 120x24 b2: button]
res: parse blk [collect [some [to set-word! keep thru word!]]]
toomasv
07:33Rather:
res: parse blk [collect [any ['style keep set-word! keep word! | skip]]]
mikeyaunish
15:40@toomasv Yes - that is what I was looking for. I like it. Much simpler. Thanks
toomasv
15:56@mikeyaunish You are welcome!
greggirwin
20:14That's where I didn't know if you wanted to collect multiple, potential set-words and words, so I erred on the side of closest to your original @mikeyaunish.

Thanks @toomasv. Sometimes showing the simplest thing is best.
toomasv
gltewalt
21:38Yeah, that will only grab one btn: button if that's what you wanted.
21:38Is skip needed when any or some is used?
21:40And if there is always going to be a sw: button, then should it be some?

toomasv
05:42Intention seems to be to collect all new style words together with original styles.

Yes, skip is needed, otherwise it may never reach style (in general case), or reach next style somewhere later.

Not much difference between any and some in this case.

GiuseppeChillemi
23:44I definitively need SET-IN obj 'word in parse to write values in objects... this would save me lot of code in parens and also using temporary words.

hiiamboris
08:41Write your parse preprocessor macro. Turn set-paths into parens.
GiuseppeChillemi
10:29Good but I think it should be included in the language as SET-IN, it is an important feature when you work initializing objects with parse.
hiiamboris
10:44Make a REP.
12:13You reduce your chances IMO by opening it in the wrong place
GiuseppeChillemi
14:08Where is the right place?
hiiamboris
14:33https://github.com/red/REP/issues
GiuseppeChillemi
14:52Thank you, I always forget about this

GiuseppeChillemi
23:05Hi, I have a binary file and I need to parse it in search of multiple 0x01 + KEYWORD sequences ending with 0x17. In the middle there is a string I want to change.

Here is an example:

BINARY-DATA
0X01 "NAME:" "<PRODUCT-NAME>" 0x17
0X01 "BATCH:" "<BATCH STRING NUMBER>" 0x17
0X01 "EXPIRE:" "<EXPIRE STRING DATE >" 0x17
BINARY-DATA


In the first string, the word "NAME:" should be deleted and only "<PRODUCT-NAME>" will remain and be changed with the target string.

How could I parse this binary file and write it back?

cloutiy
01:52Are the words BINARY-DATA part of the text to parse, or you simply included to specify what follows is binary data?
GiuseppeChillemi
10:50I have included them to specify that what is before and what is after text is binary data
10:52I have also separated strings but they are joined
hiiamboris
22:11parse works on binary!, so what's stopping you exactly?
GiuseppeChillemi
23:35@hiiamboris How could I match a string like "Hello" on binary?

toomasv
04:20@GiuseppeChillemi
>> binary: to-binary "Hello Giuseppe!" 
== #{48656C6C6F20476975736570706521}
>> parse binary reduce [to-binary "Hello" space quote s:] to-string s
== "Giuseppe!"
04:38But also:
>> parse binary ["Hello" space s:] to-string s
== "Giuseppe!"
GiuseppeChillemi
14:05Thank you, so parsing a binary searching for a string, you have implicit conversion of the string to binary.

GiuseppeChillemi
06:36How could I match one or some datatype words? I mean: how could I match string! or string! and block!
07:15Another question: why this fails?
parse [integer! string!] [some datatype! end]
rebolek
07:21because they are words
07:21parse reduce [integer! string!] [some datatype! end]
hiiamboris
10:59if you want datatype words, you should get them and check for datatype or typeset value

bubnenkoff
16:36How to measure speed of parsing file of follow code:
parse file-content [ 
   some [ 
         tag (save-parent tag-name) | ahead chars copy tag-value to "<" ( do-operation-on-tags-tree-with-value tag-value ) | to  "<" 
      ] 
   ]
]

It's seems that code slow down on big file
hiiamboris
16:52Don't use to, use skip
16:55If you want to profile it, you will have to do it manually. E.g. measure time of each some iteration and see if there's something suspicious.
bubnenkoff
16:57> Don't use to, use skip

Why? Because I can jump in wrong place?
hiiamboris
16:58to backtracks if it fails, which in worst case leads to time complexity ~ file-size^2
16:58I'm not sure if this is what happens as I don't see your rules, but it's something to be careful with.
bubnenkoff
16:58> If you want to profile it, you will have to do it manually. E.g. measure time of each some iteration and see if there's something suspicious.

How to do it? I remember about time-it, but how to wrap some with it?
hiiamboris
16:59You can't wrap a parse rule. Just use now/precise when you enter some to get the time and subtract the previous result from it.
17:01If you suspect it's not the parse but your functions that are slow, I have a handy profiler here: https://codeberg.org/hiiamboris/red-common/src/branch/master/profiling.red

Picture [here](https://user-content.gitter-static.net/0160e0439d234733f5fd1e9100ccc49d1642bd5e/68747470733a2f2f692e6779617a6f2e636f6d2f37303630356564393636616234663564646237323031396235623830633066372e676966)
bubnenkoff
17:02I looked at this chat but did not found examples of time subtraction
17:03
>> t1: now/precise
== 18-Apr-2022/20:02:50.7804+03:00
>> 
>> 
>> t2: now/precise
== 18-Apr-2022/20:02:54.1006+03:00
>> 
>> t1 - t2 
== 0
>> 
>> t2 - t1
== 0

hiiamboris
17:03
>> s: now/precise/utc
== 18-Apr-2022/17:05:34.037
>> e: now/precise/utc
== 18-Apr-2022/17:05:35.7549
>> difference e s
== 0:00:01.71785
bubnenkoff
17:04oh! thanks!
hiiamboris
17:04- just returns number of days, which is handy for calendar stuff only
17:04even that is buggy
bubnenkoff
17:20Is it correct measuring?
some [ (s: now/precise) <my parsing rules>   (e: now/precise)]

I am asking because I am measured all other functions with time-it, and they works fast, but result file is parsing slowly
hiiamboris
17:28it should be correct if you wrap in a block

bubnenkoff
10:03I need to remove namespaces from tag. I wrote rule, but it's stuck on last tag that have : inside attribute:
list: [ 
	{<ns1:foo bar="123" baz="2002-02-26" region="En">} 
	{<ns1:foo bar="123" baz="2002-02-26" region="En"/>} 
	{<foo bar="123" baz="2002-02-26" region="En"/>} 
	{<ns1:foo>} 
	{<foo x=1>} 
	{<foo x=2/>} 
	{<ns1:foo/>} 
	{<ns1:foo bar="123" baz="2002-02-26" region="En" baz="66:77">} 
	{<foo bar="123" baz="2002-02-26" region="En" baz="66:77">} 

]

foreach tag-name list [
	only-tag-name: rejoin parse tag-name [ collect [ keep "<"  opt [thru ":"] keep to end ]  ]
	probe only-tag-name
]

toomasv
14:30Is that good enough?:
foreach tag-name list [
    	starting?: yes
        only-tag-name: rejoin parse tag-name [ collect [keep "<" s: any [sp (starting?: no) :s keep to end | if (starting?) ":" keep to end | skip]]]
        probe only-tag-name
]
{<foo bar="123" baz="2002-02-26" region="En">}
{<foo bar="123" baz="2002-02-26" region="En"/>}
{<foo bar="123" baz="2002-02-26" region="En"/>}
"<foo>"
"<foo x=1>"
"<foo x=2/>"
"<foo/>"
{<foo bar="123" baz="2002-02-26" region="En" baz="66:77">}
{<foo bar="123" baz="2002-02-26" region="En" baz="66:77">}
bubnenkoff
15:12Yes! Thanks! Perfect!
toomasv
16:48:+1:

Oldes
21:45Is there any reason, why not to allow parse "a" [any [| #"a"]] return true as it does for parse "a" [any [#"a"]]?
21:46My request is simply from esthetical reasons to be able have code like:
parse "a" [
	any [
	| #"a"
	| #"b"
	]
]
21:46Now I must have:
parse "a" [
	any [
	  #"a"
	| #"b"
	]
]
21:51Possible reason is, that there would have to be another condition in the code, so it would slow down evaluation :/
hiiamboris
21:59Alan wants this too
greggirwin
23:14I've certainly had plenty of OCD formatting moments with rules through the years, especially with Red favoring tabs for indentation. But if you look at your first, single-line example: parse "a" [any [| #"a"]] to me that looks like something is missing. I think the other chat might be in red/bugs, but my thought in this moment is that it will lead to rules that are harder to reason about.
Oldes
23:19Yes.. I think it is better how it is now.

GiuseppeChillemi
00:03Yes, I see something missing too.

henrikmk
16:24I have always done this:

parse "a" [
    any [
      #"a"
      | #"b"
    ]
]

Oldes
14:34I'm really not sure, if I like this:
>> parse [1] [collect any [keep some integer! | skip]]
== [1]
>> parse [1 1] [collect any [keep any integer! | skip]]
== [[1 1]] ;=== why not just [1 1]?
14:36And just use collect collect to have [[1 1]]?
14:40Hm.. ok... it must be block... to support:
>> parse [1 "a" 2 2 "b" 3] [collect any [keep some integer! | skip]]
== [1 [2 2] 3]
toomasv
14:46@Oldes
>> parse [1 1] [collect any [keep pick any integer! | skip]]
== [1 1]
14:48
>> parse [1 "a" 2 2 "b" 3] [collect any [keep pick some integer! | skip]]
== [1 2 2 3]
Oldes
15:05Ah... good. I was not aware about pick. Is it supposed to work only with keep? If so, should not be this an error:
>> parse [1 1] [any [pick | skip]]
== true
toomasv
15:14It probably should, yes. pick is mentioned in [docs](https://github.com/red/docs/blob/master/en/parse.adoc#393-collect).
Oldes
16:30But this is strange:
>> parse [1 2 3][collect keep integer! collect keep integer! collect keep integer!]
== [1 [2] [3]] ;<-- it would be more logical to have it [[1] [2] [3]]
hiiamboris
16:35you're missing the outer collect
Oldes
16:36I know, but should not it be handled by error, or silently by adding the outer block, instead of using the first collect's block for the rest?
hiiamboris
16:37I would prefer an error
16:37asked this question myself some years ago
16:40would you like to open an issue for team's review? I don't think one exists

toomasv
06:02I don't understand, why it should be error! If first collect creates collection block, then it is only logical for all the rest to fall into this block. If you write it up with explicit block it is very clear:
parse [1 2 3][collect [keep integer! collect keep integer! collect keep integer!]]

If you want first integer to be in separate block too, add another collect
>> parse [1 2 3][collect [collect keep integer! collect keep integer! collect keep integer!]]
== [[1] [2] [3]]

or rather
>> parse [1 2 3][collect [3 collect keep integer!]]
== [[1] [2] [3]]

or use copy:
>> parse [1 2 3][collect [3 keep copy _ integer!]]
== [[1] [2] [3]]
06:12Or you can drill deeper
>> parse [1 2 3][collect [keep integer! collect [keep integer! collect keep integer!]]]
== [1 [2 [3]]]
Oldes
07:38Feel free to add your opinion here: https://github.com/red/red/issues/5167
07:41I must admit, that collect/keep in parse is much more complex than I initially thought and have many edge cases.
hiiamboris
08:02@toomasv error IMO is much better than nonsensical results that break the symmetry of how rules are written vs what results they produce.
08:04If one has written collect ... collect ... it's most likely one has forgotten to add the outer collect, hence the error would remind.
toomasv
08:52But it could perfectly be intentional, as in:
>> parse [1 2 3][collect keep integer! collect [keep integer! collect keep integer!]]
== [1 [2 [3]]]

Why should this rise error?
hiiamboris
08:54Because you have an *implicit* outer block which does not appear in the rules and by looking at the rules, it's hard to infer the result.
08:54write it explicitly [collect [keep integer! collect [keep integer! collect keep integer!]]]
Oldes
20:42Is there any example what keep pick (mentioned in the doc) should do? Because I don't see any difference:
>> parse "ab" [collect [keep ("ab")]]
== ["ab"]
>> parse "ab" [collect [keep pick ("ab")]]
== ["ab"]
>> parse [] [collect [keep ([1])]]
== [[1]]
>> parse [] [collect [keep pick ([1])]]
== [[1]]
hiiamboris
20:58it's supposed to explode a *match*
Oldes
20:58I expected, that the last one would be just [1].
hiiamboris
20:59how?
21:00if anything, it does the opposite: ensures a series
Oldes
21:00When there is:
>> parse [1 2][collect [keep 2 integer!]]
== [[1 2]]
>> parse [1 2][collect [keep pick 2 integer!]]
== [1 2]
21:02Maybe if I would see some example of the keep pick .. but there are no unit tests for it.
hiiamboris
21:08is it not clear what the docs say?
> If rule matched multiple values, they are grouped into a series of the same type as input; with pick option, values are not grouped but kept one-by-one.
21:09
>> parse "abc" [collect keep pick to end]
== [#"a" #"b" #"c"]
Oldes
21:10There is difference between expressions and rules. to end is a rule!
21:11[![image.png](https://files.gitter.im/5b147b8fd73408ce4f9bc4b4/2i7W/thumb/image.png)](https://files.gitter.im/5b147b8fd73408ce4f9bc4b4/2i7W/image.png)
hiiamboris
21:12ah, I see what you mean
21:13I think it's a deficiency in the docs
keep pick is there only to outline that it's a valid combo
but it is the same thing as keep (which is not said there)
Oldes
21:17And I think, that it is probably not implemented, because this would be better:
>> parse [1][collect [keep pick ([x: 1 +]) keep integer!]]
== [x: 1 + 1] ;== instead of current: [[x: 1 +] 1]
hiiamboris
21:18is this a real use case though?
21:19I'm not sure it's worth exploding arbitrary data
21:20though I agree, semantically that would be the expected thing to do

toomasv
03:58As doc says:

> If keep is used with paren! expression, result of its evaluation is kept as-is.
03:59But yes, I have wanted it to pick from paren-expressions too.
Oldes
08:54Should the collect set in the inner collect be excluded from the upper result?
>> parse [1 2][collect [collect keep skip]]
== [[1]]
>> parse [1 2][collect [collect set x keep skip]]
== []
hiiamboris
10:18
>> parse [1 2][collect [collect [set x keep skip]]]
== [[1]]
>> parse [1 2][collect [collect set x keep skip]]
== []
10:18it's one of those bugs that require an explicit block
Oldes
10:25I don't think so, I think it is another issue and it should work like:
>> parse [1 2][collect [collect set x keep skip]]
== [[1]]
>> x
== [1]
10:26And there should not be difference between collect [set x keep skip] and collect set x keep skip.
10:31(I mean the complete result... because x is different) So I expect this:
>> parse [1 2][collect [collect set x keep skip]]
== [[1]]
>> x
== [1]

>> parse [1 2][collect [collect [set x keep skip]]]
== [[1]]
>> x
== 1
hiiamboris
10:36I don't follow. Why should x be different?
10:37oh I get it
10:38collect set comes in conflict with collect + set
10:39so, good question if it should or not be included
10:42we can think of it as of *diverting* the collection into a new series, or as just as *marking* a word with the collection result
10:42since you can do your thing with:
>> parse [1 2][collect [set x collect keep skip]]
== [[1]]

then diverting is by design
Oldes
11:06Just to make it clear. I'm not looking for _how to do **my thing**_. I'm looking for extreme cases and their results.
11:13But it is true, that I confused myself when I made the set not related to collect.
11:18Actually it looks, that the inner set is just not included in the upper level, so it still may be by design.
>> parse [1 2][collect [keep integer! collect set x keep skip]]
== [1]
>> x
== [2]
11:19@toomasv is above good or not?
hiiamboris
15:50btw https://github.com/red/red/issues/4198
15:51so it was indeed by design not splitting expressions
Oldes
16:45When thinking about it a little bit more, it probably makes sense that the _named collects_ are excluded from the _unnamed parents_. It would be more useful in real use scenarios.

toomasv
03:28@Oldes Something seems wrong with it, yes. Giving set-rule to collect seems to ignore collect. And setting x seems also weird. Compare these
>> parse [1][collect set x keep skip]
== true
>> x
== [1]
>> parse [1][collect copy x keep skip]
== [1]
>> x
== [1]

These are correct
>> parse [1][collect keep set x skip]
== [1]
>> x
== 1
>> parse [1][collect keep copy x skip]
== [[1]]
>> x
== [1]

With your example above
>> parse [1 2][collect [keep integer! collect keep set x skip]]
== [1 [2]]
>> parse [1 2][collect [keep integer! collect keep copy x skip]]
== [1 [[2]]]
hiiamboris
07:45@toomasv collect set has a special meaning, like collect into

Oldes
14:22Is this useful?
>> a: ""  parse to-binary "ah" [collect into a keep 2 skip] a
== "#{6168}"
>> a: ""  parse to-binary "šo" [collect into a keep 2 skip] a
== "#{C5A1}"

Should not it be error like in this case?
>> a: #{} parse "1" [collect into a keep skip]
*** Script Error: PARSE - COLLECT INTO/AFTER expects a series! of compatible datatype
toomasv
14:27@hiiamboris

> collect set has a special meaning, like collect into

Ah, yes, thanks!
hiiamboris
14:29@Oldes I agree
greggirwin
15:34I agree as wel @Oldes.
toomasv
16:57But then (enforced compatibility) you would not be able to do this either
>> a: []  parse to-binary "ahhaa!" [collect into a [some keep skip]] a
== [97 104 104 97 97 33]

hiiamboris
17:15interesting trick
greggirwin
17:27So the char! into binary! case should *not* error? We do love our tricks and flexibility. Easier to make stricter on top.
Oldes
20:30It is not same.. there is difference having a as block and or string!
20:31And of course.. the main issue is with the unicode char of course

Oldes
12:24And which result makes more sense in this case?
x: 0  parse [][ 2 [(x: x + 1)] ]  x

Is it 1 or 2?
hiiamboris
12:511 if we know loops are stopped when they don't advance
2 if we make loops dumber
12:542 rule <=> 2 2 rule is a special case of N M rule, which we could require to evaluate N times unconditionally, and then depending on advancement
12:55can't see any drawbacks atm
Oldes
12:55In Rebol it is even without the block:
>> x: 0  parse [][ 2 (x: x + 1) ]  x
== 2
hiiamboris
12:56then it's a good argument for the change
12:56on the other hand,
x: 0 parse [][ 2 3 [(x: x + 1)] ] x in R2 returns 3
12:57so it doesn't even check for advancement?
Oldes
12:57Personally I don't think anybody is using this _feature_.
12:573 make sense.. in the above example:)
hiiamboris
12:58ok maybe so

snotbubble
13:35is there an equivalent of the Regex (^) in Parse?
having trouble detecting the a character at the start of a string while also skipping past an escape character, eg:
d: complement charset "\"
a: "+xx+ x\+y +yy+"
parse a [ 
  some [ 
    to [ d #"+" ] skip remove thru #"+" insert ("<s>") 
    to [ d #"+" ] skip remove thru #"+" insert ("</s>") 
  ] 
]
probe a
== "+xx<s> x\+y </s>yy<s>"

while if the beginning of the string (^) was in the bitset, it could return:
== "xx x\+y yy"
gurzgri
15:05No, "start of string" is not a character which can be part of a charset.

>> a: "+xx+ x\+y +yy+"
>> parse a [any ["\+" | change "+" "<s>" any ["\+" | not "+" skip] change "+" "</s>" | skip]] a
== "<s>xx</s> x\+y <s>yy</s>


You can test for head? with parse with e.g. [... pos: if (head? pos) ...] though. A rule will fail unless pos is at it's head.

snotbubble
03:29@gurzgri understood thanks... out of curiosity is there a benefit to using parse with nested loops vs vanilla Red in this case?
gurzgri
05:33The rule of thumb is: the parse solution is usually faster.
hiiamboris
07:16when interpreted
GiuseppeChillemi
08:47@hiiamboris how much is the difference between compiled and interpreted?
hiiamboris
08:49depends on your code
GiuseppeChillemi
08:50I have zero experience in parse, I have not material to test it.

GiuseppeChillemi
15:50I am doing my first experiment with Parse.
I would like to validate a specs block but I don't know how to check for datatype instead of a word in a subrule:

parse-ctx: context [
	datatypes: [any word!];<<<<--- need [any datatype!]
	specs: [word! ahead block! into datatypes]

]
spec: [x [word!] y [integer!]]
probe parse spec bind [
	any specs
] parse-ctx

greggirwin
16:10Looks can be deceiving:
>> type? first [integer!]
== word!
>> type? first reduce [integer!]
== datatype!
GiuseppeChillemi
16:49Gregg, I have learned this topic but I don't know to let parse get the word at check for it as datatype
16:49* and check
greggirwin
16:55You can look at help's source (specifically parse-func-spec), which reduces the type part of the spec (the block).

Oldes
21:16If we would like to swap map! and the construction syntax.. we can use something like:
swap-map-cons: function[src [string!]][
	bl: complement charset "[]"
	pb: complement charset "()#"
	cr:  [#"[" any bl opt cr #"]"]
	crn: [     any bl opt cr #"]"]
	mr:  [#"(" any pb opt tr #")"]
	mrn: [     any pb opt tr #")"]

	tr: [ any pb [
		#"#" s: [
		  #"[" (s/1: #"(") crn s: (s/-1: #")")
		| #"(" (s/1: #"[") mrn s: (s/-1: #"]")
		| tr
		]

	]]
	parse src [any tr]
	src
]

print swap-map-cons {
	#[none] #[f32! [1 3 4]] #[string! "aaa" 2]
	#(x: 1 y: #(a: 2 b: #[true]))
	#issue #{01}
	#[integer!]
}
21:17It would do the change also inside strings, but that should not be big problem.
hiiamboris
21:18https://gitlab.com/hiiamboris/red-cli/-/tree/master/mockups/mapconv
Oldes
21:20Hm.. my version looks shorter:)
hiiamboris
21:24My doesn't break strings & comments! ☻
Oldes
21:29It would not be hard to handle it... but I will rather go sleep... it would be an use-and-delete utility anyway.
21:36Btw.. I think the utility should change also strings and comments. Because if there is #[..] or #(..) in comments/strings, than it is the most probably commented out code, which also need conversion. I don't think I would find a comment inside my construction value.
hiiamboris
21:45Actually, nested strings are quite hard... (besides no one knows real lexing rules ;)
21:46I agree there are cases for that. But also e.g. charset "#(){}" you don't wanna mess things like that.
21:52gen-delims: charset ":/?#[]@" from red codebase
21:52Perhaps adding an option for comments is worth it though. I see a lot of single line comments with #[none] in my tests.
greggirwin
22:14Do the easy thing first, which gives the most value. Then analyze to see what's left.

GiuseppeChillemi
22:13How do I express: scan the whole block for THIS rule but if you find it twice, fail.
22:13I mean "if you have more than one match, fail".
hiiamboris
22:26rule opt [rule reject]?
22:27or rule not rule?
GiuseppeChillemi
22:41
>> rule: ['a integer!]
== ['a integer!]
>> parse [a 22 x x x x x b ] [rule opt [rule reject | skip]]
== false
>> parse [a 22 x x x x x a 33] [rule opt [rule reject | skip]]
== false
>>

The second should be true

The third should fail

22:42Usage: I need to check if a key present more than one time
22:42And also its next value
22:43As bonus, I whould like to check if the total of data keys are EVEN

toomasv
03:41@GiuseppeChillemi
b1: [a 1 x x] b2: [a 1 x x a 2] b3: [x a 1 x x b 2 z] b4: [a b x a 1 a c a a 2 x]
f: func [b] [parse b [any [check any [check (return false) | skip] | skip]] true]

>> f b1
== true
>> f b2
== false
>> f b3
== true
>> f b4
== false
>> b4: [a b x a 1 a c a a 2.5 x]
== [a b x a 1 a c a a 2.5 x]
>> f b4
== true
>> even? length? b4
== false
>> even? length? b1
== true
07:17
check: ['a integer!]
hiiamboris
08:17maybe you should read parse docs to understand what value parse returns or how to combine rules then
08:17
>> rule: [thru ['a integer!]]
>> parse [a 22 x x x x x b ] [rule not rule to end]
== true
>> parse [a 22 x x x x x a 33] [rule not rule to end]
== false
GiuseppeChillemi
08:22Parse is one of my last beasts. I have started to conquer VID, then will come a full work on parse.
hiiamboris
08:23push hard ;)
GiuseppeChillemi
08:24However, thru approach is dangerous for me:
08:27[a 2 b c 2] must fail as I want to process values by couples, where the first is always a word and skip by 2.
16:39@toomasv @hiiamboris I forgot to thank you.
23:16@toomasv

I was studying it your version but it has one problem:
check: ['a integer!]
f: func [b] [parse b [any [check any [check (return false) | skip] | skip]] true]

>> f [a b]
== true

It should return false.
23:35I have tried this:
>> f: func [b] [parse b [1 [check any [check (return false) | skip skip] | skip skip]]]

It works on:
>> f [a 2 b 2]
== true
f [a x]
== false

But it fails on:

f [a x b x a 2]
== false
 f [a x a 2 b x]
== false

Which should be true

toomasv
06:27@GiuseppeChillemi So single ['a integer!] should always be present, on any position? Maybe this:
f: function [b] [out: false parse b [some [check (if out [return false] out: true) | 2 skip | (out: false)]] out]
06:31What about [x a 1 x]? Should it succeed?
GiuseppeChillemi
06:33No, this should not succeed
06:37As for ['a integer! ] it must always be there 1 time and no more
toomasv
09:37So, how does the latest f perform?
GiuseppeChillemi
11:06I confess I am still in my bed surfing internet, I will try soon!
toomasv
11:24:joy:
GiuseppeChillemi
12:26@toomasv Ok, now I am out of my bed!

It works and I am continuing my experiments. I was trying to check split key/values passing a parse validation block.

split-words: func [
	word [word! object!]
	/local
	out-data
] [
	out-data: copy []
	if object? word [
		word: words-of word
		forall word [append out-data reduce [word/1 get word/1]]
	]
	if word? word [
		append out-data reduce [word get word] 
	]
	out-data
]
check-key: func [
	data [word! object! block!]
	check [block!]
] [
	either any [word? data object? data] [
		f split-words data check
	] [
		f data check
	]
	
]

This is the result on objects and blocks.
>> data: make object! [x: 22 c: 33 d: [a b c]] 
>> check-key data ['x integer!]
== true
>> check-key [a 88 x 22 d 33] ['x integer!]
== true

toomasv
17:34:+1:

GiuseppeChillemi
23:55How could append an additional button to panel p, below the x button?

view [
	p: panel 300x150 [
	x: button "hello" [append p/pane layout/only [button "world"]]
	]
]

toomasv
07:26@GiuseppeChillemi You *do* append it, just on top of x ;). Give it a different offset.
GiuseppeChillemi
20:41Ops, this is the reason why I was not finding it! I have sent to the wrong group!

bubnenkoff
08:34
flag: true
parse "foo" [ 
	some [
		"fo"
		(print "test")
		if (flag) break 	
		(print "here")

		]  
	]


08:35I want to stop parsing at getting some flag. is it good solution?
09:12strange that even with flag: false same behavior:
flag: false
parse "foo" [ 
    some [
        "fo"
        (print "test")
        if (flag) break     
        (print "here") ; not printing

        ]  
    ]
hiiamboris
16:25Do you want to stop some loop or terminate all parsing?
16:25If latter, the only solution is either return from a function or break from the loop or throw into catch.
16:27
loop 1 [
	parse "foo" [ 
	    some [
	        "fo"
	        (print "test")
	    	(if flag [break])     
	        (print "here") ; not printing
	
	        ]  
    ]
]

WayneCui
03:52Hello guys, some binary! data, 6-7 (0022) is the length of bytes (length is two bytes) I need to get to get a string, how can I do it in PARSE?
the result is com.caucho.hessian.test.TestObject, corresponding #{636F6D2E63617563686F2E6865737369616E2E746573742E546573744F626A656374}
03:52
;4D = 'M'
;74 = 't'
;7A = 'z'
data: #{7201004D740022636F6D2E63617563686F2E6865737369616E2E746573742E546573744F626A6563745300065F76616C756549000000007A7A}
 
probe collect [
    probe parse data [
        thru #{720100} thru "M"
        opt [
            thru "t" [
                ; copy len skip 4 (keep to integer! len)
            ]
        ]
        to end
    ]
]

03:56How can I express copy or set 2 bytes to a word! ?
04:11Make it! Just 2 skip instead of skip 2
04:11
data: #{7201004D740022636F6D2E63617563686F2E6865737369616E2E746573742E546573744F626A6563745300065F76616C756549000000007A7A}
 
probe parse data [
    thru #{720100} thru "M"
        opt [
            thru "t" [
                copy len 2 skip (n: to-integer len) copy class-name n skip (probe to-string class-name)
            ]
        ]   
]

greggirwin
04:37:+1: