import type { Editor } from "./main"; import type { File } from "./Editor/FileManagement"; const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); const codeReplace = (code: string): string => code.replace(/->|::/g, "&&"); const cache = new Map(); const MAX_CACHE_SIZE = 40; async function tryCatchWrapper(application: Editor, code: string): Promise { /** * Wraps the provided code in a try-catch block and executes it. * * @param application - The editor application. * @param code - The code to be executed. * @returns A promise that resolves to a boolean indicating whether the code executed successfully or not. */ try { await new Function(`"use strict"; ${codeReplace(code)}`).call(application.api); return true; } catch (error) { application.interface["error_line"].innerHTML = error as string; application.api._reportError(error as string); return false; } } const addFunctionToCache = (code: string, fn: Function) => { /** * Adds a function to the cache. * @param code - The code associated with the function. * @param fn - The function to be added to the cache. */ if (cache.size >= MAX_CACHE_SIZE) { cache.delete(cache.keys().next().value); } cache.set(code, fn); }; export async function tryEvaluate(application: Editor, code: File, timeout = 5000): Promise { /** * Tries to evaluate the provided code within a specified timeout period. * Increments the evaluation count of the code file. * If the code is valid, updates the committed code and adds the evaluated function to the cache. * If the code is invalid, retries the evaluation. * @param application - The editor application. * @param code - The code file to evaluate. * @param timeout - The timeout period in milliseconds (default: 5000). * @returns A Promise that resolves when the evaluation is complete. */ code.evaluations!++; const cachedFunction = cache.get(code.candidate); if (cachedFunction) { cachedFunction.call(application.api); return; } const wrappedCode = `let i = ${code.evaluations}; ${code.candidate}`; const isCodeValid = await Promise.race([ tryCatchWrapper(application, wrappedCode), delay(timeout) ]); if (isCodeValid) { code.committed = code.candidate; const newFunction = new Function(`"use strict"; ${codeReplace(wrappedCode)}`); addFunctionToCache(code.candidate, newFunction); } else { application.api.logOnce("Compilation error!"); await delay(100); await tryEvaluate(application, code, timeout); } } export async function evaluate(application: Editor, code: File, timeout = 1000): Promise { /** * Evaluates the given code using the provided application and timeout. * @param application The editor application. * @param code The code file to evaluate. * @param timeout The timeout value in milliseconds (default: 1000). * @returns A Promise that resolves when the evaluation is complete. */ try { await Promise.race([ tryCatchWrapper(application, code.committed as string), delay(timeout) ]); code.evaluations!++; } catch (error) { application.interface["error_line"].innerHTML = error as string; console.error(error); } } export const evaluateOnce = async ( application: Editor, code: string, ): Promise => { /** * Evaluates the code once without any caching or error-handling mechanisms besides the tryCatchWrapper. * * @param application - The application object that contains the Editor API. * @param code - The code to be evaluated. * @returns A promise that resolves when the code has been evaluated. */ await tryCatchWrapper(application, code); };