AbstractConversionWorker.java
/*
** Module : AbstractConversionWorker.java
** Abstract : Base class for pattern workers which need to convert a source
** AST to a target AST.
**
** Copyright (c) 2005-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------Description-----------------------------
** 001 ECF 20050429 @20972 Created initial version. Abstracted peer AST
** processing from uast.JavaPatternWorker, which
** now extends this class.
** 002 GES 20050928 @22871 Simplified initializeAst() processing to
** use centralized code and added the option to
** insert the node at a specified index.
** 003 GES 20090429 @42045 Match package and class name changes.
** 004 GES 20090514 @42203 Match package, class and method name changes.
** 005 GES 20090518 @42373 Import change.
** 006 SVL 20130624 Added support for virtual files.
** 007 ECF 20140405 Removed unnecessary static variable for AstManager.
** 008 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.convert;
import java.io.*;
import java.util.logging.*;
import antlr.*;
import com.goldencode.ast.*;
import com.goldencode.p2j.cfg.*;
import com.goldencode.p2j.pattern.*;
/**
* Provides common services for pattern worker subclasses which need to
* convert the source AST being processed by the pattern engine to a new,
* target AST. It is still up to the concrete conversion worker to handle
* the instantiation of the proper AST type, but this class provides helpers
* to manage peer ID cross-referencing, initialization of newly created
* target ASTs, peer ID lookups, etc.
*/
public abstract class AbstractConversionWorker
extends AbstractPatternWorker
{
/** Logger */
private static final ConversionStatus LOG = ConversionStatus.get(AbstractConversionWorker.class);
/** Common key for AST peerid */
public static final String PEER_ID = "peerid";
/**
* Default constructor.
*/
protected AbstractConversionWorker()
{
}
/**
* Initialize a newly created AST. All ID setup and parent linkages are
* established if the parent AST is passed as a parameter. Otherwise, the
* AST is left unidentified and orphaned. If a parent AST is passed, a
* resolver instance should also be passed.
* <p>
* This method always adds the node as the last child of the given parent.
*
* @param ast
* AST which is to be initialized.
* @param type
* The token type for the AST.
* @param text
* The text for the AST.
* @param parent
* The parent AST node or <code>null</code>.
* @param resolver
* AST symbol resolver if available, else <code>null</code>.
*/
public static void initializeAst(Aast ast,
int type,
String text,
Aast parent,
AstSymbolResolver resolver)
{
initializeAst(ast, type, text, parent, resolver, -1);
}
/**
* Initialize a newly created AST. All ID setup and parent linkages are
* established if the parent AST is passed as a parameter. Otherwise, the
* AST is left unidentified and orphaned. If a parent AST is passed, a
* resolver instance should also be passed.
*
* @param ast
* AST which is to be initialized.
* @param type
* The token type for the AST.
* @param text
* The text for the AST.
* @param parent
* The parent AST node or <code>null</code>.
* @param resolver
* AST symbol resolver if available, else <code>null</code>.
* @param index
* 0 to insert as the first child, -1 to insert as the last
* child or a 0-based index to specify an exact child index
* at which to insert the new child. All current children at
* that index or at a greater index, are moved right. If the
* index is greater than the current number of children, the
* new child will be added at the end.
*/
public static void initializeAst(Aast ast,
int type,
String text,
Aast parent,
AstSymbolResolver resolver,
int index)
{
// create a token
CommonToken tok = new CommonToken(type, text);
// "install" our token inside the AST (this inserts token type and
// text)
ast.initialize(tok);
Long fileId = null;
// only handle the ID processing if we have a valid parent
if (parent != null)
{
try
{
// add the child to the parent, force fixups of parent and id
parent.graftAt(ast, index);
if (resolver != null)
{
// every new AST needs to be registered with the resolver so that
// subsequent lookups are possible while this pipeline continues
// --> we can only do this for ASTs that have an ID
resolver.registerAst(ast);
}
}
catch (AstException exc)
{
LOG.log(Level.SEVERE, "", exc);
}
}
}
/**
* Worker routine to centralize initialization of a new AST that is a
* root node. A new tree ID is registered in the {@link
* com.goldencode.ast.AstManager} and set into the AST.
*
* @param ast
* AST which is the root node to be initialized.
* @param file
* The file in which to persist the new AST.
* @param resolver
* The current instance of the {@link
* com.goldencode.p2j.pattern.AstSymbolResolver} in use or
* <code>null</code>.
*/
public static void initializeRootAst(Aast ast,
File file,
AstSymbolResolver resolver)
{
String filename = file.getAbsolutePath();
String normal = Configuration.normalizeFilename(filename);
initializeRootAst(ast, normal, resolver);
}
/**
* Worker routine to centralize initialization of a new AST that is a root node. A new tree
* ID is registered in the {@link com.goldencode.ast.AstManager} and set into the AST.
*
* @param ast
* AST which is the root node to be initialized.
* @param filename
* The file in which to persist the new AST. Can be real or virtual (i.e. the file
* can be never persisted into the file system, the name is used to map some ID to
* the AST).
* @param resolver
* The current instance of the {@link com.goldencode.p2j.pattern.AstSymbolResolver}
* in use or <code>null</code>.
*/
public static void initializeRootAst(Aast ast,
String filename,
AstSymbolResolver resolver)
{
try
{
ast.brainwash(filename);
if (resolver != null)
{
// every new AST needs to be registered with the resolver so that
// subsequent lookups are possible while this pipeline continues
// --> we can only do this for ASTs that have an ID
resolver.registerAst(ast);
// set the current target AST into the resolver
resolver.setTargetRootAst(ast);
}
}
catch (AstException exc)
{
LOG.log(Level.SEVERE, "", exc);
}
}
/**
* Cross reference two ASTs with one another as peers. This is done by
* setting each AST's ID within a "peerid" annotation in the other AST.
*
* @param ast1
* AST to be cross-referenced with <code>ast2</code>.
* @param ast2
* AST to be cross-referenced with <code>ast1</code>.
*/
public static void crossReferencePeerAsts(Aast ast1, Aast ast2)
{
ast1.putAnnotation(PEER_ID, ast2.getId());
ast2.putAnnotation(PEER_ID, ast1.getId());
}
/**
* Simple helper to return the peer ID annotation from the passed-in
* node's parent.
*
* @param ast
* The source or target node to operate upon.
*
* @return The unique ID of the parent's peer or <code>null</code> if
* either the parent or the parent's <code>peerid</code>
* annotation do not exist.
*/
public static Long getParentPeer(Aast ast)
{
Aast parent = ast.getParent();
if (parent == null)
return null;
return (Long) parent.getAnnotation(PEER_ID);
}
/**
* Search the specified AST node and up each ancestor node in the path
* to the root to find the first instance of the 'peerid' annotation.
* This allows target ASTs to be attached to the correct target parent
* node, without necessarily knowing what parent might be enclosing
* it.
*
* @param ast
* The node at which to start the inspection.
*
* @return The first 'peerid' annotation found in the current node
* or the closest ancestor node that has a valid peerid.
* Returns -1 if no peerid is found in any ancestor.
*/
public static long getClosestPeerId(Aast ast)
{
Aast node = ast;
while (node != null)
{
Long id = (Long) node.getAnnotation(PEER_ID);
if (id != null)
{
return id.longValue();
}
node = node.getParent();
}
return -1;
}
}