UPDATE: Modified LRM and generate_mbap.py to ensure better samples
This commit is contained in:
parent
b5167b71e3
commit
90857e1b0a
173
docs/LRM/avap.md
173
docs/LRM/avap.md
|
|
@ -115,7 +115,41 @@ AVAP utiliza una gramática estructural mixta. Combina la fluidez de las palabra
|
||||||
La estructura `if()` evalúa una expresión lógica o de comparación. Todo bloque condicional requiere un cierre explícito utilizando el comando `end()`.
|
La estructura `if()` evalúa una expresión lógica o de comparación. Todo bloque condicional requiere un cierre explícito utilizando el comando `end()`.
|
||||||
|
|
||||||
El comando `if()` soporta dos modos de invocación:
|
El comando `if()` soporta dos modos de invocación:
|
||||||
* **Modo 1 (comparación estructurada):** `if(variable, valor, comparador)` — evalúa la comparación entre variable y valor usando el operador indicado como string (ej. `"=="`, `">"`, `"!="`). Los dos primeros argumentos deben ser identificadores simples o literales, nunca expresiones de acceso como `dict['clave']`. Si se necesita comparar un valor extraído de una estructura, debe asignarse primero a una variable.* **Modo 2 (expresión libre):** `if(None, None, "expresion_compleja")` — evalúa directamente una expresión booleana compleja proporcionada como string.
|
* **Modo 1 (comparación estructurada):** `if(variable, valor, comparador)` — evalúa la comparación entre variable y valor usando el operador indicado como string (ej. `"=="`, `">"`, `"!="`). Los dos primeros argumentos deben ser identificadores simples o literales, nunca expresiones de acceso como `dict['clave']`. Si se necesita comparar un valor extraído de una estructura, debe asignarse primero a una variable.* **Modo 2 (expresión libre):** `if(None, None, expresion_compleja)` — evalúa directamente una expresión booleana compleja proporcionada como string encapsulado entre `.
|
||||||
|
|
||||||
|
## SECCIÓN III: Lógica de Control y Estructuras de Decisión
|
||||||
|
|
||||||
|
AVAP utiliza una gramática estructural mixta. Combina la fluidez de las palabras clave para abrir bloques funcionales con la seguridad matemática de cierres estrictos.
|
||||||
|
|
||||||
|
### 3.1 El Bloque Condicional (if() / else() / end())
|
||||||
|
El comando `if()` gestiona la lógica condicional mediante dos modos de invocación estrictamente diferenciados. Es imperativo respetar los delimitadores y la posición de los argumentos.
|
||||||
|
|
||||||
|
#### Modo 1: Comparación Estructurada (Atómica)
|
||||||
|
Se utiliza para comparaciones directas entre dos valores simples.
|
||||||
|
* **Sintaxis:** `if(átomo_1, átomo_2, "operador")`
|
||||||
|
* **Argumentos 1 y 2:** Deben ser identificadores simples (variables) o literales (strings/números). **No se permite el uso de `None` en este modo.**
|
||||||
|
* **Argumento 3:** El operador de comparación debe ir obligatoriamente entre **comillas dobles** (`"=="`, `"!="`, `">"`, `"<"`, `">="`, `"<="`).
|
||||||
|
* **Restricción:** No se permiten expresiones de acceso (ej. `data.user` o `list[0]`). Estos valores deben asignarse previamente a una variable.
|
||||||
|
* **Ejemplo correcto:** `if(reintentos, 5, "<")`
|
||||||
|
|
||||||
|
#### Modo 2: Expresión Libre (Evaluación Compleja)
|
||||||
|
Se utiliza para evaluar expresiones lógicas que no encajan en la estructura atómica.
|
||||||
|
* **Sintaxis:** `if(None, None, `expresión_compleja`)`
|
||||||
|
* **Argumentos 1 y 2:** Deben ser literalmente la palabra `None` (sin comillas).
|
||||||
|
* **Argumento 3:** La expresión completa **debe** estar encapsulada entre **acentos graves (backticks)**. Esto permite incluir lógica interna, operadores `and/or` y accesos a estructuras de datos.
|
||||||
|
* **Ejemplo correcto:** `if(None, None, `user.id > 10 and email.contains("@")`)`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Tabla de Validación para el Modelo
|
||||||
|
|
||||||
|
| Entrada | Estado | Razón |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `if(count, 10, "==")` | ✅ VÁLIDO | Modo 1: Átomos válidos y operador entre comillas. |
|
||||||
|
| `if(None, None, `val > 0`)` | ✅ VÁLIDO | Modo 2: Uso correcto de `None` y backticks. |
|
||||||
|
| `if(username, None, "==")` | ❌ ERROR | El Modo 1 prohíbe el uso de `None`. Debe usarse el Modo 2. |
|
||||||
|
| `if(None, None, "val > 0")` | ❌ ERROR | El Modo 2 requiere backticks (`` ` ``), no comillas. |
|
||||||
|
| `if(user.id, 10, "==")` | ❌ ERROR | El Modo 1 no permite expresiones de acceso (`.`). |
|
||||||
|
|
||||||
### 3.2 Iteraciones Estrictas y Deterministas (startLoop / endLoop)
|
### 3.2 Iteraciones Estrictas y Deterministas (startLoop / endLoop)
|
||||||
Para garantizar el determinismo y evitar el colapso de memoria:
|
Para garantizar el determinismo y evitar el colapso de memoria:
|
||||||
|
|
@ -137,15 +171,17 @@ Diseñada para proteger la estabilidad del servidor ante fallos de I/O.
|
||||||
[ "else()" <EOL> <block> ]
|
[ "else()" <EOL> <block> ]
|
||||||
"end()" <EOL>
|
"end()" <EOL>
|
||||||
|
|
||||||
/* if() soporta dos modos:
|
<if_condition> ::= <if_structured> | <if_free_expression>
|
||||||
Modo 1 — comparación estructurada: los dos primeros argumentos deben ser
|
|
||||||
identificadores simples o literales, nunca expresiones de acceso.
|
<if_structured> ::= "if" "(" <strict_atom> "," <strict_atom> "," <backtick_string> ")"
|
||||||
Si se necesita comparar un valor extraído de una estructura (ej. dict['clave']),
|
<if_free_expression> ::= "if" "(" "None" "," "None" "," <backtick_string> ")"
|
||||||
debe asignarse previamente a una variable.
|
|
||||||
Modo 2 — expresión libre: None, None, expresión compleja como string */
|
<strict_atom> ::= <identifier> | <non_null_literal>
|
||||||
<if_condition> ::= <if_atom> "," <if_atom> "," <stringliteral>
|
<backtick_string> ::= "`" <text_content> "`"
|
||||||
| "None" "," "None" "," <stringliteral>
|
|
||||||
<if_atom> ::= <identifier> | <literal>
|
<identifier> ::= [a-zA-Z_][a-zA-Z0-9_]*
|
||||||
|
<non_null_literal>::= <number> | <string_literal_double_quotes>
|
||||||
|
/* Nota: <non_null_literal> NO incluye la palabra "None" */
|
||||||
|
|
||||||
<loop_stmt> ::= "startLoop(" <identifier> "," <expression> "," <expression> ")" <EOL>
|
<loop_stmt> ::= "startLoop(" <identifier> "," <expression> "," <expression> ")" <EOL>
|
||||||
<block>
|
<block>
|
||||||
|
|
@ -261,59 +297,116 @@ AVAP utiliza `avapConnector("TOKEN")` para la hidratación segura de credenciale
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## SECCIÓN VI: Utilidades, Criptografía y Manipulación de Datos
|
# SECCIÓN VI: Utilidades, Criptografía y Manipulación de Datos
|
||||||
|
|
||||||
AVAP incluye un set de comandos integrados de alto nivel para manipular tipos complejos (JSON y Listas), tiempos, textos y generar hashes.
|
AVAP incluye un set de comandos integrados de alto nivel para manipular tipos complejos (JSON y Listas), tiempos, textos y generar hashes.
|
||||||
|
|
||||||
### 6.1 Manipulación Nativa de Listas y Objetos JSON
|
---
|
||||||
Para extraer y mutar estructuras complejas, AVAP provee comandos nativos específicos:
|
|
||||||
* **`variableToList(elemento, destino)`**: Fuerza a que una variable escalar se convierta en una estructura iterable de lista.
|
|
||||||
* **`itemFromList(lista_origen, indice, destino)`**: Extrae de forma segura el elemento contenido en la posición `indice` de una lista.
|
|
||||||
* **`variableFromJSON(json_origen, clave, destino)`**: Parsea un objeto JSON en memoria y extrae el valor correspondiente a la `clave`.
|
|
||||||
* **`AddVariableToJSON(clave, valor, json_destino)`**: Inyecta dinámicamente una nueva propiedad dentro de un objeto JSON existente.
|
|
||||||
|
|
||||||
### 6.2 Criptografía y Expresiones Regulares
|
## 6.1 Manipulación Nativa de Listas y Objetos JSON
|
||||||
* **`encodeSHA256` y `encodeMD5(origen, destino)`**: Funciones criptográficas que encriptan de forma irreversible un texto. Vitales para el almacenamiento seguro de contraseñas.
|
|
||||||
* **`getRegex(origen, patron, destino)`**: Aplica una Expresión Regular (`patron`) sobre la variable de origen, extrayendo las coincidencias exactas.
|
|
||||||
|
|
||||||
### 6.3 Transformación de Tiempo y Cadenas
|
Para extraer y mutar estructuras complejas, AVAP provee comandos nativos específicos. En AVAP, las listas **no se instancian con literales de array**, sino que se construyen y recorren a través de un conjunto cerrado de comandos especializados:
|
||||||
* **Fechas:** `getTimeStamp` (convierte un string a Epoch), `getDateTime` (Epoch a string legible), y `stampToDatetime` (Epoch a objeto datetime estructurado). Soportan formatos de calendario y cálculos con TimeDeltas.
|
|
||||||
* **Cadenas:** `replace` (saneamiento y sustitución de texto) y `randomString` (generación determinista de claves/tokens aleatorios).
|
|
||||||
|
|
||||||
### Especificación BNF (Sección VI)
|
* **`variableToList(elemento, destino)`**: Fuerza a que una variable escalar se convierta en una estructura iterable de lista de un único elemento. Es el punto de entrada canónico para construir una lista desde cero a partir de un valor existente.
|
||||||
|
|
||||||
|
* **`itemFromList(lista_origen, indice, destino)`**: Extrae de forma segura el elemento contenido en la posición `indice` (base 0) de una lista. Equivale a un acceso por índice controlado.
|
||||||
|
|
||||||
|
* **`getListLen(lista, destino)`**: Calcula el número total de elementos contenidos en `lista` y almacena el resultado entero en `destino`. Imprescindible para construir bucles de recorrido seguro y para validar listas antes de acceder a sus índices. Se recomienda llamar siempre a `getListLen` antes de `itemFromList` para evitar accesos fuera de rango.
|
||||||
|
|
||||||
|
* **`variableFromJSON(json_origen, clave, destino)`**: Parsea un objeto JSON en memoria y extrae el valor correspondiente a la `clave`, almacenándolo en `destino`. El acceso es directo por nombre de propiedad.
|
||||||
|
|
||||||
|
* **`AddVariableToJSON(clave, valor, json_destino)`**: Inyecta dinámicamente una nueva propiedad dentro de un objeto JSON existente. Si la clave ya existe, su valor es sobreescrito.
|
||||||
|
|
||||||
|
**Patrón de recorrido típico en AVAP:**
|
||||||
|
|
||||||
|
```avap
|
||||||
|
// 1. Obtener longitud de la lista
|
||||||
|
getListLen(myList, len)
|
||||||
|
|
||||||
|
// 2. Iterar con índice controlado
|
||||||
|
i = 0
|
||||||
|
while (i < len) {
|
||||||
|
itemFromList(myList, i, currentItem)
|
||||||
|
// ... procesar currentItem ...
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.2 Criptografía y Expresiones Regulares
|
||||||
|
|
||||||
|
* **`encodeSHA256(origen, destino)`** y **`encodeMD5(origen, destino)`**: Funciones criptográficas que encriptan de forma irreversible un texto. Vitales para el almacenamiento seguro de contraseñas y la verificación de integridad de datos. SHA-256 produce un digest de 64 caracteres hexadecimales y ofrece mayor resistencia criptográfica que MD5 (32 caracteres); se recomienda SHA-256 para nuevos desarrollos.
|
||||||
|
|
||||||
|
* **`getRegex(origen, patron, destino)`**: Aplica una Expresión Regular (`patron`) sobre la variable de origen, extrayendo la primera coincidencia exacta encontrada. El patrón sigue la sintaxis estándar compatible con Python `re`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.3 Transformación de Tiempo y Cadenas
|
||||||
|
|
||||||
|
### Fechas y Timestamps
|
||||||
|
|
||||||
|
AVAP provee tres comandos complementarios para cubrir todas las conversiones posibles entre representaciones de tiempo. Los tres soportan formatos de calendario en notación `strftime` de Python y cálculos con `TimeDelta` expresados en segundos (positivo para sumar, negativo para restar):
|
||||||
|
|
||||||
|
| Comando | Entrada | Salida |
|
||||||
|
|---|---|---|
|
||||||
|
| `getTimeStamp(fecha_string, formato, timedelta, destino)` | String de fecha | Epoch (entero) |
|
||||||
|
| `stampToDatetime(epoch, formato, timedelta, destino)` | Epoch (entero) | String de fecha |
|
||||||
|
| `getDateTime(formato, timedelta, zona_horaria, destino)` | — (ahora mismo) | String de fecha |
|
||||||
|
|
||||||
|
* **`getTimeStamp(fecha_string, formato, timedelta, destino)`**: Convierte un string de fecha legible a su valor Epoch (entero Unix). Útil para almacenar fechas y realizar cálculos aritméticos sobre ellas.
|
||||||
|
|
||||||
|
* **`stampToDatetime(epoch, formato, timedelta, destino)`**: Convierte un valor Epoch a un string de fecha con el formato especificado. Útil para presentar timestamps almacenados de forma legible.
|
||||||
|
|
||||||
|
* **`getDateTime(formato, timedelta, zona_horaria, destino)`**: Captura la fecha y hora actuales del sistema, aplica el ajuste `timedelta` y las convierte a la `zona_horaria` indicada antes de almacenar el resultado. Acepta cualquier zona horaria reconocida por la librería `pytz` de Python.
|
||||||
|
|
||||||
|
### Cadenas de Texto
|
||||||
|
|
||||||
|
* **`randomString(patron, longitud, destino)`**: Genera una cadena aleatoria de `longitud` caracteres cuyos símbolos están restringidos al conjunto definido por `patron` (expresión regular de caracteres). Útil para generar tokens de sesión, contraseñas temporales o identificadores únicos.
|
||||||
|
|
||||||
|
* **`replace(origen, patron_busqueda, reemplazo, destino)`**: Localiza todas las ocurrencias de `patron_busqueda` dentro de `origen` y las sustituye por `reemplazo`, almacenando el resultado en `destino`. Facilita el saneamiento y normalización de datos de entrada antes de su procesamiento o almacenamiento.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## BNF — Gramática Formal de los Comandos de Utilidad
|
||||||
|
|
||||||
```bnf
|
```bnf
|
||||||
/* [CORRECCIÓN] Todas las subreglas de <util_command> están ahora completamente expandidas. */
|
<util_command> ::= <json_list_cmd> | <crypto_cmd> | <regex_cmd>
|
||||||
<util_command> ::= <json_list_cmd> | <crypto_cmd> | <regex_cmd> | <datetime_cmd> | <stamp_cmd> | <string_cmd> | <replace_cmd>
|
| <datetime_cmd> | <stamp_cmd> | <string_cmd> | <replace_cmd>
|
||||||
|
|
||||||
/* Manipulación de listas y JSON */
|
/* Manipulación de listas y JSON */
|
||||||
<json_list_cmd> ::= "variableToList(" <expression> "," <identifier> ")"
|
<json_list_cmd> ::= "variableToList(" <expression> "," <identifier> ")"
|
||||||
| "itemFromList(" <identifier> "," <expression> "," <identifier> ")"
|
| "itemFromList(" <identifier> "," <expression> "," <identifier> ")"
|
||||||
| "variableFromJSON(" <identifier> "," <expression> "," <identifier> ")"
|
| "getListLen(" <identifier> "," <identifier> ")"
|
||||||
| "AddVariableToJSON(" <expression> "," <expression> "," <identifier> ")"
|
| "variableFromJSON(" <identifier> "," <expression> "," <identifier> ")"
|
||||||
|
| "AddVariableToJSON(" <expression> "," <expression> "," <identifier> ")"
|
||||||
|
|
||||||
/* Criptografía */
|
/* Criptografía */
|
||||||
<crypto_cmd> ::= "encodeSHA256(" <identifier_or_string> "," <identifier> ")"
|
<crypto_cmd> ::= "encodeSHA256(" <expression> "," <identifier> ")"
|
||||||
| "encodeMD5(" <identifier_or_string> "," <identifier> ")"
|
| "encodeMD5(" <expression> "," <identifier> ")"
|
||||||
|
|
||||||
/* Expresiones regulares */
|
/* Expresiones regulares */
|
||||||
<regex_cmd> ::= "getRegex(" <identifier> "," <stringliteral> "," <identifier> ")"
|
<regex_cmd> ::= "getRegex(" <identifier> "," <expression> "," <identifier> ")"
|
||||||
|
|
||||||
<datetime_cmd> ::= "getDateTime(" <stringliteral> "," <expression> "," <stringliteral> "," <identifier> ")"
|
/* Fecha/hora actual → string */
|
||||||
/* Argumentos: formato_salida, epoch_origen, zona_horaria, destino */
|
<datetime_cmd> ::= "getDateTime(" <stringliteral> "," <expression> "," <stringliteral> "," <identifier> ")"
|
||||||
|
/* Argumentos: formato_salida, timedelta, zona_horaria, destino */
|
||||||
|
|
||||||
<stamp_cmd> ::= "stampToDatetime(" <expression> "," <stringliteral> "," <expression> "," <identifier> ")"
|
/* Conversiones epoch ↔ string */
|
||||||
|
<stamp_cmd> ::= "stampToDatetime(" <expression> "," <stringliteral> "," <expression> "," <identifier> ")"
|
||||||
/* Argumentos: epoch_origen, formato, timedelta, destino */
|
/* Argumentos: epoch_origen, formato, timedelta, destino */
|
||||||
| "getTimeStamp(" <stringliteral> "," <stringliteral> "," <expression> "," <identifier> ")"
|
| "getTimeStamp(" <stringliteral> "," <stringliteral> "," <expression> "," <identifier> ")"
|
||||||
/* Argumentos: fecha_string, formato_entrada, timedelta, destino */
|
/* Argumentos: fecha_string, formato_entrada, timedelta, destino */
|
||||||
|
|
||||||
<string_cmd> ::= "randomString(" <expression> "," <identifier> ")"
|
/* Cadenas */
|
||||||
/* Argumentos: longitud, destino */
|
<string_cmd> ::= "randomString(" <expression> "," <expression> "," <identifier> ")"
|
||||||
|
/* Argumentos: patron, longitud, destino */
|
||||||
|
|
||||||
<replace_cmd> ::= "replace(" <identifier_or_string> "," <stringliteral> "," <stringliteral> "," <identifier> ")"
|
<replace_cmd> ::= "replace(" <identifier> "," <stringliteral> "," <stringliteral> "," <identifier> ")"
|
||||||
/* Argumentos: origen, patron_busqueda, reemplazo, destino */
|
/* Argumentos: origen, patron_busqueda, reemplazo, destino */
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## SECCIÓN VII: Arquitectura de Funciones y Ámbitos (Scopes)
|
## SECCIÓN VII: Arquitectura de Funciones y Ámbitos (Scopes)
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ REGLAS ESTRICTAS para el código AVAP generado:
|
||||||
5. if() Modo 1: if(var_o_literal, var_o_literal, "operador")
|
5. if() Modo 1: if(var_o_literal, var_o_literal, "operador")
|
||||||
— los argumentos NO pueden ser expresiones de acceso como dict['key'];
|
— los argumentos NO pueden ser expresiones de acceso como dict['key'];
|
||||||
hay que extraer el valor a una variable propia primero.
|
hay que extraer el valor a una variable propia primero.
|
||||||
6. if() Modo 2: if(None, None, "expresion_completa_como_string")
|
6. if() Modo 2: if(None, None, `expresion_completa_como_string`)
|
||||||
7. _status se asigna con: addVar(_status, 404)
|
7. _status se asigna con: addVar(_status, 404)
|
||||||
8. ormAccessSelect firma: ormAccessSelect(campos, "tabla", selector, varTarget)
|
8. ormAccessSelect firma: ormAccessSelect(campos, "tabla", selector, varTarget)
|
||||||
— selector puede ser cadena vacía.
|
— selector puede ser cadena vacía.
|
||||||
|
|
@ -105,25 +105,25 @@ Ejemplo sin addParam:
|
||||||
test_list: ["re.match(r'^[a-zA-Z0-9]{16}$', token)"]
|
test_list: ["re.match(r'^[a-zA-Z0-9]{16}$', token)"]
|
||||||
|
|
||||||
FORMATO DE test_list — MUY IMPORTANTE:
|
FORMATO DE test_list — MUY IMPORTANTE:
|
||||||
Cada aserción debe ser una expresión Python con re.match() o re.search()
|
Cada aserción debe ser una expresión Python con re.match()
|
||||||
evaluable directamente sobre las variables del stack AVAP (disponibles como
|
evaluable directamente sobre las variables del stack AVAP (disponibles como
|
||||||
variables Python locales). El módulo 're' está siempre disponible.
|
variables Python locales). El módulo 're' está siempre disponible.
|
||||||
La expresión debe devolver un match object (truthy) si el test pasa.
|
La expresión debe devolver un match object (truthy) si el test pasa.
|
||||||
|
|
||||||
Reglas estrictas:
|
Reglas estrictas:
|
||||||
- USA ÚNICAMENTE re.match(r'<patrón>', <variable>) o re.search(r'<patrón>', str(<variable>))
|
- USA ÚNICAMENTE re.match(r'<patrón>', <variable>)
|
||||||
|
- NO combines expresiones re.match en una aserción, cada asercion tiene que ser un unico re.match(r'<patrón>', <variable>)
|
||||||
- Convierte a string si es necesario: re.match(r'^\\d+$', str(result))
|
- Convierte a string si es necesario: re.match(r'^\\d+$', str(result))
|
||||||
- Puedes encadenar con 'and': re.match(r'^[a-zA-Z0-9]{32}$', token) and re.match(r'.{32}', token)
|
- Puedes encadenar con 'and': re.match(r'^[a-zA-Z0-9]{32}$', token) and re.match(r'.{32}', token)
|
||||||
- Las variables referenciadas deben existir en el stack tras ejecutar el código.
|
- Las variables referenciadas deben existir en el stack tras ejecutar el código.
|
||||||
- NUNCA uses comparaciones directas (==, !=, >, <).
|
- NUNCA uses comparaciones directas (==, !=, >, <).
|
||||||
- NUNCA uses isinstance(), len(), assert, ni texto descriptivo.
|
- NUNCA uses isinstance(), len(), assert, ni texto descriptivo.
|
||||||
- NUNCA uses nada que no sea re.match() o re.search().
|
- NUNCA uses nada que no sea re.match().
|
||||||
|
|
||||||
Ejemplos correctos de test_list:
|
Ejemplos correctos de test_list:
|
||||||
"re.match(r'^[a-f0-9]{64}$', hashed)"
|
"re.match(r'^[a-f0-9]{64}$', hashed)"
|
||||||
"re.match(r'^[a-zA-Z0-9]{32}$', token)"
|
"re.match(r'^[a-zA-Z0-9]{32}$', token)"
|
||||||
"re.match(r'^\\d{4}-\\d{2}-\\d{2}$', date_str)"
|
"re.match(r'^\\d{4}-\\d{2}-\\d{2}$', date_str)"
|
||||||
"re.search(r'Hello', result)"
|
|
||||||
"re.match(r'^-?\\d+(\\.\\d+)?$', str(result))"
|
"re.match(r'^-?\\d+(\\.\\d+)?$', str(result))"
|
||||||
"re.match(r'^(par|impar)$', result)"
|
"re.match(r'^(par|impar)$', result)"
|
||||||
"re.match(r'^40[134]$', str(_status))"
|
"re.match(r'^40[134]$', str(_status))"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue