A domain specific pattern matching language made mainly for defining bot commands.
Please check out the examples subdirectory of this repository.
<>
defines a capture.[]
defines a list of captures to be matched out of order.\\
. I.e. .foo\ bar
will match the literal "foo bar"
but not "foo bar"
.You can define captures in 3 ways:
<NAME[QUANTIFIER]>
<NAME[QUANTIFIER]: FILTERS>
<NAME[QUANTIFIER]: FILTERS1; FILTERS2; FILTERS3...>
Quantifiers:
- ?
: Match this capture 1 or 0 times.
- *
: Match this capture 0 or more times. The captures will be returned in a Vec
.
- +
: Match this capture at least once. The values are returned in a Vec
.
- None: Match this exactly once.
If you use the first form, the default is to match on words (whitespace separated). Otherwise you must use a filter.
Filters are exactly like a function call in any mainstream language. They may take arguments. Arguments are always quoted strings.
Some examples:
starts("--")
foo()
Strings are always quoted with one of the "
, '
or ```.
You can escape the quotation to include it in the string.
Some more escape patterns are recognized:
\n
: newline.\t
: tab.\r
: carriage return.A capture group defines a list of patterns that will be matched out of order.
There are two forms of capture groups:
- Priority groups: These are delimited with []
and the match priority of the captures enclosed are unchanged.
- Normal group: These groups are enclosed in {}
and the enclosed captures may be re-ordered for potentially more matches.
The syntax is as follows:
Priority groups:
[ CAPTURE1 CAPTURE2 ...CAPTURE_N ]
Normal groups:
{ CAPTURE1 CAPTURE2 ...CAPTURE_N }
Example:
[<first> <second> <maybe_third?>]
^
in regex).starts
and ends
filters trim the match.This example demonstrates a command for running code.
The flags are optional but must start with --
The code block is not optional and must either start and end with:
- "```"
- "`"
Or,
- Starts with ```rust or ```rs and ends with ```.
.run
<flags*: starts("--")>
<code:
starts("
rust", "rs", "
"), ends("");
starts("`"), ends("`");
>
This example command has 3 arguments:
- book
: required, must start with "book=
- chapter
: Optional, must start with either chapter=
or ch=
, case is not important.
- verse
: optional, must start with verse=
.
Since the patterns are wrapped in []
, they can be matched out of order.
.bible
[
<book: starts("book=")>
<chapter?: starts("chapter=", "ch="), nocase()>
<verse?: starts("verse=")>
]
This basic example command lets you bet some of your discord credits. The only required argument is the amount.
.bet <amount>
This command takes 1 or more space separated arguments. It does not specify any pattern so the defaults apply: - Arguments are whitespace separated.
.tag <tags+:>
Every filter can be used any number of times, the arguments are combined into one filter.
starts(prefix1, prefix2, ...prefixN)
: Any of the given prefixes must match.ends(suffix1, suffix2, ...suffixN)
: Any of the suffixes must match.eq(s1, s2, ...sN)
: Must match any string given as an argument. Only other filter that can occur if eq
is specified is nocase
. "foo"
is shorthand for eq("foo")
.nocase()
: Ignore case while matching. Not always accurate and ignored while matching suffixes.