Minor (but nice!) %prot-http.r parsing improvements

Here's is R3-Alpha's PARSE-WRITE-DIALECT from %prot-http.r

parse-write-dialect: func [port block /local spec] [
    spec: port/spec
    parse block [
        [set block word! (spec/method: block) | (spec/method: 'post)]
        opt [set block [file! | url!] (spec/path: block)]
        [set block block! (spec/headers: block) | (spec/headers: [])]
        [set block [any-string! | binary!] (spec/content: block) | (spec/content: none)]
    ]
]

You couldn't set paths in R3-Alpha parse, which is weird. So things had to be captured into a temporary variable (it reused the input block for some reason).

Let's imagine that setting paths were legal:

parse-write-dialect: func [port block /local spec] [
    spec: port/spec
    parse block [
        [set spec/method word! | (spec/method: 'post)]
        opt [set spec/path [file! | url!]]
        [set spec/headers block! | (spec/headers: [])]
        [set spec/content [any-string! | binary!] | (spec/content: none)]
    ]
]

Let's do a quick transformation of this to PARSE3 in Ren-C, where the keyword TRY now replaces OPT:

parse-write-dialect: func [port block <local> spec] [
    spec: port.spec
    parse3 block [  ; PARSE3 is R3-Alpha-compatible parse
        [set spec.method word! | (spec.method: 'post)]
        try [set spec.path [file! | url!]]
        [set spec.headers block! | (spec.headers: [])]
        [set spec.content [any-string! | binary!] | (spec.content: null)]
    ]
]
  • The TUPLE!s help us see we're not making function calls, which is nice

  • /LOCAL is a legitimate normal refinement, and <local> variables are truly local--you can't slip them in from the caller. Because they are invisible, you can build function compositions that don't have to worry about colliding with their names.

    • It also frees up /LOCAL to just be a typical refinement, like TIME/LOCAL

Now let's throw in some UPARSE, with the SET-WORD!s for assignment...

parse-write-dialect: func [port block <local> spec] [
    spec: port.spec
    parse block [  ; PARSE is now UPARSE
        [spec.method: word! | (spec.method: 'post)]
        try [spec.path: [file! | url!]]
        [spec.headers: block! | (spec.headers: [])]
        [spec.content: [any-string! | binary!] | (spec.content: null)]
    ]
]

It looks a little tighter...but then we also have the ability to factor the assignments out. And as it happens, that last line could just be try [any-string! | binary!], because TRY would assign the result to NULL if it can't match:

parse-write-dialect: func [port block <local> spec] [
    spec: port.spec
    parse block [
        spec.method: [word! | ('post)]
        spec.path: try [file! | url!]
        spec.headers: [block! | ([])]
        spec.content: try [any-string! | binary!]
    ]
]

Improved!

3 Likes

Wow, that cleans up beautifully! You say it's minor, and maybe it is, but it looks like the kind of brevity you'll be thanking yourself for again and again when you revisit the code in the future.

4 Likes