AltME groups: search
Help · search scripts · search articles · search mailing listresults summary
world | hits |
r4wp | 134 |
r3wp | 1094 |
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 / 1228 | 1 | 2 | 3 | 4 | 5 | ... | 9 | 10 | 11 | [12] | 13 |