UNPKG

@specs-feup/kadabra

Version:

A Java source-to-source compiler written in Typescript

231 lines (208 loc) 6.03 kB
import Query from "@specs-feup/lara/api/weaver/Query.js"; import { App, Class, Method, Return } from "../Joinpoints.js"; /** * Opens a window with the AST of Spoon. * * @param name - The name of the AST window. */ export function showAST(name: string = "Spoon Tree"): void { const app = Query.root() as App; app.showAST(name); } /** * Converts a primitive type to its wrapper class. * * @param type - The primitive type to convert. * @returns An object containing the wrapper class and whether the type is primitive. */ export function convertPrimitive(type: string): { wrapper: string; isPrimitive: boolean; } { let wrapper: string; let isPrimitive = true; switch (type) { case "bool": wrapper = "Boolean"; break; case "int": wrapper = "Integer"; break; case "char": wrapper = "Character"; break; case "void": case "byte": case "short": case "long": case "float": case "double": wrapper = type.charAt(0).toUpperCase() + type.slice(1); break; default: wrapper = type; isPrimitive = false; break; } return { wrapper, isPrimitive }; } /** * Converts a primitive type to its wrapper class as a string. * * @param type - The primitive type to convert. * @returns The wrapper class as a string. */ export function primitive2Class(type: string): string { switch (type) { case "bool": return "Boolean"; case "int": return "Integer"; case "char": return "Character"; case "void": case "byte": case "short": case "long": case "float": case "double": return type.charAt(0).toUpperCase() + type.slice(1); default: return type; } } /** * Inserts multiple print statements in the main method of a class. * * @param messages - The messages to print. */ export function printOnMain(...messages: string[]): void { for (const message of messages) { beforeExitMain(`System.out.println(${JSON.stringify(message)});`); } } /** * Inserts a print statement in the main method of a class. * * @param message - The message to print. */ export function printOnMain2(message: string): void { for (const $method of Query.search(Class).search(Method, "main")) { beforeExit($method, `System.out.println(${message});`); } } /** * Inserts code before the exit of the main method. * * @param code - The code to insert. */ export function beforeExitMain(code: string): void { for (const $method of Query.search(Class).search(Method, "main")) { beforeExit($method, code); } } /** * Inserts code before the exit of a method. * * @param method - The method join point. * @param code - The code to insert. */ export function beforeExit(method: Method, code: string): void { let inserted = false; // Try to insert before return statements for (const stmt of Query.searchFrom(method.body, Return)) { stmt.insertBefore(code); inserted = true; } if (inserted) return; // Try to insert after the last statement (for void methods) if (method.body.lastStmt !== undefined) { method.body.lastStmt.insertAfter(code); return; } // Else, insert into an empty method method.body.insertReplace(code); } /** * Generates API names for concurrent package components. * * @returns An object containing the API names. */ export function getAPINames(): { concurrentPackage: string; channel: string; thread: string; product: string; } { return { concurrentPackage: "weaver.kadabra.concurrent", channel: "weaver.kadabra.concurrent.KadabraChannel", thread: "weaver.kadabra.concurrent.KadabraThread", product: "weaver.kadabra.concurrent.Product", }; } /** * Generates code to retrieve an integer property from the system. * * @param name - The name of the property. * @param defaultValue - The default value of the property (optional). * @returns The generated code as a string. */ export function integerProperty(name: string, defaultValue?: string): string { let code = `Integer.parseInt(System.getProperty(${JSON.stringify(name)}`; if (defaultValue !== undefined) { code += `, "${defaultValue}\\"`; } return code + "))"; } /** * Retrieves methods based on class and method names. * * @param className - The name of the class. * @param methodName - The name of the method. * @returns An array of method join points. */ export function getMethod(className: string = ".*", methodName?: string) { if (methodName === undefined) { methodName = className; className = ".*"; } let methods: Method | Method[] | undefined = undefined; const search = Query.search( Class, (cls) => RegExp(className).exec(cls.qualifiedName) !== null ).search(Method, methodName); for (const method of search) { if (methods === undefined) { methods = method; } else if (Array.isArray(methods)) { methods.push(method); } else { methods = [methods, method]; } } return methods; } /** * Retrieves classes based on class names. * * @param className - The name of the class. * @returns An array of class join points. */ export function getClass(className: string = ".*") { let classes: Class | Class[] | undefined = undefined; const search = Query.search( Class, (cls) => RegExp(className).exec(cls.qualifiedName) !== null ); for (const cls of search) { if (classes === undefined) { classes = cls; } else if (Array.isArray(classes)) { classes.push(cls); } else { classes = [classes, cls]; } } return classes; }