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