# JavaSymbolResolver.java

    /*
    ** Module   : JavaSymbolResolver.java
    ** Abstract : provides symbol resolution services for Java ASTs
    **
    ** Copyright (c) 2005-2023, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
    ** 001 GES 20050323 NEW   @20489 First version, with support for keyword
    **                               processing and token type/name conversion.
    ** 002 TJD 20220504       Java 11 compatibility minor changes
    ** 003 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.uast;

    import com.goldencode.p2j.convert.*;

    import java.util.*;
    import java.text.*;
    import java.lang.reflect.*;
    import java.util.logging.*;

    /**
     * Provides symbol resolution services for Java ASTs.  At this time only
     * keyword resolution is provided.  Keywords are statically defined and
     * all Java keywords are reserved and processed on a case-sensitive basis.
     * <p>
     * This class also provides a service to lookup a symbolic name for a
     * Java token type and the type that goes with a symbolic token type name.
     *
     * @author    GES
     * @version   1.0.0
     */
    public class JavaSymbolResolver
    implements JavaTokenTypes
    {
       /** Logger. */
       private static final ConversionStatus LOG = ConversionStatus.get(JavaSymbolResolver.class);

       /**
        * Stores all Java language keywords and provides name to token type
        * resolution.  This is a case-sensitive dictionary.
        */
       private static KeywordDictionary keywords = new KeywordDictionary(true);

       /** Stores a list of all names indexed by the token type. */
       private static Map typeToName = new HashMap();

       /** Stores a list of all types indexed by the symbolic type name. */
       private static Map nameToType = new HashMap();

       // Static initializer.
       static
       {
          initializeKeywordDictionary();
          buildTokenNameArray();
       }

       /**
        * Lookup a symbol to see if it is a reserved Java keyword.  Matches are
        * done on a case-sensitive basis.
        *
        * @param    symbol
        *           The symbol to lookup in the dictionary.
        *
        * @return   The token type of the reserved keyword or -1 if no match was
        *           found.
        */
       public static int lookupKeyword(String symbol)
       {
          Keyword match = keywords.lookupKeyword(symbol);

          if (match == null)
             return -1;

          return match.getTokenType();
       }

       /**
        * Translates a text representation of a Java token type into the
        * actual integer value.
        *
        * @param    tokenName
        *           The text representation of the token type.
        *
        * @return   A valid integer token type value or -1 if no match was found.
        */
       public static int lookupTokenType(String tokenName)
       {
          Integer result = (Integer)nameToType.get(tokenName.toLowerCase());

          if (result == null)
          {
             return -1;
          }

          return result.intValue();
       }

       /**
        * Translates an integer value of a Java token type into the associated
        * human readable text representation.
        *
        * @param    type
        *           The integer token type.
        *
        * @return   A valid symbolic token type name or <code>null</code> if
        *           no match was found.
        */
       public static String lookupTokenName(int type)
       {
          return (String) typeToName.get(Integer.valueOf(type));
       }

       /**
        * Assumes all <code>int</code> type fields in the {@link JavaTokenTypes}
        * interface are unique token types and it adds a bidirectional mapping
        * (name to type and type to name) for each type using reflection. This
        * assumes that all 'int' fields are token types AND that all such types
        * are UNIQUE!  This should be a safe assumption since this is the
        * purpose for that class.  The type names used as an index to the types
        * are stored in lowercase to allow case-insensitive matches.
        */
       private static void buildTokenNameArray()
       {
          try
          {
             Field[] list = JavaTokenTypes.class.getDeclaredFields();

             for (int i = 0; i < list.length; i++)
             {
                Class cls = list[i].getType();

                // assume that all "int" fields are token types AND that all such
                // types are UNIQUE!
                if ("int".equals(cls.getName()))
                {
                   Integer type = Integer.valueOf(list[i].getInt(null));
                   String  name = list[i].getName();

                   nameToType.put(name.toLowerCase(), type);
                   typeToName.put(type, name);
                }
             }
          }

          catch (Exception exc)
          {
             LOG.log(Level.SEVERE, "", exc);
          }
       }

       /**
        * Creates a <code>Keyword</code> array and initializes that array to
        * a the list of all recognized Java language keywords. The
        * initialization is done in-line and the source file is organized in
        * an easy to maintain column format.  A loop then processes this array
        * and adds each <code>Keyword</code> into the keyword dictionary.
        * <p>
        * The following values are needed for each <code>Keyword</code> object:
        * <ul>
        *    <li> full keyword text for the keyword
        *    <li> the minimum number of characters for matching (all keywords use
        *         0 which means no there are no abbreviations)
        *    <li> the integer token type to assign to the keyword on a match
        *         (see below)
        *    <li> whether it is a reserved keyword or not (true means it is
        *         reserved)
        * </ul>
        * <p>
        * See <code>{@link Keyword}</code> for more details.
        */
       private static void initializeKeywordDictionary()
       {
          Keyword[] kws =
          {
             /* format: ( Full Keyword Text, Abr, Token Type       , Reserved ) */
             new Keyword( "abstract"       ,   0, KW_ABSTRACT      , true     ),
             new Keyword( "boolean"        ,   0, KW_BOOLEAN       , true     ),
             new Keyword( "break"          ,   0, KW_BREAK         , true     ),
             new Keyword( "byte"           ,   0, KW_BYTE          , true     ),
             new Keyword( "case"           ,   0, KW_CASE          , true     ),
             new Keyword( "catch"          ,   0, KW_CATCH         , true     ),
             new Keyword( "char"           ,   0, KW_CHAR          , true     ),
             new Keyword( "class"          ,   0, KW_CLASS         , true     ),
             new Keyword( "const"          ,   0, KW_CONST         , true     ),
             new Keyword( "continue"       ,   0, KW_CONTINUE      , true     ),
             new Keyword( "default"        ,   0, KW_DEFAULT       , true     ),
             new Keyword( "do"             ,   0, KW_DO            , true     ),
             new Keyword( "double"         ,   0, KW_DOUBLE        , true     ),
             new Keyword( "else"           ,   0, KW_ELSE          , true     ),
             new Keyword( "extends"        ,   0, KW_EXTENDS       , true     ),
             new Keyword( "final"          ,   0, KW_FINAL         , true     ),
             new Keyword( "finally"        ,   0, KW_FINALLY       , true     ),
             new Keyword( "float"          ,   0, KW_FLOAT         , true     ),
             new Keyword( "for"            ,   0, KW_FOR           , true     ),
             new Keyword( "goto"           ,   0, KW_GOTO          , true     ),
             new Keyword( "if"             ,   0, KW_IF            , true     ),
             new Keyword( "implements"     ,   0, KW_IMPLEMENTS    , true     ),
             new Keyword( "import"         ,   0, KW_IMPORT        , true     ),
             new Keyword( "instanceof"     ,   0, KW_INSTANCEOF    , true     ),
             new Keyword( "int"            ,   0, KW_INT           , true     ),
             new Keyword( "interface"      ,   0, KW_INTERFACE     , true     ),
             new Keyword( "long"           ,   0, KW_LONG          , true     ),
             new Keyword( "native"         ,   0, KW_NATIVE        , true     ),
             new Keyword( "new"            ,   0, KW_NEW           , true     ),
             new Keyword( "package"        ,   0, KW_PACKAGE       , true     ),
             new Keyword( "private"        ,   0, KW_PRIVATE       , true     ),
             new Keyword( "protected"      ,   0, KW_PROTECTED     , true     ),
             new Keyword( "public"         ,   0, KW_PUBLIC        , true     ),
             new Keyword( "return"         ,   0, KW_RETURN        , true     ),
             new Keyword( "short"          ,   0, KW_SHORT         , true     ),
             new Keyword( "static"         ,   0, KW_STATIC        , true     ),
             new Keyword( "strictfp"       ,   0, KW_STRICTFP      , true     ),
             new Keyword( "super"          ,   0, KW_SUPER         , true     ),
             new Keyword( "switch"         ,   0, KW_SWITCH        , true     ),
             new Keyword( "synchronized"   ,   0, KW_SYNCHRONIZED  , true     ),
             new Keyword( "this"           ,   0, KW_THIS          , true     ),
             new Keyword( "throw"          ,   0, KW_THROW         , true     ),
             new Keyword( "throws"         ,   0, KW_THROWS        , true     ),
             new Keyword( "transient"      ,   0, KW_TRANSIENT     , true     ),
             new Keyword( "try"            ,   0, KW_TRY           , true     ),
             new Keyword( "void"           ,   0, KW_VOID          , true     ),
             new Keyword( "volatile"       ,   0, KW_VOLATILE      , true     ),
             new Keyword( "while"          ,   0, KW_WHILE         , true     )
          };

          for ( int i = 0; i < kws.length; i++ )
          {
             keywords.addKeyword( kws[i] );
          }
       }

       /**
        * Simple command line driver to print out the list of Java token types
        * and the associated symbolic names.
        *
        * @param    args
        *           All command line arguments are ignored.
        */
       public static void main(String[] args)
       {
          NumberFormat fmt = NumberFormat.getInstance();
          fmt.setMinimumIntegerDigits(4);
          fmt.setGroupingUsed(false);

          try
          {
             for (int i = 0; i < 500; i++)
             {
                String s = JavaSymbolResolver.lookupTokenName(i);

                if (s != null)
                   System.out.println("[" + fmt.format(i) + "]   " + s);
             }
          }
          catch (Exception exc)
          {
          }
       }
    }