Refactor to using patterns and hierarchy.

Patterns are declarative. Situations for which rules apply can now be structured
using a flowchart-like hierarchy of patterns. This centralizes branching logic for
different rules.

Pattern results are cached. This is a huge perf gain.