# MemberData.java

    /*
    ** Module   : MemberData.java
    ** Abstract : container for state related to a class member
    **
    ** Copyright (c) 2007-2024, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- --------------------------------------Description---------------------------------------
    ** 001 GES 20220522 Moved from an existing inner class to a standalone class. Added some state.
    **     CA  20220727 Improved memory management for parsing; cleanup is done in two phases:
    **                  1. after each legacy class file has finished parsing, the SchemaDictionary will keep only
    **                     protected temp-tables (all private tables are removed, as these can't be reached from
    **                     sub-classes; all permanent tables are removed, as each class has its own reference to
    **                     the permanent tables).  Also, the class def instance will reduce its own used memory,
    **                     which is not required when parsing sub-classes.
    **                  2. after parsing of the entire file set is finished, any SchemaDictionary or other ASTs
    **                     referenced by the ClassDefinition are released.
    **     CA  20220728 Fixed CA/20220727 - allow the Variable instance to survive parsing, but release the 'def'
    **                  AST when full parsing finishes.
    ** 002 OM  20230115 Replaced absolutePath(), relativePath(), upPath() and downPath() with faster
    **                  versions, based on node types rather on string paths.
    ** 003 CA  20230928 Refactored the fuzzy method resolution to be used by runtime, too.
    ** 004 CA  20241026 Avoid abends in case of parsing issues when the parent for a reference can't be calculated.
    ** 005 AS  20250411 Added the suffix attribute.
    */

    /*
    ** 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 java.util.*;
    import java.util.function.*;

    import com.goldencode.ast.*;

    /**
     * Container to track data associated with a member of a class.
     */
    class MemberData
    implements ProgressParserTokenTypes,
               MethodData
    {
       /** Text name. */
       String name = null;

       /** Token type. */
       int type = -1;

       /** Extent value (defaults to 0, which means scalar) of the return type. */
       int extent = 0;

       /** Access mode. */
       int access = -1;

       /** Temporary ID. */
       int tempIdx = -1;

       /** Static or instance member. */
       boolean isStatic = false;

       /** Class type name for members that return an object instance. */
       String qname = null;

       /** Parameter signature for methods. */
       ParameterKey[] signature = null;

       /** Associated variable instance for data members. */
       Variable var = null; // used only during parsing/front phase

       /** The containing class where this was defined. */
       ClassDefinition container = null;

       /** The parameter modes. */
       String modes = null;

       /**
        * Marker for OO vars which are gathered during pre-scan, and they might not be actual class
        * members (as pre-scan processes DEFINE VAR statements at all levels, including methods).
        */
       boolean provisional = false;

       /** The AST for this member definition. After parsing is finished, this is cleared. */
       Aast ast = null;

       /** The AST's ID for this member definition. */
       Long astId = null;

       /** All annotations set at the method's return type. */
       // WARNING: this is not set by initialize, in case of METHOD
       Map<String, Object> retType;

       /**
        * The converted Java name for this member. Used only for previously parsed classes, or
        * legacy builtin classes.
        */
       String javaname = null;

       /** For methods, this defines if the method overrides a parent class/interface method. */
       boolean override = false;

       /** For methods, this defines if the method is an abstract method. */
       boolean abstr = false;

       /** The suffix that needs to be appended in case of a javaname collision. */
       int suffix = 1;

       /**
        * Create an instance, setting the data members.
        *
        * @param    name
        *           The name of the member.
        * @param    var
        *           Associated variable instance for data members or <code>null</code>.
        * @param    signature
        *           Parameter signature for methods or <code>null</code>.
        * @param    type
        *           The token type associated with the member.
        * @param    access
        *           Access mode (<code>KW_PUBLIC</code>,
        *           <code>KW_PROTECTD</code> or <code>KW_PRIVATE</code>).
        * @param    isStatic
        *           <code>true</code> if the variable/property is static.
        * @param    qname
        *           Fully qualified class name where <code>type</code> equals
        *           <code>OO_METH_CLASS</code>. <code>null</code> if this method
        *           does not return an object instance.
        * @param    container
        *           The container class definition.
        * @param    tempIdx
        *           Temporary ID.
        */
       MemberData(String              name,
                  Variable            var,
                  ParameterKey[]      signature,
                  int                 type,
                  int                 access,
                  boolean             isStatic,
                  String              qname,
                  ClassDefinition     container,
                  int                 tempIdx,
                  Map<String, Object> retType)
       {
          this.name      = name;
          this.var       = var;
          this.signature = signature;
          this.type      = type;
          this.access    = access;
          this.isStatic  = isStatic;
          this.qname     = qname;
          this.retType   = retType;
          this.container = container;
          this.tempIdx   = tempIdx;

          if (signature != null)
          {
             this.modes = "";
             for (ParameterKey pk : signature)
             {
                if (pk.mode == null)
                {
                   modes = modes + "B";
                   continue;
                }

                switch (pk.mode)
                {
                   case KW_INPUT:
                      modes = modes + "I";
                      break;
                   case KW_OUTPUT:
                      modes = modes + "O";
                      break;
                   case KW_IN_OUT:
                      modes = modes + "U";
                      break;
                   case KW_BUFFER:
                      modes = modes + "B";
                      break;
                }
             }
          }
       }

       /**
        * Get the signature of this method.
        *
        * @return   See above.
        */
       @Override
       public ParameterKey[] getSignature()
       {
          return signature;
       }

       /**
        * Get the signature for the parameter at the specified 0-based index.
        *
        * @param    idx
        *           The 0-based index for the parameter.
        *
        * @return   See above.
        */
       @Override
       public ParameterKey getSignature(int idx)
       {
          return signature[idx];
       }

       /**
        * Render the state of the instance in a text form.
        *
        * @return   The rendered instance.
        */
       public String toString()
       {
          StringBuilder sb = new StringBuilder();

          String qual = (qname == null) ? "" : String.format(" - %s", qname);

          sb.append(String.format("%s%s member %s (%s%s), extent %d, javaname %s, override %b, " +
                                  "abstract %b in class %s, tempIdx %d\n",
                                  ProgressParser.lookupTokenName(access),
                                  isStatic ? " static" : " instance",
                                  name,
                                  ProgressParser.lookupTokenName(type),
                                  qual,
                                  extent,
                                  javaname == null ? "NONE" : javaname,
                                  override,
                                  abstr,
                                  container.getName(),
                                  tempIdx));

          if (signature != null)
          {
             sb.append(String.format("   PARAMETERS: %d\n", signature.length));

             for (int i = 0; i < signature.length; i++)
             {
                sb.append(String.format("      %s\n", signature[i]));
             }
          }

          return sb.toString();
       }

       /**
        * The parse for this entire file has finished, and the AST IDs have been computed.
        * This is the time the capture the AST IDs or add other annotations, as is executed just
        * before the AST is persisted.
        *
        * @param    global
        *           Flag indicating that the parsing of all files has finished, and a global cleanup can be done
        *           for this instance.
        */
       void parseFinished(boolean global)
       {
          BiConsumer<Aast, Aast> p = (ast, parent) ->
          {
             if (ast.isAnnotation("access-mode"))
             {
                parent.putAnnotation("access-mode", (Long) ast.getAnnotation("access-mode"));
                ast.removeAnnotation("access-mode");
             }
             if (ast.isAnnotation("oo-data-store"))
             {
                parent.putAnnotation("oo-data-store", (String) ast.getAnnotation("oo-data-store"));
                ast.removeAnnotation("oo-data-store");
             }
             if (ast.isAnnotation("static"))
             {
                parent.putAnnotation("static", (Boolean) ast.getAnnotation("static"));
                ast.removeAnnotation("static");
             }
          };
          if (ast != null)
          {
             if (ast.getParent() == null)
             {
                System.out.println("WARNING: Can not copy annotations for member in " + container.getName() + ": parent is null");
                return;
             }

             int type = ast.getType();
             if (type == KW_TEMP_TAB ||
                 (type == SYMBOL && ast.getParent().getType() == DEFINE_BUFFER))
             {
                Aast parent = ast.getParent();
                p.accept(ast, parent);

                if (type == KW_TEMP_TAB || type == KW_WORK_TAB)
                {
                   ast = parent;
                }
                else
                {
                   ast = parent;
                   ast = ast.getImmediateChild(KW_FOR, null);
                   ast = (Aast) ast.getFirstChild();
                }
             }
             if (type == SYMBOL && ast.upPath(DEFINE_QUERY, KW_QUERY))
             {
                Aast parent = ast.getAncestor(2);
                p.accept(ast, parent);

                parent.putAnnotation("name", ast.getText());
                ast = parent;
             }

             astId = ast.getId();
             ast = null;
          }

          if (var != null)
          {
             var.parseFinished(global);
          }
       }

       /**
        * Set the {@link #provisional} state of this member.
        *
        * @param    provisional
        *           The new state.
        */
       void setProvisional(boolean provisional)
       {
          this.provisional = provisional;
       }
    }