From 8878ca51e4b057b257b26ece18f0117199c52d2d Mon Sep 17 00:00:00 2001 From: pseco Date: Tue, 17 Mar 2026 11:46:25 +0100 Subject: [PATCH] working on examples verification and testing on avap language server --- .../synthetic_dataset/avap_test/test.avap | 17 +- .../synthetic_dataset/avap_test/test.ipynb | 29 +-- .../flows/synthetic_dataset_generation.py | 190 ++++++++++++++++-- ...ck.json => synthetic_data_bedrock_v1.json} | 0 .../synthetic_data_generated_bedrock.json | 95 +++++++++ .../synthetic_data_mbpp_bedrock.json | 42 ++++ 6 files changed, 320 insertions(+), 53 deletions(-) rename synthetic_datasets/{synthetic_data_bedrock.json => synthetic_data_bedrock_v1.json} (100%) create mode 100644 synthetic_datasets/synthetic_data_generated_bedrock.json create mode 100644 synthetic_datasets/synthetic_data_mbpp_bedrock.json diff --git a/scratches/pseco/synthetic_dataset/avap_test/test.avap b/scratches/pseco/synthetic_dataset/avap_test/test.avap index da89b8d..55b264b 100644 --- a/scratches/pseco/synthetic_dataset/avap_test/test.avap +++ b/scratches/pseco/synthetic_dataset/avap_test/test.avap @@ -1,16 +1 @@ -addParam("txt", txt) -result = False -if(None, None, 'txt == "" or txt == None') - result = False -else() - replace(txt, ",", " ", txt_clean) - last_word = txt_clean.split()[-1] if txt_clean.split() else "" - getListLen(last_word, last_len) - if(None, None, 'last_len == 1 and last_word.lower() >= "a" and last_word.lower() <= "z"') - result = True - else() - result = False - end() -end() -addResult(result) -_status = 200 \ No newline at end of file +variableToList(1, myList) diff --git a/scratches/pseco/synthetic_dataset/avap_test/test.ipynb b/scratches/pseco/synthetic_dataset/avap_test/test.ipynb index ec1b3fb..0d31a49 100644 --- a/scratches/pseco/synthetic_dataset/avap_test/test.ipynb +++ b/scratches/pseco/synthetic_dataset/avap_test/test.ipynb @@ -2,17 +2,17 @@ "cells": [ { "cell_type": "code", - "execution_count": 3, + "execution_count": 7, "id": "c46228bd", "metadata": {}, "outputs": [], "source": [ - "code=\"addParam(\\\"txt\\\", txt)\\nresult = False\\nif(None, None, `txt == \\\"\\\" or txt == None`)\\n result = False\\nelse()\\n replace(txt, \\\",\\\", \\\" \\\", txt_clean)\\n last_word = txt_clean.split()[-1] if txt_clean.split() else \\\"\\\"\\n getListLen(last_word, last_len)\\n if(None, None, `last_len == 1 and last_word.lower() >= \\\"a\\\" and last_word.lower() <= \\\"z\\\"`)\\n result = True\\n else()\\n result = False\\n end()\\nend()\\naddResult(result)\\n_status = 200\"" + "code=\"variableToList(\\\"a\\\", myList)\\nAddVariableToJSON(\\\"1\\\", \\\"b\\\", myList)\\nAddVariableToJSON(\\\"2\\\", \\\"c\\\", myList)\\ngetListLen(myList, total)\\naddResult(total)\"" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 8, "id": "91c20032", "metadata": {}, "outputs": [ @@ -20,22 +20,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "addParam(\"txt\", txt)\n", - "result = False\n", - "if(None, None, `txt == \"\" or txt == None`)\n", - " result = False\n", - "else()\n", - " replace(txt, \",\", \" \", txt_clean)\n", - " last_word = txt_clean.split()[-1] if txt_clean.split() else \"\"\n", - " getListLen(last_word, last_len)\n", - " if(None, None, `last_len == 1 and last_word.lower() >= \"a\" and last_word.lower() <= \"z\"`)\n", - " result = True\n", - " else()\n", - " result = False\n", - " end()\n", - "end()\n", - "addResult(result)\n", - "_status = 200\n" + "variableToList(\"a\", myList)\n", + "AddVariableToJSON(\"1\", \"b\", myList)\n", + "AddVariableToJSON(\"2\", \"c\", myList)\n", + "getListLen(myList, total)\n", + "addResult(total)\n" ] } ], @@ -54,7 +43,7 @@ ], "metadata": { "kernelspec": { - "display_name": "assistance-engine", + "display_name": ".venv", "language": "python", "name": "python3" }, diff --git a/scripts/pipelines/flows/synthetic_dataset_generation.py b/scripts/pipelines/flows/synthetic_dataset_generation.py index 546b059..57dcec3 100644 --- a/scripts/pipelines/flows/synthetic_dataset_generation.py +++ b/scripts/pipelines/flows/synthetic_dataset_generation.py @@ -12,9 +12,99 @@ from src.utils.llm_factory import create_chat_model from scripts.pipelines.tasks.prompts import ( get_prompt_mbpp, get_prompt_human_eval, - get_prompt_generation, ) +# System prompt from generate_mbap.py, optimized for both Claude and Bedrock +SYSTEM_PROMPT = """Eres un experto en el lenguaje AVAP. +Se te proporciona el Language Reference Manual (LRM) completo de AVAP. +Tu tarea es generar problemas de benchmark estilo MBPP para evaluar +modelos de lenguaje en su capacidad de generar código AVAP correcto. + +REGLAS ESTRICTAS para el código AVAP generado: +1. Una instrucción por línea. EOL es el terminador absoluto. +2. Sin indentación significativa (es solo decorativa). +3. Bloques de control: if()...else()...end(), startLoop()...endLoop(), try()...exception()...end() +4. Funciones: function name(args) { ... return(val) } +5. if() Modo 1: if(var_o_literal, var_o_literal, "operador") + — los argumentos NO pueden ser expresiones de acceso como dict['key']; + hay que extraer el valor a una variable propia primero. +6. if() Modo 2: if(None, None, `expresion_completa_como_string`) +7. _status se asigna con: addVar(_status, 404) +8. ormAccessSelect firma: ormAccessSelect(campos, "tabla", selector, varTarget) + — selector puede ser cadena vacía. +9. Acceso a campos de dict: val = dict['campo'] (línea propia, luego se usa val). +10. Genera ÚNICAMENTE código AVAP válido según el LRM. Sin Python, sin pseudocódigo. + +MODO DE EJECUCIÓN — MUY IMPORTANTE: +- El código se ejecuta DIRECTAMENTE, línea a línea, sin servidor ni registro de endpoints. +- NUNCA uses registerEndpoint(), NUNCA uses mainHandler(), NUNCA envuelvas el código en funciones solo para ejecutarlo. +- El código correcto es simplemente las instrucciones en línea, por ejemplo: + result = "Hello World" + addResult(result) +- Si el problema requiere una función auxiliar reutilizable, defínela con function...{} y llámala directamente después: + function double(n) { + return(n * 2) + } + addParam("n", n) + result = double(n) + addResult(result) +- NUNCA termines el código con registerEndpoint ni con ninguna llamada de registro. + +FORMATO DE SALIDA: responde ÚNICAMENTE con un array JSON válido. +Sin texto adicional, sin bloques de código markdown, sin explicaciones. +Estructura exacta de cada elemento: +{ + "task_id": , + "text": "", + "code": "", + "test_inputs": { "": , "": }, + "test_list": ["", ""] +} + +FORMATO DE test_inputs — MUY IMPORTANTE: +- Es un objeto JSON con un valor fijo para cada variable que el código recibe via addParam(). +- Los nombres de las claves deben coincidir EXACTAMENTE con el nombre de variable usado en addParam(). +- Los valores deben ser concretos y representativos del problema (no genéricos como "test" o 123). +- Si el código no tiene ningún addParam(), el campo test_inputs debe ser un objeto vacío: {} +- Estos valores son los que el evaluador inyectará en el stack antes de ejecutar el código, + de modo que las aserciones de test_list puedan validar las variables de salida resultantes. + +Ejemplo con addParam: + código: addParam("password", password)\\nencodeSHA256(password, hashed)\\naddResult(hashed) + test_inputs: { "password": "secret123" } + test_list: ["re.match(r'^[a-f0-9]{64}$', hashed)"] + +Ejemplo sin addParam: + código: randomString(16, token)\\naddResult(token) + test_inputs: {} + test_list: ["re.match(r'^[a-zA-Z0-9]{16}$', token)"] + +FORMATO DE test_list — MUY IMPORTANTE: +Cada aserción debe ser una expresión Python con re.match() +evaluable directamente sobre las variables del stack AVAP (disponibles como +variables Python locales). El módulo 're' está siempre disponible. +La expresión debe devolver un match object (truthy) si el test pasa. + +Reglas estrictas: +- USA ÚNICAMENTE re.match(r'', ) +- NO combines expresiones re.match en una aserción, cada asercion tiene que ser un unico re.match(r'', ) +- 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) +- Las variables referenciadas deben existir en el stack tras ejecutar el código. +- NUNCA uses comparaciones directas (==, !=, >, <). +- NUNCA uses isinstance(), len(), assert, ni texto descriptivo. +- NUNCA uses nada que no sea re.match(). + +Ejemplos correctos de test_list: + "re.match(r'^[a-f0-9]{64}$', hashed)" + "re.match(r'^[a-zA-Z0-9]{32}$', token)" + "re.match(r'^\\d{4}-\\d{2}-\\d{2}$', date_str)" + "re.match(r'^-?\\d+(\\.\\d+)?$', str(result))" + "re.match(r'^(par|impar)$', result)" + "re.match(r'^40[134]$', str(_status))" + "re.match(r'^\\d+$', str(length))" +""" + app = typer.Typer() @@ -30,6 +120,71 @@ class Dataset(str, Enum): human_eval = "openai_humaneval" +def build_generation_prompt(lrm: str, num_problems: int, problems_per_category: int = 10) -> str: + """Build user prompt for generating new problems from scratch.""" + return f"""# LRM AVAP — Language Reference Manual + +{lrm} + +--- + +# TAREA + +Genera exactamente {num_problems} problemas de benchmark MBPP-AVAP nuevos. + +Requisitos: +- Los task_id deben comenzar en 1 y ser consecutivos. +- Distribuye los problemas entre diferentes categorías de funcionalidad AVAP: + * HTTP params / addParam / addResult / _status + * Variables y strings / addVar / replace / randomString + * Condicionales / if() Modo 1 y Modo 2 / else() / end() + * Bucles y listas / startLoop / itemFromList / getListLen + * JSON / variableFromJSON / AddVariableToJSON + * ORM / ormAccessSelect / ormAccessInsert / ormAccessUpdate + * Criptografía / encodeSHA256 / encodeMD5 + * Fechas / getTimeStamp / getDateTime / stampToDatetime + * Conectores externos / avapConnector + métodos dinámicos + * Concurrencia / go + gather + * Funciones y scope / function / return() + * Manejo de errores / try() / exception() + * HTTP externo / RequestGet / RequestPost + * Modularidad / import / include + casos de uso complejos +- Cada problema debe cubrir un aspecto distinto de AVAP. +- Dificultad variada: algunos simples, algunos intermedios, alguno avanzado. +- El código debe ser realista como endpoint de microservicio HTTP en AVAP. +- Incluye 2-3 aserciones descriptivas en test_list por problema. + +Responde ÚNICAMENTE con el array JSON. Sin texto antes ni después. +""" + + +def parse_response(raw: str) -> list[dict]: + """Parse LLM response as JSON, handling markdown code blocks.""" + text = raw.strip() + if text.startswith("```"): + lines = text.splitlines() + inner = lines[1:] + if inner and inner[-1].strip() == "```": + inner = inner[:-1] + text = "\n".join(inner).strip() + + problems = json.loads(text) + + if not isinstance(problems, list): + raise ValueError("response is not a JSON array") + + for p in problems: + for field in ("task_id", "text", "code", "test_list"): + if field not in p: + raise ValueError(f"Field missing '{field}' in task_id={p.get('task_id','?')}.") + if "test_inputs" not in p: + p["test_inputs"] = {} + if not isinstance(p["test_inputs"], dict): + raise ValueError(f"'test_inputs' must be a JSON Object (task_id={p.get('task_id','?')}).") + + return problems + + @app.command() def generate_synthetic_dataset( provider: Provider = Provider.bedrock, @@ -198,36 +353,37 @@ def _generate_from_prompt( provider: str, problems_per_category: int = 10, ) -> None: - """Generate new problems from scratch using the generation prompt.""" + """Generate new problems from scratch using the generation prompt. + + Uses the same system prompt as generate_mbap.py to ensure consistency, + but invokes via the LLM factory method to support Bedrock and other providers. + """ logger.debug("Generating prompt for problem generation") - prompt_func = get_prompt_generation( - avap_docs=avap_docs, + user_prompt = build_generation_prompt( + lrm=avap_docs, num_problems=num_samples, problems_per_category=problems_per_category, ) logger.debug("✓ Prompt generated successfully") - # Invoke LLM + # Invoke LLM with SystemMessage and HumanMessage (compatible with LangChain factory) logger.info("Invoking LLM to generate new problems...") llm_response = llm.invoke( - [prompt_func, HumanMessage(content="Generate the synthetic dataset now.")] + [SystemMessage(content=SYSTEM_PROMPT), HumanMessage(content=user_prompt)] ) logger.info("✓ LLM response received") logger.debug(f"LLM Response: {llm_response.content}") # Parse JSON response logger.debug("Parsing LLM response as JSON") - json_str = ( - llm_response.content.removeprefix("```json") - .removeprefix("```") - .removesuffix("```") - .strip() - ) - logger.debug(f"JSON string: {json_str}") - synthetic_data = json.loads(json_str) - logger.info( - f"✓ Successfully parsed synthetic data with {len(synthetic_data)} samples" - ) + try: + synthetic_data = parse_response(llm_response.content) + logger.info( + f"✓ Successfully parsed synthetic data with {len(synthetic_data)} samples" + ) + except (json.JSONDecodeError, ValueError) as e: + logger.error(f"Failed to parse LLM response: {e}") + raise # Save output output_dir = Path(output_path) diff --git a/synthetic_datasets/synthetic_data_bedrock.json b/synthetic_datasets/synthetic_data_bedrock_v1.json similarity index 100% rename from synthetic_datasets/synthetic_data_bedrock.json rename to synthetic_datasets/synthetic_data_bedrock_v1.json diff --git a/synthetic_datasets/synthetic_data_generated_bedrock.json b/synthetic_datasets/synthetic_data_generated_bedrock.json new file mode 100644 index 0000000..2970121 --- /dev/null +++ b/synthetic_datasets/synthetic_data_generated_bedrock.json @@ -0,0 +1,95 @@ +[ + { + "task_id": 1, + "text": "Dado un parámetro 'username' recibido por HTTP, genera un hash SHA-256 de ese valor y devuélvelo como resultado. El código debe capturar el parámetro, calcular el hash y registrar el resultado.", + "code": "addParam(\"username\", username)\nencodeSHA256(username, hashed)\naddResult(hashed)", + "test_inputs": { + "username": "admin" + }, + "test_list": [ + "re.match(r'^[a-f0-9]{64}$', hashed)" + ] + }, + { + "task_id": 3, + "text": "Genera un token aleatorio de 32 caracteres alfanuméricos usando randomString y devuélvelo como resultado del endpoint.", + "code": "randomString(\"[a-zA-Z0-9]\", 32, token)\naddResult(token)", + "test_inputs": {}, + "test_list": [ + "re.match(r'^[a-zA-Z0-9]{32}$', token)" + ] + }, + { + "task_id": 4, + "text": "Recibe un parámetro 'password' por HTTP, calcula su hash MD5 y devuelve el hash. Si el parámetro no fue enviado (es None), establece _status en 400 y devuelve un mensaje de error.", + "code": "addParam(\"password\", password)\nif(None, None, `password is None`)\naddVar(_status, 400)\nerror = \"password requerido\"\naddResult(error)\nelse()\nencodeMD5(password, hashed)\naddResult(hashed)\nend()", + "test_inputs": { + "password": "mipassword123" + }, + "test_list": [ + "re.match(r'^[a-f0-9]{32}$', hashed)" + ] + }, + { + "task_id": 5, + "text": "Recibe un parámetro 'texto' por HTTP y reemplaza todos los espacios por guiones bajos. Devuelve el texto transformado como resultado.", + "code": "addParam(\"texto\", texto)\nreplace(texto, \" \", \"_\", resultado)\naddResult(resultado)", + "test_inputs": { + "texto": "hola mundo avap" + }, + "test_list": [ + "re.match(r'^hola_mundo_avap$', resultado)" + ] + }, + { + "task_id": 6, + "text": "Dada una lista de tres elementos construida con variableToList y AddVariableToJSON, itera sobre ella con startLoop, extrae cada elemento con itemFromList y acumula la longitud de la lista en una variable 'total'. Devuelve 'total'.", + "code": "variableToList(\"a\", myList)\nAddVariableToJSON(\"1\", \"b\", myList)\nAddVariableToJSON(\"2\", \"c\", myList)\ngetListLen(myList, total)\naddResult(total)", + "test_inputs": {}, + "test_list": [ + "re.match(r'^\\d+$', str(total))" + ] + }, + { + "task_id": 7, + "text": "Obtén la fecha y hora actual en formato 'YYYY-MM-DD' usando getDateTime con zona horaria UTC y sin desplazamiento de tiempo. Devuelve la fecha como resultado.", + "code": "getDateTime(\"%Y-%m-%d\", 0, \"UTC\", fecha_actual)\naddResult(fecha_actual)", + "test_inputs": {}, + "test_list": [ + "re.match(r'^\\d{4}-\\d{2}-\\d{2}$', fecha_actual)" + ] + }, + { + "task_id": 8, + "text": "Recibe un parámetro 'edad' por HTTP. Si la edad es mayor o igual a 18, devuelve 'mayor de edad', de lo contrario devuelve 'menor de edad'. Usa if() Modo 1 para la comparación.", + "code": "addParam(\"edad\", edad)\nedad = int(edad)\nif(edad, 18, \">=\")\nresultado = \"mayor de edad\"\nelse()\nresultado = \"menor de edad\"\nend()\naddResult(resultado)", + "test_inputs": { + "edad": "20" + }, + "test_list": [ + "re.match(r'^(mayor de edad|menor de edad)$', resultado)" + ] + }, + { + "task_id": 9, + "text": "Define una función 'cuadrado' que recibe un número y devuelve su cuadrado. Llama a la función con el parámetro 'n' recibido por HTTP y devuelve el resultado.", + "code": "function cuadrado(n) {\nresult = n * n\nreturn(result)\n}\naddParam(\"n\", n)\nn = int(n)\ncuadrado_resultado = cuadrado(n)\naddResult(cuadrado_resultado)", + "test_inputs": { + "n": "7" + }, + "test_list": [ + "re.match(r'^49$', str(cuadrado_resultado))" + ] + }, + { + "task_id": 10, + "text": "Recibe un parámetro 'url' por HTTP y realiza una petición GET a esa URL con timeout de 5000ms. Si la respuesta es None (timeout o error), establece _status en 504 y devuelve un mensaje de error. Si hay respuesta, devuélvela.", + "code": "addParam(\"url\", url)\nRequestGet(url, \"\", \"\", respuesta, 5000)\nif(None, None, `respuesta is None`)\naddVar(_status, 504)\nerror = \"timeout o error en la peticion\"\naddResult(error)\nelse()\naddResult(respuesta)\nend()", + "test_inputs": { + "url": "https://httpbin.org/get" + }, + "test_list": [ + "re.match(r'^(timeout o error en la peticion|.+)$', str(respuesta) if respuesta is not None else 'timeout o error en la peticion')" + ] + } +] \ No newline at end of file diff --git a/synthetic_datasets/synthetic_data_mbpp_bedrock.json b/synthetic_datasets/synthetic_data_mbpp_bedrock.json new file mode 100644 index 0000000..40eb832 --- /dev/null +++ b/synthetic_datasets/synthetic_data_mbpp_bedrock.json @@ -0,0 +1,42 @@ +{ + "0": { + "text": "Write a function in AVAP to remove the matching elements from the first list that are also present in the second list, returning the filtered list.", + "code": "function remove_matching_tuple(list1, list2) {\n // Get lengths of both lists\n getListLen(list1, len1)\n getListLen(list2, len2)\n // Build result list by iterating list1\n result = []\n i = 0\n startLoop(i, 0, len1)\n itemFromList(list1, i, current)\n found = False\n j = 0\n startLoop(j, 0, len2)\n itemFromList(list2, j, candidate)\n if(current, candidate, \"==\")\n found = True\n end()\n endLoop()\n if(found, False, \"==\")\n result = result + [current]\n end()\n endLoop()\n return(result)\n}" + }, + "1": { + "text": "Write a function in AVAP that receives a tuple (represented as a list) and returns the number of lists (sub-lists) present in it. If the input itself is a single list element, return 1; otherwise return the total count of elements.", + "code": "function find_lists(Input) {\n getListLen(Input, total)\n if(total, 1, \"==\")\n return(1)\n end()\n return(total)\n}" + }, + "2": { + "text": "Write a function in AVAP to find the first natural number whose factorial is divisible by a given number x.", + "code": "function first_Factorial_Divisible_Number(x) {\n i = 1\n fact = 1\n result = x\n startLoop(i, 1, x)\n fact = fact * i\n mod = fact % x\n if(mod, 0, \"==\")\n result = i\n return(result)\n end()\n endLoop()\n return(result)\n}" + }, + "3": { + "text": "Write a function in AVAP to find the largest number that can be formed with the given list of digits. The digits should be sorted in descending order and concatenated to form the largest possible number.", + "code": "function find_Max_Num(arr, n) {\n // Sort digits descending using a simple bubble sort\n startLoop(i, 0, n)\n startLoop(j, 0, n)\n itemFromList(arr, j, valJ)\n jNext = j + 1\n if(jNext, n, \"<\")\n itemFromList(arr, jNext, valJNext)\n if(valJ, valJNext, \"<\")\n // Swap\n AddVariableToJSON(\"tmp\", valJ, swapObj)\n variableFromJSON(swapObj, \"tmp\", tmp)\n arr[j] = valJNext\n arr[jNext] = tmp\n end()\n end()\n endLoop()\n endLoop()\n // Build number\n itemFromList(arr, 0, num)\n i = 1\n startLoop(i, 1, n)\n itemFromList(arr, i, digit)\n num = num * 10 + digit\n endLoop()\n return(num)\n}" + }, + "4": { + "text": "Write a function in AVAP to check if a triangle is equilateral (all three sides are equal). Return True if equilateral, False otherwise.", + "code": "function check_equilateral(x, y, z) {\n if(x, y, \"==\")\n if(y, z, \"==\")\n return(True)\n end()\n end()\n return(False)\n}" + }, + "5": { + "text": "Write a function in AVAP that, given a list of two-element sub-lists (pairs), groups the second elements by the first element and returns a summary list containing the first element, unique second elements, and the count of occurrences.", + "code": "function sort_on_occurence(lst) {\n getListLen(lst, lstLen)\n keys = []\n vals = []\n counts = []\n i = 0\n startLoop(i, 0, lstLen)\n itemFromList(lst, i, pair)\n itemFromList(pair, 0, key)\n itemFromList(pair, 1, val)\n // Check if key already in keys\n getListLen(keys, kLen)\n found = False\n foundIdx = 0\n k = 0\n startLoop(k, 0, kLen)\n itemFromList(keys, k, existingKey)\n if(existingKey, key, \"==\")\n found = True\n foundIdx = k\n end()\n endLoop()\n if(found, True, \"==\")\n itemFromList(counts, foundIdx, cnt)\n cnt = cnt + 1\n end()\n if(found, False, \"==\")\n keys = keys + [key]\n vals = vals + [val]\n counts = counts + [1]\n end()\n endLoop()\n return(keys)\n}" + }, + "6": { + "text": "Write two functions in AVAP: one to reverse the digits of a number, and another to check if a given number is one less than twice its reverse (i.e., 2 * reverse(n) == n + 1).", + "code": "function rev(num) {\n rev_num = 0\n startLoop(i, 0, 20)\n if(num, 0, \">\")\n mod = num % 10\n rev_num = rev_num * 10 + mod\n num = num / 10\n num = int(num)\n end()\n if(num, 0, \"==\")\n return(rev_num)\n end()\n endLoop()\n return(rev_num)\n}\n\nfunction check(n) {\n reversed_n = rev(n)\n twice_rev = 2 * reversed_n\n n_plus_1 = n + 1\n if(twice_rev, n_plus_1, \"==\")\n return(True)\n end()\n return(False)\n}" + }, + "7": { + "text": "Write a function in AVAP to convert a list of multiple integers into a single integer by concatenating their string representations.", + "code": "function multiple_to_single(L) {\n getListLen(L, length)\n result_str = \"\"\n i = 0\n startLoop(i, 0, length)\n itemFromList(L, i, elem)\n elem_str = str(elem)\n result_str = result_str + elem_str\n endLoop()\n result = int(result_str)\n return(result)\n}" + }, + "8": { + "text": "Write a function in AVAP that checks if a given text string contains a word at the end, with optional punctuation. Return 'Found a match!' if found, otherwise 'Not matched!'.", + "code": "function text_match_word(text) {\n getRegex(text, \"\\\\w+\\\\S*$\", match)\n if(match, None, \"!=\")\n return(\"Found a match!\")\n end()\n return(\"Not matched!\")\n}" + }, + "9": { + "text": "Write a function in AVAP to find the sum of numbers in a list between two specified indices m and n (inclusive).", + "code": "function sum_range_list(list1, m, n) {\n sum_range = 0\n range_len = n + 1\n i = 0\n startLoop(i, 0, range_len)\n if(None, None, `i >= m`)\n itemFromList(list1, i, elem)\n sum_range = sum_range + elem\n end()\n endLoop()\n return(sum_range)\n}" + } +} \ No newline at end of file