• Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

AltME groups: search

Help · search scripts · search articles · search mailing list

results summary

worldhits
r4wp134
r3wp1094
total:1228

results window for this page: [start: 1101 end: 1200]

world-name: r3wp

Group: Parse ... Discussion of PARSE dialect [web-public]
BrianH:
19-Apr-2011
If you want to fail to an alternate, you can assign the block [end 
skip] to a variable that would normally be set to none, and then 
make references to that variable whenever you want to trigger a failure 
condition.
BrianH:
19-Apr-2011
opt-fail: none

parse "abc" [some [["a" | "b" | (opt-fail: [end skip])] opt-fail]]
Maxim:
26-Apr-2011
in R2,  the best way is to set a word to the value you're evaluating, 
and conditional to that value's pass/fail, you switch the following 
rule to allow it to continue or track back, so it matches another 
rule.


here is a rather verbose example.  note that this can be tweaked 
to be a shorter rule, but it becomes hard to map out how each part 
of the rules relate.. here, each part is clearly layed out.

rebol []


pass-rule: [none]
fail-rule: [thru end]

condition-rule: pass-rule



parse [
	word-a
	"ere"
	835
	word-b
	15
	word
	86
	bullshit
	#doglieru3
	word-c
][
	any [
		
		[
			; this rule only matches words ending with "-?"
			set val word! 
			[
				[
					(
						val: to-string val
						either #"-" = pick (back back tail val) 1  [
							condition-rule: pass-rule
						][
							condition-rule: fail-rule
						]
					)
					condition-rule
					(print ["PATTERN WORD:" val])
				]
				|[
					(print ["Arbitrary word: " val])
				]
			]
		]
		
		| skip
	]
]

ask ""
Steeve:
26-Apr-2011
R3 but obfuscated.

