Match

REBOL is an ideal language for building Domain Specific Languages—it has rich and comprehensive set of expressions that can be arranged and applied to many domains (dialects). In the PARSE function, REBOL has a heavyweight language constructor capable of implementing sophisticated and nuanced dialects fit for many purposes.

However, PARSE has a relatively linear method of identifying a sequence of values. Allowing a more free-form arrangement of values can be beneficial for shorter dialects with a specific purpose. Enter MATCH:

MATCH takes a block of values, matches against a given rule, returns an object of the matched values if the match is successful or an ERROR if it is not:

>> match [foo:// %bar][foo: url! bar: file!]
== make object! [
foo: foo://
bar: %bar
]

This works whichever order the values are in:

>> match [%bar foo://][foo: url! bar: file!]
== make object! [
foo: foo://
bar: %bar
]

MATCH will fail if the values do not match the rule—not enough or too many values:

>> match [%bar][foo: url! bar: file!]
== error!

>> match [foo:// %bar 2][foo: url! bar: file!]
== error!

It can be specified in the rule whether a value is optional, if there are zero or more values, or one or more values:

>> match [%bar][foo: opt url! bar: file!]
== make object! [
foo: none
bar: %bar
]

>> match [%foo %bar][foo: any url! bar: some file!]
== make object! [
foo: []
bar: [%foo %bar]
]

Additionally, more than one value type can be assigned to a single word:

>> match [foo://][foo: url! | file!]
== make object! [
foo: foo://
]

>> match [%bar][foo: url! | file!]
== make object! [
foo: %bar
]

A combination of types and occurrences can be used:

>> match [foo:// %bar][foo: some url! | file!]
== make object! [
foo: [foo:// %bar]
]

Words can be used in place of types in order to use words as flags:

>> match [optional][flag: opt 'optional]
== make object! [
flag: 'optional
]

>> match [][flag: opt 'optional]
== make object! [
flag: none
]

Where two words are assigned the same type, words and values are assigned relative to their position in the source and the rule:

>> match [%foo %bar][foo: file! bar: file!]
== make object! [
foo: %foo
bar: %bar
]

MATCH has a LOOSE refinement that is permissive in the case of too many values:

>> match/loose [foo:// %bar 2][foo: url! bar: file!]
== make object! [
foo: foo://
bar: %bar
]

Non-Linear Dialects

An example of where I’ve used this dialect is in the construction of HTML tags, in this case an IMG tag:

image-rule: [
src: file! | url!
size: opt pair! | integer!
alt: string!
title: opt string!
id: opt issue!
]

Running this against some inputs would yield:

>> match [%image.jpg "Image"] image-rule
== make object! [
src: %image.jpg
size: none
alt: "Image"
title: none
id: none
]

>> match ["Image" http://reb4.me/image.jpg #pic "A Majestic Landscape" 300x120] image-rule
== make object! [
src: http://reb4.me/image.jpg
size: 300x120
alt: "Image"
title: "A Majestic Landscape"
id: #pic
]

It’s a pretty handy way to put together an ad hoc dialect where options can vary without adding unnecessary metadata.