@specs-feup/kadabra
Version:
A Java source-to-source compiler written in Typescript
144 lines • 5.74 kB
JavaScript
import Query from "@specs-feup/lara/api/weaver/Query.js";
import { Class, FileJp, Method } from "../../Joinpoints.js";
import { getOrNewClass } from "../Factory.js";
export function CreateClassGenerator(adapterMethod, $interfaceMethod, adapterClass = ".*", $storingClass) {
let $adaptMethod;
let generate;
let generateQualified;
for (const $method of Query.search(FileJp)
.search(Class, (c) => RegExp(adapterClass).exec(c.name) !== null)
.search(Method, adapterMethod)) {
if ($adaptMethod != undefined) {
throw new Error("More than one target method generator was found, please define a finer selection");
}
const adapter = FunctionGenerator($method, $interfaceMethod, $storingClass);
$adaptMethod = adapter.$adaptMethod;
generate = adapter.generate;
generateQualified = adapter.generateQualified;
}
if ($adaptMethod == undefined) {
throw new Error("Could not find given method generator: " +
adapterMethod +
" in " +
adapterClass);
}
return {
$adaptMethod: $adaptMethod,
generate: generate,
generateQualified: generateQualified,
};
}
export function FunctionGenerator($adapterMethod, $interfaceMethod, $storingClass = getOrNewClass("kadabra.utils.Adapters")) {
console.log("[FunctionGenerator] Creating new functional class with " +
$interfaceMethod +
" and " +
$adapterMethod);
const $adaptMethod = $storingClass.newFunctionalClass($interfaceMethod, $adapterMethod);
const generate = function (...args) {
let invoke = $adaptMethod + "(";
const _args = args.slice();
invoke += _args.join(", ");
invoke += ")";
return invoke;
};
const generateQualified = function (...args) {
let invoke = $storingClass.qualifiedName + "." + $adaptMethod + "(";
const _args = args.slice();
invoke += _args.join(", ");
invoke += ")";
return invoke;
};
return {
$adaptMethod: $adapterMethod,
generate: generate,
generateQualified: generateQualified,
};
}
/**
*
*/
export function CreateAdapter(target, adapter, name, targetClass = ".*", adapterClass = ".*") {
let $adaptClass;
let addField;
const $methods = Query.search(FileJp)
.search(Class, (c) => RegExp(targetClass).exec(c.name) !== null)
.search(Method, { name: target });
for (const $adaptMethod of Query.search(FileJp)
.search(Class, (c) => RegExp(adapterClass).exec(c.name) != null)
.search(Method, { name: adapter })) {
for (const $method of $methods) {
if ($method.equals($adaptMethod)) {
if ($adaptClass != undefined) {
throw new Error("More than one target class/adapter method was found, please define a finer selection");
}
name ??=
$method.name.charAt(0).toUpperCase() +
$method.name.substring(1) +
"_" +
adapter +
"_" +
$adaptMethod.name.charAt(0).toUpperCase() +
$adaptMethod.name.substring(1) +
"_Adapter";
const _adapter = TransformMethod($method, $adaptMethod, name); //, $target.name.firstCharToUpper()+"Adapter");
$adaptClass = _adapter.$adaptClass;
addField = _adapter.addField;
}
}
}
return { $adaptClass: $adaptClass, addField: addField };
}
/**
* Create an adapter based on the target class and the method that transforms the class bytecodes.
*
*/
export function TransformMethod($target, $adaptMethod, name = defaultTransformMethodName($target, $adaptMethod)) {
let $adaptClass;
for (const $class of Query.search(FileJp).search(Class, { name: name })) {
$adaptClass = $class;
}
if ($adaptClass === undefined) {
try {
$adaptClass = $target.createAdapter($adaptMethod, name);
}
catch (e) {
if (e instanceof Error)
console.log(e.message);
}
}
if ($adaptClass === undefined) {
throw new Error("[TransformMethod] couldn't create $adaptClass");
}
//this method returns information regarding the field and class, as well as the methods that can be invoked in the field
const addField = ($class = $adaptClass, fieldName = $adaptClass.name.charAt(0).toLowerCase() +
$adaptClass.name.substring(1), init = false) => {
const $newField = $class.newField(["public", "static"], $adaptClass.qualifiedName, fieldName, "new " + $adaptClass.name + "()");
const field = {
name: fieldName,
$field: $newField,
addAdapter: "weaver.kadabra.agent.AgentUtils.addAdapter(" +
fieldName +
");",
adapt: (...args) => {
let invoke = $newField.staticAccess + ".adapt(";
const _args = args.slice();
invoke += _args.join(", ");
invoke += ");";
return invoke;
},
};
if (init) {
$class.insertStatic(`${field.addAdapter}`);
}
return field;
};
return { $adaptClass: $adaptClass, addField: addField };
}
function defaultTransformMethodName($target, $adaptMethod) {
return ($target.name.charAt(0).toUpperCase() +
$target.name.substring(1) +
$adaptMethod.name.charAt(0).toUpperCase +
$adaptMethod.name.substring(1) +
"Adapter");
}
//# sourceMappingURL=Adapter.js.map