Menu

scScript Pattern Errors

Pattern matching, as you have witnessed, is inherently complex, so it should be no surprise that there are a few common errors:

The first mistake is often quite a head scratcher, as the match records no results and does not call the RFunc callback. While many such problems can be seemingly fixed with smarter defaults, the problems they introduce, when the smart defaults are wrong, would be even harder to catch! Perhaps a better solution would be to have an optional check function to warn if the pattern match is suspect.

The At Pat, although a convenient predicate for matching, can also cause a few problems, especially if the particular Match is called with explicit StartPos and FirstPos values. For example, Pat.At(2) will default to #Rel, so counts 2 characters from FirstPos given to the Match function. But a preceeding Pat.Go(2) will have advanced 2 characters from StartPos, perhaps a very different location. Similarly, Pat.At(2, Pat.#Abs) will count from the very beginning of the buffer, Pos 0, regardless of FirstPos or StartPos.

In summary, #Rel (default) for Go, counts characters from the current Match position, which will be StartPos in a fresh Match. But #Rel for At counts chars from FirstPos/LastPos. Similarly, #Abs for Go measures from FirstPos/LastPos given to the Match, but #Abs for At measures from the very beginning/end of the Buffer. So #Abs in Go generally corresponds to #Rel in At! (One can also argue for a future #Byte count option in Go and At Pats.)

A final common error is altering the Match buffer during the match. It is quite tempting to call Ed.Del or Ed.Write (even Ed.Xfer) from an SFunc or RFunc. But the low-level machinery will not expect or understand such buffer changes! If nothing else, this will alter the buffer length and the current Match position, typically leading to an infinite loop or (more often) a crash. An innocuous Pat like At(-1) cannot function if the buffer length is changed! The only workable approach is to use the Match buffer as the source template and copy/xfer as necessary to a new buffer, skipping all that should be deleted.

**I had a bewildering error when Goto was used in a test file to jump (over other code) directly to a Match call I wanted to study. Alas, the overzealous Goto I wrote also jumped over the RFunc definition/assignment, so the Match function was being fed int 0 instead of the expected RFunc closure! Match was perfectly happy and ran normally, no errors or warnings, but no RFunc was ever called. Turns out the compiler saw the RFunc Function and declared its variable, but the function innards was not defined at runtime because of the Goto, so it kept its initial value of int 0.