AltME: Rebol School

Messages

Gregg
LAUNCH (and RUN) were problematic in the past, but you can do the same thing with system/options/boot and CALL. One catch is if you may run encapped or not. A lesson for Redbol is making header info universally available for consistent access.

Marco
I am trying to write a function to replace find/any with parse and I have done this:
    find-any: func ["Finds a value in a series using wildcards and returns the series at the start of it."
        series [series!] value /local elem pos
        ][
        value: copy value
        while [find value "**"] [replace/all value "**" "*"]
        replace/all value "*" ":*:"
        replace/all value "?" ":?:"
        value: parse value ":"
        remove-each elem value ["" = elem]
        replace/all value "*" 'thru
        replace/all value "?" 'skip
        value: compose/deep [any [to (first value) pos: (value) to end | thru (first value)] ]
        either parse/all series value [pos][none]
    ]
Could you please give it a try and tell me if it works and how to improve it?
Gregg
Is your goal to emulate find/any's behavior, or more to learn parse? I have a LIKE? func that does similar pattern matching, generating parse rules from a simple pattern grammar. Replace is a concise, if not the most efficient, way to break things up, and you handle compressed * runs as well, whcih is nice.
It doesn't work if * is the first or last thing in your pattern.

Gabriele
I think it will also fail if your pattern has colons in it.
Gregg
Good point Gab.

Marco
I found like.r and I will investigate it, thank you.

Marco
After investigatin like.r this is my second try:
    find-any: func [
        "Finds a value in a string using wildcards and returns the string at the start of it."
        series [series!] value [string!] /match /last
        /local str give_head emit pos pos2 non-wild-chars plain-chars tmp rule
        ][
        last*: get 'last
        give_head: none
        str: copy to string! series
        value: copy value
        if empty? value [return none]
        ; normalize pattern
        while [find value "**"] [replace/all value "**" "*"]
        while [find value "*?"] [replace/all value "*?" "*"]
        if value = "*" [return series]
        if last [
            value: reverse value
            str: reverse str
        ]
        if #"*" = first value [
            remove value
            if not any [last match] [give_head: series]
            match: none
        ]
        emit: func [arg][append rule arg]
        non-wild-chars: complement charset "*?"
        plain-chars: [copy tmp some non-wild-chars (emit copy tmp)]
        rule: copy []
        parse/all value [
            some [plain-chars | "*" (emit 'thru) | "?" (emit 'skip)]
        ]
        ; If the last thing in our pattern is thru, it won't work so we
        ; remove the trailing thru.
        if 'thru = last* rule [remove back tail rule]
        value: compose/deep [any [(all [none? match 'to]) (first rule) pos: (rule) pos2: to end | thru (first rule)] ]
        if none? parse/all str value [return none]
        if last [pos: skip series (length? series) - (index? pos2) + 1]
        any [give_head pos]
    ]
Perhaps still not perfect but should work in most cases.
Gregg
Sometimes I'll include a sampling of test cases, so people can see what's covered, and quickly try functions out.

Gabriele
I don't think that:
    last*: get 'last
does what you expect it to do. You probably want:
   last*: get in system/words 'last
Though, since I think you only use last* once, it may be easier to just replace last* with system/words/last, like:
    if 'thru = system/words/last rule [...]
Steeve
Hi, it's been a while since I talked here (2 years ?)
Do you know  if there is a better way to code this function  ?
extend-mask: func[i][
    ; set bits at the right of the MSB
    ; used to control if joining ADD operations together
    ;   is allowed by their prefixed casting operation (and MASK).  
    ; e.g. 00100100 => 00111111
    ; Sorry if it's ugly since REBOL does not have a native for that.
    ; Well, the utility is rare, except when you write a code optimizer.
    int(2 ** (int (log-2 i) + 1) - 1)
]
(int) is a shortcut fot to-integer
Steeve
I don't want to use a  precompiled array as a solution, the speed is not a problem... (currently)
Gregg
No quick suggestions here, but it's nice to see you again.
Geomol
Some ideas, but yours seem to be faster:
extend-mask: func [
    i
][
    i or either i > 0 [extend shift i 1] [0]
]
extend-mask: func [
    i
    /local r
][
    r: i
    while [0 < i: shift i 1] [r: r or i]
    r
]
hm, *extend* should be extend-mask in first one.
so a recursive

Gabriele
If speed is not a problem, then your version is probably the best choice.
If speed becomes a problem and you want to avoid floating point, there is a faster version of what Geomol proposed:
func [i] [
    i: i or shift i 1
    i: i or shift i 2
    i: i or shift i 4
    i: i or shift i 8
    i or shift i 16
]
You need an extra line if you are using R3 and 64 bits integers.
Geomol
That's neat, Gabriele!
It seems, Steeve only need the function to work on 8 bits at a time, so this is faster!
extend-mask: func [i] [i: i or shift i 1 i: i or shift i 2 i: i or shift i 4]
DideC
With Steeve func optimized, it's as fast as Gabriele's one on 8 bits :
extend-mask: func [i] [to integer! 2 ** (1 + to integer! log-2 i) - 1]

Gabriele
In REBOL's case the interpretation overhead is probably much bigger than the floating point operations.

Last message posted 188 weeks ago.