Ask HN: Rebol/Red parse is great. Has it been re-implemented in other languages? - macmac
======
greggirwin
You won't find anything quite like it in any other language, and there's a
reason for that. Like Lisp, Redbol langs are homoiconic. Rebol was initially
designed as a messaging language, and has a lot of datatypes with literal
forms that don't exist in other languages. That's important because the
`parse` function can operate at 2 levels: `string` parsing (what you find in
other parser toolkits), and `block` parsing. Block parsing means the data has
been loaded and tokenized already, and you can parse by high level datatype.
I'll try not to get too carried away, but that's tough for me. :^)

Example 1. Red's infix operator precedence is strictly left to right. But Red
has a built in `math` function that can take an expression like `2 + 4 * 3`
and produce the result you expect from many other languages.

    
    
        >> 2 + 4 * 3
        == 18
        >> math [2 + 4 * 3]
        == 14
    

You can see how it works by using `source math` in the REPL. It's about 7
lines of `parse` rules.

OK, I got carried away. Here's a little dialect I just whipped up as an
example (error handling omitted for brevity). It has some supporting funcs at
the top, to show how you trigger actions while parsing. If you look at the
rules, you can see that some literal words are used as keywords, then
different datatypes are matched according to their action.

    
    
        ; Actions
        call-phone: func [number [issue!] time][
            print ["Call" mold number "at" time]
        ]
        send-email: func [dest [email!] data [string!]][
            print ["Send" dest length? data "bytes"]
        ]
        post-data:  func [dest [url!] data [string!] time][
            print [
                "Post" length? data "bytes to" dest
                either time? time ['at]['on]
                time
            ]
        ]
    
        ; Rules
        when=:  [['at | 'on] set when [date! | time!]]
        call=:  ['call set dest issue! opt when= (call-phone dest any [when now])]
        email=: ['email set dest email! content= (send-email dest content)]
        post=:  ['post content= 'to set dest url! when= (post-data dest content when)]
        content=: [
            set content [string! | file! | url!]
            (if not string? content [content: attempt [read content]])
        ]
        contact=: [call= | email= | post=]
        rules=: [any contact=]
    
        ; Entry point (dialected function)
        contactor: func [input [block!]][
            parse input rules=
        ]
    
        ; Sample call
        contactor [
            call #000.555.1212 at 12:34
            email user@host.dom "On for lunch?"
            post %news.txt to http://all-the-news.com/news.txt on 1-jan-2018
        ]
    
        ; Test run output
        Call #000.555.1212 at 12:34:00
        Send user@host.dom 13 bytes
        Post 1815 bytes to http://all-the-news.com/news.txt on 1-Jan-2018
    

Other langs can implement something like it, but the fact that Redbol langs
were designed to solve this very problem--the exchange of information between
people and machines--provides a big advantage.

------
macmac
I mean, how can you not love:

    
    
      expr:    [term ["+" | "-"] expr | term]
      term:    [factor ["*" | "/"] term | factor]
      factor:  [primary "**" factor | primary]
      primary: [some digit | "(" expr ")"]
      digit:   charset "0123456789"

------
dwohnitmok
Instaparse in Clojure
([https://github.com/Engelberg/instaparse](https://github.com/Engelberg/instaparse))
seems similar (although I don't know Rebol/Red so I'm purely guessing from
looking at parse examples).

You can get close-ish results with parser combinator libraries as well.

------
jacques_chester
I think you can find these advertised as PEGs, or Parser Expression Grammars.
The first I learned about was Lua's LPeg: [http://www.inf.puc-
rio.br/~roberto/lpeg/](http://www.inf.puc-rio.br/~roberto/lpeg/)

------
odonnellryan
What is this? A std library function?

~~~
macmac
Quoting from the red docs:

    
    
      So, in short, what is Parse? It is an embedded DSL (we 
      call them "dialects" in the Rebol world) for parsing 
      input series using grammar rules.

~~~
dominotw
Its different from antlr and co in the sense that there is no code generation
step?

~~~
macmac
Because parse is a embedded DSL you have access to all of rebol/red which lets
you easily generate/interpret code. As an example here is a BF interpreter:
[https://gist.github.com/dockimbel/7713170](https://gist.github.com/dockimbel/7713170)