match: [
	  some [thru #"-"] skip end 	(print [w "end with -?"])
	| some [thru #"*"] end		(print [w "end with *"])
]

parse  [
	word-a 	"ere" 	835 	word-b 	15
	word* 	w86	bullshit*	#doglieru3 	word-c
][
	some [
 		  and change set w word! [(form w)]
		  change [do into match | skip] w
		| skip
	]
]
Ladislav:
27-Apr-2011
[thru end] is not a good rule to use to fail. A much more reasonable 
rule is [end skip]
Maxim:
27-Apr-2011
Lad   [thru end] means *exactly* the same thing as  [end skip].  
 I don't know why R3 decided to change that, but I find that a regression.
Ladislav:
27-Apr-2011
It does not, Max.

[thru end] is supposed to mean:

[end | skip]

, i.e. it fails in R2 only because of the faulty implementation
Ladislav:
27-Apr-2011
Err, correcting myself

a: [thru end] is supposed to mean the same as a: [end | skip a]
Ladislav:
27-Apr-2011
Just try the idiom

a: [b | skip a]

and you will see, that it always means the same as

a: [thru b]
Ladislav:
27-Apr-2011
Exactly like the idiom a: [b | skip a], which you did not even try
Maxim:
27-Apr-2011
well... to/thru are listed alongside  skip under "skipping input" 
in both r2 and r3 docs...  they cannot use sub rules, since they 
only do a find on the input.
Gregg:
27-Apr-2011
I wouldn't call it a trick John, just a non-obvious syntax. I haven't 
used it much, but I wrote a func a long time ago when I needed it 
for something.

literalize-int-rules: func [template /local mark] [
; Turn a single integer value into a quantity-of-one integer
; rule for parse (e.g. 1 becomes 1 1 1, 4 becomes 1 1 4).
	rule: [
		any [
			into rule
			| mark: integer! (insert mark [1 1]) 2 skip 
			| skip
		]
	]
	parse template rule
	template
]
Maxim:
29-Apr-2011
rebol []

=tags=: [ "[a]" | "[b]" | "[cc]" ] 
    
data: "xxxx[a]aa aa[b]xxxx[a] yyyy[d]yyy[cc]dd[e]ddd[b][A]zz[zz"


blk: []
parse/all data [
	start:
	any [
		here: copy tag =tags= there: (
			append blk copy/part start here
			append blk tag
		) start:

		| skip
	]
	(append blk start)
]

?? blk

ask ""
Steeve:
29-Apr-2011
even if, just replace 
>skip
by 
> skip opt to "["
(not tested)
Steeve:
29-Apr-2011
>[skip to "[" | to end]
should be even better
Steeve:
29-Apr-2011
> [skip to "[" | end skip]
skip an extra loop by exiting with a fail
BrianH:
1-May-2011
By "It could be considered a useful feature" I mean that if this 
were not allowed, you would have to write this:
    parse data [set x ['a 'b]]
like this instead:
    parse data [and ['a 'b] set x skip skip]
Geomol:
1-May-2011
I've thought some more about [thru end], which return false in the 
R2 version, but return true in R3. My version return false as R2, 
but I better understand the R3 way, now I've programmed it. It can 
be seen as, how THRU should be understood (, as also Ladislav said 
something about)? Do we think of

[thru rule]
as
[to rule rule] or
[to rule skip]

? If the TO keyword can handle complex rules like:
parse [a b] [to ['a 'b] ['a 'b]]

then the first might make better sense, and [thru end] should return 
true. But we can't parse like that in R2, so maybe we think more 
of it as the second, and then [thru end] should return false. But 
if you look in my version, I have to catch this special case, where 
END follows THRU, so it takes more code, which isn't good.


In any case, Ladislav's suggestion to use [end skip] as a fail rule 
is much better. If you're not at the end, the first word (end) will 
give false, else the next will fail, as you can't skip past end.
Geomol:
1-May-2011
I think about downgrading. :-) You know, keep it simple. Like dropping 
SKIP as it's the same as any-type! etc. If I want SKIP, I can just 
define it then: skip: :any-type!
Geomol:
1-May-2011
Having skip as a keyword mean, you can't use that word as a variable.
BrianH:
1-May-2011
Most people tend to not use 'skip as a variable anyways, because 
of the SKIP function.
Ladislav:
1-May-2011
Geomol:

    [to rule skip]

does not mean the same as

    [thru rule]

, as can be demonstrated when comparing the behaviour of

   thru rule

for 

    rule = "abc"

It is quite a surprise for me, that you don't see the difference.
Geomol:
2-May-2011
In R2 parsing a block:

>> parse ["abc"] [to "abc" skip]
== true
>> parse ["abc"] [thru "abc"]   
== true


I know, it's different when parsing a string instead of a block. 
My comparison of [thru rule] to the alternatives was meant as a loose 
comparison, not to be taken literally. So it's easy to think of THRU 
to work this way, because it does in many cases, therefore the confusion.
Ladislav:
2-May-2011
But, the recursive description:

    a: [b | skip a]

is quite natural.
Geomol:
2-May-2011
Yes, and that should work in all cases, if the b rule is found, complex 
or not. And this will return true, if b is END, because  END is a 
repeatable rule (you can't go past it with SKIP).


NONE is also repeatable, and if you look in the code, I have to take 
care of this too separately. This mean, we can't parse none of datatype 
none! by using the NONE keyword, but we can using a datatype:

>> parse reduce [none] [none] 
== false
>> parse reduce [none] [none!]
== true


So it raises the question, if the NONE keyword should be there? What 
are the consequences, if we drop NONE as a keyword? And are there 
other repeatable rules beside END and NONE? In R2 or R3.
Geomol:
4-May-2011
[any end]Êand [some end]

As we don't have warnings, I suggest these to produce errors. They 
can produce endless loops, and that should be pointed out in the 
docs, if they don't produce errors.
[opt end]

Yes, it's legit, but what's the point of this combination? At best, 
the programmer knows, what she does, and the combination will do 
nothing else than slowing the program down. At worst, the programmer 
misinterpret this combination, and since it doesn't produce an error 
or anything, it's a source of confusion. I suggest to make it produce 
an error.
[into end]
Produces an error today, so fine.
[set end ...] and [copy end ...]

I wasn't thinking of [set var end], but about setting a var named 
end to something, like [set end integer!]. Problem with this is, 
that now the var, end, can be used and looks exactly like the keyword, 
end, maybe leading to confusion. But after a second thought, maybe 
this being allowed is ok.
[thru end]

Making this produce an error will solve the problem with the confusion 
around, what this combination mean. And in the first place, it's 
a bad way to produce a 'fail' rule (in R2, in R3 it has the value 
true, and parsing continues). It's slow compared to e.g. [end skip].
BrianH:
4-May-2011
If you're going to make a better parse, it might be good to take 
into account the efforts that have already started to improve it 
in R3. The R3 improvements need a little work in some cases, but 
the thought that went into the process is quite valuable.


[set end ...] or [copy end ...]: In R3, using any PARSE keyword (not 
just 'end) in a rule for other reasons triggers an error.
>> parse [a] [set end skip]
** Script error: PARSE - command cannot be used as variable: end

[any end] or [some end]: What Ladislav said.


[opt end]: The point of the combination is [opt [end (do something)]]. 
[opt anything] is no more useless than [opt end]. Don't exclude something 
that has no effect just for that reason. Remember, [none] has no 
effect as well, but it's still valuable for making rules more readable.
Geomol:
31-Oct-2011
ne: ["←" | "↵"]	; and the rest of the named entities
s: "To send, press the ← arrow & then press ↵."
parse s [
	any [
		to #"&" [ne | skip mark: (insert mark "amp;")]
	]
]
s

== {To send, press the ← arrow & then press ↵.}
Ladislav:
31-Oct-2011
I guess, that this should be efficient:

alpha: make bitset! [#"a" - #"z" #"A" - #"Z"]
escape-amps: func [
	text [string!]
	entities [hash!]
	/local result pos1 pos2
][
	result: copy ""
	parse/all text [
		pos1:
		any [
			; find the next amp
			thru #"&"
			pos2:
			[
				; entity check
				some alpha pos3: #";" (
					; entity candidate
					unless find entities copy/part pos2 pos3 [
						; not an entity
						insert insert tail result copy/part pos1 pos2 "amp;"
						pos1: pos2
					]
				)
				| (
					; not an entity
					insert insert tail result copy/part pos1 pos2 "amp;"
					pos1: pos2
				)
			]
			| (insert tail result pos1) end skip ; no amp found
		]
	]
	result
]
Ladislav:
31-Oct-2011
This alternative does not use the COPY call, so, it has to be faster:

alpha: make bitset! [#"a" - #"z" #"A" - #"Z"]
escape-amps: func [
	text [string!]
	entities [hash!]
	/local result pos1 pos2 pos3
][
	result: copy ""
	parse/all text [
		pos1:
		any [
			; find the next amp
			thru #"&"
			pos2:
			[
				; entity check
				some alpha pos3: #";" (
					; entity candidate
					unless find entities copy/part pos2 pos3 [
						; not an entity
						insert insert/part tail result pos1 pos2 "amp;"
						pos1: pos2
					]
				)
				| (
					; not an entity
					insert insert/part tail result pos1 pos2 "amp;"
					pos1: pos2
				)
			]
			| (insert tail result pos1) end skip ; no amp found
		]
	]
	result
]
PeterWood:
1-Nov-2011
Perhaps building a parse rule from the list of entities may be faster 
if there is a lot of text to process:

This assumes the entities are provided as strings in a block.

escape-amps: func [

  text [string!]

  entities [block!]

][
  
  skip-it: complement charset [#"&"]

  entity: copy []

  foreach ent entities [ insert entity compose [(ent) |]]

  head remove back tail entity

  parse/all text 
[
    any [

      entity |

      "&" pos: (insert pos "amp;" pos: skip pos 4) :pos |

      some skip-it
     ]

  ]

  head tex
t
]
PeterWood:
1-Nov-2011
Also I feel using skip could be very slow if the text contains a 
lot of "non-matching text". The "skip-it" technique could also be 
applied to Ladislav's code.
Ladislav:
1-Nov-2011
'The "skip-it" technique could also be applied to Ladislav's code.' 
- I do not think so
Endo:
1-Dec-2011
I want to keep the digits and remove all the rest,

t: "abc56xyz" parse/all t [some [digit (prin "d") | x: (prin "." 
remove x)]] print head t

this do the work but never finish. If I add a "skip" to the second 
part the result is "b56y".
How do I do?
Endo:
1-Dec-2011
I just did the same thing:


t: "abc56xyz" parse/all t [some [x: non-digit (prin first x remove 
x x: back x) :x | skip]] head t
Endo:
1-Dec-2011
a bit more clear:

t: "abc56xyz" parse/all t [some [x: non-digit (x: back remove x) 
:x | skip]] head t
Endo:
1-Dec-2011
Oh I think no need to "back"

t: "abc56xyz" parse/all t [some [x: non-digit (remove x) :x | skip]] 
head t
Dockimbel:
1-Dec-2011
Endo: in your first attempt, your second rule in SOME block is not 
making the input advance when the end of the string is reached because 
(remove "") == "", so it enters an infinite loop. A simple fix could 
be:


t: "abc56xyz" parse/all t [any [digit (prin "d") | x: skip (prin 
"." remove x) :x]]


(remember to correctly reset the input cursor when modifying the 
parsed series) 


As others have suggested, they are more optimal ways to achieve this 
trimming.
Endo:
1-Dec-2011
Strange but I tried to remove the whole part in one time, but its 
slower than the other:


aaa: [t: "abc56def7" parse/all t [some [x: some non-digit y: (remove/part 
x y) :x | skip]] head t]

bbb: [t: "abc56def7" parse/all t [some [x: non-digit (remove x) :x 
| skip]] head t]
>> benchmark2 aaa bbb ;(executes block 10'000'000 times.)
Execution time for the #1 job: 0:00:11.719
Execution time for the #2 job: 0:00:11.265
#1 is slower than #2 by factor ~ 1.04030181979583
Gregg:
2-Dec-2011
load-csv: func [
        "Parse newline delimited CSV records"
        input [file! string!]
        /local p1 p2 lines
    ] [
        lines: collect line [
            parse input [

                some [p1: [to newline | to end] p2: (line: copy/part p1 p2) skip]
            ]
        ]
        collect/only rec [
            foreach line lines [
                if not empty? line [rec: parse/all line ","]
            ]
        ]
    ]
BrianH:
20-Dec-2011
Be careful, if you don't quote string values then the character set 
of your values can't include cr, lf or your delimiter. It requires 
so many changes that it would be more efficient to add new formatter 
functions to the associated FUNCT/with object, then duplicate the 
code in TO-CSV that calls the formatter. Like this:

to-csv: funct/with [
	"Convert a block of values to a CSV-formatted line in a string."
	data [block!] "Block of values"

 /with "Specify field delimiter (preferably char, or length of 1)"
	delimiter [char! string! binary!] {Default ","}
	; Empty delimiter, " or CR or LF may lead to corrupt data
	/no-quote "Don't quote values (limits the characters supported)"
] [
	output: make block! 2 * length? data
	delimiter: either with [to-string delimiter] [","]
	either no-quote [
		unless empty? data [append output format-field-nq first+ data]

  foreach x data [append append output delimiter format-field-nq :x]
	] [
		unless empty? data [append output format-field first+ data]
		foreach x data [append append output delimiter format-field :x]
	]
	to-string output
] [
	format-field: func [x [any-type!] /local qr] [

  ; Parse rule to put double-quotes around a string, escaping any inside

  qr: [return [insert {"} any [change {"} {""} | skip] insert {"}]]
		case [
			none? :x [""]
			any-string? :x [parse copy x qr]
			:x = #"^(22)" [{""""}]
			char? :x [ajoin [{"} x {"}]]
			money? :x [find/tail form x "$"]
			scalar? :x [form x]
			date? :x [to-iso-date x]

   any [any-word? :x binary? :x any-path? :x] [parse to-string :x qr]
			'else [cause-error 'script 'expect-set reduce [

    [any-string! any-word! any-path! binary! scalar! date!] type? :x
			]]
		]
	]
	format-field-nq: func [x [any-type!]] [
		case [
			none? :x [""]
			any-string? :x [x]
			money? :x [find/tail form x "$"]
			scalar? :x [form x]
			date? :x [to-iso-date x]
			any [any-word? :x binary? :x any-path? :x] [to-string :x]
			'else [cause-error 'script 'expect-set reduce [

    [any-string! any-word! any-path! binary! scalar! date!] type? :x
			]]
		]
	]
]


If you want to add error checking to make sure the data won't be 
corrupted, you'll have to pass in the delimiter to format-field-nq 
and trigger an error if it, cr or lf are found in the field data.
Group: !REBOL3 GUI ... [web-public]
Ashley:
25-Jan-2010
ctx-rebgui3: make object! [

	cursors: make object! [
		app-start: 32650
		hand: 32649
		help: 32651
		hourglass: 32650
		arrow: 32512
		cross: 32515
		i-shape: 32513
		no: 32648
		size-all: 32646
		size-nesw: 32643
		size-ns: 32645
		size-nwse: 32642
		size-we: 32644
		up-arrow: 32516
		wait: 32514
	]

	colors: make object! [
		page: white
		edit: white
		text: black
		true: leaf
		false: red
		link: blue
		theme: [165.217.246 0.105.207 0.55.155]
		outline: [207.207.207 160.160.160 112.112.112]
	]

	metrics: make object! [
		cell: 4
		gap: cell * 2
		line: cell * 5
		margin: cell * 4
		margin-size: as-pair margin margin
		radius: 2
	]

	;	Private functions

	set 'make-gob make function! [[

  spec [block!] ; offset, size and one or more attribute/value pairs
		/data object
		/local size text gob axis
	][
		size: spec/2
		if any [negative? size/x negative? size/y] [
			text: select spec 'text
			all [block? text text: first find text string!]

   size: 8x4 + size-text make gob! compose [size: 9999x9999 text: (text)]
			all [negative? spec/2/x spec/2/x: size/x]
			all [negative? spec/2/y spec/2/y: size/y]
		]
		gob: copy []
		;	attributes are (text, color, effect, image and draw)
		foreach [attribute value] spec [
			switch attribute [
				box [
					attribute: 'draw
					value: compose [
						pen (get value/1)
						line-width 1
						fill-pen (get value/2)
						box 0x0 (spec/2 - 1x1) (metrics/radius)
					]
				]
				pill [
					attribute: 'draw
					axis: either spec/2/x >= spec/2/y [2] [1]
					value: compose/deep [
						pen (colors/outline/3)
						line-width 1

      grad-pen linear (spec/2/:axis * .1) (spec/2/:axis * .9) (all [axis 
      = 2 90]) [(colors/outline/1) (white) (colors/outline/1)]
						box 0x0 (spec/2 - 1x1) (metrics/radius)
					]
				]
			]
			append gob reduce [attribute value]
		]
		spec: gob

  gob: make gob! compose [offset: spec/1 size: spec/2 (to set-word! 
  spec/3) spec/4 data: (make object! any [object copy []])]
		foreach [attribute value] skip spec 2 [

   append gob make gob! compose [offset: 0x0 size: spec/2 (to set-word! 
   attribute) value]
		]
		gob
	]]

	;	Public functions

	set 'display make function! [[
		title spec

  /local gob xy max-x max-y left-to-right? after-count after-limit 
  here arg append-widget widget last-widget word
		action
		handler
		size
		text
		color
	][
		xy: metrics/margin-size
		max-x: xy/x
		max-y: xy/y
		left-to-right?: true
		after-count: 1
		after-limit: 9999
		
		gob: make gob! compose [text: (title) data: (make object! [])]

		append-widget: make function! [[][
			unless widget [exit]
			unless handler [

    handler: compose/deep [on-down: make function! [[event][(action)]]]
			]
			append gob switch widget [
				bar [

     make-gob compose [(xy) (as-pair max-x - metrics/margin 1) color (colors/outline/3)]
				]
				button [
					all [none? size size: 15x5]

     make-gob/data compose/deep [(xy) (size * metrics/cell) pill none 
     text [center (text)]] handler
				]
				text [
					all [none? size size: 15x5]

     make-gob/data compose/only [(xy) (size * metrics/cell) color (white) 
     text (text)] handler
				]
			]
			last-widget: last gob/pane
			;	1st reverse item?
			unless left-to-right? [

    last-widget/offset/x: last-widget/offset/x - last-widget/size/x
			]
			xy: last-widget/offset
			;	max vertical size
			max-y: max max-y xy/y + last-widget/size/y
			;	horizontal pos adjustments
			all [
				left-to-right?
				xy/x: xy/x + last-widget/size/x
				max-x: max max-x xy/x
			]
			;	after limit reached?
			either after-count < after-limit [
				;	spacing

    xy/x: xy/x + either left-to-right? [metrics/gap] [negate metrics/gap]
				++ after-count
			] [
				xy: as-pair metrics/margin max-y + metrics/gap
				after-count: 1
			]
			all [:word set :word last-widget]
			word: widget: action: handler: size: text: color: none
		]]


  parse reduce/only spec [after bar button handler return reverse rich 
  text] [
			any [
				opt [here: set arg paren! (here/1: do arg) :here] [
					'return (
						append-widget
						xy: as-pair metrics/margin max-y + metrics/gap
						left-to-right?: true
						after-limit: 9999
					)
					| 'reverse (
						append-widget
						xy: as-pair max-x max-y + metrics/gap
						left-to-right?: false
						after-limit: 9999
					)
					| 'after set arg integer! (
						;	return unless this is first widget
						if widget [
							append-widget
							xy: as-pair metrics/margin max-y + metrics/gap
						]
						after-count: 1
						after-limit: arg
					)
					| 'handler set arg block! (handler: arg)
					| 'rich set arg block! (text: arg)
					| [set arg integer! | set arg pair!] (size: arg)
					| set arg string! (text: arg)
					| [set arg tuple! | set arg none!] (color: arg)
					| set arg block! (action: arg)
					| set arg set-word! (append-widget word: :arg)
					| set arg word! (append-widget widget: arg)
				]
			]
		]

		append-widget
		gob/size: metrics/margin-size + as-pair max-x max-y
		gob/offset: system/view/metrics/work-size - gob/size / 2
		append system/view/screen-gob gob
		show system/view/screen-gob
	]]

	set 'undisplay make function! [[gob][
		remove find system/view/screen-gob gob
		show system/view/screen-gob
	]]

	;	Start global GUI event handler

	active-gob: none
	system/view/event-port: open [scheme: 'event]

 system/view/event-port/awake: make function! [[event /local evt gob][
		evt: map-event event
		gob: evt/gob
		while [not object? gob/data] [gob: gob/parent]
		if all [event/type = 'move gob <> active-gob] [
			attempt [active-gob/data/on-away event]
			active-gob: gob
			attempt [active-gob/data/on-over event]
		]
		evt: to word! ajoin ['on- event/type]
		attempt [gob/data/:evt event]
	]]
]
Steeve:
3-Mar-2010
Henrik, in your last try, if you skip some time events  then the 
animation slow down but it's eating only 50% of my cpu (a small celeron).

tick: 0
...
handler: func [event] [
	switch event/type [
		time [
			++ tick
			if all [picked-obj tick > 30] [ 
				tick: 0
...

Rebol is slow for such animations
Henrik:
10-Mar-2010
BrianH, yes, that would be a work around, so I'm not using triggers.


I've written a GET-DB-PANEL function now that fulfill the specs, 
including SKIP, TABLE, _DATA, scoping, etc. This function is custom 
to RM-Asset, so I'm not sure we want it in the R3 GUI other than 
as an extension package.


Also, I've written an EMIT reactor that emits the panel in GET-DB-PANEL's 
object format as an SQLite record (predefined object).

I'm using options for now along with GET-DB-PANEL.

What this shows:

- Writing reactores is easy peasy.
- Using reactors is even easier.

- Doesn't break anything in the R3 GUI, if you GET-PANEL instead 
of GET-DB-PANEL.

An example of how this is used:

rec: make object! [] ; the SQLite database record object

view [
	form-panel: panel 1 [
		id: field options [skip: true]		; write-only field
		name: field				; stored in the object as 'name
		age: field				; stored in the object as 'age

  note: field options [_data: true]	; both these will be stored in 
  the _data map!
		bytheway: field options [_data: true]
	] options [record: 'rec]
	button "Emit" emit 'form-panel
	button "Submit" submit 'form-panel %form.txt
	button "Acquire" acquire 'form-panel %form.txt
]

So when you press Emit, 'rec will be set to:

make object! [
	name: ""
	age: ""
	_data: make map! [
		note: ""
		bytheway: ""
	]
]

If you press Submit, this object is made:

make object! [
	id: ""
	name: ""
	age: ""
	note: ""
	bytheway: ""
]

and is stored on disk with the name %form.txt


If you press Acquire, the above mentioned object is automatically 
loaded from disk and into the form.


Still need a one-liner for loading SQLite data into the form. Going 
to work on that now.
Steeve:
12-Mar-2010
recycle/ballast 50000
screen: system/view/screen-gob
system/view/event-port: open event://
font1: make system/standard/font [size: 20]
fire: [
	line-width 0.5 pen black fill-pen white line-pattern white 
	text vectorial 0x70 [font font1 bold "F I R E !!!"]
]

insert strokes: skip find fire 'line-pattern 2 rand: [0 0 1 1 2 3 
3 4 4 5]
img: make image! xy: 100x100

show append screen gob: make gob! [offset: xy size: xy image: img]

forever [
	change img copy/part skip img 0x1 100x76
	change strokes random rand
	draw img fire
	effect img [blur difference 2.5.10]
	wait 0.03
	show gob
]
Steeve:
13-Mar-2010
recycle/ballast 50000
screen: system/view/screen-gob
system/view/event-port: open event://
font1: make system/standard/font [size: 20]
insert strokes: skip fire: [
	image img (first random [1x-2 0x-2 1x-2 0x-2 -1x-2])
	line-width 0.5 pen red fill-pen white line-pattern black 
	text vectorial 0x40 [font font1 bold "F I R E !!!"]
] 'line-pattern 2 rand: [0 1 1 1 2 5 ]
img: make image! xy: 100x70

show append screen gob: make gob! [offset: xy size: xy image: img]
forever [
	change strokes random rand
	draw img fire
	effect img [difference 3.5.8 blur img]
	wait 0.05 show gob
]
Pekr:
13-Mar-2010
Script: "Untitled" Version: none Date: none

** Script error: skip does not allow word! for its offset argument
** Where: catch either either applier do
** Near: catch/quit either var [[do/next data var]] [data]
Steeve:
13-Mar-2010
insert strokes: skip find fire: [
amacleod:
13-Mar-2010
Steeve, above script does not run for me using latest R3...

Script error: skip does not allow word! for its offset argument

first version works though..
Steeve:
13-Mar-2010
insert strokes: skip find fire: [
Henrik:
30-Sep-2010
A basic example of how it looks right now:

f: view [
	form-panel: panel 2 [
		group 1 [
			title "Record fields"
			bar
			group 2 [
				label "Name"		name: field		; stored as name
				label "Address"	address: field	; stored as address
				label "Age"		age: field		; stored as age

    label "Skipped"	skip-field: field options [skip: true]	; not in the 
    list
				label "Ignored"	field			; not in the list
			]
		]
	] options [record: 'rec]
	group 6 [
		button "New" obtain 'form-panel add-record
		button "Save" emit 'form-panel update-record
		button "Delete" do [delete-record]
		pad
		button "<" obtain 'form-panel next-record
		button ">" obtain 'form-panel previous-record
	]
]


The 'rec is a record object, which is filled with data from the server, 
using the backend function, and when submitting, is used to gather 
data from the form and into the server.
Pekr:
30-Sep-2010
what is 'skip for the field? Is it for tabbing to ingore the field?
Henrik:
30-Sep-2010
The trick is that a panel acts like a record. You specify the record 
object in OPTIONS. Then any named field, checkbox, slider or whatever 
participates in the record unless the option SKIP is true.
Henrik:
30-Sep-2010
SKIP allowed reading the record, but not writing back changes, such 
as a "last updated" field, which you don't want to write back.
Henrik:
30-Sep-2010
The SKIP and RECORD options are scoping, so if you define a panel 
with SKIP, everything inside it is skipped on EMIT.
Pekr:
12-Oct-2010
I hope soon enough we will be able to see fully working area, navigation 
by keyboard, tabbing system (including the ability to set the order, 
skip certain widgets, etc.), styles like tabs, tree (fully keyboard 
navigation support), table/grid (ditto). With those three styles, 
we can be kings ....
Robert:
15-Oct-2010
The thing is: Either the number is like a SKIP refinement or like 
the number for LOOP
Robert:
15-Oct-2010
IMO SKIP is more useful as it eleminates explict NEWLINE items.
GrahamC:
4-Mar-2011
Script: "Include" Version: $Id$ Date: 27-Oct-2010/9:57:54+2:00

** Script error: skip does not allow none! for its series argument

** Where: unless actor all foreach do-style if if actor all foreach 
do-style act

or all foreach do-style actor all foreach do-style either if either 
do-event do-

event either -apply- wake-up loop -apply- wait do-events if view 
catch either ei
ther -apply- do
** Near: unless any [
    not arg/1
    0 >= (pos: arg/1 - parent/sta...
GrahamC:
4-Mar-2011
( fix by allow none for skip argument! )
Group: !REBOL3 ... [web-public]
Geomol:
7-Jun-2011
Also look at:

>> s: "abc"
== "abc"
>> insert/only s skip s 2
== 		; some crap in R3, so check R2 here.
>> s
== "cabc"
Geomol:
7-Jun-2011
Right.

For blocks, inserting doens't change position of other indexes to 
same series. What I expect, is that the insert is from the index 
given, before the insert is carried out. Like:

>> s: [a b c]
>> insert/only s skip s 2
should result in
	[[c] a b c]

, where the first element is a pointer to one before the end of s, 
not two before the end of s as we have today.
Endo:
7-Jun-2011
Here is the trace log (R2)
>> s: [a b c]
== [a b c]
>> trace on
Result: (unset)
>> insert/only s skip s 2
Trace:  insert/only (path)
Trace:  s (word)
Trace:  skip (word)
Trace:  s (word)
Trace:  2 (integer)
Result: [c] (block)
Gregg:
17-Jul-2011
I don't know where the test suite for SPLIT is, but the rule in effect 
for that changed from the old source that Gabriele and I originally 
created. The final rule, for string/char/bitset delimiters was originally 
this:


    [any [mk1: some [mk2: dlm break | skip] (emit copy/part mk1 mk2)]]

but is now this:


    [any [mk1: [to dlm mk2: dlm | to end mk2:] (keep copy/part mk1 mk2)]]


It looks like that changed due to http://issue.cc/r3/573, but obviously 
wasn't run through a test suite. I don't know what caused the issue 
with the above bug, as that parse rule returns a correct result.
Gregg:
17-Jul-2011
The original was written before MAP-EACH and the new COLLECT. Here 
is the source I have, updated to use those as the current version 
does, but with the last rule reverted to the original.

Related cc reports: 
    http://issue.cc/r3/1096
    http://issue.cc/r3/690

split: func [

    "Split a series into pieces; fixed or variable size, fixed number, 
    or at delimiters"
    series	[series!] "The series to split"

    dlm		[block! integer! char! bitset! any-string!] "Split size, delimiter(s), 
    or rule(s)." 

    /into	"If dlm is an integer, split into n pieces, rather than pieces 
    of length n."
    /local size count mk1 mk2
][
    either all [block? dlm  parse dlm [some integer!]] [
            map-each len dlm [
                either positive? len [
                    copy/part series series: skip series len
                ] [
                    series: skip series negate len

                    ; return unset so that nothing is added to output
                    ()
                ]
            ]
    ][
        size: dlm   ; alias for readability
        collect [
            parse/all series case [
                all [integer? size into] [

                    if size < 1 [cause-error 'Script 'invalid-arg size]
                    count: size - 1
                    size: round/down divide length? series size
                    [

                        count [copy series size skip (keep/only series)]
                        copy series to end (keep/only series)
                    ]
                ]
                integer? dlm [

                    if size < 1 [cause-error 'Script 'invalid-arg size]

                    [any [copy series 1 size skip (keep/only series)]]
                ]

                'else [ ; = any [bitset? dlm  any-string? dlm  char? dlm]

                    [any [mk1: some [mk2: dlm break | skip] (keep copy/part mk1 mk2)]]
                ]
            ]
        ] 
    ]
]
Gregg:
17-Jul-2011
Another bug has crept in somewhere along the way:

    series: skip series negate len


The NEGATE messes up the skip of the already negative value, which 
breaks cases like this:

    >> split [1 2 3 4 5 6] [3 2 2 -2 2 -4 3]
    == [[1 2 3] [4 5] [6] [5 6] [3 4 5]]
Gregg:
17-Jul-2011
split: func [

    "Split a series into pieces; fixed or variable size, fixed number, 
    or at delimiters"
    series	[series!] "The series to split"

    dlm		[block! integer! char! bitset! any-string!] "Split size, delimiter(s), 
    or rule(s)." 

    /into	"If dlm is an integer, split into n pieces, rather than pieces 
    of length n."

    /local size piece-size count mk1 mk2 res fill-val add-fill-val
][
    either all [block? dlm  parse dlm [some integer!]] [
        map-each len dlm [
            either positive? len [
                copy/part series series: skip series len
            ] [
                series: skip series len
                ; return unset so that nothing is added to output
                ()
            ]
        ]
    ][
        size: dlm   ; alias for readability
        res: collect [
            parse/all series case [
                all [integer? size  into] [

                    if size < 1 [cause-error 'Script 'invalid-arg size]
                    count: size - 1

                    piece-size: to integer! round/down divide length? series size
                    if zero? piece-size [piece-size: 1]
                    [

                        count [copy series piece-size skip (keep/only series)]
                        copy series to end (keep/only series)
                    ]
                ]
                integer? dlm [

                    if size < 1 [cause-error 'Script 'invalid-arg size]

                    [any [copy series 1 size skip (keep/only series)]]
                ]

                'else [ ; = any [bitset? dlm  any-string? dlm  char? dlm]

                    [any [mk1: some [mk2: dlm break | skip] (keep/only copy/part mk1 
                    mk2)]]
                ]
            ]
        ]

        ;-- Special processing, to handle cases where the spec'd more items 
        in

        ;   /into than the series contains (so we want to append empty items),

        ;   or where the dlm was a char/string/charset and it was the last 
        char

        ;   (so we want to append an empty field that the above rule misses).
        fill-val: does [copy either any-block? series [[]] [""]]
        add-fill-val: does [append/only res fill-val]
        case [
            all [integer? size  into] [

                ; If the result is too short, i.e., less items than 'size, add
                ; empty items to fill it to 'size.

                ; We loop here, because insert/dup doesn't copy the value inserted.
                if size > length? res [
                    loop (size - length? res) [add-fill-val]
                ]
            ]
            ; integer? dlm [
            ; ]

            'else [ ; = any [bitset? dlm  any-string? dlm  char? dlm]

                ; If the last thing in the series is a delimiter, there is an

                ; implied empty field after it, which we add here.
                case [
                    bitset? dlm [

                        ; ATTEMPT is here because LAST will return NONE for an 

                        ; empty series, and finding none in a bitest is not allowed.

                        if attempt [find dlm last series] [add-fill-val]
                    ]
                    char? dlm [
                        if dlm = last series [add-fill-val]
                    ]
                    string? dlm [
                        if all [
                            find series dlm
                            empty? find/last/tail series dlm
                        ] [add-fill-val]
                    ]
                ]
            ]
        ]
                
        res
    ]
]
Gregg:
17-Jul-2011
A quick scan of the docs showed that negative skip val usage changed 
from the original design. I will revert the negate on those to match 
the doc'd behavior.
Gregg:
17-Jul-2011
split: func [

    "Split a series into pieces; fixed or variable size, fixed number, 
    or at delimiters"
    series	[series!] "The series to split"

    dlm		[block! integer! char! bitset! any-string!] "Split size, delimiter(s), 
    or rule(s)." 

    /into	"If dlm is an integer, split into n pieces, rather than pieces 
    of length n."

    /local size piece-size count mk1 mk2 res fill-val add-fill-val
][
    either all [block? dlm  parse dlm [some integer!]] [
        map-each len dlm [
            either positive? len [
                copy/part series series: skip series len
            ] [
                series: skip series negate len
                ; return unset so that nothing is added to output
                ()
            ]
        ]
    ][
        size: dlm   ; alias for readability
        res: collect [
            parse/all series case [
                all [integer? size  into] [

                    if size < 1 [cause-error 'Script 'invalid-arg size]
                    count: size - 1

                    piece-size: to integer! round/down divide length? series size
                    if zero? piece-size [piece-size: 1]
                    [

                        count [copy series piece-size skip (keep/only series)]
                        copy series to end (keep/only series)
                    ]
                ]
                integer? dlm [

                    if size < 1 [cause-error 'Script 'invalid-arg size]

                    [any [copy series 1 size skip (keep/only series)]]
                ]

                'else [ ; = any [bitset? dlm  any-string? dlm  char? dlm]

                    [any [mk1: some [mk2: dlm break | skip] (keep/only copy/part mk1 
                    mk2)]]
                ]
            ]
        ]

        ;-- Special processing, to handle cases where the spec'd more items 
        in

        ;   /into than the series contains (so we want to append empty items),

        ;   or where the dlm was a char/string/charset and it was the last 
        char

        ;   (so we want to append an empty field that the above rule misses).
        fill-val: does [copy either any-block? series [[]] [""]]
        add-fill-val: does [append/only res fill-val]
        case [
            all [integer? size  into] [

                ; If the result is too short, i.e., less items than 'size, add
                ; empty items to fill it to 'size.

                ; We loop here, because insert/dup doesn't copy the value inserted.
                if size > length? res [
                    loop (size - length? res) [add-fill-val]
                ]
            ]
            ; integer? dlm [
            ; ]

            'else [ ; = any [bitset? dlm  any-string? dlm  char? dlm]

                ; If the last thing in the series is a delimiter, there is an

                ; implied empty field after it, which we add here.
                case [
                    bitset? dlm [

                        ; ATTEMPT is here because LAST will return NONE for an 

                        ; empty series, and finding none in a bitest is not allowed.

                        if attempt [find dlm last series] [add-fill-val]
                    ]
                    char? dlm [
                        if dlm = last series [add-fill-val]
                    ]
                    string? dlm [
                        if all [
                            find series dlm
                            empty? find/last/tail series dlm
                        ] [add-fill-val]
                    ]
                ]
            ]
        ]
                
        res
    ]
]
Gregg:
17-Jul-2011
; Old design for negative skip vals

;test [split [1 2 3 4 5 6] [3 2 2 -2 2 -4 3]]    [[1 2 3] [4 5] [6] 
[5 6] [3 4 5]]
; New design for negative skip vals
test [split [1 2 3 4 5 6] [2 -2 2]]             [[1 2] [5 6]]
Steeve:
18-Jul-2011
Well, I just read the code.

You replaced this:

    [any [mk1: some [mk2: dlm break | skip] (emit copy/part mk1 mk2)]]
by this:

    [any [mk1: [to dlm mk2: dlm | to end mk2:] (keep copy/part mk1 mk2)]]


In the first case: the rule is used to extract the matching sequences

In the second case, the rule is used to exclude the matching sequences.
Gregg:
19-Jul-2011
The original design used negative numbers to skip backwards. I don't 
think I changed the design, but I understand the reasoning behind 
how they work now. Keywords were probably not used as it would have 
complicated the dialect. Well, it would have made it a dialect which 
is really isn't today.
BrianH:
19-Jul-2011
The non-dialected behaviors seem simple enough (for the purposes 
of discussion I've read the docs). The problem is in the dialect, 
especially these:

- "Negative values can be used to skip in the series without returning 
that part:"  Why not use a 'skip keyword for that?

- "Note that for greater control, you can use simple parse rules:" 
 Which ones?

It really is a dialect, but the language is not confusing (first 
case) and not well defined (second case). Using keywords would make 
the dialect easier to understand (and thus use), and potentially 
more efficient to implement using command dispatch.
Gregg:
29-Jul-2011
Brian, DELIMIT means something very different to me. My DELIMIT func 
inserts delimiters.


I don't have a problem with using a 'skip keyword. As I said, the 
current behavior wasn't the original design and may be Carl's doing. 
Check with him on that.


There is a conceptual conflict between the treatment of splitting 
into parts by length and splitting by delimiter...

 -- I don't see that, but I'm biased. I'm always happy to see alternative 
 designs.
Gregg:
4-Aug-2011
On the DELIMIT func name topic, my original suggestion, long ago, 
was to add /SKIP to INSERT, but that never went anywhere. What is 
the current feeling toward that (knowing that getting it added might 
be an obstacle).
Pekr:
4-Aug-2011
I generally like /skip. Just recently I used find/skip - very usefull, 
as it treats series as a set of records.
Henrik:
11-Oct-2011
would it not be practical if REMOVE-EACH could /SKIP ?
Ladislav:
11-Oct-2011
remove-each [value skip] my-block [...]
Marco:
26-Nov-2011
wish for R3 / Topaz / Red / World:

I wish that refinements would be totally reworked (not R2 compatible 
:( ).

Current situation with some examples:

view/new/title/offset/options win "Dialog" 20x20 'resize

remove_last: func [{remove last (n) element(s) of a series}
	serie [series!] /n num [integer!]
	][
	num: any [num 1]
	remove/part skip tail serie negate num num
]


append: func [{Appends a value to the tail of a series and returns 
the series head.} 
    series [series! port!] value /only
	][
    head either only [
        insert/only tail series :value
    ] [
        insert tail series :value
    ]
]

New situation with different syntax and default values:

view win /new true /title "Dialog" /offset 20x20 /options 'resize

remove_last: func [{remove last (n) element(s) of a series}
	series [series!] /n: 1 [integer!]
	][
	remove skip tail series negate n /part n
]


append: func [{Appends a value to the tail of a series and returns 
the series head.} 
    series [series! port!] value /part /only /dup
	][
    head insert tail series :value /part part /only only /dup dup
]


Note that append could also be redifined as: #macro append [] [head 
insert tail]
Group: Power Mezz ... Discussions of the Power Mezz [web-public]
Kaj:
20-Dec-2010
Scraping a title is the simplest example. In reality, you get all 
sorts of tags with extra attributes that you need to skip, and values 
with extraneous newlines. He wouldn't understand how to normalise 
that, so his data would be left as a mess
Group: Core ... Discuss core issues [web-public]
Gregg:
15-Oct-2010
James, here is another way, if you know the words you want to remove, 
rather than the words you want to keep.

remove-words: func [

    "Returns a copy of the object with the specified words removed."
    object [object!]
    words  [word! block!] "The word, or words, to remove"
    /local spec
][
    spec: third object
    foreach word compose [(words)] [
        remove/part find/skip spec to set-word! word 2 2
    ]
    make object! spec
]

o: context [a: 1 b: 2 c: 3 d: 4 e: 5]
probe remove-words o 'c
probe remove-words o [a e]
Maxim:
18-Oct-2010
pre tag should always have had a  tag=""  paramter which allowed 
it to skip html content until it found a closing <pre> tag with the 
same tag attribute (my 2 cents).
Sunanda:
21-Nov-2010
This does it without using a temporary word....and it should work 
even if the counter name is not amenable to Cyphre's path notation 
(ie you are using something more exotic that strings for counter 
ids, or are using an older version of /Core).
   b:  next find/skip head b "a" 2 b b/1: b/1 + 1
Just remember to reset ....
   b: head b
....once in a while:)
Ladislav:
16-Dec-2010
; implementation:
swap-sub: func [
	{swap the subseries using the SWAP-FIRST function}
	a [series!]
	b [integer!]
	/local la lb pa pb
][
	pa: a
	la: b - 1
	pb: skip a la
	lb: (length? a) - la
	while [all [la > 0 lb > 0]][
		either la <= lb [
			loop la [
				swap-first pa pb
				pa: next pa
				pb: next pb
			]
			pb: skip pa la
			lb: lb - la
		][
			pa: skip pa la - lb
			loop lb [
				swap-first pa pb
				pa: next pa
				pb: next pb
			]
			pa: skip pa negate la
			la: la - lb
			pb: skip pa la
		]
	]
	a
]
Ladislav:
16-Dec-2010
this may look more readable:

; implementation:
swap-n: func [
	{swap n elements}
	a [series!]
	b [series!]
	n [integer!]
][
	loop n [swap-first a b a: next a b: next b]
]

swap-sub: func [
	{swap the subseries using the SWAP-FIRST function}
	a [series!]
	b [integer!]
	/local la lb pa pb
][
	pa: a
	la: b - 1
	pb: skip a la
	lb: (length? a) - la
	while [all [la > 0 lb > 0]][
		either la <= lb [
			swap-n pa pb la
			pb: skip pa la
			lb: lb - la
		][
			pa: skip pa la - lb
			swap-n pa pb lb
			pa: skip pa negate la
			la: la - lb
			pb: skip pa la
		]
	]
	a
]
Ladislav:
16-Dec-2010
swap-sub: func [
	{swap the subseries using the SWAP-FIRST function}
	a [series!]
	b [integer!]
	/local la lb pa pb
][
	pa: a
	la: b - 1
	pb: skip a la
	lb: (length? a) - la
	while [all [la > 0 lb > 0]][
		either la <= lb [
			swap-n pa pb la
			pa: pb
			pb: skip pa la
			lb: lb - la
		][
			swap-n skip pa la - lb pb lb
			la: la - lb
			pb: skip pa la
		]
	]
	a
]

swap-first: func [
	{swap the first elements of A and B}
	a [series!]
	b [series!]
	/local t
][
	k: k + 1
	set/any 't first a
	change/only a first b
	change/only b get/any 't
]

k: 0
swap-sub [1 2 3 4 5 6 7 8 9] 7
k ; == 6
Steeve:
16-Dec-2010
Thanks for your hard work.
I didn't read your proposals yet, though.

I think I found the optimal way. As you noticed, it involves modulo 
maths.

swap-sub: func [s pos /local len e sav][
	-- pos
	sav: s
	forever [
		e: skip s pos
		len: length? s
		loop len - pos [swap ++ s ++ e]
		if zero? len // pos [break]
		pos: pos - (len // pos)
	]
	sav
]
Sunanda:
9-Feb-2011
This may work too:
  sort/compare/skip block func [a b][return true] length? block
BrianH:
23-Feb-2011
Here's a working version:

map-each: func [

 "Evaluates a block for each value(s) in a series and returns them 
 as a block."
	[throw catch]

 'word [word! block!] "Word or block of words to set each time (local)"
	data [block!] "The series to traverse"
	body [block!] "Block to evaluate each time"
	/into "Collect into a given series, rather than a new block"

 output [any-block! any-string!] "The series to output to" ; Not image!
	/local init len x
][
	; Shortcut return for empty data
	either empty? data [any [output make block! 0]] [
		; BIND/copy word and body
		word: either block? word [
			if empty? word [throw make error! [script invalid-arg []]]

   copy/deep word  ; /deep because word is rebound before errors checked
		] [reduce [word]]
		word: use word reduce [word]
		body: bind/copy body first word
		; Build init code
		init: none
		parse word [any [word! | x: set-word! (
			unless init [init: make block! 4]
			; Add [x: at data index] to init, and remove from word
			insert insert insert tail init first x [at data] index? x
			remove x
		) :x | x: skip (

   throw make error! reduce ['script 'expect-set [word! set-word!] type? 
   first x]
		)]]
		len: length? word ; Can be zero now (for advanced code tricks)
		; Create the output series if not specified
		unless into [output: make block! divide length? data max 1 len]
		; Process the data (which is not empty at this point)

  until [ ; Note: output: insert/only output needed for list! output
			set word data  do init

   unless unset? set/any 'x do body [output: insert/only output :x]
			tail? data: skip data len
		]
		; Return the output and clean up memory references
		also either into [output] [head output] (
			set [word data body output init x] none
		)
	]
]
BrianH:
12-Apr-2011
Have you tried using SELECT/skip ... 2?
BrianH:
20-Apr-2011
Onetom, that error has been reported already and fixed in R2/Forward, 
but it hasn't made it into R2 yet. Here is the revised MAP-EACH:

map-each: func [

 "Evaluates a block for each value(s) in a series and returns them 
 as a block."
	[throw catch]

 'word [word! block!] "Word or block of words to set each time (local)"
	data [block!] "The series to traverse"
	body [block!] "Block to evaluate each time"
	/into "Collect into a given series, rather than a new block"

 output [any-block! any-string!] "The series to output to" ; Not image!
	/local init len x
][
	; Shortcut return for empty data
	either empty? data [any [output make block! 0]] [
		; BIND/copy word and body
		word: either block? word [
			if empty? word [throw make error! [script invalid-arg []]]

   copy/deep word  ; /deep because word is rebound before errors checked
		] [reduce [word]]
		word: use word reduce [word]
		body: bind/copy body first word
		; Build init code
		init: none
		parse word [any [word! | x: set-word! (
			unless init [init: make block! 4]
			; Add [x: at data index] to init, and remove from word
			insert insert insert tail init first x [at data] index? x
			remove x
		) :x | x: skip (

   throw make error! reduce ['script 'expect-set [word! set-word!] type? 
   first x]
		)]]
		len: length? word ; Can be zero now (for advanced code tricks)
		; Create the output series if not specified
		unless into [output: make block! divide length? data max 1 len]
		; Process the data (which is not empty at this point)

  until [ ; Note: output: insert/only output needed for list! output
			set word data  do init

   unless unset? set/any 'x do body [output: insert/only output :x]
			tail? data: skip data len
		]
		; Return the output and clean up memory references
		also either into [output] [head output] (
			set [word data body output init x] none
		)
	]
]
Geomol:
13-May-2011
Tonight's Moment of REBOL Zen:

>> skip [a b c] to integer! true
== [b c]
>> skip [a b c] true
== [a b c]
BrianH:
13-May-2011
Yup. The order of logic values as considered by SKIP, PICK and POKE 
is true then false. This was done to make PICK compatible with EITHER.
BrianH:
13-May-2011
Yup, because PICK, POKE, AT, INDEX? and /1 work with indexes, while 
SKIP works with offsets.
Endo:
10-Jun-2011
They are different and not backward compatible.
>> b: [1 2 3]
== [1 2 3]
>> c: skip b 3
== []
>> empty? b
== false
>> empty? c
== true
; c references to b, b is not empty, but c is.
Oldes:
20-Jul-2011
>> select [1 2 2 3] 2
== 2
>> select/skip [1 2 2 3] 2 2
== [3]

Why the second returns a block?
Group: !REBOL3 Proposals ... For discussion of feature proposals [web-public]
BrianH:
11-Nov-2010
Well it comes down to this: Functions are defined lexically. Though 
they are called dynamically, they aren't called until after they 
have already been bound, definitionally. But as a side effect of 
tasking, those bindings are stack-relative, and those stacks are 
task-local. But random blocks of code outside of functions are bound 
to object contexts, and those are *not* task-local. So that means 
that the old R2 practice of calling shared blocks of code is a really 
bad idea in R3 if any words are modified, unless there is some kind 
of locking or synchronization. This means that those blocks need 
to be moved into functions if their code is meant to be sharable, 
which means that at least as far as RETURN and EXIT are concerned, 
they can be considered lexically scoped. The advantage that we would 
get from being able to call a shared block of code and explicitly 
return in that block is moot, because we can't really do that much 
anymore. This means that we don't lose anything by switching to definitional 
code that we haven't already lost for other reasons. At least as 
far as functions are concerned, all task-safe code is definitional.


Loops are also defined lexically, more or less, and the rebinding 
ones are also task-safe because they are BIND/copy'd to a selfless 
object context that is only used for that one call and thrown away 
afterwards. And most calls to loops are task-safe anyways because 
they are contained in functions. However, the LOOP, FORALL, FORSKIP 
and WHILE loops do not rebind at the moment. We actually prefer to 
use those particular loops sometimes in R3 code because they can 
be more efficient than *EACH and REPEAT, because they don't have 
that BIND/copy overhead. Other times we prefer to use *EACH or REPEAT, 
in case particular loop fits better, or has high-enough repetitions 
and enough word references that the 27% overhead for stack-local 
word reference is enough to be more than the once-per-loop BIND/copy 
overhead. Since you don't have to move blocks into *loops* to make 
them task-safe, you can use blocks referred to by word to hold code 
that would be shared between different bits of code in the same function. 
This is called manual common subexpression elimination (CSE), and 
is a common optimization trick in advanced REBOL code, because we 
have to hand-optimize REBOL using tricks that the compiler would 
do for us if we were using a compiled language. Also, PARSE rules 
are often called from loops, and they are frequently (and in specific 
cases necessarily) referred to by word instead of lexically nested; 
most of the time these rules can be quite large, maximizing BIND/copy 
overhead, so you definitely don't want to put the extensive ones 
in a FOREACH or a closure.

Switching to definitional break would have three real downsides:

* Every loop would need to BIND/copy, every time the loop is called, 
including the loops that we were explicitly using because they *don't* 
BIND/copy.

* Code that is not nested in the main loop block would not be able 
to break from that loop. And code that is nested in the main loop 
would BIND/copy.

* We can in theory catch unwinds, run some recovery code, and send 
them on their way (hopefully only in native code, see #1521). Definitional 
escapes might be hard or impossible to catch in this way, depending 
on how they are implemented, and that would mean that you couldn't 
recover from breaks anymore.


The upside to definitional break would be that you could skip past 
a loop or two if you wanted to, something you currently can't do. 
Another way to accomplish that would be to add /name options to all 
the loop functions, and that wouldn't have the BIND/copy overhead. 
Or to use THROW or THROW/name.


The situation with THROW is similar to that of the non-binding loops, 
but more so, still task-safe because of functions. But CATCH and 
THROW are typically the most useful in two scenarios:

* Escaping through a lot of levels that would catch dynamic breaks 
or returns.

* Premade custom escape functions that might need to enforce specific 
semantics.


Both of these uses can cause a great deal of difficulty if we switched 
to definitional throw. In the first case, the code is often either 
broken into different functions (and thus not nested), or all dumped 
into a very large set of nested code that we wouldn't want to BIND/copy. 
Remember, the more levels we want to throw past, the more code that 
goes into implementing those levels. In the second case definitional 
throw would usually not work at all because the CATCH and the THROW 
would contained in different functions, and the code that calls the 
function wrapping the THROW would not be nested inside the CATCH. 
So you would either need to rebind every bit of code that called 
the THROW, or the definitional THROW would need to be passed to the 
code that wants to call it like a continuation (similar concept). 
Either way would be really awkward.


On the plus side of dynamic (whatever), at least it's easy to catch 
an unwind for debugging, testing or recovery purposes. For that matter, 
the main advantage of using THROW/name as the basic operation that 
developers can use to make custom dynamic escape functions is that 
we can build in a standard way to catch it and that will work for 
every custom escape that is built with it. The end to the arms race 
of break-through and catch.
Maxim:
27-Jan-2011
INTERLEAVE is a very usefull function, using two series and mixing 
them up with many options like counts, skip, duplicates, all cooperating.
Group: !REBOL3 Parse ... REBOL3 Parse [web-public]
Steeve:
14-Jan-2011
>> parse ["12"][into [2 skip] ??]
end!: []
== true

>> parse ["12"][into [skip accept] ??]
== false

should be true to my mind
Ladislav:
14-Jan-2011
Steeve instead of TO RULE use WHILE [at rule break | skip | reject], 
and instead of THRU RULE use WHILE [rule break | skip | reject]
1101 / 122812345...91011[12] 13