Menu

scScript Pattern Design

Regular Expressions (RE) have traditionally been used for matching text patterns. While an extremely compact and powerful pattern representation, RE are conceptually abstruse with a terse and effectively write-only syntax. In that sense, RE are perfectly fine for the machine, but not so much for the human being who writes them, or worse has to read and comprehend them.

scScript introduces a new, more procedural, Pattern (Pat) paradigm, drawing inspiration from SNOBOL as well as Parse Expression patterns. Recursive Pat objects are first defined and created, then matched against text from editor buffers. Only a few pre-defined Pat types are required, but this simple model can easily accommodate more types as well as specialized and custom functionality to suit client applications. Importantly, strings used to define Pats are simple text, there are no additional in-band cryptic symbols and no forests of escape chars.

A Pat typically refers to strings, other Pats, and even callback scScript functions that should be called during a match. Once created, the Pat is simply stored in a variable. It is thus passed around and used/re-used by many other Pats or matching functions. The matching process is also re-entrant. So a callback (scScript function closure) invoked from one Pat can itself match other Pats before returning results to its caller.

The simplest Pat just matches a string: MyPat = Pat.Seq("hello world");

But a single string is trivial and not very interesting. The matching process (Pat.Match) can in fact accept a string directly, so MyPat is also superfluous! Perhaps a better example would be: MyPat = Pat.Seq("hello", " ", "world");
where Seq is just a (conjunctive) sequence of strings that it will match in order.

But this being English, the first word can be capitalized! So a better Pat would be: MyPat = Pat.Seq(Pat.#InSen, "hello", " ", Pat.#Sen, "world");
where the #Sen/#InSen are flags that modulate case sensitivity for subsequent args. There are many possible flags, but they all work the same way. When a flag appears it sets the relevant parameters for all subsequent args, until another flag countermands it. The args say what to match, the flags say how!

Similarly, a #Neg (or #Pos) flag can be used to explicitly exclude/include subsequent args. So MyPat = Pat.Seq("hello", " ", Pat.#Sen, "world", #Pat.Neg, ",")
would match "Hello world!" or "Hello world." but not "Hello world, I am so happy."!

Note: both #Pos and #Insen are defaults, therefore elided at the beginning.

So far, MyPat has been quite rigid about the space char. How would this Pat match if there was a linebreak or even a tab character for whitespace? A better approach would be: WSPat = Pat.Char(Pat.#WSpace); MyPat = Pat.Seq("hello", WSPat, Pat.#Sen, "world");

Char is a Pat that matches any character within its defined range, here using the pre-defined set of whitespace characters. So MyPat would easily match: "Hello world"    or    "Hello<tab>world"    etc...

But this needs another modification, as there could be more than one space or tab: WSPat = Pat.Char(Pat.#WSpace); MyPat = Pat.Seq("hello", Pat.Rep(1, 0, WSPat), Pat.#Sen, "world");

Ideally, Rep would be Pat.Rep(1, 0, Pat.#Self + Pat.#Max, WSPat) so it selfishly and maximally matches the entire whitespace without looking to see whether the Seq matches. More on this later.

The Rep above repeats its args one or more times (Min is 1 and Max is 0, meaning there is no maximum limits), so MyPat can match any reasonably spaced version of "Hello world"   or even    "Hello<tab><space><space><newline><tab>world".

But of course, language is full of twists and turns... and sometimes Hello becomes Greetings and World becomes Everyone! The following can easily accommodate such a permutation: WSPat = Pat.Char(Pat.#WSpace); MyPat = Pat.Seq(Pat.Alt("hello", "hi", "greetings"), Pat.Rep(1, 0, Pat.#Self + Pat.#Max, WSPat), Pat.Alt(Pat.#Sen, "world", "everyone"));

Finally MyPat can match against any reasonable first greeting as Alt are disjunctions, choosing the first constituent alternative that matches; whereas Seq are conjunctions, all must match in sequence.

Pat1.sc in the SampleSC directory will have most of the above examples, matching against Sample_BigC.txt, a fairly large sample data file (based on old source codes for scScript).

So the Pat here, ignoring case sensitivity, is defined as

scScript Pats obviously requires a few more characters than an equivalent RE, but humans can read/write remarkably quickly when it actually makes sense!