CompactaEVE y semántica de coincidencia
CompactaEVE es la forma compilada concisa del lenguaje EVE, y la entrada que el compilador de patrones analiza en realidad. Cada construcción de ExpandaEVE se reduce a un símbolo de CompactaEVE antes de ejecutarse. Esta página documenta los símbolos compactos, lo que el compilador acepta y cómo un patrón compilado decide si un candidato coincide.
No tienes que escribir CompactaEVE a mano: el traductor de ExpandaEVE lo produce. Pero leerlo es útil para entender exactamente cómo se comporta un patrón, y un documento puede crearse directamente en el dialecto compacto.
Las formas de instrucción compactas
Las directivas de nivel de documento mantienen los mismos nombres en minúsculas:
| ExpandaEVE | CompactaEVE |
|---|---|
DEFINE name AS id |
define name as id |
LET function(name) BE a OR b |
let &name be a|b |
REALM x |
realm x |
HEAR n AS body / FIND n AS body |
hear n as body |
MATCH n AS body |
match n as body |
ANYWHERE n AS ... |
anywhere n as g1 !! g2 |
SEQUENCE n AS ... |
sequence n as ... |
Los miembros de clase y los brazos de grupo se separan con la barra | en lugar de OR. Una clase se referencia con &name. El resto de esta página cubre el cuerpo de patrón de una regla difusa, que es donde viven los símbolos compactos.
Marcadores de raíz
Exactamente un marcador de raíz separa el tallo raíz del resto del patrón:
| Símbolo | De ExpandaEVE | Significado |
|---|---|---|
[^^] |
(WHOLE) |
La raíz coincide como palabra completa. La ruta debe llegar hasta un límite de palabra. |
[*^] |
(ROOT) |
La raíz es un tallo sobre el que se construyen las partes posteriores. |
El texto antes del marcador es el tallo raíz. ni[*^] tiene el tallo ni; spic[^^] tiene el tallo spic y requiere una coincidencia de palabra completa.
Partes: las piezas de un fragmento
Un fragmento (una raíz, un brazo de grupo, un sufijo) se analiza en una lista ordenada de partes. El compilador reconoce estos tokens; todo lo demás se acumula como una serie literal.
| Token | Tipo | Coincide con |
|---|---|---|
| texto plano | Literal | Los caracteres exactos, en orden. |
@ |
Cualquiera | Exactamente un carácter de material de palabra. |
(#*) |
Hueco | Una serie de caracteres cualesquiera, letras o no. No determinista: puede terminar en cualquier posición alcanzable. |
($^) |
Hueco (letras) | Una serie de letras (material de palabra) únicamente. |
[swap:...] |
Swap | Cualquiera de varios brazos alternativos con reglas de límite. |
Un literal coincide exactamente. @ consume un byte de palabra. Un hueco es la tolerancia del motor a los caracteres insertados: puede saltar cero o más posiciones, y el matcher prueba cada fin alcanzable.
Material de palabra
El material de palabra es una letra ASCII o cualquier byte no ASCII. Un glifo de varios bytes como un emoji es una serie de bytes de palabra, así que las series de glifos se tokenizan y se delimitan como palabras. Ningún byte ASCII se trata como byte de símbolo, así que el texto ordinario queda sin cambios.
Raíces y alternativas de raíz
La raíz puede tomar tres formas:
- Un tallo plano:
masturb[*^]compila a una raíz. - Una referencia de clase:
&name...se expande de modo que cada miembro de la clase se convierte en una alternativa de raíz, conservando cualquier texto final. - Una raíz segmentada
[[..][..]]: consulta Raíces segmentadas.
Los corchetes de anulación iniciales y los productos de prefijo generan más alternativas de raíz:
[text;]antes de la raíz reemplaza el literal inicial de la raíz context, produciendo una grafía alternativa. Esto es a lo que se reduce ALIAS. Una anulación[text^^;]o[text*^;]también establece el límite de esa alternativa.[+[a|b]]antes de la raíz es un producto cruzado de prefijo: cada prefijo listado se antepone a cada raíz, multiplicando las alternativas. Esto es lo que usa ALSO cuando se sitúa antes de la raíz, y a lo que se expande una referencia de clase dentro de[+[...]].
Las alternativas de raíz se ordenan primero por el literal más largo, así que una grafía más específica se prueba antes que una más corta. Una alternativa de raíz se omite pronto cuando un literal que debe consumir está ausente del candidato.
Raíces segmentadas
Una raíz segmentada se escribe [[seg1][seg2]...] donde un segmento que termina en * es un punto de entrada. Genera alternativas que empiezan en cada segmento con asterisco, opcionalmente prefijadas por los segmentos anteriores. Esto permite que una raíz como re[tard] se alcance tanto como palabra completa como desde el segmento flexible. Una raíz segmentada sin punto de entrada con asterisco es un error.
Sufijos y terminaciones (finales)
Las terminaciones viven en la lista de sufijos finales. En CompactaEVE se añaden con |[a|b|...] después de la raíz, que es a lo que se reduce suffix(...). Una ruta coincide solo cuando el candidato termina en uno de los sufijos finales y llega hasta el final de la palabra.
Un brazo vacío (NONE) hace opcional el sufijo.
Sufijos de reescritura
Un brazo final escrito from>to es una reescritura. Coincide con un candidato que termina en to quitando to, añadiendo from y probando el resultado contra el patrón central. y>ies permite que una raíz que termina en y también coincida con una palabra que termina en ies, así que una raíz alcanza tanto baby como babies. El marcador > es el único lugar donde se interpreta una reescritura, así que todos los lectores de sufijos finales coinciden en su significado.
Grupos
Entre la raíz y los sufijos finales, el patrón es una secuencia de grupos. Un grupo es un conjunto de brazos alternativos, cualquiera de los cuales puede satisfacerlo. Un grupo tiene un tipo:
| Tipo | CompactaEVE | Comportamiento |
|---|---|---|
| Normal | `[a | b]` |
| Plus (flotante) | `[+[a | b]]` |
| Hard (anclado) | una referencia de clase hard | Una alternativa anclada que coincide desde el principio. |
Un brazo vacío hace opcional su grupo. Un grupo escrito como un hueco simple, (#*) o ($^), es un grupo de hueco opcional, que es a lo que se reduce un GAP o LETTERS independiente entre partes.
Referencias de clase como grupos
&name en la posición de grupo expande la clase en un grupo de brazos, uno por miembro. &!name hace opcional el grupo (se añade un brazo vacío extra), que es a lo que se reduce MAYBE FUNCTION. Una referencia puede llevar [^^] o [*^] para forzar coincidencia hard o soft; de lo contrario hereda la dureza declarada de la clase. Una referencia de clase hard se convierte en un grupo anclado hard.
Grupos plus (flotantes)
Un grupo plus [+[...]] no se sitúa en un orden fijo. Después de consumir la raíz y los grupos normales, el matcher calcula cada posición alcanzable y deja que el grupo plus se una en cualquiera de ellas, llegando hasta el final de la palabra. Así es como las funciones ADDITIVE y ALSO flotan respecto al tallo.
Swaps
[swap:a|b] coincide con cualquier brazo en una posición. Cada brazo lleva flags de límite decididas por sus asteriscos:
- Un solo
*inicial libera el límite de inicio. - Un solo
*final libera el límite de fin. - Sin asterisco, o un
**inicial doble, ancla ambos lados.
Un lado anclado requiere un límite de palabra ahí: el inicio debe seguir a un byte que no sea de palabra (o ser el inicio de la cadena), y el fin debe preceder a un byte que no sea de palabra (o ser el fin de la cadena). Un swap puede escribirse en línea en un fragmento o como su propio grupo.
Exclusiones (veto)
[-[a|b]] es una lista de veto, que es a lo que se reduce NEVER. Cada frase listada es una prueba de subcadena simple contra toda la línea, en minúsculas. Si alguna frase está presente, el patrón no se dispara, independientemente del resto de la coincidencia.
Precheck y control posterior
Dos construcciones regulan un patrón según la línea circundante:
{pre:a|b}es un precheck, de BEFORE. El patrón permanece inerte a menos que una de las frases sea una subcadena de la línea, en minúsculas.{post:a|b}es una condición posterior, de AFTER. Se inserta en el marcador de raíz como un grupo inicial opcional de terminaciones permitidas.
Un patrón regulado (uno con un precheck) se dispara solo cuando una frase de precheck está presente en la línea, o cuando el candidato satisface la condición posterior por sí solo: comienza con el tallo raíz y termina con una de las terminaciones posteriores, tolerando un plural final s. Los hechos de precheck y veto dependen solo de la línea, no del candidato, así que se calculan una vez por línea y se reutilizan entre candidatos.
Skeletons
{skel:...} es la lista blanca de skeleton, de SKELETON. Se expande en tiempo de compilación a un conjunto de palabras concretas. Un candidato exactamente igual a una de esas palabras coincide inmediatamente, antes de que se ejecute el matcher central.
Dentro de un skeleton:
[a,b,c]es una lista de opciones en línea: una posición que puede ser cualquier miembro separado por comas. Los miembros pueden ser de varios caracteres. Los espacios en blanco alrededor de un miembro se recortan.&namese expande a los miembros de esa clase. Un nombre de clase numérico se expande dígito por dígito; una clase con nombre se expande como letras.
La expansión es el producto cruzado completo de cada opción, en minúsculas.
Envoltorios de flag
{name:y?...} y {name:n?...} envuelven un patrón en una condición de flag, de FLAG. La forma y requiere la flag activada, la forma n requiere que esté desactivada. Se pueden anidar varios envoltorios. El nombre de la flag debe declararse con define, o el documento no se carga. Las flags declaradas son lo que el filtro reporta como categoría.
Comentarios
{#c:...} es un comentario en línea, de NOTE. Se elimina antes de la compilación, incluidas las llaves anidadas. Los comentarios de línea completa usan un # inicial.
Cómo coincide un patrón difuso
Cuando una palabra candidata se prueba contra un patrón difuso compilado, el motor ejecuta estas comprobaciones en orden:
- Regulación. Si el patrón tiene un precheck y ni hay una frase de precheck presente en la línea ni se satisface la condición posterior, no coincide. Si alguna frase de veto está presente en la línea, no coincide.
- Skeleton. Si el candidato es exactamente igual a una palabra de skeleton, coincide.
- Coincidencia central. El motor principal se ejecuta (abajo).
- Respaldo de reescritura. Para cada sufijo de reescritura, si el candidato termina en el lado
to, se restaura el ladofromy se reintenta la coincidencia central sobre la palabra restaurada.
La coincidencia central
El matcher central decide si toda la palabra candidata queda cubierta por una ruta:
- Un rechazo rápido descarta el candidato cuando le falta cada literal que una ruta central debe contener.
- Los grupos anclados hard se prueban desde el principio; una ruta que llega a una terminación permitida coincide.
- Cada alternativa de raíz se ejecuta desde el principio. Una raíz cuyos literales requeridos están ausentes se omite. Los fines alcanzables alimentan la secuencia de grupos normales.
- Los grupos normales se enhebran en orden desde los fines de la raíz. Una ruta coincide cuando llega a un sufijo final permitido que se extiende hasta el final de la palabra. A menos que la ruta sea puramente literal, al menos un brazo no vacío debe haberse disparado.
- Los grupos plus flotantes se prueban en cada ranura alcanzable, y un grupo plus coincide cuando uno de sus brazos se extiende desde un anclaje alcanzable hasta el final de la palabra.
Los límites de palabra provienen del material de palabra: existe un límite en los fines de la cadena y dondequiera que un byte que no sea de palabra se encuentre con un byte de palabra. Los huecos saltan series de caracteres de forma no determinista, así que el matcher explora cada posición que un hueco puede alcanzar.
Anclajes y el prefiltro de escaneo
Para cada regla difusa, el compilador calcula un conjunto de anclajes literales requeridos: literales tales que un candidato que no contenga ninguno de ellos no puede coincidir. Si una regla puede coincidir sin ningún literal garantizado (por ejemplo, una ruta puramente de hueco o regulada), su conjunto de anclajes está vacío y la regla siempre se ejecuta. Los anclajes de cada regla construyen un prefiltro Aho-Corasick que, en una sola pasada sobre un mensaje, marca qué reglas podrían coincidir, de modo que las reglas cuyos literales están ausentes se omiten. Esto es solo una optimización: nunca omite una regla que podría coincidir.
Reglas estrictas (MATCH)
Una regla MATCH usa el lenguaje estricto en lugar del motor difuso. Un patrón estricto está anclado: solo tiene éxito cuando sus términos consumen toda la entrada de principio a fin. Se usa para entradas estructuradas como números y direcciones, y puede capturar piezas con nombre.
Primitivas estrictas
| Palabra clave | Coincide con |
|---|---|
digit |
Exactamente un dígito. |
digits |
Una serie de dígitos. |
letter |
Exactamente una letra. |
letters |
Una serie de letras. |
word |
Una serie de letras, dígitos o guion bajo. |
number |
Una serie de dígitos. |
ip |
Una serie de dígitos y puntos. |
space |
Exactamente un carácter de espacio en blanco. |
spaces |
Una serie de espacios en blanco. |
anything |
Cualquier tramo de texto. |
La coincidencia de palabras clave ignora las mayúsculas. Un token "..." es un literal, respetando los escapes de barra invertida.
Cuantificadores y estructura estrictos
| Construcción | Efecto |
|---|---|
any x |
Cero o más de x, codicioso. |
many x |
Uno o más de x, codicioso. |
maybe x |
Cero o uno de x. |
m to n x |
Entre m y n de x. |
n digit (etc.) |
Exactamente n de una clase, por ejemplo 3 digit. |
( ... ) |
Un grupo que coincide como subsecuencia. |
x or y |
Alternancia: cualquiera de las ramas puede satisfacer la posición. |
then |
Pegamento legible opcional entre términos; se ignora. |
x as name |
Captura el texto coincidente de x bajo name. |
Un cuantificador aplicado a una clase plural la reduce a su forma de un solo carácter para que se repita de carácter en carácter. La repetición es solo codiciosa; no hay modo perezoso, y una repetición vacía no puede formar un bucle.
Referencias de lista y búsqueda difusa en estricto
&name en un patrón estricto se expande a una alternancia de los miembros de la clase como literales. Un término entre acentos graves find `pattern` incrusta un patrón difuso de EVE: el matcher estricto entrega un tramo sin espacios al patrón difuso compilado y acepta el tramo cuando coincide. Ambos necesitan el registro, que está disponible cuando se compila un documento.
Reglas anywhere y sequence
ANYWHERE y SEQUENCE son tipos de regla distintos. ANYWHERE se dispara cuando cada grupo (separado por !! en forma compacta, WITH en ExpandaEVE) tiene un miembro que se encuentra en algún lugar del mensaje; cada miembro se compila como un matcher difuso de palabra completa, y la regla necesita al menos dos grupos. SEQUENCE coincide con una serie ordenada de glifos y la usa el tablero de símbolos, que está documentado por separado; un prefijo mirror también acepta el orden invertido, y la regla necesita al menos dos glifos.