Function.java
/*
** Module : Function.java
** Abstract : contains the data needed to define a Progress function
**
** Copyright (c) 2005-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------------Description------------------------------------
** 001 GES 20050413 @20719 First version, simple bean-like approach
** including a temporary index to allow the
** linking of a function call to its original
** definition at parse time. This is needed
** because project-unique IDs can't be easily
** generated at parse time, but are only added
** after the entire tree is complete.
** 002 GES 20050608 @21451 Improvement in annotations for better
** function definition conversion.
** 003 GES 20070919 @35135 Added support for the fully qualified name
** of the class represented by a FUNC_CLASS.
** 004 ECF 20080704 @39144 Minor memory optimization. Use Boolean
** constants instead of instantiating new
** Boolean objects.
** 005 GES 20090518 @42407 Import change.
** 006 GES 20110901 Added some class annotations.
** 007 CA 20121212 tempidx for functions is no longer needed, as the
** refid is computed during conversion.
** 008 GES 20181228 Added return value extent annotation.
** 009 CA 20191002 Annotate function call parameters with their index.
** 010 CA 20210203 Fixed conversion issues with OUTPUT/INPUT-OUTPUT for extent or scalar parameters,
** involved in dynamic or static OO calls, functions or procedure calls. This
** includes mostly cases for OO properties/variables (static and non-static).
** CA 20210216 Fix for the 'cast-to-object' case for a single extent argument in a dynamic call,
** when INPUT modifier exists or not.
** TJD 20220504 Java 11 compatibility minor changes
*/
/*
** 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.ast.*;
/**
* A simple wrapper class to contain all related data about a function.
*/
class Function
implements ProgressParserTokenTypes,
TokenDataWrapper
{
/** The full text name of the function. */
private String name = null;
/** Parser defined integer constant matching the token type of the function. */
private int tokenType = -1;
/** Return value extent (defaults to 0, which is scalar). */
private int extent = 0;
/** Defines if this function definition is user-defined or builtin. */
private boolean builtin = false;
/**
* Defines if this function can return the unknown value. If set to
* <code>null</code>, then no information on this topic is known.
*/
private Boolean returnsUnknown = null;
/** Fully qualified class name of the object instance returned. */
private String cls = null;
/**
* Constructs an instance with the required data to be contained. By
* default builtin functions have their returns unknown state set to
* <code>false</code>. This can be overridden by a subsequent method
* call to {@link #setReturnsUnknown}.
*
* @param name
* The full name of the function.
* @param tokenType
* The token type (as defined by the parser) of the function.
* @param builtin
* <code>true</code> if this function is 'built in' to the
* Progress runtime.
* @param cls
* Fully qualified class name of the object instance returned
* or <code>null</code> if this function does not return an
* object instance.
*/
public Function(String name, int tokenType, boolean builtin, String cls)
throws IllegalArgumentException
{
if (name == null || tokenType == -1)
throw new IllegalArgumentException("Invalid name or type.");
this.name = name;
this.tokenType = tokenType;
this.builtin = builtin;
this.cls = cls;
if (builtin)
{
returnsUnknown = Boolean.FALSE;
}
}
/**
* Returns the full name of the function.
*
* @return The full name of the function.
*/
public String getName()
{
return name;
}
/**
* Sets the full name of the function.
*
* @param name
* The full name of the function.
*/
public void setName(String name)
{
this.name = name;
}
/**
* Returns the parser-defined token type of the function.
*
* @return The token type of the function.
*/
public int getTokenType()
{
return tokenType;
}
/**
* Sets the parser-defined token type of the function.
*
* @param tokenType
* The token type of the function.
*/
public void setTokenType(int tokenType)
{
this.tokenType = tokenType;
}
/**
* This is a no-op, as for function references the associated function
* definition is computed during conversion.
*
* @return Always returns -1.
*/
public int getTempIndex()
{
return -1;
}
/**
* This is a no-op, as for function references the associated function
* definition is computed during conversion.
*
* @param tempIdx
* The temporary index.
*/
public void setTempIndex(int tempIdx)
{
// no-op
}
/**
* Determines if this function definition is user-defined or builtin.
*
* @return <code>true</code> if the function is builtin.
*/
public boolean isBuiltin()
{
return builtin;
}
/**
* Sets whether this function definition is user-defined or builtin.
*
* @param builtin
* <code>true</code> if the function is builtin.
*/
public void setBuiltin(boolean builtin)
{
this.builtin = builtin;
}
/**
* Obtains the fully qualified name of the class of the object instance
* returned by this function.
*
* @return The fully qualified name of the class of the object instance
* returned by this function or <code>null</code> if this
* function does not return an object instance.
*/
public String getClassName()
{
return cls;
}
/**
* Sets the fully qualified name of the class of the object instance
* returned by this function.
*
* @param cls
* The fully qualified name of the class of the object instance
* returned by this function or <code>null</code> if this
* function does not return an object instance.
*/
public void setClassName(String cls)
{
this.cls = cls;
}
/**
* Determines if this function can return the unknown value.
*
* @return <code>true</code> if the function can return the unknown
* value, <code>false</code> if not and <code>null</code> if
* this fact is not known.
*/
public Boolean returnsUnknown()
{
return returnsUnknown;
}
/**
* Sets whether or not this function can return the unknown value.
*
* @param unknown
* <code>true</code> if the function can return the unknown
* value, <code>false</code> if not and <code>null</code> if
* this fact is not known.
*/
public void setReturnsUnknown(Boolean unknown)
{
this.returnsUnknown = unknown;
}
/**
* Stores all non-standard options as annotations to the AST passed as
* a parameter if this is the original definition, otherwise it stores
* a subset of values, most important of which is the cross-reference
* index to allow the original definition to be easily identified and
* accessed from a reference. If an option has the default value, it is
* not saved as an annotation.
*
* @param ast
* The AST to annotate.
* @param original
* <code>true</code> if this is to annotate the AST of the
* original definition, <code>false</code> if the AST is only
* a reference.
* @param sym
* The current symbol resolver.
*/
public void annotateOptions(Aast ast, boolean original, SymbolResolver sym)
{
if (ast == null)
{
// nothing to do
return;
}
if (original)
{
this.extent = SymbolResolver.readExtent(ast);
}
if (this.extent != 0)
{
ast.putAnnotation("extent", Long.valueOf(this.extent));
}
if (tokenType == FUNC_CLASS && cls != null)
{
sym.annotateClassRef(cls, ast);
}
// the following annotations are only stored in the original defining
// AST rather than in references, unless the reference is to a builtin
// function which has no defining reference
if (original || builtin)
{
if (original)
{
// storing the name and type in annotations makes function
// definitions easier to generate at conversion time
ast.putAnnotation("name", name);
ast.putAnnotation("type", Long.valueOf(tokenType));
}
ast.putAnnotation("builtin", builtin ? Boolean.TRUE : Boolean.FALSE);
if (returnsUnknown != null)
{
ast.putAnnotation("returnsunknown", returnsUnknown);
}
}
if (!original)
{
int callType = ast.getType();
long callOldType = ast.isAnnotation("oldtype") ? (long) ast.getAnnotation("oldtype") : -1;
// walk the direct children and annotate their parameter index
Aast parm = (Aast) ast.getFirstChild();
if (callOldType == KW_NEW && ast.getType() == FUNC_CLASS)
{
parm = (Aast) ast.getImmediateChild(LPARENS, null);
parm = (Aast) parm.getFirstChild();
}
int parIdx = 0;
while (parm != null)
{
int type = parm.getType();
int pos = parm.getIndexPos();
if (parm.getParent() == ast)
{
// skip the STRING argument for DYNAMIC-FUNCTION
if (pos == 0 && callType == FUNC_POLY && callOldType == KW_DYN_FUNC)
{
parm = (Aast) parm.getNextSibling();
continue;
}
// skip the STRING argument for DYNAMIC-NEW
if (pos == 0 && callType == FUNC_CLASS && callOldType == KW_DYN_NEW)
{
parm = (Aast) parm.getNextSibling();
continue;
}
// skip the OO reference and STRING argument for DYNAMIC-INVOKE
if (pos <= 1 && callType == FUNC_POLY && callOldType == KW_DYN_INVK)
{
parm = (Aast) parm.getNextSibling();
continue;
}
// skip the CLASS_NAME argument for NEW
if (pos == 0 && callType == FUNC_CLASS && callOldType == KW_NEW)
{
parm = (Aast) parm.getNextSibling();
continue;
}
}
// avoid the optional mode or table parm modifiers
if (type != KW_INPUT &&
type != KW_IN_OUT &&
type != KW_OUTPUT &&
type != KW_APPEND &&
type != KW_BIND &&
type != KW_BY_REF &&
type != KW_BY_VALUE)
{
parm.putAnnotation("param_index", (long) parIdx);
parIdx = parIdx + 1;
}
parm = (Aast) parm.getNextSibling();
}
}
}
}