diff --git a/Clava-JS/src-api/Joinpoints.ts b/Clava-JS/src-api/Joinpoints.ts index d29d515b5..df2fab366 100644 --- a/Clava-JS/src-api/Joinpoints.ts +++ b/Clava-JS/src-api/Joinpoints.ts @@ -17,6 +17,8 @@ import { wrapJoinPoint, unwrapJoinPoint, } from "lara-js/api/LaraJoinPoint.js"; +import eventListener from "./clava/events/EventListener.js"; +import { Event, EventTime } from "./clava/events/Events.js"; type PrivateMapper = { "Joinpoint": typeof Joinpoint, @@ -354,79 +356,174 @@ export class Joinpoint extends LaraJoinPoint { /** * True, if this node is a Java instance of the given name, which corresponds to a simple Java class name of an AST node. For an equivalent function for join point names, use 'instanceOf(joinPointName)' */ - astIsInstance(className: string): boolean { return wrapJoinPoint(this._javaObject.astIsInstance(unwrapJoinPoint(className))); } + astIsInstance(className: string): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "astIsInstance", this, undefined, className)); + const res = wrapJoinPoint(this._javaObject.astIsInstance(unwrapJoinPoint(className))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "astIsInstance", this, res, className)); + return res; + } /** * True if the given node is a descendant of this node */ - contains(jp: Joinpoint): boolean { return wrapJoinPoint(this._javaObject.contains(unwrapJoinPoint(jp))); } + contains(jp: Joinpoint): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "contains", this, undefined, jp)); + const res = wrapJoinPoint(this._javaObject.contains(unwrapJoinPoint(jp))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "contains", this, res, jp)); + return res; + } /** * Looks for an ancestor joinpoint name, walking back on the AST */ - getAncestor(type: string): Joinpoint { return wrapJoinPoint(this._javaObject.getAncestor(unwrapJoinPoint(type))); } + getAncestor(type: string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getAncestor", this, undefined, type)); + const res = wrapJoinPoint(this._javaObject.getAncestor(unwrapJoinPoint(type))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getAncestor", this, res, type)); + return res; + } /** * @deprecated Looks for an ancestor AST name, walking back on the AST */ - getAstAncestor(type: string): Joinpoint { return wrapJoinPoint(this._javaObject.getAstAncestor(unwrapJoinPoint(type))); } + getAstAncestor(type: string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getAstAncestor", this, undefined, type)); + const res = wrapJoinPoint(this._javaObject.getAstAncestor(unwrapJoinPoint(type))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getAstAncestor", this, res, type)); + return res; + } /** * Returns the child of the node at the given index, considering null nodes */ - getAstChild(index: number): Joinpoint { return wrapJoinPoint(this._javaObject.getAstChild(unwrapJoinPoint(index))); } + getAstChild(index: number): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getAstChild", this, undefined, index)); + const res = wrapJoinPoint(this._javaObject.getAstChild(unwrapJoinPoint(index))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getAstChild", this, res, index)); + return res; + } /** * Looks for an ancestor joinpoint name, walking back on the joinpoint chain */ - getChainAncestor(type: string): Joinpoint { return wrapJoinPoint(this._javaObject.getChainAncestor(unwrapJoinPoint(type))); } + getChainAncestor(type: string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getChainAncestor", this, undefined, type)); + const res = wrapJoinPoint(this._javaObject.getChainAncestor(unwrapJoinPoint(type))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getChainAncestor", this, res, type)); + return res; + } /** * Returns the child of the node at the given index, ignoring null nodes */ - getChild(index: number): Joinpoint { return wrapJoinPoint(this._javaObject.getChild(unwrapJoinPoint(index))); } + getChild(index: number): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getChild", this, undefined, index)); + const res = wrapJoinPoint(this._javaObject.getChild(unwrapJoinPoint(index))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getChild", this, res, index)); + return res; + } /** * Retrieves the descendants of the given type */ - getDescendants(type: string): Joinpoint[] { return wrapJoinPoint(this._javaObject.getDescendants(unwrapJoinPoint(type))); } + getDescendants(type: string): Joinpoint[] { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getDescendants", this, undefined, type)); + const res = wrapJoinPoint(this._javaObject.getDescendants(unwrapJoinPoint(type))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getDescendants", this, res, type)); + return res; + } /** * Retrieves the descendants of the given type, including the node itself */ - getDescendantsAndSelf(type: string): Joinpoint[] { return wrapJoinPoint(this._javaObject.getDescendantsAndSelf(unwrapJoinPoint(type))); } + getDescendantsAndSelf(type: string): Joinpoint[] { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getDescendantsAndSelf", this, undefined, type)); + const res = wrapJoinPoint(this._javaObject.getDescendantsAndSelf(unwrapJoinPoint(type))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getDescendantsAndSelf", this, res, type)); + return res; + } /** * Looks in the descendants for the first node of the given type */ - getFirstJp(type: string): Joinpoint { return wrapJoinPoint(this._javaObject.getFirstJp(unwrapJoinPoint(type))); } + getFirstJp(type: string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getFirstJp", this, undefined, type)); + const res = wrapJoinPoint(this._javaObject.getFirstJp(unwrapJoinPoint(type))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getFirstJp", this, res, type)); + return res; + } /** * String with the full Java class name of the type of the Java field with the provided name */ - getJavaFieldType(fieldName: string): string { return wrapJoinPoint(this._javaObject.getJavaFieldType(unwrapJoinPoint(fieldName))); } + getJavaFieldType(fieldName: string): string { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getJavaFieldType", this, undefined, fieldName)); + const res = wrapJoinPoint(this._javaObject.getJavaFieldType(unwrapJoinPoint(fieldName))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getJavaFieldType", this, res, fieldName)); + return res; + } /** * Java Class instance with the type of the given key */ - getKeyType(key: string): object { return wrapJoinPoint(this._javaObject.getKeyType(unwrapJoinPoint(key))); } + getKeyType(key: string): object { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getKeyType", this, undefined, key)); + const res = wrapJoinPoint(this._javaObject.getKeyType(unwrapJoinPoint(key))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getKeyType", this, res, key)); + return res; + } /** * Retrives values that have been associated to nodes of the AST with 'setUserField' */ - getUserField(fieldName: string): object { return wrapJoinPoint(this._javaObject.getUserField(unwrapJoinPoint(fieldName))); } + getUserField(fieldName: string): object { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getUserField", this, undefined, fieldName)); + const res = wrapJoinPoint(this._javaObject.getUserField(unwrapJoinPoint(fieldName))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getUserField", this, res, fieldName)); + return res; + } /** * The value associated with the given property key */ - getValue(key: string): object { return wrapJoinPoint(this._javaObject.getValue(unwrapJoinPoint(key))); } + getValue(key: string): object { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getValue", this, undefined, key)); + const res = wrapJoinPoint(this._javaObject.getValue(unwrapJoinPoint(key))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getValue", this, res, key)); + return res; + } /** * True, if the given join point or AST node is the same (== test) as the current join point AST node */ - hasNode(nodeOrJp: object): boolean { return wrapJoinPoint(this._javaObject.hasNode(unwrapJoinPoint(nodeOrJp))); } + hasNode(nodeOrJp: object): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "hasNode", this, undefined, nodeOrJp)); + const res = wrapJoinPoint(this._javaObject.hasNode(unwrapJoinPoint(nodeOrJp))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "hasNode", this, res, nodeOrJp)); + return res; + } /** * Performs a copy of the node and its children, but not of the nodes in its fields */ - copy(): Joinpoint { return wrapJoinPoint(this._javaObject.copy()); } + copy(): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "copy", this, undefined)); + const res = wrapJoinPoint(this._javaObject.copy()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "copy", this, res)); + return res; + } /** * Clears all properties from the .data object */ - dataClear(): void { return wrapJoinPoint(this._javaObject.dataClear()); } + dataClear(): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "dataClear", this, undefined)); + const res = wrapJoinPoint(this._javaObject.dataClear()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "dataClear", this, res)); + return res; + } /** * Performs a copy of the node and its children, including the nodes in their fields (only the first level of field nodes, this function is not recursive) */ - deepCopy(): Joinpoint { return wrapJoinPoint(this._javaObject.deepCopy()); } + deepCopy(): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "deepCopy", this, undefined)); + const res = wrapJoinPoint(this._javaObject.deepCopy()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "deepCopy", this, res)); + return res; + } /** * Removes the node associated to this joinpoint from the AST */ - detach(): Joinpoint { return wrapJoinPoint(this._javaObject.detach()); } + detach(): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "detach", this, undefined)); + const res = wrapJoinPoint(this._javaObject.detach()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "detach", this, res)); + return res; + } /** * Inserts the given join point after this join point */ @@ -438,7 +535,12 @@ export class Joinpoint extends LaraJoinPoint { /** * Inserts the given join point after this join point */ - insertAfter(p1: Joinpoint | string): Joinpoint { return wrapJoinPoint(this._javaObject.insertAfter(unwrapJoinPoint(p1))); } + insertAfter(p1: Joinpoint | string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "insertAfter", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.insertAfter(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "insertAfter", this, res, p1)); + return res; + } /** * Inserts the given join point before this join point */ @@ -450,15 +552,30 @@ export class Joinpoint extends LaraJoinPoint { /** * Inserts the given join point before this join point */ - insertBefore(p1: Joinpoint | string): Joinpoint { return wrapJoinPoint(this._javaObject.insertBefore(unwrapJoinPoint(p1))); } + insertBefore(p1: Joinpoint | string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "insertBefore", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.insertBefore(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "insertBefore", this, res, p1)); + return res; + } /** * Adds a message that will be printed to the user after weaving finishes. Identical messages are removed */ - messageToUser(message: string): void { return wrapJoinPoint(this._javaObject.messageToUser(unwrapJoinPoint(message))); } + messageToUser(message: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "messageToUser", this, undefined, message)); + const res = wrapJoinPoint(this._javaObject.messageToUser(unwrapJoinPoint(message))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "messageToUser", this, res, message)); + return res; + } /** * Removes the children of this node */ - removeChildren(): void { return wrapJoinPoint(this._javaObject.removeChildren()); } + removeChildren(): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "removeChildren", this, undefined)); + const res = wrapJoinPoint(this._javaObject.removeChildren()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "removeChildren", this, res)); + return res; + } /** * Replaces this node with the given node */ @@ -474,19 +591,39 @@ export class Joinpoint extends LaraJoinPoint { /** * Replaces this node with the given node */ - replaceWith(p1: Joinpoint | string | Joinpoint[]): Joinpoint { return wrapJoinPoint(this._javaObject.replaceWith(unwrapJoinPoint(p1))); } + replaceWith(p1: Joinpoint | string | Joinpoint[]): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "replaceWith", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.replaceWith(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "replaceWith", this, res, p1)); + return res; + } /** * Overload which accepts a list of strings */ - replaceWithStrings(node: string[]): Joinpoint { return wrapJoinPoint(this._javaObject.replaceWithStrings(unwrapJoinPoint(node))); } + replaceWithStrings(node: string[]): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "replaceWithStrings", this, undefined, node)); + const res = wrapJoinPoint(this._javaObject.replaceWithStrings(unwrapJoinPoint(node))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "replaceWithStrings", this, res, node)); + return res; + } /** * Setting data directly is not supported, this action just emits a warning and does nothing */ - setData(source: object): void { return wrapJoinPoint(this._javaObject.setData(JSON.stringify(source))); } + setData(source: object): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setData", this, undefined, source)); + const res = wrapJoinPoint(this._javaObject.setData(JSON.stringify(source))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setData", this, res, source)); + return res; + } /** * Replaces the first child, or inserts the join point if no child is present */ - setFirstChild(node: Joinpoint): void { return wrapJoinPoint(this._javaObject.setFirstChild(unwrapJoinPoint(node))); } + setFirstChild(node: Joinpoint): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setFirstChild", this, undefined, node)); + const res = wrapJoinPoint(this._javaObject.setFirstChild(unwrapJoinPoint(node))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setFirstChild", this, res, node)); + return res; + } /** * Sets the commented that are embedded in a node */ @@ -498,15 +635,30 @@ export class Joinpoint extends LaraJoinPoint { /** * Sets the commented that are embedded in a node */ - setInlineComments(p1: string[] | string): void { return wrapJoinPoint(this._javaObject.setInlineComments(unwrapJoinPoint(p1))); } + setInlineComments(p1: string[] | string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setInlineComments", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.setInlineComments(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setInlineComments", this, res, p1)); + return res; + } /** * Replaces the last child, or inserts the join point if no child is present */ - setLastChild(node: Joinpoint): void { return wrapJoinPoint(this._javaObject.setLastChild(unwrapJoinPoint(node))); } + setLastChild(node: Joinpoint): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setLastChild", this, undefined, node)); + const res = wrapJoinPoint(this._javaObject.setLastChild(unwrapJoinPoint(node))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setLastChild", this, res, node)); + return res; + } /** * Sets the type of a node, if it has a type */ - setType(type: Type): void { return wrapJoinPoint(this._javaObject.setType(unwrapJoinPoint(type))); } + setType(type: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setType", this, undefined, type)); + const res = wrapJoinPoint(this._javaObject.setType(unwrapJoinPoint(type))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setType", this, res, type)); + return res; + } /** * Associates arbitrary values to nodes of the AST */ @@ -518,15 +670,30 @@ export class Joinpoint extends LaraJoinPoint { /** * Associates arbitrary values to nodes of the AST */ - setUserField(p1: string | Record, p2?: object): object { return wrapJoinPoint(this._javaObject.setUserField(unwrapJoinPoint(p1), unwrapJoinPoint(p2))); } + setUserField(p1: string | Record, p2?: object): object { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setUserField", this, undefined, p1, p2)); + const res = wrapJoinPoint(this._javaObject.setUserField(unwrapJoinPoint(p1), unwrapJoinPoint(p2))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setUserField", this, res, p1, p2)); + return res; + } /** * Sets the value associated with the given property key */ - setValue(key: string, value: object): Joinpoint { return wrapJoinPoint(this._javaObject.setValue(unwrapJoinPoint(key), unwrapJoinPoint(value))); } + setValue(key: string, value: object): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setValue", this, undefined, key, value)); + const res = wrapJoinPoint(this._javaObject.setValue(unwrapJoinPoint(key), unwrapJoinPoint(value))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setValue", this, res, key, value)); + return res; + } /** * Replaces this join point with a comment with the same contents as .code */ - toComment(prefix: string = "", suffix: string = ""): Joinpoint { return wrapJoinPoint(this._javaObject.toComment(unwrapJoinPoint(prefix), unwrapJoinPoint(suffix))); } + toComment(prefix: string = "", suffix: string = ""): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "toComment", this, undefined, prefix, suffix)); + const res = wrapJoinPoint(this._javaObject.toComment(unwrapJoinPoint(prefix), unwrapJoinPoint(suffix))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "toComment", this, res, prefix, suffix)); + return res; + } } export class Attribute extends Joinpoint { @@ -563,7 +730,12 @@ export class Comment extends Joinpoint { }; get text(): string { return wrapJoinPoint(this._javaObject.getText()) } set text(value: string) { this._javaObject.setText(unwrapJoinPoint(value)); } - setText(text: string): void { return wrapJoinPoint(this._javaObject.setText(unwrapJoinPoint(text))); } + setText(text: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setText", this, undefined, text)); + const res = wrapJoinPoint(this._javaObject.setText(unwrapJoinPoint(text))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setText", this, res, text)); + return res; + } } /** @@ -694,27 +866,57 @@ export class FileJp extends Joinpoint { /** * The complete path to the file that will be generated by the weaver, given a destination folder */ - getDestinationFilepath(destinationFolderpath?: string): string { return wrapJoinPoint(this._javaObject.getDestinationFilepath(unwrapJoinPoint(destinationFolderpath))); } + getDestinationFilepath(destinationFolderpath?: string): string { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getDestinationFilepath", this, undefined, destinationFolderpath)); + const res = wrapJoinPoint(this._javaObject.getDestinationFilepath(unwrapJoinPoint(destinationFolderpath))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getDestinationFilepath", this, res, destinationFolderpath)); + return res; + } /** * Adds a C include to the current file. If the file already has the include, it does nothing */ - addCInclude(name: string, isAngled: boolean = false): void { return wrapJoinPoint(this._javaObject.addCInclude(unwrapJoinPoint(name), unwrapJoinPoint(isAngled))); } + addCInclude(name: string, isAngled: boolean = false): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addCInclude", this, undefined, name, isAngled)); + const res = wrapJoinPoint(this._javaObject.addCInclude(unwrapJoinPoint(name), unwrapJoinPoint(isAngled))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addCInclude", this, res, name, isAngled)); + return res; + } /** * Adds a function to the file that returns void and has no parameters */ - addFunction(name: string): Joinpoint { return wrapJoinPoint(this._javaObject.addFunction(unwrapJoinPoint(name))); } + addFunction(name: string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addFunction", this, undefined, name)); + const res = wrapJoinPoint(this._javaObject.addFunction(unwrapJoinPoint(name))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addFunction", this, res, name)); + return res; + } /** * Adds a global variable to this file */ - addGlobal(name: string, type: Joinpoint, initValue: string): Vardecl { return wrapJoinPoint(this._javaObject.addGlobal(unwrapJoinPoint(name), unwrapJoinPoint(type), unwrapJoinPoint(initValue))); } + addGlobal(name: string, type: Joinpoint, initValue: string): Vardecl { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addGlobal", this, undefined, name, type, initValue)); + const res = wrapJoinPoint(this._javaObject.addGlobal(unwrapJoinPoint(name), unwrapJoinPoint(type), unwrapJoinPoint(initValue))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addGlobal", this, res, name, type, initValue)); + return res; + } /** * Adds an include to the current file. If the file already has the include, it does nothing */ - addInclude(name: string, isAngled: boolean = false): void { return wrapJoinPoint(this._javaObject.addInclude(unwrapJoinPoint(name), unwrapJoinPoint(isAngled))); } + addInclude(name: string, isAngled: boolean = false): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addInclude", this, undefined, name, isAngled)); + const res = wrapJoinPoint(this._javaObject.addInclude(unwrapJoinPoint(name), unwrapJoinPoint(isAngled))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addInclude", this, res, name, isAngled)); + return res; + } /** * Overload of addInclude which accepts a join point */ - addIncludeJp(jp: Joinpoint): void { return wrapJoinPoint(this._javaObject.addIncludeJp(unwrapJoinPoint(jp))); } + addIncludeJp(jp: Joinpoint): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addIncludeJp", this, undefined, jp)); + const res = wrapJoinPoint(this._javaObject.addIncludeJp(unwrapJoinPoint(jp))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addIncludeJp", this, res, jp)); + return res; + } /** * Adds the node in the join point to the start of the file */ @@ -726,7 +928,12 @@ export class FileJp extends Joinpoint { /** * Adds the node in the join point to the start of the file */ - insertBegin(p1: Joinpoint | string): void { return wrapJoinPoint(this._javaObject.insertBegin(unwrapJoinPoint(p1))); } + insertBegin(p1: Joinpoint | string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "insertBegin", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.insertBegin(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "insertBegin", this, res, p1)); + return res; + } /** * Adds the node in the join point to the end of the file */ @@ -738,27 +945,57 @@ export class FileJp extends Joinpoint { /** * Adds the node in the join point to the end of the file */ - insertEnd(p1: Joinpoint | string): void { return wrapJoinPoint(this._javaObject.insertEnd(unwrapJoinPoint(p1))); } + insertEnd(p1: Joinpoint | string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "insertEnd", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.insertEnd(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "insertEnd", this, res, p1)); + return res; + } /** * Recompiles only this file, returns a join point to the new recompiled file, or throws an exception if a problem happens */ - rebuild(): FileJp { return wrapJoinPoint(this._javaObject.rebuild()); } + rebuild(): FileJp { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "rebuild", this, undefined)); + const res = wrapJoinPoint(this._javaObject.rebuild()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "rebuild", this, res)); + return res; + } /** * Recompiles only this file, returns a join point to the new recompiled file, or returns a clavaException join point if a problem happens */ - rebuildTry(): Joinpoint { return wrapJoinPoint(this._javaObject.rebuildTry()); } + rebuildTry(): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "rebuildTry", this, undefined)); + const res = wrapJoinPoint(this._javaObject.rebuildTry()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "rebuildTry", this, res)); + return res; + } /** * Changes the name of the file */ - setName(filename: string): void { return wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(filename))); } + setName(filename: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setName", this, undefined, filename)); + const res = wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(filename))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setName", this, res, filename)); + return res; + } /** * Sets the path to the folder of the source file relative to the base source path */ - setRelativeFolderpath(path: string): void { return wrapJoinPoint(this._javaObject.setRelativeFolderpath(unwrapJoinPoint(path))); } + setRelativeFolderpath(path: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setRelativeFolderpath", this, undefined, path)); + const res = wrapJoinPoint(this._javaObject.setRelativeFolderpath(unwrapJoinPoint(path))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setRelativeFolderpath", this, res, path)); + return res; + } /** * Writes the code of this file to a given folder */ - write(destinationFoldername: string): string { return wrapJoinPoint(this._javaObject.write(unwrapJoinPoint(destinationFoldername))); } + write(destinationFoldername: string): string { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "write", this, undefined, destinationFoldername)); + const res = wrapJoinPoint(this._javaObject.write(unwrapJoinPoint(destinationFoldername))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "write", this, res, destinationFoldername)); + return res; + } } export class ImplicitValue extends Expression { @@ -838,7 +1075,12 @@ export class MemberAccess extends Expression { get memberChain(): Expression[] { return wrapJoinPoint(this._javaObject.getMemberChain()) } get memberChainNames(): string[] { return wrapJoinPoint(this._javaObject.getMemberChainNames()) } get name(): string { return wrapJoinPoint(this._javaObject.getName()) } - setArrow(isArrow: boolean): void { return wrapJoinPoint(this._javaObject.setArrow(unwrapJoinPoint(isArrow))); } + setArrow(isArrow: boolean): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setArrow", this, undefined, isArrow)); + const res = wrapJoinPoint(this._javaObject.setArrow(unwrapJoinPoint(isArrow))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setArrow", this, res, isArrow)); + return res; + } } /** @@ -861,15 +1103,30 @@ export class NamedDecl extends Decl { /** * Sets the name of this namedDecl */ - setName(name: string): void { return wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(name))); } + setName(name: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setName", this, undefined, name)); + const res = wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(name))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setName", this, res, name)); + return res; + } /** * Sets the qualified name of this namedDecl (changes both the name and qualified prefix) */ - setQualifiedName(name: string): void { return wrapJoinPoint(this._javaObject.setQualifiedName(unwrapJoinPoint(name))); } + setQualifiedName(name: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setQualifiedName", this, undefined, name)); + const res = wrapJoinPoint(this._javaObject.setQualifiedName(unwrapJoinPoint(name))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setQualifiedName", this, res, name)); + return res; + } /** * Sets the qualified prefix of this namedDecl */ - setQualifiedPrefix(qualifiedPrefix: string): void { return wrapJoinPoint(this._javaObject.setQualifiedPrefix(unwrapJoinPoint(qualifiedPrefix))); } + setQualifiedPrefix(qualifiedPrefix: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setQualifiedPrefix", this, undefined, qualifiedPrefix)); + const res = wrapJoinPoint(this._javaObject.setQualifiedPrefix(unwrapJoinPoint(qualifiedPrefix))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setQualifiedPrefix", this, res, qualifiedPrefix)); + return res; + } } export class NewExpr extends Expression { @@ -942,9 +1199,24 @@ export class Pragma extends Joinpoint { /** * All the nodes below the target node, including the target node, up until a pragma with the name given by argument 'endPragma'. If no end pragma is found, returns the same result as if not providing the argument */ - getTargetNodes(endPragma?: string): Joinpoint[] { return wrapJoinPoint(this._javaObject.getTargetNodes(unwrapJoinPoint(endPragma))); } - setContent(content: string): void { return wrapJoinPoint(this._javaObject.setContent(unwrapJoinPoint(content))); } - setName(name: string): void { return wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(name))); } + getTargetNodes(endPragma?: string): Joinpoint[] { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getTargetNodes", this, undefined, endPragma)); + const res = wrapJoinPoint(this._javaObject.getTargetNodes(unwrapJoinPoint(endPragma))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getTargetNodes", this, res, endPragma)); + return res; + } + setContent(content: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setContent", this, undefined, content)); + const res = wrapJoinPoint(this._javaObject.setContent(unwrapJoinPoint(content))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setContent", this, res, content)); + return res; + } + setName(name: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setName", this, undefined, name)); + const res = wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(name))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setName", this, res, name)); + return res; + } } /** @@ -1002,55 +1274,120 @@ export class Program extends Joinpoint { /** * Adds a path to an include that the current program depends on */ - addExtraInclude(path: string): void { return wrapJoinPoint(this._javaObject.addExtraInclude(unwrapJoinPoint(path))); } + addExtraInclude(path: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addExtraInclude", this, undefined, path)); + const res = wrapJoinPoint(this._javaObject.addExtraInclude(unwrapJoinPoint(path))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addExtraInclude", this, res, path)); + return res; + } /** * Adds a path based on a git repository to an include that the current program depends on */ - addExtraIncludeFromGit(gitRepo: string, path?: string): void { return wrapJoinPoint(this._javaObject.addExtraIncludeFromGit(unwrapJoinPoint(gitRepo), unwrapJoinPoint(path))); } + addExtraIncludeFromGit(gitRepo: string, path?: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addExtraIncludeFromGit", this, undefined, gitRepo, path)); + const res = wrapJoinPoint(this._javaObject.addExtraIncludeFromGit(unwrapJoinPoint(gitRepo), unwrapJoinPoint(path))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addExtraIncludeFromGit", this, res, gitRepo, path)); + return res; + } /** * Adds a library (e.g., -pthreads) that the current program depends on */ - addExtraLib(lib: string): void { return wrapJoinPoint(this._javaObject.addExtraLib(unwrapJoinPoint(lib))); } + addExtraLib(lib: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addExtraLib", this, undefined, lib)); + const res = wrapJoinPoint(this._javaObject.addExtraLib(unwrapJoinPoint(lib))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addExtraLib", this, res, lib)); + return res; + } /** * Adds a path to a source that the current program depends on */ - addExtraSource(path: string): void { return wrapJoinPoint(this._javaObject.addExtraSource(unwrapJoinPoint(path))); } + addExtraSource(path: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addExtraSource", this, undefined, path)); + const res = wrapJoinPoint(this._javaObject.addExtraSource(unwrapJoinPoint(path))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addExtraSource", this, res, path)); + return res; + } /** * Adds a path based on a git repository to a source that the current program depends on */ - addExtraSourceFromGit(gitRepo: string, path?: string): void { return wrapJoinPoint(this._javaObject.addExtraSourceFromGit(unwrapJoinPoint(gitRepo), unwrapJoinPoint(path))); } + addExtraSourceFromGit(gitRepo: string, path?: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addExtraSourceFromGit", this, undefined, gitRepo, path)); + const res = wrapJoinPoint(this._javaObject.addExtraSourceFromGit(unwrapJoinPoint(gitRepo), unwrapJoinPoint(path))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addExtraSourceFromGit", this, res, gitRepo, path)); + return res; + } /** * Adds a file join point to the current program */ - addFile(file: FileJp): Joinpoint { return wrapJoinPoint(this._javaObject.addFile(unwrapJoinPoint(file))); } + addFile(file: FileJp): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addFile", this, undefined, file)); + const res = wrapJoinPoint(this._javaObject.addFile(unwrapJoinPoint(file))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addFile", this, res, file)); + return res; + } /** * Adds a file join point to the current program, from the given path, which can be either a Java File or a String */ - addFileFromPath(filepath: object): Joinpoint { return wrapJoinPoint(this._javaObject.addFileFromPath(unwrapJoinPoint(filepath))); } + addFileFromPath(filepath: object): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addFileFromPath", this, undefined, filepath)); + const res = wrapJoinPoint(this._javaObject.addFileFromPath(unwrapJoinPoint(filepath))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addFileFromPath", this, res, filepath)); + return res; + } /** * Adds a path based on a git repository to a project that the current program depends on */ - addProjectFromGit(gitRepo: string, libs: string[], path?: string): void { return wrapJoinPoint(this._javaObject.addProjectFromGit(unwrapJoinPoint(gitRepo), unwrapJoinPoint(libs), unwrapJoinPoint(path))); } + addProjectFromGit(gitRepo: string, libs: string[], path?: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addProjectFromGit", this, undefined, gitRepo, libs, path)); + const res = wrapJoinPoint(this._javaObject.addProjectFromGit(unwrapJoinPoint(gitRepo), unwrapJoinPoint(libs), unwrapJoinPoint(path))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addProjectFromGit", this, res, gitRepo, libs, path)); + return res; + } /** * Registers a function to be executed when the program exits */ - atexit(func: FunctionJp): void { return wrapJoinPoint(this._javaObject.atexit(unwrapJoinPoint(func))); } + atexit(func: FunctionJp): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "atexit", this, undefined, func)); + const res = wrapJoinPoint(this._javaObject.atexit(unwrapJoinPoint(func))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "atexit", this, res, func)); + return res; + } /** * Discards the AST at the top of the ASt stack */ - pop(): void { return wrapJoinPoint(this._javaObject.pop()); } + pop(): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "pop", this, undefined)); + const res = wrapJoinPoint(this._javaObject.pop()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "pop", this, res)); + return res; + } /** * Creates a copy of the current AST and pushes it to the top of the AST stack */ - push(): void { return wrapJoinPoint(this._javaObject.push()); } + push(): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "push", this, undefined)); + const res = wrapJoinPoint(this._javaObject.push()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "push", this, res)); + return res; + } /** * Recompiles the program currently represented by the AST, transforming literal code into AST nodes. Returns true if all files could be parsed correctly, or false otherwise */ - rebuild(): boolean { return wrapJoinPoint(this._javaObject.rebuild()); } + rebuild(): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "rebuild", this, undefined)); + const res = wrapJoinPoint(this._javaObject.rebuild()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "rebuild", this, res)); + return res; + } /** * Similar to rebuild, but tries to fix compilation errors. Resulting program may not represent the originally intended functionality */ - rebuildFuzzy(): void { return wrapJoinPoint(this._javaObject.rebuildFuzzy()); } + rebuildFuzzy(): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "rebuildFuzzy", this, undefined)); + const res = wrapJoinPoint(this._javaObject.rebuildFuzzy()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "rebuildFuzzy", this, res)); + return res; + } } /** @@ -1077,7 +1414,12 @@ export class RecordJp extends NamedDecl { /** * Adds a field to a record (struct, class). */ - addField(field: Field): void { return wrapJoinPoint(this._javaObject.addField(unwrapJoinPoint(field))); } + addField(field: Field): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addField", this, undefined, field)); + const res = wrapJoinPoint(this._javaObject.addField(unwrapJoinPoint(field))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addField", this, res, field)); + return res; + } } export class Statement extends Joinpoint { @@ -1220,27 +1562,57 @@ export class Type extends Joinpoint { /** * Returns a new node based on this type with the qualifier const */ - asConst(): Type { return wrapJoinPoint(this._javaObject.asConst()); } + asConst(): Type { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "asConst", this, undefined)); + const res = wrapJoinPoint(this._javaObject.asConst()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "asConst", this, res)); + return res; + } /** * Sets the desugared type of this type */ - setDesugar(desugaredType: Type): void { return wrapJoinPoint(this._javaObject.setDesugar(unwrapJoinPoint(desugaredType))); } + setDesugar(desugaredType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setDesugar", this, undefined, desugaredType)); + const res = wrapJoinPoint(this._javaObject.setDesugar(unwrapJoinPoint(desugaredType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setDesugar", this, res, desugaredType)); + return res; + } /** * Sets a single template argument type of a template type */ - setTemplateArgType(index: number, templateArgType: Type): void { return wrapJoinPoint(this._javaObject.setTemplateArgType(unwrapJoinPoint(index), unwrapJoinPoint(templateArgType))); } + setTemplateArgType(index: number, templateArgType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setTemplateArgType", this, undefined, index, templateArgType)); + const res = wrapJoinPoint(this._javaObject.setTemplateArgType(unwrapJoinPoint(index), unwrapJoinPoint(templateArgType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setTemplateArgType", this, res, index, templateArgType)); + return res; + } /** * Sets the template argument types of a template type */ - setTemplateArgsTypes(templateArgTypes: Type[]): void { return wrapJoinPoint(this._javaObject.setTemplateArgsTypes(unwrapJoinPoint(templateArgTypes))); } + setTemplateArgsTypes(templateArgTypes: Type[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setTemplateArgsTypes", this, undefined, templateArgTypes)); + const res = wrapJoinPoint(this._javaObject.setTemplateArgsTypes(unwrapJoinPoint(templateArgTypes))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setTemplateArgsTypes", this, res, templateArgTypes)); + return res; + } /** * Changes a single occurence of a type field that has the current value with new value. Returns true if there was a change */ - setTypeFieldByValueRecursive(currentValue: object, newValue: object): boolean { return wrapJoinPoint(this._javaObject.setTypeFieldByValueRecursive(unwrapJoinPoint(currentValue), unwrapJoinPoint(newValue))); } + setTypeFieldByValueRecursive(currentValue: object, newValue: object): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setTypeFieldByValueRecursive", this, undefined, currentValue, newValue)); + const res = wrapJoinPoint(this._javaObject.setTypeFieldByValueRecursive(unwrapJoinPoint(currentValue), unwrapJoinPoint(newValue))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setTypeFieldByValueRecursive", this, res, currentValue, newValue)); + return res; + } /** * Replaces an underlying type of this instance with new type, if it matches the old type. Returns true if there were changes */ - setUnderlyingType(oldValue: Type, newValue: Type): Type { return wrapJoinPoint(this._javaObject.setUnderlyingType(unwrapJoinPoint(oldValue), unwrapJoinPoint(newValue))); } + setUnderlyingType(oldValue: Type, newValue: Type): Type { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setUnderlyingType", this, undefined, oldValue, newValue)); + const res = wrapJoinPoint(this._javaObject.setUnderlyingType(unwrapJoinPoint(oldValue), unwrapJoinPoint(newValue))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setUnderlyingType", this, res, oldValue, newValue)); + return res; + } } /** @@ -1288,7 +1660,12 @@ export class UnaryExprOrType extends Expression { get hasArgExpr(): boolean { return wrapJoinPoint(this._javaObject.getHasArgExpr()) } get hasTypeExpr(): boolean { return wrapJoinPoint(this._javaObject.getHasTypeExpr()) } get kind(): string { return wrapJoinPoint(this._javaObject.getKind()) } - setArgType(argType: Type): void { return wrapJoinPoint(this._javaObject.setArgType(unwrapJoinPoint(argType))); } + setArgType(argType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setArgType", this, undefined, argType)); + const res = wrapJoinPoint(this._javaObject.setArgType(unwrapJoinPoint(argType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setArgType", this, res, argType)); + return res; + } } export class UnaryOp extends Op { @@ -1341,7 +1718,12 @@ export class Varref extends Expression { * Expression from where the attribute 'use' is calculated. In certain cases (e.g., array access, pointer dereference) the 'use' attribute is not calculated on the node itself, but on an ancestor of the node. This attribute returns that node */ get useExpr(): Expression { return wrapJoinPoint(this._javaObject.getUseExpr()) } - setName(name: string): void { return wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(name))); } + setName(name: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setName", this, undefined, name)); + const res = wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(name))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setName", this, res, name)); + return res; + } } export class WrapperStmt extends Statement { @@ -1422,7 +1804,12 @@ export class ArrayType extends Type { /** * Sets the element type of the array */ - setElementType(arrayElementType: Type): void { return wrapJoinPoint(this._javaObject.setElementType(unwrapJoinPoint(arrayElementType))); } + setElementType(arrayElementType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setElementType", this, undefined, arrayElementType)); + const res = wrapJoinPoint(this._javaObject.setElementType(unwrapJoinPoint(arrayElementType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setElementType", this, res, arrayElementType)); + return res; + } } export class BinaryOp extends Op { @@ -1437,8 +1824,18 @@ export class BinaryOp extends Op { set left(value: Expression) { this._javaObject.setLeft(unwrapJoinPoint(value)); } get right(): Expression { return wrapJoinPoint(this._javaObject.getRight()) } set right(value: Expression) { this._javaObject.setRight(unwrapJoinPoint(value)); } - setLeft(left: Expression): void { return wrapJoinPoint(this._javaObject.setLeft(unwrapJoinPoint(left))); } - setRight(right: Expression): void { return wrapJoinPoint(this._javaObject.setRight(unwrapJoinPoint(right))); } + setLeft(left: Expression): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setLeft", this, undefined, left)); + const res = wrapJoinPoint(this._javaObject.setLeft(unwrapJoinPoint(left))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setLeft", this, res, left)); + return res; + } + setRight(right: Expression): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setRight", this, undefined, right)); + const res = wrapJoinPoint(this._javaObject.setRight(unwrapJoinPoint(right))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setRight", this, res, right)); + return res; + } } export class BoolLiteral extends Literal { @@ -1544,7 +1941,12 @@ export class Call extends Expression { * Similar to $function.signature, but if no function decl could be found (e.g., function from system include), returns a signature based on just the name of the function */ get signature(): string { return wrapJoinPoint(this._javaObject.getSignature()) } - getArg(index: number): Expression { return wrapJoinPoint(this._javaObject.getArg(unwrapJoinPoint(index))); } + getArg(index: number): Expression { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getArg", this, undefined, index)); + const res = wrapJoinPoint(this._javaObject.getArg(unwrapJoinPoint(index))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getArg", this, res, index)); + return res; + } /** * Adds an argument at the end of the call, creating an expression using the given code and type. If a type is not provided, a dummy type is used */ @@ -1556,21 +1958,51 @@ export class Call extends Expression { /** * Adds an argument at the end of the call, creating an expression using the given code and type. If a type is not provided, a dummy type is used */ - addArg(p1: string, p2?: Type | string): void { return wrapJoinPoint(this._javaObject.addArg(unwrapJoinPoint(p1), unwrapJoinPoint(p2))); } + addArg(p1: string, p2?: Type | string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addArg", this, undefined, p1, p2)); + const res = wrapJoinPoint(this._javaObject.addArg(unwrapJoinPoint(p1), unwrapJoinPoint(p2))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addArg", this, res, p1, p2)); + return res; + } /** * Tries to inline this call */ - inline(): boolean { return wrapJoinPoint(this._javaObject.inline()); } - setArg(index: number, expr: Expression): void { return wrapJoinPoint(this._javaObject.setArg(unwrapJoinPoint(index), unwrapJoinPoint(expr))); } - setArgFromString(index: number, expr: string): void { return wrapJoinPoint(this._javaObject.setArgFromString(unwrapJoinPoint(index), unwrapJoinPoint(expr))); } + inline(): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "inline", this, undefined)); + const res = wrapJoinPoint(this._javaObject.inline()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "inline", this, res)); + return res; + } + setArg(index: number, expr: Expression): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setArg", this, undefined, index, expr)); + const res = wrapJoinPoint(this._javaObject.setArg(unwrapJoinPoint(index), unwrapJoinPoint(expr))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setArg", this, res, index, expr)); + return res; + } + setArgFromString(index: number, expr: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setArgFromString", this, undefined, index, expr)); + const res = wrapJoinPoint(this._javaObject.setArgFromString(unwrapJoinPoint(index), unwrapJoinPoint(expr))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setArgFromString", this, res, index, expr)); + return res; + } /** * Changes the name of the call */ - setName(name: string): void { return wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(name))); } + setName(name: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setName", this, undefined, name)); + const res = wrapJoinPoint(this._javaObject.setName(unwrapJoinPoint(name))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setName", this, res, name)); + return res; + } /** * Wraps this call with a possibly new wrapping function */ - wrap(name: string): void { return wrapJoinPoint(this._javaObject.wrap(unwrapJoinPoint(name))); } + wrap(name: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "wrap", this, undefined, name)); + const res = wrapJoinPoint(this._javaObject.wrap(unwrapJoinPoint(name))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "wrap", this, res, name)); + return res; + } } export class Case extends Statement { @@ -1693,7 +2125,12 @@ export class Class extends RecordJp { /** * Adds a method to a class. If the given method has a definition, creates an equivalent declaration and adds it to the class, otherwise simply added the declaration to the class. In both cases, the declaration is only added to the class if there is no declaration already with the same signature. */ - addMethod(method: Method): void { return wrapJoinPoint(this._javaObject.addMethod(unwrapJoinPoint(method))); } + addMethod(method: Method): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addMethod", this, undefined, method)); + const res = wrapJoinPoint(this._javaObject.addMethod(unwrapJoinPoint(method))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addMethod", this, res, method)); + return res; + } } export class Continue extends Statement { @@ -1714,8 +2151,18 @@ export class CudaKernelCall extends Call { }; get config(): Expression[] { return wrapJoinPoint(this._javaObject.getConfig()) } set config(value: Expression[]) { this._javaObject.setConfig(unwrapJoinPoint(value)); } - setConfig(args: Expression[]): void { return wrapJoinPoint(this._javaObject.setConfig(unwrapJoinPoint(args))); } - setConfigFromStrings(args: string[]): void { return wrapJoinPoint(this._javaObject.setConfigFromStrings(unwrapJoinPoint(args))); } + setConfig(args: Expression[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setConfig", this, undefined, args)); + const res = wrapJoinPoint(this._javaObject.setConfig(unwrapJoinPoint(args))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setConfig", this, res, args)); + return res; + } + setConfigFromStrings(args: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setConfigFromStrings", this, undefined, args)); + const res = wrapJoinPoint(this._javaObject.setConfigFromStrings(unwrapJoinPoint(args))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setConfigFromStrings", this, res, args)); + return res; + } } export class DeclStmt extends Statement { @@ -1914,7 +2361,12 @@ export class FunctionJp extends Declarator { */ get signature(): string { return wrapJoinPoint(this._javaObject.getSignature()) } get storageClass(): StorageClass { return wrapJoinPoint(this._javaObject.getStorageClass()) } - getDeclaration(withReturnType: boolean): string { return wrapJoinPoint(this._javaObject.getDeclaration(unwrapJoinPoint(withReturnType))); } + getDeclaration(withReturnType: boolean): string { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getDeclaration", this, undefined, withReturnType)); + const res = wrapJoinPoint(this._javaObject.getDeclaration(unwrapJoinPoint(withReturnType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getDeclaration", this, res, withReturnType)); + return res; + } /** * Adds a new parameter to the function */ @@ -1926,11 +2378,21 @@ export class FunctionJp extends Declarator { /** * Adds a new parameter to the function */ - addParam(p1: Param | string, p2?: Type): void { return wrapJoinPoint(this._javaObject.addParam(unwrapJoinPoint(p1), unwrapJoinPoint(p2))); } + addParam(p1: Param | string, p2?: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addParam", this, undefined, p1, p2)); + const res = wrapJoinPoint(this._javaObject.addParam(unwrapJoinPoint(p1), unwrapJoinPoint(p2))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addParam", this, res, p1, p2)); + return res; + } /** * Clones this function assigning it a new name, inserts the cloned function after the original function. If the name is the same and the original method, automatically removes the cloned method from the class */ - clone(newName: string, insert: boolean = true): FunctionJp { return wrapJoinPoint(this._javaObject.clone(unwrapJoinPoint(newName), unwrapJoinPoint(insert))); } + clone(newName: string, insert: boolean = true): FunctionJp { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "clone", this, undefined, newName, insert)); + const res = wrapJoinPoint(this._javaObject.clone(unwrapJoinPoint(newName), unwrapJoinPoint(insert))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "clone", this, res, newName, insert)); + return res; + } /** * Generates a clone of the provided function on a new file with the provided name (or with a weaver-generated name if one is not provided). */ @@ -1942,7 +2404,12 @@ export class FunctionJp extends Declarator { /** * Generates a clone of the provided function on a new file with the provided name (or with a weaver-generated name if one is not provided). */ - cloneOnFile(p1: string, p2?: string | FileJp): FunctionJp { return wrapJoinPoint(this._javaObject.cloneOnFile(unwrapJoinPoint(p1), unwrapJoinPoint(p2))); } + cloneOnFile(p1: string, p2?: string | FileJp): FunctionJp { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "cloneOnFile", this, undefined, p1, p2)); + const res = wrapJoinPoint(this._javaObject.cloneOnFile(unwrapJoinPoint(p1), unwrapJoinPoint(p2))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "cloneOnFile", this, res, p1, p2)); + return res; + } /** * Inserts the joinpoint before the return points of the function (return statements and implicitly, at the end of the function). Returns the last inserted node */ @@ -1954,19 +2421,39 @@ export class FunctionJp extends Declarator { /** * Inserts the joinpoint before the return points of the function (return statements and implicitly, at the end of the function). Returns the last inserted node */ - insertReturn(p1: Joinpoint | string): Joinpoint { return wrapJoinPoint(this._javaObject.insertReturn(unwrapJoinPoint(p1))); } + insertReturn(p1: Joinpoint | string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "insertReturn", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.insertReturn(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "insertReturn", this, res, p1)); + return res; + } /** * Creates a new call to this function */ - newCall(args: Joinpoint[]): Call { return wrapJoinPoint(this._javaObject.newCall(unwrapJoinPoint(args))); } + newCall(args: Joinpoint[]): Call { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "newCall", this, undefined, args)); + const res = wrapJoinPoint(this._javaObject.newCall(unwrapJoinPoint(args))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "newCall", this, res, args)); + return res; + } /** * Sets the body of the function */ - setBody(body: Scope): void { return wrapJoinPoint(this._javaObject.setBody(unwrapJoinPoint(body))); } + setBody(body: Scope): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setBody", this, undefined, body)); + const res = wrapJoinPoint(this._javaObject.setBody(unwrapJoinPoint(body))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setBody", this, res, body)); + return res; + } /** * Sets the type of the function */ - setFunctionType(functionType: FunctionType): void { return wrapJoinPoint(this._javaObject.setFunctionType(unwrapJoinPoint(functionType))); } + setFunctionType(functionType: FunctionType): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setFunctionType", this, undefined, functionType)); + const res = wrapJoinPoint(this._javaObject.setFunctionType(unwrapJoinPoint(functionType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setFunctionType", this, res, functionType)); + return res; + } /** * Sets the parameter of the function at the given position */ @@ -1978,23 +2465,48 @@ export class FunctionJp extends Declarator { /** * Sets the parameter of the function at the given position */ - setParam(p1: number, p2: Param | string, p3?: Type): void { return wrapJoinPoint(this._javaObject.setParam(unwrapJoinPoint(p1), unwrapJoinPoint(p2), unwrapJoinPoint(p3))); } + setParam(p1: number, p2: Param | string, p3?: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setParam", this, undefined, p1, p2, p3)); + const res = wrapJoinPoint(this._javaObject.setParam(unwrapJoinPoint(p1), unwrapJoinPoint(p2), unwrapJoinPoint(p3))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setParam", this, res, p1, p2, p3)); + return res; + } /** * Sets the type of a parameter of the function */ - setParamType(index: number, newType: Type): void { return wrapJoinPoint(this._javaObject.setParamType(unwrapJoinPoint(index), unwrapJoinPoint(newType))); } + setParamType(index: number, newType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setParamType", this, undefined, index, newType)); + const res = wrapJoinPoint(this._javaObject.setParamType(unwrapJoinPoint(index), unwrapJoinPoint(newType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setParamType", this, res, index, newType)); + return res; + } /** * Sets the parameters of the function */ - setParams(params: Param[]): void { return wrapJoinPoint(this._javaObject.setParams(unwrapJoinPoint(params))); } + setParams(params: Param[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setParams", this, undefined, params)); + const res = wrapJoinPoint(this._javaObject.setParams(unwrapJoinPoint(params))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setParams", this, res, params)); + return res; + } /** * Overload that accepts strings that represent type-varname pairs (e.g., int param1) */ - setParamsFromStrings(params: string[]): void { return wrapJoinPoint(this._javaObject.setParamsFromStrings(unwrapJoinPoint(params))); } + setParamsFromStrings(params: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setParamsFromStrings", this, undefined, params)); + const res = wrapJoinPoint(this._javaObject.setParamsFromStrings(unwrapJoinPoint(params))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setParamsFromStrings", this, res, params)); + return res; + } /** * Sets the return type of the function */ - setReturnType(returnType: Type): void { return wrapJoinPoint(this._javaObject.setReturnType(unwrapJoinPoint(returnType))); } + setReturnType(returnType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setReturnType", this, undefined, returnType)); + const res = wrapJoinPoint(this._javaObject.setReturnType(unwrapJoinPoint(returnType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setReturnType", this, res, returnType)); + return res; + } } export class FunctionType extends Type { @@ -2010,11 +2522,21 @@ export class FunctionType extends Type { /** * Sets the type of a parameter of the FunctionType. Be careful that if you directly change the type of a paramemter and the function type is associated with a function declaration, this change will not be reflected in the function. If you want to change the type of a parameter of a function declaration, use $function.setParaType */ - setParamType(index: number, newType: Type): void { return wrapJoinPoint(this._javaObject.setParamType(unwrapJoinPoint(index), unwrapJoinPoint(newType))); } + setParamType(index: number, newType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setParamType", this, undefined, index, newType)); + const res = wrapJoinPoint(this._javaObject.setParamType(unwrapJoinPoint(index), unwrapJoinPoint(newType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setParamType", this, res, index, newType)); + return res; + } /** * Sets the return type of the FunctionType */ - setReturnType(newType: Type): void { return wrapJoinPoint(this._javaObject.setReturnType(unwrapJoinPoint(newType))); } + setReturnType(newType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setReturnType", this, undefined, newType)); + const res = wrapJoinPoint(this._javaObject.setReturnType(unwrapJoinPoint(newType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setReturnType", this, res, newType)); + return res; + } } export class GotoStmt extends Statement { @@ -2029,7 +2551,12 @@ export class GotoStmt extends Statement { /** * Sets the label of the goto */ - setLabel(label: LabelDecl): void { return wrapJoinPoint(this._javaObject.setLabel(unwrapJoinPoint(label))); } + setLabel(label: LabelDecl): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setLabel", this, undefined, label)); + const res = wrapJoinPoint(this._javaObject.setLabel(unwrapJoinPoint(label))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setLabel", this, res, label)); + return res; + } } export class If extends Statement { @@ -2049,15 +2576,30 @@ export class If extends Statement { /** * Sets the condition of the if */ - setCond(cond: Expression): void { return wrapJoinPoint(this._javaObject.setCond(unwrapJoinPoint(cond))); } + setCond(cond: Expression): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setCond", this, undefined, cond)); + const res = wrapJoinPoint(this._javaObject.setCond(unwrapJoinPoint(cond))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setCond", this, res, cond)); + return res; + } /** * Sets the body of the else */ - setElse(elseStatement: Statement): void { return wrapJoinPoint(this._javaObject.setElse(unwrapJoinPoint(elseStatement))); } + setElse(elseStatement: Statement): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setElse", this, undefined, elseStatement)); + const res = wrapJoinPoint(this._javaObject.setElse(unwrapJoinPoint(elseStatement))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setElse", this, res, elseStatement)); + return res; + } /** * Sets the body of the if */ - setThen(then: Statement): void { return wrapJoinPoint(this._javaObject.setThen(unwrapJoinPoint(then))); } + setThen(then: Statement): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setThen", this, undefined, then)); + const res = wrapJoinPoint(this._javaObject.setThen(unwrapJoinPoint(then))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setThen", this, res, then)); + return res; + } } export class IntLiteral extends Literal { @@ -2091,7 +2633,12 @@ export class LabelStmt extends Statement { /** * Sets the label of the label statement */ - setDecl(label: LabelDecl): void { return wrapJoinPoint(this._javaObject.setDecl(unwrapJoinPoint(label))); } + setDecl(label: LabelDecl): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setDecl", this, undefined, label)); + const res = wrapJoinPoint(this._javaObject.setDecl(unwrapJoinPoint(label))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setDecl", this, res, label)); + return res; + } } export class Loop extends Statement { @@ -2171,51 +2718,111 @@ export class Loop extends Statement { /** * Tests whether the loops are interchangeable. This is a conservative test. */ - isInterchangeable(otherLoop: Loop): boolean { return wrapJoinPoint(this._javaObject.isInterchangeable(unwrapJoinPoint(otherLoop))); } + isInterchangeable(otherLoop: Loop): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "isInterchangeable", this, undefined, otherLoop)); + const res = wrapJoinPoint(this._javaObject.isInterchangeable(unwrapJoinPoint(otherLoop))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "isInterchangeable", this, res, otherLoop)); + return res; + } /** * Interchanges two for loops, if possible */ - interchange(otherLoop: Loop): void { return wrapJoinPoint(this._javaObject.interchange(unwrapJoinPoint(otherLoop))); } + interchange(otherLoop: Loop): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "interchange", this, undefined, otherLoop)); + const res = wrapJoinPoint(this._javaObject.interchange(unwrapJoinPoint(otherLoop))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "interchange", this, res, otherLoop)); + return res; + } /** * Sets the body of the loop */ - setBody(body: Scope): void { return wrapJoinPoint(this._javaObject.setBody(unwrapJoinPoint(body))); } + setBody(body: Scope): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setBody", this, undefined, body)); + const res = wrapJoinPoint(this._javaObject.setBody(unwrapJoinPoint(body))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setBody", this, res, body)); + return res; + } /** * Sets the conditional statement of the loop. Works with loops of kind 'for' */ - setCond(condCode: string): void { return wrapJoinPoint(this._javaObject.setCond(unwrapJoinPoint(condCode))); } + setCond(condCode: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setCond", this, undefined, condCode)); + const res = wrapJoinPoint(this._javaObject.setCond(unwrapJoinPoint(condCode))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setCond", this, res, condCode)); + return res; + } /** * Changes the operator of a canonical condition, if possible. Supported operators: lt, le, gt, ge */ - setCondRelation(operator: Relation): void { return wrapJoinPoint(this._javaObject.setCondRelation(unwrapJoinPoint(operator))); } + setCondRelation(operator: Relation): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setCondRelation", this, undefined, operator)); + const res = wrapJoinPoint(this._javaObject.setCondRelation(unwrapJoinPoint(operator))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setCondRelation", this, res, operator)); + return res; + } /** * Sets the end value of the loop. Works with loops of kind 'for' */ - setEndValue(initCode: string): void { return wrapJoinPoint(this._javaObject.setEndValue(unwrapJoinPoint(initCode))); } + setEndValue(initCode: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setEndValue", this, undefined, initCode)); + const res = wrapJoinPoint(this._javaObject.setEndValue(unwrapJoinPoint(initCode))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setEndValue", this, res, initCode)); + return res; + } /** * Sets the init statement of the loop */ - setInit(initCode: string): void { return wrapJoinPoint(this._javaObject.setInit(unwrapJoinPoint(initCode))); } + setInit(initCode: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setInit", this, undefined, initCode)); + const res = wrapJoinPoint(this._javaObject.setInit(unwrapJoinPoint(initCode))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setInit", this, res, initCode)); + return res; + } /** * Sets the init value of the loop. Works with loops of kind 'for' */ - setInitValue(initCode: string): void { return wrapJoinPoint(this._javaObject.setInitValue(unwrapJoinPoint(initCode))); } + setInitValue(initCode: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setInitValue", this, undefined, initCode)); + const res = wrapJoinPoint(this._javaObject.setInitValue(unwrapJoinPoint(initCode))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setInitValue", this, res, initCode)); + return res; + } /** * Sets the attribute 'isParallel' of the loop */ - setIsParallel(isParallel: boolean): void { return wrapJoinPoint(this._javaObject.setIsParallel(unwrapJoinPoint(isParallel))); } + setIsParallel(isParallel: boolean): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setIsParallel", this, undefined, isParallel)); + const res = wrapJoinPoint(this._javaObject.setIsParallel(unwrapJoinPoint(isParallel))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setIsParallel", this, res, isParallel)); + return res; + } /** * Sets the kind of the loop */ - setKind(kind: string): void { return wrapJoinPoint(this._javaObject.setKind(unwrapJoinPoint(kind))); } + setKind(kind: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setKind", this, undefined, kind)); + const res = wrapJoinPoint(this._javaObject.setKind(unwrapJoinPoint(kind))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setKind", this, res, kind)); + return res; + } /** * Sets the step statement of the loop. Works with loops of kind 'for' */ - setStep(stepCode: string): void { return wrapJoinPoint(this._javaObject.setStep(unwrapJoinPoint(stepCode))); } + setStep(stepCode: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setStep", this, undefined, stepCode)); + const res = wrapJoinPoint(this._javaObject.setStep(unwrapJoinPoint(stepCode))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setStep", this, res, stepCode)); + return res; + } /** * Applies loop tiling to this loop. */ - tile(blockSize: string, reference: Statement, useTernary: boolean = true): Statement { return wrapJoinPoint(this._javaObject.tile(unwrapJoinPoint(blockSize), unwrapJoinPoint(reference), unwrapJoinPoint(useTernary))); } + tile(blockSize: string, reference: Statement, useTernary: boolean = true): Statement { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "tile", this, undefined, blockSize, reference, useTernary)); + const res = wrapJoinPoint(this._javaObject.tile(unwrapJoinPoint(blockSize), unwrapJoinPoint(reference), unwrapJoinPoint(useTernary))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "tile", this, res, blockSize, reference, useTernary)); + return res; + } } /** @@ -2260,7 +2867,12 @@ export class Method extends FunctionJp { /** * Removes the of the method */ - removeRecord(): void { return wrapJoinPoint(this._javaObject.removeRecord()); } + removeRecord(): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "removeRecord", this, undefined)); + const res = wrapJoinPoint(this._javaObject.removeRecord()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "removeRecord", this, res)); + return res; + } } /** @@ -2396,19 +3008,39 @@ export class Omp extends Pragma { /** * The variable names for the given reduction kind, or empty array if no reduction of that kind is defined */ - getReduction(kind: string): string[] { return wrapJoinPoint(this._javaObject.getReduction(unwrapJoinPoint(kind))); } + getReduction(kind: string): string[] { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getReduction", this, undefined, kind)); + const res = wrapJoinPoint(this._javaObject.getReduction(unwrapJoinPoint(kind))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getReduction", this, res, kind)); + return res; + } /** * True if the directive has at least one clause of the given clause kind, false otherwise */ - hasClause(clauseName: string): boolean { return wrapJoinPoint(this._javaObject.hasClause(unwrapJoinPoint(clauseName))); } + hasClause(clauseName: string): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "hasClause", this, undefined, clauseName)); + const res = wrapJoinPoint(this._javaObject.hasClause(unwrapJoinPoint(clauseName))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "hasClause", this, res, clauseName)); + return res; + } /** * True if it is legal to use the given clause kind in this directive, false otherwise */ - isClauseLegal(clauseName: string): boolean { return wrapJoinPoint(this._javaObject.isClauseLegal(unwrapJoinPoint(clauseName))); } + isClauseLegal(clauseName: string): boolean { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "isClauseLegal", this, undefined, clauseName)); + const res = wrapJoinPoint(this._javaObject.isClauseLegal(unwrapJoinPoint(clauseName))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "isClauseLegal", this, res, clauseName)); + return res; + } /** * Removes any clause of the given kind from the OpenMP pragma */ - removeClause(clauseKind: string): void { return wrapJoinPoint(this._javaObject.removeClause(unwrapJoinPoint(clauseKind))); } + removeClause(clauseKind: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "removeClause", this, undefined, clauseKind)); + const res = wrapJoinPoint(this._javaObject.removeClause(unwrapJoinPoint(clauseKind))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "removeClause", this, res, clauseKind)); + return res; + } /** * Sets the value of the collapse clause of an OpenMP pragma */ @@ -2420,47 +3052,102 @@ export class Omp extends Pragma { /** * Sets the value of the collapse clause of an OpenMP pragma */ - setCollapse(p1: string | number): void { return wrapJoinPoint(this._javaObject.setCollapse(unwrapJoinPoint(p1))); } + setCollapse(p1: string | number): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setCollapse", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.setCollapse(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setCollapse", this, res, p1)); + return res; + } /** * Sets the variables of a copyin clause of an OpenMP pragma */ - setCopyin(newVariables: string[]): void { return wrapJoinPoint(this._javaObject.setCopyin(unwrapJoinPoint(newVariables))); } + setCopyin(newVariables: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setCopyin", this, undefined, newVariables)); + const res = wrapJoinPoint(this._javaObject.setCopyin(unwrapJoinPoint(newVariables))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setCopyin", this, res, newVariables)); + return res; + } /** * Sets the value of the default clause of an OpenMP pragma */ - setDefault(newDefault: string): void { return wrapJoinPoint(this._javaObject.setDefault(unwrapJoinPoint(newDefault))); } + setDefault(newDefault: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setDefault", this, undefined, newDefault)); + const res = wrapJoinPoint(this._javaObject.setDefault(unwrapJoinPoint(newDefault))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setDefault", this, res, newDefault)); + return res; + } /** * Sets the variables of a firstprivate clause of an OpenMP pragma */ - setFirstprivate(newVariables: string[]): void { return wrapJoinPoint(this._javaObject.setFirstprivate(unwrapJoinPoint(newVariables))); } + setFirstprivate(newVariables: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setFirstprivate", this, undefined, newVariables)); + const res = wrapJoinPoint(this._javaObject.setFirstprivate(unwrapJoinPoint(newVariables))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setFirstprivate", this, res, newVariables)); + return res; + } /** * Sets the directive kind of the OpenMP pragma. Any unsupported clauses will be discarded */ - setKind(directiveKind: string): void { return wrapJoinPoint(this._javaObject.setKind(unwrapJoinPoint(directiveKind))); } + setKind(directiveKind: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setKind", this, undefined, directiveKind)); + const res = wrapJoinPoint(this._javaObject.setKind(unwrapJoinPoint(directiveKind))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setKind", this, res, directiveKind)); + return res; + } /** * Sets the variables of a lastprivate clause of an OpenMP pragma */ - setLastprivate(newVariables: string[]): void { return wrapJoinPoint(this._javaObject.setLastprivate(unwrapJoinPoint(newVariables))); } + setLastprivate(newVariables: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setLastprivate", this, undefined, newVariables)); + const res = wrapJoinPoint(this._javaObject.setLastprivate(unwrapJoinPoint(newVariables))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setLastprivate", this, res, newVariables)); + return res; + } /** * Sets the value of the num_threads clause of an OpenMP pragma */ - setNumThreads(newExpr: string): void { return wrapJoinPoint(this._javaObject.setNumThreads(unwrapJoinPoint(newExpr))); } + setNumThreads(newExpr: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setNumThreads", this, undefined, newExpr)); + const res = wrapJoinPoint(this._javaObject.setNumThreads(unwrapJoinPoint(newExpr))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setNumThreads", this, res, newExpr)); + return res; + } /** * Sets the value of the ordered clause of an OpenMP pragma */ - setOrdered(parameters?: string): void { return wrapJoinPoint(this._javaObject.setOrdered(unwrapJoinPoint(parameters))); } + setOrdered(parameters?: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setOrdered", this, undefined, parameters)); + const res = wrapJoinPoint(this._javaObject.setOrdered(unwrapJoinPoint(parameters))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setOrdered", this, res, parameters)); + return res; + } /** * Sets the variables of a private clause of an OpenMP pragma */ - setPrivate(newVariables: string[]): void { return wrapJoinPoint(this._javaObject.setPrivate(unwrapJoinPoint(newVariables))); } + setPrivate(newVariables: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setPrivate", this, undefined, newVariables)); + const res = wrapJoinPoint(this._javaObject.setPrivate(unwrapJoinPoint(newVariables))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setPrivate", this, res, newVariables)); + return res; + } /** * Sets the value of the proc_bind clause of an OpenMP pragma */ - setProcBind(newBind: string): void { return wrapJoinPoint(this._javaObject.setProcBind(unwrapJoinPoint(newBind))); } + setProcBind(newBind: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setProcBind", this, undefined, newBind)); + const res = wrapJoinPoint(this._javaObject.setProcBind(unwrapJoinPoint(newBind))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setProcBind", this, res, newBind)); + return res; + } /** * Sets the variables for a given kind of a reduction clause of an OpenMP pragma */ - setReduction(kind: string, newVariables: string[]): void { return wrapJoinPoint(this._javaObject.setReduction(unwrapJoinPoint(kind), unwrapJoinPoint(newVariables))); } + setReduction(kind: string, newVariables: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setReduction", this, undefined, kind, newVariables)); + const res = wrapJoinPoint(this._javaObject.setReduction(unwrapJoinPoint(kind), unwrapJoinPoint(newVariables))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setReduction", this, res, kind, newVariables)); + return res; + } /** * Sets the value of the chunck size in the schedule clause of an OpenMP pragma. Can only be called if there is already a schedule clause in the directive, otherwise throws an exception */ @@ -2472,19 +3159,39 @@ export class Omp extends Pragma { /** * Sets the value of the chunck size in the schedule clause of an OpenMP pragma. Can only be called if there is already a schedule clause in the directive, otherwise throws an exception */ - setScheduleChunkSize(p1: string | number): void { return wrapJoinPoint(this._javaObject.setScheduleChunkSize(unwrapJoinPoint(p1))); } + setScheduleChunkSize(p1: string | number): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setScheduleChunkSize", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.setScheduleChunkSize(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setScheduleChunkSize", this, res, p1)); + return res; + } /** * Sets the value of the schedule clause of an OpenMP pragma */ - setScheduleKind(scheduleKind: string): void { return wrapJoinPoint(this._javaObject.setScheduleKind(unwrapJoinPoint(scheduleKind))); } + setScheduleKind(scheduleKind: string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setScheduleKind", this, undefined, scheduleKind)); + const res = wrapJoinPoint(this._javaObject.setScheduleKind(unwrapJoinPoint(scheduleKind))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setScheduleKind", this, res, scheduleKind)); + return res; + } /** * Sets the value of the modifiers in the schedule clause of an OpenMP pragma. Can only be called if there is already a schedule clause in the directive, otherwise throws an exception */ - setScheduleModifiers(modifiers: string[]): void { return wrapJoinPoint(this._javaObject.setScheduleModifiers(unwrapJoinPoint(modifiers))); } + setScheduleModifiers(modifiers: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setScheduleModifiers", this, undefined, modifiers)); + const res = wrapJoinPoint(this._javaObject.setScheduleModifiers(unwrapJoinPoint(modifiers))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setScheduleModifiers", this, res, modifiers)); + return res; + } /** * Sets the variables of a shared clause of an OpenMP pragma */ - setShared(newVariables: string[]): void { return wrapJoinPoint(this._javaObject.setShared(unwrapJoinPoint(newVariables))); } + setShared(newVariables: string[]): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setShared", this, undefined, newVariables)); + const res = wrapJoinPoint(this._javaObject.setShared(unwrapJoinPoint(newVariables))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setShared", this, res, newVariables)); + return res; + } } export class ParenType extends Type { @@ -2499,7 +3206,12 @@ export class ParenType extends Type { /** * Sets the inner type of this paren type */ - setInnerType(innerType: Type): void { return wrapJoinPoint(this._javaObject.setInnerType(unwrapJoinPoint(innerType))); } + setInnerType(innerType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setInnerType", this, undefined, innerType)); + const res = wrapJoinPoint(this._javaObject.setInnerType(unwrapJoinPoint(innerType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setInnerType", this, res, innerType)); + return res; + } } export class PointerType extends Type { @@ -2518,7 +3230,12 @@ export class PointerType extends Type { /** * Sets the pointee type of this pointer type */ - setPointee(pointeeType: Type): void { return wrapJoinPoint(this._javaObject.setPointee(unwrapJoinPoint(pointeeType))); } + setPointee(pointeeType: Type): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setPointee", this, undefined, pointeeType)); + const res = wrapJoinPoint(this._javaObject.setPointee(unwrapJoinPoint(pointeeType))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setPointee", this, res, pointeeType)); + return res; + } } export class QualType extends Type { @@ -2577,29 +3294,64 @@ export class Scope extends Statement { /** * The number of statements in the scope, including the statements inside the declaration and bodies of structures such as ifs and loops, and not considering comments and pragmas. If flat is true, does not consider the statements inside structures such as ifs and loops (e.g., a loop counts as one statement) */ - getNumStatements(flat: boolean = false): number { return wrapJoinPoint(this._javaObject.getNumStatements(unwrapJoinPoint(flat))); } + getNumStatements(flat: boolean = false): number { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "getNumStatements", this, undefined, flat)); + const res = wrapJoinPoint(this._javaObject.getNumStatements(unwrapJoinPoint(flat))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "getNumStatements", this, res, flat)); + return res; + } /** * Adds a new local variable to this scope */ - addLocal(name: string, type: Joinpoint, initValue?: string): Joinpoint { return wrapJoinPoint(this._javaObject.addLocal(unwrapJoinPoint(name), unwrapJoinPoint(type), unwrapJoinPoint(initValue))); } + addLocal(name: string, type: Joinpoint, initValue?: string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "addLocal", this, undefined, name, type, initValue)); + const res = wrapJoinPoint(this._javaObject.addLocal(unwrapJoinPoint(name), unwrapJoinPoint(type), unwrapJoinPoint(initValue))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "addLocal", this, res, name, type, initValue)); + return res; + } /** * CFG tester */ - cfg(): string { return wrapJoinPoint(this._javaObject.cfg()); } + cfg(): string { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "cfg", this, undefined)); + const res = wrapJoinPoint(this._javaObject.cfg()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "cfg", this, res)); + return res; + } /** * Clears the contents of this scope (untested) */ - clear(): void { return wrapJoinPoint(this._javaObject.clear()); } + clear(): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "clear", this, undefined)); + const res = wrapJoinPoint(this._javaObject.clear()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "clear", this, res)); + return res; + } /** * DFG tester */ - dfg(): string { return wrapJoinPoint(this._javaObject.dfg()); } + dfg(): string { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "dfg", this, undefined)); + const res = wrapJoinPoint(this._javaObject.dfg()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "dfg", this, res)); + return res; + } insertBegin(node: Joinpoint): Joinpoint; insertBegin(code: string): Joinpoint; - insertBegin(p1: Joinpoint | string): Joinpoint { return wrapJoinPoint(this._javaObject.insertBegin(unwrapJoinPoint(p1))); } + insertBegin(p1: Joinpoint | string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "insertBegin", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.insertBegin(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "insertBegin", this, res, p1)); + return res; + } insertEnd(node: Joinpoint): Joinpoint; insertEnd(code: string): Joinpoint; - insertEnd(p1: Joinpoint | string): Joinpoint { return wrapJoinPoint(this._javaObject.insertEnd(unwrapJoinPoint(p1))); } + insertEnd(p1: Joinpoint | string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "insertEnd", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.insertEnd(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "insertEnd", this, res, p1)); + return res; + } /** * Inserts the joinpoint before the return points of the scope (return statements and implicitly, at the end of the scope). Returns the last inserted node */ @@ -2611,11 +3363,21 @@ export class Scope extends Statement { /** * Inserts the joinpoint before the return points of the scope (return statements and implicitly, at the end of the scope). Returns the last inserted node */ - insertReturn(p1: Joinpoint | string): Joinpoint { return wrapJoinPoint(this._javaObject.insertReturn(unwrapJoinPoint(p1))); } + insertReturn(p1: Joinpoint | string): Joinpoint { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "insertReturn", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.insertReturn(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "insertReturn", this, res, p1)); + return res; + } /** * Sets the 'naked' status of a scope (a scope is naked if it does not have curly braces) */ - setNaked(isNaked: boolean): void { return wrapJoinPoint(this._javaObject.setNaked(unwrapJoinPoint(isNaked))); } + setNaked(isNaked: boolean): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setNaked", this, undefined, isNaked)); + const res = wrapJoinPoint(this._javaObject.setNaked(unwrapJoinPoint(isNaked))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setNaked", this, res, isNaked)); + return res; + } } export class TagType extends Type { @@ -2706,7 +3468,12 @@ export class Vardecl extends Declarator { /** * If vardecl already has an initialization, removes it. */ - removeInit(removeConst: boolean = true): void { return wrapJoinPoint(this._javaObject.removeInit(unwrapJoinPoint(removeConst))); } + removeInit(removeConst: boolean = true): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "removeInit", this, undefined, removeConst)); + const res = wrapJoinPoint(this._javaObject.removeInit(unwrapJoinPoint(removeConst))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "removeInit", this, res, removeConst)); + return res; + } /** * Sets the given expression as the initialization of this vardecl. If undefined is passed and vardecl already has an initialization, removes that initialization */ @@ -2718,15 +3485,30 @@ export class Vardecl extends Declarator { /** * Sets the given expression as the initialization of this vardecl. If undefined is passed and vardecl already has an initialization, removes that initialization */ - setInit(p1: Expression | string): void { return wrapJoinPoint(this._javaObject.setInit(unwrapJoinPoint(p1))); } + setInit(p1: Expression | string): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setInit", this, undefined, p1)); + const res = wrapJoinPoint(this._javaObject.setInit(unwrapJoinPoint(p1))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setInit", this, res, p1)); + return res; + } /** * Sets the storage class specifier, which can be none, extern, static, __private_extern__, autovardecl */ - setStorageClass(storageClass: StorageClass): void { return wrapJoinPoint(this._javaObject.setStorageClass(unwrapJoinPoint(storageClass))); } + setStorageClass(storageClass: StorageClass): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setStorageClass", this, undefined, storageClass)); + const res = wrapJoinPoint(this._javaObject.setStorageClass(unwrapJoinPoint(storageClass))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setStorageClass", this, res, storageClass)); + return res; + } /** * Creates a new varref based on this vardecl */ - varref(): Varref { return wrapJoinPoint(this._javaObject.varref()); } + varref(): Varref { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "varref", this, undefined)); + const res = wrapJoinPoint(this._javaObject.varref()); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "varref", this, res)); + return res; + } } export class VariableArrayType extends ArrayType { @@ -2741,7 +3523,12 @@ export class VariableArrayType extends ArrayType { /** * Sets the size expression of this variable array type */ - setSizeExpr(sizeExpr: Expression): void { return wrapJoinPoint(this._javaObject.setSizeExpr(unwrapJoinPoint(sizeExpr))); } + setSizeExpr(sizeExpr: Expression): void { + eventListener.emit("ACTION", new Event(EventTime.BEFORE, "setSizeExpr", this, undefined, sizeExpr)); + const res = wrapJoinPoint(this._javaObject.setSizeExpr(unwrapJoinPoint(sizeExpr))); + eventListener.emit("ACTION", new Event(EventTime.AFTER, "setSizeExpr", this, res, sizeExpr)); + return res; + } } export class Body extends Scope { diff --git a/Clava-JS/src-api/clava/events/EventListener.ts b/Clava-JS/src-api/clava/events/EventListener.ts new file mode 100644 index 000000000..378119bd9 --- /dev/null +++ b/Clava-JS/src-api/clava/events/EventListener.ts @@ -0,0 +1,5 @@ +import { EventEmitter } from "events"; + +const eventListener = new EventEmitter(); + +export default eventListener; diff --git a/Clava-JS/src-api/clava/events/Events.ts b/Clava-JS/src-api/clava/events/Events.ts new file mode 100644 index 000000000..ce11a0ac0 --- /dev/null +++ b/Clava-JS/src-api/clava/events/Events.ts @@ -0,0 +1,28 @@ +import { Joinpoint } from "../../Joinpoints.js"; + +export enum EventTime { + BEFORE = "Before", + AFTER = "After", +} + +export class Event { + public timing: EventTime; + public description: string; + public mainJP: Joinpoint; + public returnValue?: any; + public inputs: unknown[]; + + constructor( + timing: EventTime, + description: string, + mainJP: Joinpoint, + returnJP?: Joinpoint, + ...inputs: unknown[] + ) { + this.timing = timing; + this.description = description; + this.mainJP = mainJP; + this.returnValue = returnJP; + this.inputs = inputs; + } +} diff --git a/Clava-JS/src-api/clava/history/History.test.ts b/Clava-JS/src-api/clava/history/History.test.ts new file mode 100644 index 000000000..5037aed00 --- /dev/null +++ b/Clava-JS/src-api/clava/history/History.test.ts @@ -0,0 +1,179 @@ +import { registerSourceCode } from "lara-js/jest/jestHelpers"; +import Clava from "../Clava"; +import { FunctionJp, Joinpoint, Loop, ReturnStmt } from "../../Joinpoints"; +import Query from "lara-js/api/weaver/Query"; +import ophistory from "./History"; +import {jest} from '@jest/globals' + + +const code: string = `void func() { + for (int i = 0; i < 1; i++){ + i++; + } + for (int i = 0; i < 2; i++){ + i++; + } +} + +void test() {} + +int main(int argc, char *argv[]) { + func(); + return 0; +} +`; + +describe("Transformation History: Multiple operations", () => { + registerSourceCode(code); + ophistory.checkpoint(); + + it("Inserts and detaches code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt1 = Query.search(Loop).get().at(0) as Joinpoint; + const loopStmt2 = Query.search(Loop).get().at(1) as Joinpoint; + loopStmt1.insertBefore(loopStmt2.deepCopy()); + loopStmt2.insertAfter(loopStmt1.deepCopy()); + + loopStmt1.detach(); + loopStmt2.detach(); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(4); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Replaces and detach code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt1 = Query.search(Loop).get().at(0) as Joinpoint; + const returnStmt = Query.search(ReturnStmt).get().at(0) as Joinpoint; + + let cur = loopStmt1.replaceWith(returnStmt.deepCopy()); + cur = cur.replaceWith("aaaaa"); + cur = cur.replaceWithStrings(["aaaaa", "bbbbb", "ccccc"]); + cur = cur.toComment(); + cur.detach(); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(5); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Children set and removes code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt1 = Query.search(Loop).get().at(0) as Joinpoint; + const testFunc = Query.search(FunctionJp).get().at(1) as FunctionJp; + const returnStmt = Query.search(ReturnStmt).get().at(0) as Joinpoint; + + testFunc.body.setFirstChild(loopStmt1.deepCopy()); + testFunc.body.setLastChild(returnStmt.deepCopy()); + testFunc.body.setFirstChild(loopStmt1.deepCopy()); + testFunc.body.setLastChild(returnStmt.deepCopy()); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(4); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Log an error message on undo operation (single rollback)", () => { + const errorSpy = jest.spyOn(global.console, "error") + .mockImplementation(() => {}); + + const loopStmt1 = Query.search(Loop).get().at(0) as Joinpoint; + + loopStmt1.replaceWith("aaaa"); + loopStmt1.detach(); + + ophistory.rollback(2); + + expect(errorSpy).toHaveBeenCalledTimes(1); + + errorSpy.mockRestore(); + }); + + it("Checkpoints code comparison", () => { + + const loopStmt1 = Query.search(Loop).get().at(0) as Joinpoint; + const loopStmt2 = Query.search(Loop).get().at(1) as Joinpoint; + loopStmt1.insertBefore(loopStmt2.deepCopy()); + loopStmt2.insertAfter(loopStmt1.deepCopy()); + + ophistory.checkpoint(); + const a: string = Clava.getProgram().code; + + loopStmt1.detach(); + loopStmt2.detach(); + + const b: string = Clava.getProgram().code; + + ophistory.returnToLastCheckpoint(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Log an error message on undo operation (checkpoint rollback)", () => { + const errorSpy = jest.spyOn(global.console, "error") + .mockImplementation(() => {}); + + const loopStmt1 = Query.search(Loop).get().at(0) as Joinpoint; + + ophistory.checkpoint(); + loopStmt1.replaceWith("aaaa"); + loopStmt1.detach(); + + ophistory.returnToLastCheckpoint(); + + expect(errorSpy).toHaveBeenCalledTimes(1); + + errorSpy.mockRestore(); + }); + + it("Start and stop history recording", () => { + ophistory.stop(); + + const a: string = Clava.getProgram().code; + + const loopStmt1 = Query.search(Loop).get().at(0) as Joinpoint; + loopStmt1.replaceWith("aaaa"); + + const b: string = Clava.getProgram().code; + + ophistory.start(); + + const returnStmt = Query.search(Loop).get().at(0) as Joinpoint; + const comment = returnStmt.toComment(); + ophistory.checkpoint(); + const c: string = Clava.getProgram().code; + + comment.detach(); + const d: string = Clava.getProgram().code; + + ophistory.returnToLastCheckpoint(); + const e: string = Clava.getProgram().code; + + expect(c).toEqual(e); + expect(a).not.toEqual(b); + expect(a).not.toEqual(c); + expect(a).not.toEqual(d); + expect(b).not.toEqual(c); + expect(b).not.toEqual(d); + expect(c).not.toEqual(d); + }); + +}); \ No newline at end of file diff --git a/Clava-JS/src-api/clava/history/History.ts b/Clava-JS/src-api/clava/history/History.ts new file mode 100644 index 000000000..98e25b554 --- /dev/null +++ b/Clava-JS/src-api/clava/history/History.ts @@ -0,0 +1,73 @@ +import { Operation } from "./Operations.js" +import "./OperationEvents.js" + +class OperationHistory { + private operations: Operation[]; + private locked: boolean; + + constructor() { + this.operations = []; + this.locked = true; + } + + private lock() { + this.locked = true; + } + + private unlock() { + this.locked = false; + } + + private undo() { + const op = this.operations.pop(); + if (op !== undefined) { + try { + this.lock(); + op.undo(); + } catch (error) { + console.error("Failed to undo operation:", error); + } finally { + this.unlock(); + } + } + } + + start() { + this.operations.length = 0; + this.unlock(); + } + + stop() { + this.lock(); + this.operations.length = 0; + } + + newOperation(operation: Operation) { + if (!this.locked) { + this.operations.push(operation); + } + } + + rollback(n: number = 1) { + if (n > 0){ + while (n--){ + this.undo(); + } + } + } + + checkpoint() { + this.operations.length = 0; + this.unlock(); + } + + returnToLastCheckpoint() { + while (this.operations.length > 0) { + this.undo(); + } + } +} + +const ophistory = new OperationHistory(); + +export default ophistory; \ No newline at end of file diff --git a/Clava-JS/src-api/clava/history/OperationEvents.ts b/Clava-JS/src-api/clava/history/OperationEvents.ts new file mode 100644 index 000000000..872661f27 --- /dev/null +++ b/Clava-JS/src-api/clava/history/OperationEvents.ts @@ -0,0 +1,137 @@ +import { Event, EventTime } from "../events/Events.js"; +import ophistory from "../history/History.js" +import { DetachOperation, DetachReference, InlineCommentOperation, InsertOperation, RemoveChildrenOperation, ReplaceOperation, SetChildOperation, TypeChangeOperation, ValueOperation } from "../history/Operations.js"; +import { Joinpoint } from "../../Joinpoints.js"; +import eventListener from "../events/EventListener.js"; + +// Used for saving previous child in setFirstChild and setLastChild +let auxJP: Joinpoint; + +eventListener.on("ACTION", (e: Event) => { + + switch (e.timing) { + case EventTime.BEFORE: + switch (e.description) { + case "detach": + detachOperationFromEvent(e); + break; + case "removeChildren": + removeChildrenOperationFromEvent(e); + break; + case "setType": + changeTypeFromEvent(e); + break; + case "setFirstChild": + auxJP = e.mainJP.firstChild; + break; + case "setLastChild": + auxJP = e.mainJP.lastChild; + break; + case "setInlineComments": + inlineCommentOperationFromEvent(e); + break; + case "setValue": + setValueOperationFromEvent(e); + break; + default: + break; + } + break; + case EventTime.AFTER: + switch (e.description){ + case "insertAfter": + case "insertBefore": + insertOperationFromEvent(e); + break; + case "replaceWith": + if (e.inputs.length > 0){ + if (typeof e.inputs[0] === 'string' || e.inputs[0] instanceof Joinpoint){ + replaceSingleOperationFromEvent(e); + } + else { + replaceMultipleOperationFromEvent(e); + } + } + break; + case "replaceWithStrings": + if (e.inputs.length > 0){ + replaceMultipleOperationFromEvent(e); + } + break; + case "toComment": + replaceSingleOperationFromEvent(e); + break; + case "setFirstChild": + setFirstChildFromEvent(e, auxJP); + break; + case "setLastChild": + setLastChildFromEvent(e, auxJP); + break; + default: + break; + } + break; + } +}); + +function insertOperationFromEvent(e: Event) { + if (e.returnValue !== undefined){ + ophistory.newOperation(new InsertOperation(e.returnValue)) + } +} + +function replaceSingleOperationFromEvent(e: Event) { + if (e.returnValue !== undefined){ + ophistory.newOperation(new ReplaceOperation(e.mainJP, e.returnValue, 1)); + } +} + +function replaceMultipleOperationFromEvent(e: Event) { + if (e.returnValue !== undefined){ + ophistory.newOperation(new ReplaceOperation(e.mainJP, e.returnValue, (e.inputs[0] as (Joinpoint[] | string[])).length)); + } +} + +function detachOperationFromEvent(e: Event) { + let refJP: Joinpoint, ref: DetachReference; + if (e.mainJP.siblingsLeft.length >= 1){ + refJP = e.mainJP.leftJp; + ref = DetachReference.LEFT; + } else if (e.mainJP.siblingsRight.length >= 1) { + refJP = e.mainJP.rightJp; + ref = DetachReference.RIGHT; + } else { + refJP = e.mainJP.parent; + ref = DetachReference.TOP; + } + ophistory.newOperation(new DetachOperation(e.mainJP, refJP, ref)); +} + +function setFirstChildFromEvent(e: Event, aux: Joinpoint) { + ophistory.newOperation(new SetChildOperation(e.mainJP.firstChild, aux)); +} + +function setLastChildFromEvent(e: Event, aux: Joinpoint) { + ophistory.newOperation(new SetChildOperation(e.mainJP.lastChild, aux)); +} + +function removeChildrenOperationFromEvent(e: Event) { + ophistory.newOperation(new RemoveChildrenOperation(e.mainJP, e.mainJP.children)); +} + +function changeTypeFromEvent(e: Event) { + ophistory.newOperation(new TypeChangeOperation(e.mainJP, e.mainJP.type)); +} + +function inlineCommentOperationFromEvent(e: Event) { + const comments = e.mainJP.inlineComments + .map((comment) => comment.text) + .filter((comment): comment is string => comment !== null); + ophistory.newOperation(new InlineCommentOperation(e.mainJP, comments)); +} + +function setValueOperationFromEvent(e: Event) { + if (e.inputs && e.inputs.at(0)) { + ophistory.newOperation(new ValueOperation(e.mainJP, e.inputs.at(0) as string, e.mainJP.getValue(e.inputs.at(0) as string))); + } +} \ No newline at end of file diff --git a/Clava-JS/src-api/clava/history/Operations.test.ts b/Clava-JS/src-api/clava/history/Operations.test.ts new file mode 100644 index 000000000..36e5c6313 --- /dev/null +++ b/Clava-JS/src-api/clava/history/Operations.test.ts @@ -0,0 +1,374 @@ +import { registerSourceCode } from "lara-js/jest/jestHelpers"; +import Clava from "../../../api/clava/Clava"; +import Query from "lara-js/api/weaver/Query"; +import ophistory from "./History"; +import { FunctionJp, Loop, ReturnStmt, Vardecl } from "../../Joinpoints"; +import ClavaJoinPoints from "../../../api/clava/ClavaJoinPoints"; + +const code: string = `void func() { + for (int i = 0; i < 1; i++){ + i++; + } + for (int i = 0; i < 2; i++){ + i++; + } +} + +void test() {} + +int main(int argc, char *argv[]) { + func(); + return 0; +} +`; + +describe("Transformation History: Operations", () => { + registerSourceCode(code); + ophistory.checkpoint(); + + it("Initial code, insert before and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + loopStmt?.insertBefore(loopStmt.deepCopy()); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, insert after and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + loopStmt?.insertAfter(loopStmt.deepCopy()); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, replace singular string and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + loopStmt?.replaceWith("aaaaa"); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, replace singular joinpoint and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + const returnStmt = Query.search(ReturnStmt).first(); + if (returnStmt !== undefined){ + loopStmt?.replaceWith(returnStmt.deepCopy()); + } + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, replace multiple joinpoints and rollback code comparison", () => { + // TODO: fix error regarding Joinpoint[] overload not found + /*const a: string = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + const returnStmt = Query.search(ReturnStmt).first(); + if (returnStmt !== undefined){ + loopStmt?.replaceWith(returnStmt.deepCopy()); + } + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c);*/ + }); + + it("Initial code, replace multiple strings and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + loopStmt?.replaceWithStrings(["aaaa", "bbbb", "cccc"]); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, comment joinpoint and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + loopStmt?.toComment(); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, detach first child and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const func = Query.search(FunctionJp).first(); + func?.body.firstChild.detach(); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, detach only child and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const func = Query.search(FunctionJp).first(); + func?.body.detach(); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, detach last child and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const func = Query.search(FunctionJp).first(); + func?.body.lastChild.detach(); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, replace first child and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const func = Query.search(FunctionJp).first(); + const returnStmt = Query.search(ReturnStmt).first(); + if (returnStmt !== undefined){ + func?.body.setFirstChild(returnStmt); + } + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, set first child and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const testFunc = Query.search(FunctionJp).get().at(1); + const returnStmt = Query.search(ReturnStmt).first(); + if (returnStmt !== undefined){ + testFunc?.body.setFirstChild(returnStmt); + } + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, replace last child and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const func = Query.search(FunctionJp).first(); + const returnStmt = Query.search(ReturnStmt).first(); + if (returnStmt !== undefined){ + func?.body.setLastChild(returnStmt); + } + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, set last child and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const testFunc = Query.search(FunctionJp).get().at(1); + const returnStmt = Query.search(ReturnStmt).first(); + if (returnStmt !== undefined){ + testFunc?.body.setLastChild(returnStmt); + } + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, remove children and rollback code comparison", () => { + const a: string = Clava.getProgram().code; + + const func = Query.search(FunctionJp).first(); + func?.body.removeChildren(); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Change type and rollback comparison", () => { + const a: string = Clava.getProgram().code; + + const vd = Query.search(Vardecl).first(); + vd?.setType(ClavaJoinPoints.type("test")); + + const b: string = Clava.getProgram().code; + + ophistory.rollback(); + const c: string = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(a).not.toEqual(b); + }); + + it("Initial code, set inline comment and rollback code comparison", () => { + const a = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + loopStmt?.setInlineComments("aaaaa"); + + const b = Clava.getProgram().code; + + ophistory.rollback(); + const c = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, set inline comments and rollback code comparison", () => { + const a = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + loopStmt?.setInlineComments(["aaaaa", "bbbbb"]); + + const b = Clava.getProgram().code; + + ophistory.rollback(); + const c = Clava.getProgram().code; + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); + + it("Initial code, set inline comments and rollback code comparison", () => { + const a = Clava.getProgram().code; + + const loopStmt = Query.search(Loop).get().at(0); + + loopStmt?.setInlineComments(["aaaaa", "bbbbb"]); + const b = Clava.getProgram().code; + + loopStmt?.setInlineComments([""]); + const c = Clava.getProgram().code; + + loopStmt?.setInlineComments("ccccc"); + const d = Clava.getProgram().code; + + loopStmt?.setInlineComments(""); + const e = Clava.getProgram().code; + + ophistory.rollback(); + const f = Clava.getProgram().code; + + ophistory.rollback(); + const g = Clava.getProgram().code; + + ophistory.rollback(); + const h = Clava.getProgram().code; + + ophistory.rollback(); + const i = Clava.getProgram().code; + + expect(a).toEqual(i); + expect(a).toEqual(e); + expect(b).toEqual(h); + expect(c).toEqual(g); + expect(d).toEqual(f); + expect(a).not.toEqual(b); + expect(a).not.toEqual(c); + expect(a).not.toEqual(d); + expect(b).not.toEqual(c); + expect(b).not.toEqual(d); + expect(c).not.toEqual(d); + }); + + it("Initial code, set id value and rollback value comparison", () => { + const key = "id"; + const loopStmt = Query.search(Loop).get().at(0); + const a = loopStmt?.getValue(key); + loopStmt?.setValue(key, {}); + + const b = loopStmt?.getValue(key); + + ophistory.rollback(); + const c = loopStmt?.getValue(key); + + expect(a).toEqual(c); + expect(b).not.toEqual(c); + }); +}); diff --git a/Clava-JS/src-api/clava/history/Operations.ts b/Clava-JS/src-api/clava/history/Operations.ts new file mode 100644 index 000000000..881d7f7bb --- /dev/null +++ b/Clava-JS/src-api/clava/history/Operations.ts @@ -0,0 +1,107 @@ +import { Joinpoint, Type } from "../../Joinpoints.js"; + +export interface Operation { + undo(): void; +} + +export class InsertOperation implements Operation { + constructor(private newJP: Joinpoint) {} + + undo(): void { + this.newJP.detach(); + } +} + +export class ReplaceOperation implements Operation { + constructor(private oldJP: Joinpoint, private newJP: Joinpoint, private count: number) {} + + undo(): void { + const siblings: Joinpoint[] = this.newJP.siblingsRight; + for (let i = 0; i < this.count - 1; i++){ + siblings.at(i)?.detach(); + } + this.newJP.replaceWith(this.oldJP); + } +} + +export enum DetachReference { + LEFT = "Left", + RIGHT = "Right", + TOP = "Top" +} + +export class DetachOperation implements Operation { + constructor(private mainJP: Joinpoint, private refJP: Joinpoint, private ref: string) {} + + undo(): void { + if (this.ref === DetachReference.LEFT){ + this.refJP.insertAfter(this.mainJP) + } + else if (this.ref === DetachReference.RIGHT){ + this.refJP.insertBefore(this.mainJP); + } + else { + this.refJP.setFirstChild(this.mainJP); + } + } +} + +export class SetChildOperation implements Operation { + constructor(private newChildJP: Joinpoint, private oldChildJP?: Joinpoint) {} + + undo(): void { + if (this.oldChildJP){ + this.newChildJP.replaceWith(this.oldChildJP); + } + else { + this.newChildJP.detach(); + } + } +} + +export class RemoveChildrenOperation implements Operation { + constructor(private parentJP: Joinpoint, private childrenJPs: Joinpoint[]) {} + + undo(): void { + if (this.childrenJPs.length > 0) { + if (this.childrenJPs.at(0)){ + this.parentJP.setFirstChild(this.childrenJPs.at(0) as Joinpoint); + let prev = this.parentJP.firstChild; + for (let i = 1; i < this.childrenJPs.length; i++) { + if (i < this.childrenJPs.length && this.childrenJPs.at(i)) { + prev = prev.insertAfter(this.childrenJPs.at(i) as Joinpoint); + } + } + } + } + } +} + +export class TypeChangeOperation implements Operation { + constructor(private jp: Joinpoint, private oldType: Type) {} + + undo(): void { + this.jp.setType(this.oldType); + } +} + +export class InlineCommentOperation implements Operation { + constructor(private jp: Joinpoint, private oldComments: string[]) {} + + undo(): void { + if (this.oldComments.length === 0) { + this.jp.setInlineComments(""); + } + else { + this.jp.setInlineComments(this.oldComments); + } + } +} + +export class ValueOperation implements Operation { + constructor(private jp: Joinpoint, private key: string, private oldValue: object) {} + + undo(): void { + this.jp.setValue(this.key, this.oldValue); + } +}