# 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;
       }
    }