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