@specs-feup/lara
Version:
A js port of the popular framework for building source-to-source compilers
306 lines (263 loc) • 9.05 kB
text/typescript
import {
LaraJoinPoint,
getJoinpointMappers,
wrapJoinPoint,
} from "../LaraJoinPoint.js";
import JavaInterop from "../lara/JavaInterop.js";
import Strings from "../lara/Strings.js";
import DataStore from "../lara/util/DataStore.js";
import JavaTypes, { JavaClasses } from "../lara/util/JavaTypes.js";
import PrintOnce from "../lara/util/PrintOnce.js";
import WeaverOptions from "./WeaverOptions.js";
import Io from "../lara/Io.js";
/**
* @internal Lara Common Language dirty hack. IMPROPER USAGE WILL BREAK THE WHOLE WEAVER!
*/
let usingLaraCommonLanguage = false;
/**
* @internal Lara Common Language dirty hack. IMPROPER USAGE WILL BREAK THE WHOLE WEAVER!
*/
export function setUsingLaraCommonLanguage(value: boolean = false) {
usingLaraCommonLanguage = value;
}
/**
* Contains utility methods related to the weaver.
*/
export default class Weaver {
/**
* If defined, sets the default weaver command.
*/
static DEFAULT_WEAVER_COMMAND = undefined;
/**
* @returns The Java instance of the current WeaverEngine
*/
static getWeaverEngine(): JavaClasses.WeaverEngine {
return JavaTypes.WeaverEngine.getThreadLocalWeaver();
}
static getLaraLoc() {
return JavaTypes.LaraIUtils.getLaraLoc(
Weaver.getWeaverEngine(),
Weaver.getWeaverEngine().getData().get()
);
}
static getLaraLocTotals() {
var laraLoc = JavaTypes.getType("pt.up.fe.specs.lara.loc.LaraLoc");
return JavaTypes.getType("org.lara.interpreter.utils.LaraIUtils")
.getLaraLoc(
Weaver.getWeaverEngine(),
Weaver.getWeaverEngine().getData().get()
)
.get(laraLoc.getTotalsKey());
}
static writeCode(outputFolder: any) {
if (outputFolder === undefined) {
console.log("Weaver.writeCode: Output folder not defined");
return;
}
Weaver.getWeaverEngine().writeCode(outputFolder);
}
/**
* @deprecated Use the javascript `instanceof` operator instead
*/
static isJoinPoint($joinpoint: LaraJoinPoint): boolean;
/**
* @deprecated Use the javascript `instanceof` operator instead
*/
static isJoinPoint($joinpoint: LaraJoinPoint, type?: string): boolean {
if (type === undefined) {
return $joinpoint instanceof LaraJoinPoint;
}
return $joinpoint.instanceOf(type);
}
/**
* @param joinPointType - The type of the join point
* @returns The name of the default attribute for the given join point type, or undefined if there is no default attribute
*/
static getDefaultAttribute<T extends typeof LaraJoinPoint>(
joinPointType: T
): keyof T | null;
static getDefaultAttribute(joinPointType: string): string | null;
static getDefaultAttribute<T extends typeof LaraJoinPoint>(
joinPointType: T | string
): keyof T | string | null;
static getDefaultAttribute<T extends typeof LaraJoinPoint>(
joinPointType: T | string
): keyof T | string | null {
if (usingLaraCommonLanguage === true) {
return JavaTypes.getType(
"pt.up.fe.specs.lara.commonlang.LaraCommonLang"
).getDefaultAttribute(joinPointType) as string | null;
}
if (typeof joinPointType === "string") {
// Search for the default attribute in the joinpoint mappers
for (const mapper of getJoinpointMappers()) {
if (mapper[joinPointType]) {
return mapper[joinPointType]._defaultAttributeInfo.name;
}
}
// No wrapper was found, attempt to the collect information from the weaver
return Weaver.getWeaverEngine().getDefaultAttribute(joinPointType);
} else {
return joinPointType._defaultAttributeInfo.name;
}
}
/**
* Finds the name of the joinpoint class, given the js wrapper class itself
* @param type - The joinpoint class to find the name of
* @returns The name of the joinpoint class
*/
static findJoinpointTypeName<T extends typeof LaraJoinPoint>(
type: T
): string | undefined {
const joinpointMappers = getJoinpointMappers();
for (const mapper of joinpointMappers) {
const match = Object.keys(mapper).find((key) => mapper[key] === type);
if (match) {
return match;
}
}
return undefined;
}
static findJoinpointType(name: string): typeof LaraJoinPoint | undefined {
const joinpointMappers = getJoinpointMappers();
for (const mapper of joinpointMappers) {
if (mapper[name]) {
return mapper[name];
}
}
return undefined;
}
/**
* @param jpTypeName - a join point, or the name of a join point
* @param attributeName - the name of the attribute to check
*
* @returns True, if the given join point or join point name support the attribute with the given name
*
* @deprecated The typescript compiler will tell you this
*/
static hasAttribute(jpTypeName: string, attributeName: string): boolean {
const joinPoint: any = Weaver.getWeaverEngine()
.getLanguageSpecificationV2()
.getJoinPoint(jpTypeName);
if (joinPoint === null) {
return false;
}
return !joinPoint.getAttribute(attributeName).isEmpty();
}
/**
* Converts a given join point to a string.
*
* @param $jp - The join point to serialize.
*
* @returns A string representation of the join point.
*/
static serialize($jp: LaraJoinPoint): string {
if (JavaTypes.SpecsSystem.getJavaVersionNumber() > 16) {
PrintOnce.message(
"Weaver.serialize: Java version 17 or higher detected, XML serialization of AST might not work"
);
}
return Strings.toXml($jp.node);
}
/**
* Converts a serialized join point back to an object.
*
* @param string - The serialized join point.
*
* @returns The deserialized join point.
*/
static deserialize(string: string): LaraJoinPoint {
if (JavaTypes.SpecsSystem.getJavaVersionNumber() > 16) {
PrintOnce.message(
"Weaver.deserialize: Java version 17 or higher detected, XML serialization of AST might not work"
);
}
return wrapJoinPoint(
Weaver.AST_METHODS.toJavaJoinPoint(Strings.fromXml(string))
);
}
/**
* An instance of the basic interface that the AST nodes must support.
*/
static AST_METHODS = Weaver.getWeaverEngine().getAstMethods();
/**
* Adapts a Java object to JavaScript. Currently converts:
*
* - Null to undefined;
* - Java array to JS array;
* - List to array;
*
*/
static toJs(javaObject: any) {
return Weaver.getWeaverEngine().getScriptEngine().toJs(javaObject);
}
/**
* @returns The name of the currently executing LARA compiler.
*/
static getName(): string {
return Weaver.getWeaverEngine().getName();
}
/**
* Launches several weaving sessions in parallel.
*
* @param argsLists - An array where each element is an array with the arguments to pass to the weaver, as if it was launched from the command-line
* @param threads - Number of threads to use
* @param weaverCommand - The command we should use to call the weaver (e.g., /usr/local/bin/clava)
*
* @returns A list with the results of each of the executions. The executing script must use weaver.Script to set the output (i.e. Script.setOutput())
*/
static runParallel(
argsLists: string[][],
threads = -1,
weaverCommand: string | string[] = []
) {
if (weaverCommand === undefined) {
weaverCommand = [];
if (Weaver.DEFAULT_WEAVER_COMMAND !== undefined) {
weaverCommand.push(Weaver.DEFAULT_WEAVER_COMMAND);
}
}
if (!(weaverCommand instanceof Array)) {
weaverCommand = [weaverCommand.toString()];
}
// Assures all elements in the argsLists are String
const safeArgsLists = [];
for (const argsList of argsLists) {
safeArgsLists.push(argsList.map((value) => value.toString()));
}
const weaverData = WeaverOptions.getData();
const WeaverLauncher = JavaTypes.WeaverLauncher;
const jsonStrings = WeaverLauncher.executeParallelStatic(
safeArgsLists,
threads,
JavaInterop.arrayToStringList(weaverCommand),
weaverData.getContextFolder().getAbsolutePath()
);
// Read each json file into its own object
const results = [];
for (const jsonString of jsonStrings) {
results.push(JSON.parse(jsonString));
}
return results;
}
static get laraArgs(): any {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
const datastore = new DataStore(Weaver.getWeaverEngine().getData().get());
let jsonString = datastore.get(
JavaTypes.LaraiKeys.ASPECT_ARGS as string
) as string | undefined;
jsonString ??= "";
jsonString.trim();
if (jsonString.endsWith(".json")) {
return Io.readJson(jsonString);
}
// Fix curly braces
if (!jsonString.startsWith("{")) {
jsonString = "{" + jsonString;
}
if (!jsonString.endsWith("}")) {
jsonString = jsonString + "}";
}
return JSON.parse(jsonString);
}
}