113 lines
3.7 KiB
TypeScript
113 lines
3.7 KiB
TypeScript
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<string, Function>();
|
|
const MAX_CACHE_SIZE = 40;
|
|
|
|
async function tryCatchWrapper(application: Editor, code: string): Promise<boolean> {
|
|
/**
|
|
* 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<void> {
|
|
/**
|
|
* 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<void> {
|
|
/**
|
|
* 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<void> => {
|
|
/**
|
|
* 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);
|
|
};
|
|
|
|
|
|
|
|
|