Skip to content
Masataro Asai edited this page Oct 13, 2021 · 20 revisions

Level 1 matchers/patterns are the foundations of all level 2 patterns and optimizers. It provides only 2 patterns. Their roles are primitive and thus its compiler can be dead simple & clean.

All level 2 patterns are expanded into level 1 patterns with defpattern. Likewise, All level 2 matcher macros are expanded into level 1 matcher macros.

Guard1 Pattern

(guard1 symbol test-form {generator-form subpattern}*)
  • It binds the current matching value to symbol with let and conduct checking on it with test-form. It the test fails, it goes to the next pattern.
  • if the test succeeds, each generator-form is evaluated and its value is matched against the corresponding subpattern.
  • Unlike guard pattern in Optima, guard1 pattern does not allow subpatterns in symbol (and is thus more primitive). Subpatterns are only permitted in {generator-form subpattern}* part. One guard1 pattern corresponds to exactly one type checking.
  • While symbol does not contain subpatterns, it has an additional functionality: symbol may contain additional lexical information. For details see the next section.
  • Level-1 patterns should be canonical. That is, there should be no forward-referenced symbols.

Thus, compilation of guard1 is equivalent to just building a form consisting of if and let binding. match1 assumes the matching tree is already valid and optimized.

Example:

(match1 '(1 2)
  ((guard1 temp (consp temp)
           (car temp) (guard1 a t)
           (cadr temp) (guard1 b t))
   (vector a b)))

;; --> #(1 2)

Note that, since even variable patterns are missing in Level 1, one should use (guard1 a t) to bind the value generated by (car temp). It produces a code like below.

(LET ((#:WHAT1862 '(1 2)))
  (BLOCK NIL
    (LET ((TEMP #:WHAT1862))
      (WHEN (CONSP TEMP)
        (LET ((A (CAR TEMP)))
          (WHEN T
            (LET ((B (CADR TEMP)))
              (WHEN T (RETURN (LOCALLY (VECTOR A B)))))))))))

Extended Syntax of Guard1

As noted earlier, guard1 may contain additional lexical declaration information within symbol. While the normal syntax of guard1 is as follows:

(guard1 symbol test-form {generator-form subpattern}*)

the extended guard1 syntax is:

(guard1 (sym &key
           (type t)
           (binder 'let)
           (ignorable (if (symbol-package sym) nil t))
           dynamic-extent
           special
         &allow-other-keys)
        test-form {generator-form subpattern}*)
type
a type specifier. It is added to the declaration after let.
binder
either a symbol `let`, `symbol-macrolet`, `progv`. The resulting binding is generated with these special forms. For example, with `symbol-macrolet`, then the symbol is bound with symbol-macrolet and the accessor becomes setf-able.
ignorable
If non-nil, symbol is declared to be ignorable. Default value is T when symbol is an apparently uninterned symbol, and NIL otherwise.
dynamic-extent
If non-nil, it adds `dynamic-extent` declaration.
special
If non-nil, it adds `special` declaration.

Note that type does not affect the pattern optimizer nor the test form. The declaration is added only to the conditional branch where the test form is evaluated to be true.

Or1 Pattern

(or1 subpattens*)

Or1 has an important role called consistency check, of checking if the set of variables in each branch is set-equal to each other. If two subpatterns have the different sets of variables, missing variables are assigned NIL.

(defun test (x)
   (match x
     ;; using level2 cons/vector pattern for convenience
     ((or1 (cons   a b)
           (vector a c)) (values a b c))))

(test '(1 . 2)) ;; --> 1, 2, nil
(test #(1 2)) ;; --> 1, nil, 2

This behavior can be changed by setting *or-pattern-allow-unshared-variables* to NIL, in which case variable inconsitency will signal an assertion error of type or1-pattern-inconsistency, with (repair-pattern subpattern) restart. You may fix and replace the subpattern by calling this handler with a new pattern.

When a symbol is declared to be ignorable by guard1, it is not accounted for consistency check.