Ir para o conteúdo

The EVE Language

EVE is the pattern-matching engine behind the Verité chat filter. It ships with its own small language for authoring filter files. This page is the top-level guide: what EVE is, how a filter file is structured, and the directives that make up a document. The two dialects each have their own page:

  • ExpandaEVE is the spelled-out form you write by hand. It uses words like HEAR, SUFFIX, NEVER and PLURAL.
  • CompactaEVE is the terse compiled form and the matcher semantics underneath it. Every ExpandaEVE construct lowers to a CompactaEVE symbol before it runs.

What EVE is

EVE reads a filter document and produces a set of compiled rules. Each rule is a pattern that decides whether a candidate word (or, for some rule kinds, a whole message) is a match. The engine is deliberately tolerant of evasion: a fuzzy rule matches through vowel swaps, inserted gaps, stretched letters, and similar tricks, so a single authored root catches many spellings without the author listing each one.

A filter file is plain UTF-8 text. Lines that are blank or begin with # are ignored, so # starts a whole-line comment.

The two forms and how they relate

You author in ExpandaEVE. When a document is loaded, each statement is translated into CompactaEVE, and the CompactaEVE is compiled into the runnable matcher. The flow is:

ExpandaEVE source  ->  CompactaEVE source  ->  compiled rules
     (authoring)          (terse form)          (the matcher)

The translation is purely a rewrite. Anything you can express in ExpandaEVE becomes real CompactaEVE, and every matching decision is made by the compiled form. A document may also be written directly in CompactaEVE: the statement verbs are the same words in lower case (hear, match, let, define, realm, and so on), and a statement that uses no ExpandaEVE-only construct passes through the translator almost verbatim.

Which form should I read?

If you are writing or reading .eve files, start with ExpandaEVE. Read CompactaEVE when you want to understand exactly how a pattern matches, or when you are reading the compiled output.

Document structure

A document is a sequence of statements, one per logical line. The recognized statement keywords are DEFINE, LET, REALM, HEAR, FIND, MATCH, ANYWHERE, and SEQUENCE, plus the eve: header line. Any line that is not blank, not a comment, and does not begin with a recognized keyword raises an error rather than being skipped.

The eve: header

An optional first line declares the version and language:

eve: 1.0 English

The text after eve: up to the first space is the version. The remainder is the language name. Both are recorded on the compiled program. A header with only a version and no language is accepted.

DEFINE: declaring flag ids

DEFINE registers a flag name and the id it maps to. Every flag a rule sets with FLAG(...) must be declared, or the document fails to load.

DEFINE sh AS selfharm
DEFINE ea AS abuse
DEFINE pf AS profanity

The name on the left is what rules reference. The id on the right is the category the filter reports. See Flags for how rules use them.

LET: defining a function (named class)

LET function(name) BE ... declares a named class: a list of interchangeable words or fragments a rule can pull in by name. In CompactaEVE the same class is written let &name be ....

LET function(genderword) BE female OR girl OR woman OR male OR guy OR guys OR men OR man

Members are separated by OR. Once declared, a class is referenced elsewhere with function(name) in ExpandaEVE or &name in CompactaEVE. A class reference expands to all of its members. Classes may carry a default (WHOLE) or (ROOT) marker on the name, which is inherited by references unless the reference overrides it:

LET function(frenchstuff) (WHOLE) BE franger OR frenchie OR jizzbag

See Functions and classes for the full reference, including how a class is used as a root, as a group, as an alias, and inside a skeleton.

Numbered classes and vowels

A class whose name is made entirely of digits contributes its single-character members to the built-in vowel set that relaxed matching uses. This is how the vowel alphabet for leetspeak tolerance is assembled. See Skeletons and the character-class list.

REALM: grouping rules

REALM sets the realm that every following rule belongs to, until the next REALM. A realm is a label used to organize and scope rules. It does not change how a rule matches.

REALM racial_and_ethnic_slurs

Every HEAR, FIND, MATCH, ANYWHERE, and SEQUENCE rule that follows carries that realm name until you declare a different realm.

The rule statements

Five statements declare rules. Each is written as the verb, a name, the keyword AS, and a body. The name and body may span multiple lines: the body runs until the next statement keyword at the start of a line.

Statement Rule kind Matches
HEAR name AS ... Fuzzy A single word, tolerant of evasion. This is the common case.
FIND name AS ... Fuzzy Identical to HEAR. An alternate spelling of the same verb.
MATCH name AS ... Strict The whole input, with exact classes and captures. See Strict rules.
ANYWHERE name AS ... Anywhere Fires when every listed group appears somewhere in the message.
SEQUENCE name AS ... Sequence An ordered run of glyphs appearing in order across the message.

HEAR and FIND are the same rule kind, so this guide uses HEAR throughout. A fuzzy rule body is a full ExpandaEVE pattern: a root plus any of the constructs on the ExpandaEVE page.

ANYWHERE and SEQUENCE

ANYWHERE builds a co-occurrence rule: the body is a list of groups separated by WITH, and the rule fires only when at least one member of every group is found somewhere in the message. Each member is compiled as its own whole-word fuzzy matcher, so members still tolerate evasion. An ANYWHERE rule needs at least two groups.

SEQUENCE is used for ordered symbol and emoji patterns and is documented with the symbol board, which is covered separately. It fires when its glyph steps all appear in order across the message, and a mirror prefix also accepts the reversed order. A SEQUENCE rule needs at least two glyphs.

A complete minimal file

eve: 1.0 English

DEFINE pf AS profanity

REALM profanity

HEAR rule
AS
  shit(WHOLE)
  suffix(NONE OR s OR ty OR head OR heads)
  NEVER(shitake OR shiitake OR mishit)
  FLAG(pf YES)

This declares one flag, opens a realm, and adds one fuzzy rule. The rule matches the whole word shit with any of the listed endings, refuses the listed innocent words, and reports the profanity category. Read the ExpandaEVE reference for every construct used here.