<?xml version="1.0"?>

<!-- 
/*
** Module   : base_structure.xml
** Abstract : creates the stub of a class file and determines the class name
**            (which forms the root structure upon which the Java AST will be built)
**
** Copyright (c) 2005-2023, Golden Code Development Corporation.
**
** _#_ _I_ __Date__ __JPRM__ ___________________________________Description___________________________________
** 001 GES 20050721   @21755 Good working version which converts the core
**                           Progress AST structure into an equivalent  Java AST structure.
** 002 GES 20050729   @21917 Added the progressSourceName constant to
**                           enable the program-name() built-in.
** 003 GES 20050819   @22179 Save off the converted classname in source AST.
** 004 GES 20050825   @22250 Modifications to unnamed stream init.
** 005 SIY 20051103   @23184 Using annotations "pkgname" and "classname".
** 006 GES 20051109   @23291 Removed lastKey instance var.
** 007 GES 20060123   @24029 Removed returnValue instance var.
** 008 GES 20060125   @24057 Removed source filename static var.
** 009 GES 20060131   @24168 Added full package name annotation to the kw_class node of the JAST.
** 010 GES 20060201   @24179 Handle annotation of target classname for run filename.
**                           This must be done after annotations and before core conversion.
** 011 GES 20060207   @24347 Removed unnamed stream instance vars.
** 012 GES 20060319   @25111 Fixup parameter types for RUN of external
**                           procs, internal procs and function calls.
** 013 GES 20060410   @25450 Exclude builtin funcs from func signature processing.
** 014 GES 20060412   @25495 Safety code for RUN VALUE() cases.
** 015 GES 20080701   @39042 Add static imports in compact mode.
** 016 GES 20081003   @40021 Only BlockManager is statically imported for
**                           all programs. Others are added elsewhere as needed.
** 017 GES 20090518   @42310 Import change.
** 018 GES 20111213          Added bogus hack to support missing filenames for
**                           RUN statements.
** 019 EVL 20121101          Fixing the filename file separator value for statements like RUN 
**                           FILENAME in Windows OS conversion environment. Merged with recent
**                           code base.
** 020 CA  20121207          Added support for persistent procedures, procedure handles and super
**                           procedures. All RUN statements are now converted using ControlFlowOps
**                           APIs, so explicit Java code is not emitted for them anymore.
** 021 CA  20130129          Added longchar support.
** 022 SVL 20130213          Implemented naming of schema triggers main functions.
** 023 GES 20130219          Added a qualifier to constant references.
** 024 CA  20130309          Convert the unknown vals passed as a parameter to builtin functions
**                           or methods to the appropriate wrapper instance. Also: all literals 
**                           passed as parameters will be marked with the "wrap" annotation, if
**                           the function/method is registered with common-progress.rules's 
**                           needs_wrapped_literals function; all undeteremined, _POLY, 
**                           expressions are wrapped using the parameter type.
** 025 CA  20130313          Fixed conversion of "RUN ... IN _POLY" stateemnt (_POLY needs to be
**                           wrapped using handle).
** 026 GES 20130313          Rework to move to generic ECW.expressionType() instead of the
**                           ECW.parameterTypeName().
** 027 VMN 20130314          "needs_wrapped_literals", second parameter added
** 028 CA  20130315          As the HANDLE attribute is converted to the resource instance, when
**                           set as a parameter to a function/method call it needs to be wrapped
**                           in a handle instance.
** 029 CA  20130316          Any _POLY-evaluated expression used as a parameter for a simple
**                           user-defined function call needs to be wrapped.
** 030 OM  20130322          Removed wrapping BaseDataType values in a BaseDataType.
** 031 GES 20130323          Removed some unnecessary wrapping with BDT types that actually have
**                           known return values AND with the op2/op3 of the ternary function.
** 032 OM  20130325          Replaced lock_type_literals with compiler_constants.
** 033 OM  20130405          Added wrappers for numerical types function/procedure parameters.
** 034 CA  20130611          Do not process the parameter modes emitted when calling functions
**                           defined IN handle or IN SUPER.
** 035 OM  20130520          Added wrappers for date-types function/procedure parameters.
** 036 CA  20130924          Fixed a regression related to parameter modes for functions.
** 037 OM  20130925          Moved 'chp_wrapper' annotation to first operator in if it is enclosed
**                           into one or more superfluous pairs of parenthesis.
** 038 CA  20131024          Added conditional rule-set processing flags for dynamic query
**                           conversion.
** 039 OM  20131128          Fixed trigger procedure generation and annotation using data
**                           previously saved in schema-triggers.xml.
** 040 OM  20140107          Fixed schema trigger generation when buffer declarations are required
**                           to appear before the TRIGGER_PROCEDURE statement.
** 041 SVL 20140320          Do not load name_map.cache and schema-triggers.xml in runtime mode.
** 042 OM  20140711          Wrote back schema-triggers.xml with additional information needed
**                           for loading the triggers at runtime.
** 043 OM  20151019          Dropped wrapping where parent node accepts _POLY arguments.
** 044 GES 20160519          Removed compact mode support (non-compact mode no longer exists).
** 045 CA  20170827          Wrap literals in a FOR ... KW_BY expression.
** 046 CA  20171024          Unknown literal can't be wrapped using BaseDataType.
** 047 OM  20180118          Dropped intermediary schema-triggers.xml file.
** 048 OM  20180209          Do not drop the intermediary schema triggers file.
** 049 CA  20180512          Unknown values for PUT-KEY-VALUE and SET-KEY-VALUE must be wrapped.
**                           SUBSTRING statement POLY argument support.
**     CA  20180514          Fixes for COPY-LOB: FROM STARTING/FOR, CONVERT SOURCE/TARGET code-page.
** 050 CA  20181113          Fixed UNKNOWN_VAL for SET-DB-CLIENT's second parameter.
** 051 GES 20181208          Added class and interface support.
**     CA  20181213          Fixed NEW arguments processing (as they are parented by a LPARENS).
**     CA  20181218          If a attribute setter's rvalue is POLY, then wrap it in a c'tor 
**                           accordingly to the attribute's type.
** 052 CA  20190423          Fixed some issues with OO method calls arguments (the argument index
**                           was not computed correct).
** 053 CA  20190509          For DYNAMIC-NEW ... NO-ERROR, the NO-ERROR is emitted as same level
**                           as parameters, so needs to be ignored.
**     ECF 20190511          Removed wrapping for COPY-LOB option expressions.
**     CA  20190520          Fixed POLY rvalue for attribute assignment and ENTRY function.
** 054 CA  20190611          Save a 'class_def_peerid' annotation at the root AST, to know where 
**                           to attach legacy annotations.
** 055 IAS 20190604          Wrapping UNKNOWN literal as CLIENT-PRINCIPAL:INITIALIZE args
** 056 CA  20190706          PUBLISH can have the event from a POLY expression.
** 057 AIL 20190722          Trigger information is no longer provided by schema-triggers.xml, 
**                           but by the AST itself. Removed override proprety of a trigger procedure.
**     AIL 20190821          Assign Triggers with new value have a reference towards EmptyBuffer.
** 058 CA  20190927          Added support for direct Java access from 4GL code.
** 059 CA  20200412          Added incremental conversion support.
** 060 CA  20200428          Legacy DEFINE ENUM conversion support.
**                           Do not throw exception if a function/method call can't be resolved 
**                           (no type-list annotation).
**     CA  20200429          Legacy DEFINE ENUM conversion support.
**     GES 20200430          Modifications to match new enum approach.
**     CA  20200503          Always wrap the literal in a CASE statement.
**                           A fix for property setter calls, where the type must be checked.
**     CA  20200508          OO class references are qualified only if 4GL qualifies them.
**     GES 20200515          Properly implemented implicitly added methods (fixed GetEnum to have the correct
**                           annotations, added SetFlag/ToggleFlag/UnsetFlag).
**     GES 20200603          Fixed incorrect wrapping case for virtual method enum processing of typelist.
**     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.
**     OM  20210312          Avoid incorrectly wrapping parameters as character for methods which support
**                           runtime _poly parameter to 
**     CA  20210428          For function/OO calls passed as an argument to another call, evaluate them via a
**                           lambda expression so that the 'output parameter assigner' is not corrupted.
**     OM  20210430          Dropped incorrectly wrapping for parameters of GET-CODEPAGE (kw_get_codp).
**                           Avoid wrapping warning for methods/function supporting _poly parameters.
**     CA  20210528          Save the class_def_peerid for the trigger procedures, too - so they can have the
**                           DatabaseReferences annotation emitted.
**     CA  20210609          Reworked INPUT/INPUT-OUTPUT parameters to a new approach, where they are explicitly 
**                           initialized at the method's execution, and not at the caller's arguments.
**                           (backed out CA/20210428).
**     HC  20211001          Implementation of i18n support.
**     CA  20220516          Emit a @LegacySerializable annotation for SERIALIZABLE legacy classes.
** 061 OM  20230115          Replaced absolutePath(), relativePath(), upPath() and downPath() with faster
**                           versions, based on node types rather on string paths.
** 062 OM  20230921          Moved DatabaseTrigger to com.goldencode.p2j.persist.trigger package.
*/
-->

<!--
** 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.
-->

<cfg>
   <!-- register worker objects -->
   <worker class="com.goldencode.p2j.uast.ProgressPatternWorker"           namespace="prog" />
   <worker class="com.goldencode.p2j.uast.JavaPatternWorker"               namespace="java" />
   <worker class="com.goldencode.p2j.convert.NameConverterWorker"          namespace="names" />
   <worker class="com.goldencode.p2j.pattern.TemplateWorker"               namespace="tw" />
   <worker class="com.goldencode.p2j.convert.ConverterHelper"              namespace="help" />
   <worker class="com.goldencode.p2j.convert.ExpressionConversionWorker"   namespace="ecw" />
   <worker class="com.goldencode.p2j.xml.XmlPatternWorker"                 namespace="xml" />
   <worker class="com.goldencode.p2j.schema.P2OAccessWorker"               namespace="p2o" />

   <!-- expression libraries -->
   <include name="common-progress" />
   <include name="i18n" />
   <include name="convert/common-convert" />
  
   <func-library access="private">
      <function name="function_or_method_call">
         <parameter name="ref" type="com.goldencode.ast.Aast" />

         (ref.type &gt; prog.begin_functypes and 
          ref.type &lt; prog.end_functypes   and 
          ref.isAnnotation("builtin")        and
          #(java.lang.Boolean) ref.getAnnotation("builtin")) or
         (ref.type &gt; prog.begin_meth and
          ref.type &lt; prog.end_meth))
      </function>
   </func-library>
  
   <!-- variables -->
   <variable name="parIdx"     type="java.lang.Long" />
   <variable name="methDefId"  type="java.lang.Long" />
   <variable name="refid"      type="java.lang.Long" />
   <variable name="oldtype"    type="java.lang.Long" />
   <variable name="classname"  type="java.lang.String" />
   <variable name="targetname" type="java.lang.String" />
   <variable name="pkgname"    type="java.lang.String" />
   <variable name="wrapper"    type="java.lang.String" />
   <variable name="needed"     type="java.lang.String" />
   <variable name="cls"        type="java.lang.String" />
   <variable name="casttype"   type="java.lang.String" />
   <variable name="errmsg"     type="java.lang.String" />   
   <variable name="modes"      type="java.lang.String" />   
   <variable name="pmode"      type="java.lang.String" />   
   <variable name="candidate"  type="java.lang.String" />
   <variable name="isClass"    type="java.lang.Boolean" />
   <variable name="isIface"    type="java.lang.Boolean" />   
   <variable name="isEnum"     type="java.lang.Boolean" />
   <variable name="flagsEnum"  type="java.lang.Boolean" />   
   <variable name="ooLangImp"  type="java.lang.Boolean" />   
   <variable name="typelist"   type="java.util.ArrayList" />
   <variable name="ref"        type="com.goldencode.ast.AnnotatedAst" />
   <variable name="pref"       type="com.goldencode.ast.AnnotatedAst" />
   <variable name="lref"       type="com.goldencode.ast.Aast" />
   <variable name="iref"       type="com.goldencode.ast.Aast" />

   <variable name="titer"            type="java.lang.Integer"/>
   <variable name="trname"           type="java.lang.String"/>
   <variable name="crt_tr"           type="com.goldencode.p2j.xml.XmlAst" />
   <variable name="runtimeQueryMode" type="java.lang.Boolean" />

   <!-- pipeline of rule-sets to process -->
  
   <!-- global initialization (once per pipeline) -->
   <init-rules>
      <rule>setAutoload(true)</rule>
      <rule>tw.load("convert/java_templates")</rule>
      <rule>runtimeQueryMode = isRuntimeQueryMode()</rule>
      <rule>errmsg = "Passing unknown value literal to builtin func!"</rule>
   </init-rules>
  
   <!-- main processing (once per tree) -->
   <rule-set input="tree" load-condition="runtime-query">
   
      <variable name="numparms"   type="java.lang.Long" />
      <variable name="lastid"     type="java.lang.Long" />
      <variable name="execname"   type="java.lang.String" />
      <variable name="is_trigger" type="java.lang.Boolean" />
      <variable name="buf_class"  type="java.lang.String" />
      <variable name="extends"    type="java.lang.String" />
      <variable name="access"     type="java.lang.String" />
      <variable name="jname"      type="java.lang.String" />
      <variable name="qname"      type="java.lang.String" />
      <variable name="qual_oo"    type="java.lang.String" />
      <variable name="clsref"     type="com.goldencode.ast.Aast" />
      <variable name="parref"     type="com.goldencode.ast.Aast" />
      <variable name="jclsdef"    type="com.goldencode.ast.Aast" />

      <init-rules>
         <rule>ooLangImp = false</rule>
         
         <rule>qname = execLib("compute_package", this.getAnnotation("package-base"))</rule>
         <rule>qname.isEmpty()
            <rule>qname = this.getAnnotation("classname")</rule>
            <rule on="false">qname = sprintf("%s.%s", qname, this.getAnnotation("classname"))</rule>
         </rule>
         <rule>qname = qname.replaceAll("\.", "_")</rule>
         
         <rule>deleteDictionary("function")</rule>
         
         <rule>is_trigger = downPath(this, prog.statement, prog.trigger_procedure)</rule>
         <rule>isClass = descendant(prog.class_def, 1)</rule>
         <rule>isIface = descendant(prog.interface_def, 1)</rule>
         <rule>isEnum = descendant(prog.enum_def, 1)</rule>
         
         <!-- add package name -->   
         <rule>pkgname = getNoteString("pkgname")</rule>
         <rule>createJavaAst(java.kw_package, pkgname, javaRootId)</rule>
         
         <!-- import the core runtime package -->   
         <rule>createImport("com.goldencode.p2j.util.*")</rule>
         
         <!-- statically import some of the core runtime package, except for enums -->
         <rule>!isEnum
            <action>createStaticImport("com.goldencode.p2j.util.BlockManager.*")</action>
         </rule>
         
         <!-- obtain the root of the class and a method definition for the
              primary entry point and associate the primary entry point with
              the BLOCK that is the external procedure (this is implicit
              because the top level node of all Progress source ASTs
              is always the same and is the current node in the init
              rules) --> 
         <rule>classname = getNoteString("classname")</rule>
         
         <!-- save this name off for the future -->
         <rule>putNote("javaname", classname)</rule>

         <variable name="triggerRef"   type="com.goldencode.ast.Aast" />
         <variable name="tableRef"     type="com.goldencode.ast.Aast" />
         <variable name="oldValueName" type="java.lang.String" />
         <variable name="buffer_class" type="java.lang.String" />
         <variable name="event_type"   type="java.lang.String" />
         <variable name="hasOldBuffer" type="java.lang.Boolean" />
         <variable name="eventType"    type="java.lang.String" />

         <variable name="trg_event"    type="java.lang.String" />
         <variable name="trg_field"    type="java.lang.String" />
         <variable name="trg_table"    type="java.lang.String" />

         <!-- schema trigger case -->
         <rule>is_trigger
            <!-- analyze information from ast tree: the TRIGGER_PROCEDURE statement might not
                 be the first one because one (or more) DEFINE_BUFFER statement and the
                 BUFFER_SCOPE declarations can be promoted to external-level
                 if they were defined in the trigger body -->
            <rule>triggerRef = copy.getImmediateChild(prog.statement, null)</rule>
            <while>triggerRef != null
               <rule>triggerRef.descendant(1, prog.trigger_procedure)
                  <break/>
               </rule>

               <rule>triggerRef = copy.getImmediateChild(prog.statement, triggerRef)</rule>
            </while>
            <rule>triggerRef = triggerRef.getImmediateChild(prog.trigger_procedure, null)</rule>
            <!-- at this moment triggerRef should contain the TRIGGER_PROCEDURE node;
                 it cannot be null as we are in [is_trigger] case -->

            <action>eventType = execLib("get_db_event_type", triggerRef)</action>
            <rule>(triggerRef.descendant(1, prog.kw_write)   or
                   triggerRef.descendant(1, prog.kw_repl_wri)) and
                  triggerRef.descendant(1, prog.kw_new)
               <!-- for write trigger prefer look into KW_NEW for buffer instead -->
               <action>tableRef = triggerRef.getImmediateChild(prog.kw_new, null)
                                       .getImmediateChild(prog.table, null)</action>
               <!-- all other triggers -->
               <action on="false">tableRef = triggerRef.getImmediateChild(prog.table, null)</action>
            </rule>
            <!-- store the buffer to global for declaring the DatabaseTrigger generic class -->
            <rule>tableRef != null
               <action>buf_class = #(java.lang.String) tableRef.getAnnotation("bufclassname")</action>

               <!-- tableRef is null in the case of SCHEMA/ASSIGN/NEW -->
               <action on="false">buf_class = ""</action>
            </rule>
            <rule>(triggerRef.descendant(1, prog.kw_write)     or
                   triggerRef.descendant(1, prog.kw_repl_wri)  or
                   triggerRef.descendant(1, prog.kw_assign))   and
                   triggerRef.descendant(1, prog.kw_old)
               <action>
                  oldValueName = #(java.lang.String) triggerRef.getImmediateChild(prog.kw_old, null)
                                 .getAnnotation("javaname")
               </action>
               <action>hasOldBuffer = true</action>
               <action on="false">hasOldBuffer = false</action>
            </rule>
            
            <rule>tableRef != null
               <action>trg_table = tableRef.getAnnotation("schemaname")</action>
               <action>trg_field = ""</action>
               <rule>triggerRef.descendant(1, prog.kw_assign)
                  <action>trg_field = triggerRef.getChildAt(2).getAnnotation("fieldName")</action>
               </rule>
               <action on="false">trg_table = ""</action>
               <action on="false">trg_field = ""</action>
            </rule>
         </rule>
         
         <!-- create the skeleton of the top level trigger class -->
         <rule>is_trigger
            <action>createImport("com.goldencode.p2j.persist.trigger.*")</action>
            <!-- add field property only if we have a field trigger (assign trigger) -->
            <rule>trg_field.isEmpty()
               <rule> buf_class.isEmpty()
                  <action>buf_class = "EmptyBuffer"</action>
               </rule>
               <action>
                  tw.graft("schema_trigger_annotation_record", null, javaRootId,
                           "buffer_class",    sprintf("%s.class", buf_class),
                           "event_type",      eventType,
                           "table_name",      trg_table,
                           "old_buffer",      hasOldBuffer.toString())
               </action>
               <action on="false">
                  tw.graft("schema_trigger_annotation_field", null, javaRootId,
                           "buffer_class",    sprintf("%s.class", buf_class),
                           "event_type",      eventType,
                           "field_name",      trg_field,
                           "table_name",      trg_table,
                           "old_buffer",      hasOldBuffer.toString())
               </action>
            </rule>
            <action>
               ref = tw.graft("trigger_class_def", null, javaRootId,
                              "bufclass",  buf_class,
                              "classname", classname,
                              "pkgname",   pkgname)
            </action>
            <action>putNote("class_def_peerid", ref.id)</action>
            
            <!--set the name of the trigger class as an attribute.
               'crt_tr' must be not null, otherwise is_trigger is false -->
            <variable name="xmlUtilNode" type="com.goldencode.p2j.xml.XmlAst"/>
            <action>xmlUtilNode = xml.createAst(xml.attribute_node, "class", crt_tr)</action>
            <action>xml.createAst(xml.content,
                                  sprintf("%s.%s", pkgname, classname),
                                  xmlUtilNode)</action>
            <action>xmlUtilNode = xml.createAst(xml.attribute_node, "buffer", crt_tr)</action>
            <action>xml.createAst(xml.content,
                                  sprintf("%s", buf_class),
                                  xmlUtilNode)</action>
            
            <rule>!trg_field.isEmpty()
               <action>xmlUtilNode = xml.createAst(xml.attribute_node, "property", crt_tr)</action>
               <action>xml.createAst(xml.content,
                                     trg_field,
                                     xmlUtilNode)</action>
            </rule>
         </rule>

         <!-- exteral procedure case -->
         <rule>!is_trigger and !isClass and !isIface and !isEnum
            <action>
               ref = tw.graft("class_def", null, javaRootId,
                              "classname", classname,
                              "pkgname",   pkgname,
                              "access",    "public")
            </action>
            <action>putNote("class_def_peerid", ref.id)</action>
         </rule>

         <rule>!isClass and !isIface and !isEnum
            <!-- create the root node for the external procedure -->
            <rule>methDefId = getSectionAnchor(java.cs_instance_methods).id</rule>
            <rule>isNote("execname")
               <action>execname = getNoteString("execname")</action>
               <action on="false">execname = "execute"</action>
            </rule>
   
            <rule>lastid = createPeerAst(java.method_def, execname, methDefId)</rule>
   
            <!-- if we have parameters, add an LPARENS to root them and store
                 the ID for future use by the define parameter nodes -->
            <rule>isNote("numparms")
               <action>numparms = getNoteLong("numparms")</action>
               <rule>numparms > 0
                  <action>lastid = createJavaAst(java.lparens, "(", lastid)</action>
                  <action>putNote("parmroot", lastid)</action>
               </rule>
            </rule>
         </rule>
         
         <!-- OO 4GL cases -->
         <rule>isClass or isIface or isEnum
         
            <action>extends = null</action>
            
            <!-- there are no private or protected classes or interfaces -->
            <action>access = "public"</action>
            
            <rule>isClass
               <action>clsref = this.getImmediateChild(prog.class_def, null)</action>
               <action>clsref = clsref.getImmediateChild(prog.kw_class, null)</action>
               
               <rule on="false">isIface
                  <action>
                     clsref = this.getImmediateChild(prog.interface_def, null)
                  </action>
                  <action>
                     clsref = clsref.getImmediateChild(prog.kw_interfac, null)
                  </action>

                  <action on="false">
                     clsref = this.getImmediateChild(prog.enum_def, null)
                  </action>
                  <action on="false">
                     clsref = clsref.getImmediateChild(prog.kw_enum, null)
                  </action>
               </rule>
            </rule>
            <action>parref = clsref.getImmediateChild(prog.kw_inherits, null)</action>
            <rule>parref != null
               <action>parref = parref.getChildAt(0)</action>
               <action>extends = execLib("resolveClassReference", parref, null)</action>
               <rule on="false">isClass
                  <action>extends = "BaseObject"</action>
                  <action>ooLangImp = true</action>
               </rule>
               <rule on="false">isEnum
                  <rule>downPath(clsref, prog.kw_flags)
                     <action>extends = "FlagsEnum"</action>
                     <action>flagsEnum = true</action>
                     <action on="false">extends = "LegacyEnum"</action>
                     <action on="false">flagsEnum = false</action>
                  </rule>
                  <action>ooLangImp = true</action>
               </rule>
            </rule>
         </rule>
         <rule>isClass or isEnum
            <action>
               jclsdef = tw.graft("class_def_ext", null, javaRootId,
                                                   "classname", classname,
                                                   "pkgname",   pkgname,
                                                   "extends",   extends,
                                                   "access",    access)
            </action>
            <action>putNote("class_def_peerid", jclsdef.id)</action>
            <rule>clsref.descendant(1, prog.kw_abstract)
               <action>jclsdef.putAnnotation("abstract", true)</action>
            </rule>
            <rule>clsref.descendant(1, prog.kw_final) or isEnum
               <action>jclsdef.putAnnotation("final", true)</action>
            </rule>

            <rule>isClass
               <!-- create the root node for the external procedure, where the initialization
                    code will reside -->
               <action>methDefId = getSectionAnchor(java.cs_instance_methods).id</action>
               <action>execname = sprintf("__%s_execute__", qname)</action>
               <action>lastid = createPeerAst(java.method_def, execname, methDefId)</action>
               
               <rule>downPath(clsref, prog.kw_serialab)
                  <!-- emit a @LegacySerializable annotation for this class -->
                  <action>
                     createJavaAst(java.annotation, "LegacySerializable", jclsdef.parent.id, jclsdef.indexPos)
                  </action> 
               </rule>
            </rule>
         </rule>
         <rule>isIface
            <!-- if there is no explicit parent interface, we implicitly inherit from the
                 master parent interface that allows references to interfaces to be treated
                 as Progress.Lang.Objects -->
            <rule>extends == null
               <action>extends = "com.goldencode.p2j.oo.lang._BaseObject_"</action>
            </rule>
            <action>
               jclsdef = tw.graft("interface_def_ext", null, javaRootId,
                                                       "classname", classname,
                                                       "pkgname",   pkgname,
                                                       "extends",   extends,
                                                       "access",    access)
            </action>
         </rule>

         <!-- for 4GL classes and external procedures -->
         <rule>!isIface and !isEnum and getConfigParameter("i18n-enable", false))
            <action>execLib("initClassI18n", pkgname, classname)</action>
         </rule>

      </init-rules>
      
      <descent-rules>
         <!-- obtain type list for FUNC_* calls and save it in the dictionary -->
         <rule>evalLib("function_calls") or evalLib("oo_call_type", this, null)
            <action>addScope("function")</action>

            <action>refid = getNoteLong("refid")</action>
            <action>typelist = null</action>
            <action>modes = null</action>
            
            <!-- avoid builtin funcs -->
            <rule>refid != null
               <action>iref = getAst(refid)</action>

               <action>
                  typelist = iref.getAnnotation("typelist")
               </action>
               <action>modes = iref.getAnnotation("param_modes")</action>

               <rule>typelist == null and 
                     isNote("cls-property") and 
                     getNoteBoolean("cls-property") and
                     "setter" == getNoteString("property-access-type")
                  <action>typelist = create("java.util.ArrayList")</action>
                  <action>typelist.add(iref.getAnnotation("classname"))</action>
                  <action>modes = "I"</action>
               </rule>
            
               <action>
                  addDictionaryObject("function", "typelist", typelist)
               </action>
               <action>
                  addDictionaryObject("function", "modes", modes)
               </action>
            </rule>
         </rule>
      </descent-rules>
      
      <walk-rules>
      
         <!-- all attribute setters for which the expression is POLY must be annotated with
              the attribute's type -->
         <rule>this.type &gt; prog.begin_attr and 
               this.type &lt; prog.end_attr   and
               this.indexPos == 1             and
               parent.type == prog.colon      and
               parent.indexPos == 0           and
               upPath(this, prog.assign, prog.colon)
            <action>ref = copy.parent.parent.getChildAt(1)</action>
            <action>wrapper = ecw.expressionType(ref, false)</action>

            <rule>wrapper == null or wrapper.equals("BaseDataType")
               <action>wrapper = ecw.expressionType(copy)</action>
               
               <rule>!(wrapper == null or wrapper.equals("BaseDataType"))
                  <action>ref.putAnnotation("classname", wrapper)</action>
                  <action>ref.putAnnotation("wrap_parameter", true)</action>
                  
                  <!-- there are POLY attributes - we don't know how to wrap these --> 
                  <action on="false">
                     printfln("WARNING: received a POLY rvalue for POLY attribute assignment %s",
                              this.dumpTree(true))
                  </action>
               </rule>
            </rule>
         </rule>
         
         <!-- convert the implements clause for OO classes -->
         <rule>relativePath(this, prog.class_def, prog.kw_class, prog.kw_implemts)
            <action>createPeerAst(java.kw_implements, "implements", jclsdef.id, 0)</action>
         </rule>
         <rule>relativePath(this, prog.kw_implemts, prog.class_name)
            <action>jname = execLib("resolveClassReference", copy, null)</action>
            <action>createPeerAst(java.class_reference, jname, closestPeerId)</action>
         </rule>
         
         <!--  all RUN statement cases will be converted using ControlFlowOps
               APIs; explicit Java code is no longer emitted for these cases,
               as 4GL allows an internal proc name to have the same name as an
               external procedure (and the internal procedures are searched
               first) -->
               
         <!-- TODO: some "virtual" OO method calls (e.g. Progress.Lang.Enum:GetEnum) have no original method
                    definition to reference, which means there is no refid; wrapping for these will not work
                    right now; to avoid bad behavior we must not try to process the dictionary lookup since
                    it will NOT have non-null values for this current call and may return an enclosing method
                    or function call's typelist/modes instead; this is why we exclude the missing refid case
                    -->
         <rule>
            parent != null                                                                        and
            parent.isAnnotation("refid")                                                          and
            ((evalLib("function_call_type", parent.type)                                  and 
              (!parent.isAnnotation("param_modes") or copy.indexPos > 0))                      or 
             (evalLib("oo_call_type", parent, copy) and !evalLib("is_builtin_cls", parent) and
              !evalLib("is_java_cls", parent) and isNote("param_index")))
            
            <action>
               typelist = lookupDictionaryObject("function", "typelist")
            </action>
            <action>
               modes = lookupDictionaryObject("function", "modes")
            </action>

            <rule>
               !parent.isAnnotation("builtin") or
               #(java.lang.Boolean) parent.getAnnotation("builtin") == false
                             
               <!-- TODO: this test doesn't make sense since it can find enclosing function/method call
                          typelists instead of the current call; this happens in the "virtual" method
                          cases like GetEnum; we really need a foolproof approach here -->
               <rule>typelist != null

                  <action>parIdx = #(long) (-1)</action>
                  <rule>copy.isAnnotation("param_index")
                     <action>parIdx = #(long) copy.getAnnotation("param_index")</action>
                  
                     <rule on="false">parent.isAnnotation("param_modes")
                        <action>parIdx = #(long) copy.indexPos - 1</action>
                        <action on="false">parIdx = #(long) copy.indexPos</action>
                     </rule>
                  </rule>
                  <action>wrapper = typelist.get(parIdx)</action>
   
                  <!-- mark with the proper wrapper:
                       - unknown value literals used in user defined function 
                         call parameters types
                       - all string literals to their proper types-->
                  <rule>type == prog.string or type == prog.unknown_val
                     <action>putNote("classname", wrapper)</action>
                  </rule>
                  
                  <!-- longchar and character parameters may need to be
                       wrapped, as in 4GL char and longchar are inter-changeble
                       int64 also need to be wrapped as integer if the case;
                       same case for date/datetime/datetime-tz.
                       -->
                  <rule>wrapper != null and
                        (wrapper.equals("longchar") or wrapper.equals("character")   or 
                         wrapper.equals("integer")  or wrapper.equals("decimal")     or
                         wrapper.equals("int64"))   or wrapper.equals("datetime")    or
                         wrapper.equals("date")     or wrapper.equals("datetimetz"))
                     <variable name="nodeRef" type="com.goldencode.ast.Aast" />
                     
                     <action>nodeRef = copy</action>
                     <!-- look for the true node, leaving the superfluos parenthesis away -->
                     <while>nodeRef != null and 
                            (nodeRef.type == prog.lparens or nodeRef.type == prog.expression)
                        <!-- usually there are no extra LPARENS so there will be no iteration -->
                        <action>nodeRef = nodeRef.getChildAt(0)</action>
                     </while>
                     
                     <rule>nodeRef != null
                        <rule>!(evalLib("type_pair", this, prog.func_poly, prog.kw_dyn_func) or
                                evalLib("type_pair", this, prog.func_poly, prog.kw_dyn_invk) or
                                evalLib("type_pair", this, prog.func_poly, prog.kw_dyn_prop) or
                                evalLib("type_pair", this, prog.attr_poly, prog.kw_buf_val)  or
                                this.type == prog.db_ref_non_static)
                          <action>nodeRef.putAnnotation("chp_wrapper", wrapper)</action>
                        </rule>
                     </rule>

                     <action>pmode = modes.substring(parIdx, parIdx + 1)</action>
                     <rule>pmode == 'O' or pmode == 'U'
                        <action>putNote("output_mode", true)</action>
                     </rule>
                  </rule>
                  
                  <rule>wrapper != null
                  
                     <!-- deal with dynamic-function casttype cases to avoid unnecessary
                          wrapping -->
                     <rule>
                        evalLib("type_pair", copy, prog.func_poly, prog.kw_dyn_func) and
                        isNote("casttype")
                        <action>casttype = getNoteString("casttype")</action>
                        <action on="false">casttype = null</action>
                     </rule>
                  
                     <!-- only process for the indeterminate cases (_POLY) or the HANDLE
                          attribute -->
                     <action>candidate = ecw.expressionType(copy, false)</action>
                     <rule>
                        candidate == null                or
                        candidate.equals("BaseDataType") or 
                        candidate.equals("WrappedResource")
                         
                        <!-- user defined funcs can't have unknown or BDT types so that this
                             point wrapper is a safe coercion target; but we only wrap if the
                             casttype is not there OR if the casttype is not assignment
                             compatible with what we need to pass as the parameter.
                             assignment-compatible can't be used here: the cast may have a common
                             super-class with the defined argument (like TextOps for longchar and 
                              character), but the caller may not be a sub-class -->
                        <rule>casttype == null or !casttype.equals(wrapper)
                           <rule>!(evalLib("type_pair", this, prog.func_poly, prog.kw_dyn_func) or
                                   evalLib("type_pair", this, prog.func_poly, prog.kw_dyn_invk) or
                                   evalLib("type_pair", this, prog.func_poly, prog.kw_dyn_prop) or
                                   evalLib("type_pair", this, prog.attr_poly, prog.kw_buf_val)  or
                                   this.type == prog.db_ref_non_static)

                              <action>putNote("wrap_parameter", true)</action>
                              <action>putNote("classname", wrapper)</action>

                              <!-- Mark the function call as poly witn an annotation -->
                              <action on="false">copy.parent.putAnnotation("isPoly", true)</action>
                           </rule>
                        </rule>
                     </rule>
                  </rule>
                  
                  <action on="false">printfln("%s %s", errmsg, parent.dumpTree(true))</action>
               </rule>
            </rule>

         </rule>
         
         <rule>parent.type == prog.kw_publish and
               this.indexPos == 0             and
               this.type == prog.expression
            
            <rule>cls = ecw.expressionType(this, false)</rule>
            
            <rule>cls == null || cls.equals("BaseDataType") 
               <action>putNote("wrap_parameter", true)</action>
               <action>putNote("classname", "character")</action>
            </rule>
         </rule>
         
         <!-- check clauses for some special statements -->
         <rule>parent.type == prog.kw_run
            <rule>ref = null</rule>

            <rule>type == prog.kw_in
               <action>ref = copy.getFirstChild()</action>
            </rule>
            
            <rule>ref != null
               <rule>cls = ecw.expressionType(ref, false)</rule>
   
               <rule>cls == null || cls.equals("BaseDataType") 
                  <action>wrapper = "handle"</action>
                  <!-- mark this node, so that we can wrap it in expressions.rules -->
                  <action>ref.putAnnotation("wrap_parameter", true)</action>
                  <action>ref.putAnnotation("classname", wrapper)</action>
               </rule>
            </rule>
         </rule>
         
         <rule>this.type == prog.expression and
               copy.firstChild != null      and 
               evalLib("literals", copy.firstChild.type)
            
            <rule>parent.type == prog.kw_by or parent.type == prog.kw_case
               <action>putNote("wrap", true)</action>
            </rule>
            
            <rule>(upPath(this, prog.kw_this_obj, prog.lparens, prog.parameter) or 
                   upPath(this, prog.kw_super, prog.lparens, prog.parameter)) and
                  parent.parent.parent.isAnnotation("javaname")
               <action>putNote("wrap", true)</action>
            </rule>
         </rule>
         <rule>evalLib("literals", this.type) and 
               (upPath(this, prog.object_invocation) or upPath(this, prog.object_invocation, prog.expression))
            <action>putNote("wrap", true)</action>
         </rule>
         
         <rule>this.type == prog.unknown_val and 
               (upPath(this, prog.statement, prog.kw_put_k_v, prog.kw_section, prog.expression)           or
                upPath(this, prog.statement, prog.kw_put_k_v, prog.kw_key, prog.expression)               or
                upPath(this, prog.statement, prog.kw_get_k_v, prog.kw_section, prog.expression)           or
                upPath(this, prog.statement, prog.kw_get_k_v, prog.kw_key, prog.expression))
            <action>copy.parent.putAnnotation("classname", "character")</action>
         </rule>
         
         <rule>this.indexPos >= 1            and
               (upPath(this, prog.statement, prog.kw_substr)                  or
                upPath(this, prog.statement, prog.assign, prog.kw_substr)     or
                upPath(this, prog.statement, prog.kw_assign, prog.kw_substr)  or
                upPath(this, prog.statement, prog.kw_entry)                   or
                upPath(this, prog.statement, prog.assign, prog.kw_entry)      or
                upPath(this, prog.statement, prog.kw_assign, prog.kw_entry))
            <action>candidate = ecw.expressionType(copy, false)</action>
            <rule>candidate == null                or
                  candidate.equals("BaseDataType") or 
                  candidate.equals("WrappedResource")
               <action>copy.putAnnotation("wrap_parameter", true)</action>
               
               <rule>parent.type == prog.kw_substr
                  <rule>copy.indexPos == 1
                     <action>classname = "character"</action>
                     <action on="false">classname = "integer"</action>
                  </rule>
                  
                  <rule on="false">copy.indexPos == 1
                     <action>classname = "integer"</action>
                     <action on="false">classname = "character"</action>
                  </rule>
               </rule>
               
               <action>copy.putAnnotation("classname", classname)</action>
            </rule>
         </rule> 
         
         <!-- for builtin functions and for methods, we need to wrap these cases:
              - unknown value
              - some literals (depending on type and context)
              - parameter expressions which don't have a determined type (i.e. _POLY
                or other) -->
         <rule>this.type != prog.kw_no_error and 
               this.type != prog.kw_input    and
               this.type != prog.kw_in_out   and
               this.type != prog.kw_output   and
               this.type != prog.kw_append   and
               this.type != prog.kw_bind     and
               this.type != prog.kw_by_ref   and
               this.type != prog.kw_by_value and
               ((evalLib("function_or_method_call", parent)                 and
                 !evalLib("type_pair", parent, prog.func_class, prog.kw_new) and  
                 !evalLib("supports_poly_argument", copy.parent, copy.indexPos)) or
                 (parent.type == prog.lparens and  
                  evalLib("type_pair", parent.parent, prog.func_class, prog.kw_new)))
            
            <action>pref = parent</action>
            <rule>pref.type == prog.lparens
               <action>pref = pref.parent</action>
            </rule>
            <action>oldtype = #(long) pref.getAnnotation("oldtype")</action>
            <action>wrapper = null</action> 

            <!-- in some cases, the parameter is one level down -->
            <action>ref = copy</action>
            <while>
               ref.type == prog.kw_in      or
               ref.type == prog.parameter  or
               ref.type == prog.expression or
               ref.type == prog.lparens
               
               <action>ref = ref.getChildAt(0)</action>
            </while>
            
            <!-- if unknown val, the classname is the parameter's type -->
            <rule>ref.type == prog.unknown_val or
                  (ref.type == prog.expression and downPath(ref, prog.unknown_val))
               <action>wrapper = ecw.expressionType(ref)</action>
               
               <rule>wrapper != null
                  <rule>wrapper.equals("unknown") or wrapper.equals("BaseDataType")
                     <action>wrapper = null</action>
                  </rule>
                  <rule>wrapper != null and wrapper.equals("WrappedResource")
                     <action>wrapper = "handle"</action>
                  </rule>
               </rule>
               
               <!-- SET-DB-CLIENT's second parameter is poly (integer or character) - so force
                    a 'character' wrapper for an unknown value -->
               <rule>oldtype == prog.kw_set_dbcl and ref.indexPos == 1
                  <action>wrapper = "character"</action>
               </rule>
               
               <!--  CLIENT-PRINCIPAL:INITIALIZE --> 
               <rule>oldtype == prog.kw_init_c_p and ref.indexPos == 1
                  <action>wrapper = "character"</action>
               </rule>

               <rule>oldtype == prog.kw_init_c_p and ref.indexPos == 2
                  <action>wrapper = "datetimetz"</action>
               </rule>

               <!-- use 'rowid' for unknown val -->
               <rule>oldtype == prog.kw_repos_2i
                  <action>wrapper = "rowid"</action>
               </rule>

               <rule>wrapper != null
                  <rule>downPath(ref, prog.unknown_val)
                     <action>lref = ref.getFirstChild()</action>
                     <action on="false">lref = ref</action>
                  </rule>
                  
                  <action>lref.putAnnotation("classname", wrapper)</action>
               </rule>
            </rule>

            <!-- mark literals which need to be wrapped -->
            <rule>wrapper == null
               <rule>ref.parent.type == prog.expression
                  <action>lref = ref.parent</action>
                  <action on="false">lref = ref</action>
               </rule>

               <rule>
                  evalLib("literals", ref.type) and !evalLib("compiler_constants", ref.type)
                  <!-- in this case, the classname annotation will not be set, but change the 
                       wrapper so no warning is shown -->
                  <action>wrapper = "bogus"</action>
                  <rule>evalLib("needs_wrapped_literals", oldtype,  this.indexPos)
                     <!-- mark this literal so it will be wrapped. this mustn't use the 
                          expected type, as we must get compile errors if wrong literal is 
                          passed to a parameter (i.e. integer literal for character parameter)
                          -->
                     <action>lref.putAnnotation("wrap", true)</action>
                  </rule>
               </rule>
            </rule>
            
            <!-- all other cases - check if the type of the parameter's expression can be determined -->
            <rule>wrapper == null and !pref.isAnnotation("supportsPolyParameter")
               <!-- see if we can determine the type without context analysis -->
               <action>wrapper = ecw.expressionType(ref, false)</action>
               
               <!-- if the HANDLE attribute is passed as a parameter to a function or method call,
                    then it needs to be wrapped in a handle instance. -->
               <rule>wrapper != null and wrapper.equals("WrappedResource")
                  <action>ref.putAnnotation("wrap_parameter", true)</action>
                  <action>ref.putAnnotation("classname", "handle")</action>
               </rule>
                  
               <!-- indeterminate types need wrapping -->
               <rule>wrapper == null or wrapper.equals("BaseDataType")
               
                  <!-- use our context this time, to get the type -->
                  <action>wrapper = ecw.expressionType(ref, true)</action>
                  
                  <!-- lookup the type that the containing function requires -->
                  <action>needed = parameterTypeName(pref, copy.indexPos, true)</action>
                  
                  <!-- deal with dynamic-function casttype cases to avoid unnecessary wrapping -->
                  <rule>
                     evalLib("type_pair", ref, prog.func_poly, prog.kw_dyn_func) and
                     ref.isAnnotation("casttype")
                     <action>casttype = ref.getAnnotation("casttype")</action>
                     <action on="false">casttype = null</action>
                  </rule>
                  
                  <!-- the wrapper must be assignment compatible with what is needed by the
                       function/method, if not we coerce the type here -->
                  <rule>needed != null and !ecw.isAssignmentCompatible(wrapper, needed)
                     <action>wrapper = needed</action>
                  </rule>
                  
                  <!-- the wrapper has to be something wrappable;  we bypass wrapping for the
                       ternary operands (2 and 3) because we will wrap downstream if needed;
                       we bypass dynamic-function wrapping if the type is known AND is assignment
                       compatible with the wrapper (which must already be known to be assignment
                       compatible with what is needed) -->
                  <rule>
                     wrapper != null                                                       and
                     !wrapper.equals("unknown")                                            and
                     !wrapper.equals("BaseDataType")                                       and
                     (casttype == null or !ecw.isAssignmentCompatible(wrapper, casttype))  and
                     !(evalLib("type_pair", pref, prog.func_poly, prog.kw_if) and copy.indexPos &gt; 0)
                       
                     <!-- mark this node, so that we can wrap it in expressions.rules -->
                     <action>ref.putAnnotation("wrap_parameter", true)</action>
                     <action>ref.putAnnotation("classname", wrapper)</action>
                  </rule>
                  
                  <!-- bypass error below, since this is not an indeterminate case -->
                  <action on="false">wrapper = "bogus"</action>
               </rule>
            </rule>
            
            <!-- do not show warnings for functions which accept unknown or can handle _Poly parameters -->
            <rule>wrapper == null             and 
                  oldtype != prog.kw_dyn_func and 
                  oldtype != prog.kw_super    and
                  !copy.parent.isAnnotation("supportsPolyParameter")
               <action>
                  printfln("WARNING: Could not determine wrapper for parameter %d [%s] for function/method %s [%d] @%d:%d.",
                           copy.indexPos,
                           copy.lookupTokenName(ref.type),
                           copy.lookupTokenName(oldtype),
                           pref.id,
                           pref.line,
                           pref.column)
               </action>
            </rule>
         </rule>

      </walk-rules>
      
      <ascent-rules>
         <rule>this.type == prog.enum_def
            <action>lastid = getSectionAnchor(java.cs_instance_vars).id</action>
            <action>pref = this.getAncestor(-1)</action>
            <action>qual_oo = pref.getAnnotation("qualified_oo_name")</action>
            
            <action>createStaticImport("com.goldencode.p2j.report.ReportConstants.*")</action>
            <action>createStaticImport("com.goldencode.p2j.util.InternalEntry.Type")</action>
            
            <!-- emit the GetEnum static methods -->
            <action>ref = getSectionAnchor(java.cs_static_methods)</action>
            <action>
               tw.graftAt("enum_static_getenum_methods", null, ref.parent.id, ref.indexPos,
                          "classname", classname,
                          "qualified", qual_oo.toLowerCase())
            </action>
            <action>ref.remove()</action>

            <!-- this is no longer being used -->
            <!-- emit the SetFlag/ToggleFlag/UnsetFlag methods -->
            <!--
            <rule>flagsEnum
               <action>ref = getSectionAnchor(java.cs_instance_methods)</action>
               <action>
                  tw.graftAt("enum_instance_bitflag_methods", null, ref.parent.id, ref.indexPos,
                             "classname", classname,
                             "qualified", qual_oo.toLowerCase())
               </action>
               <action>ref.remove()</action>
            </rule>
            -->
            
            <!-- emit a static constructor -->
            <action>ref = getSectionAnchor(java.cs_constructors)</action>
            <action>ref = createJavaAst(java.block, "", ref)</action>
            <action>ref.putAnnotation("static", true)</action>
            <action>ref.putAnnotation("constructor", true)</action>
            <action>copy.parent.putAnnotation("static_ctor", ref.id)</action>

            <!-- register the enum -->
            <action>
               tw.graft("enum_register", null, ref.id, "classname", classname, "name", qual_oo)
            </action>
            <action>createJavaAst(java.skip, "", ref)</action>
            
            <!-- emit a 2-arg private constructor -->
            <action>ref = getSectionAnchor(java.cs_constructors)</action>
            <action>tw.graft("enum_constructor", null, ref.id, "classname", classname)</action>
         </rule>
         
         <rule>this.type == prog.kw_convert and 
               upPath(this, prog.statement, prog.kw_cpy_lob)
            <rule>downPath(this, prog.kw_source) and downPath(this, prog.kw_target)
               <!-- standardize the order -->
               <rule>this.firstChild.type == prog.kw_target
                  <action>ref = copy.firstChild</action>
                  <action>ref.move(copy, 1)</action>
               </rule>
               
               <rule on="false">not downPath(this, prog.kw_source)
                  <!-- create a CONVERT SOURCE ?, which will ignore it -->
                  <action>ref = copy.firstChild</action>
                  <action>ref = ref.duplicateFresh()</action>
                  <action>copy.graftAt(ref, 0)</action>

                  <action>ref.type = prog.kw_source</action>
                  <action>ref = ref.getImmediateChild(prog.expression, null)</action>
                  <action>ref.putAnnotation("classname", "character")</action>
                  <action>ref.removeChildren()</action>
                  <action>ref = createProgressAst(prog.unknown_val, "?", ref)</action>
                  <action>ref.putAnnotation("is-literal", true)</action>
                  
               </rule>
            </rule>
         </rule>
         
         <rule>evalLib("function_calls") or evalLib("oo_call_type", this, null)
            <action>deleteScope("function")</action>
         </rule>
      </ascent-rules>
      
   </rule-set>
   
   <!-- persist both the source and target ASTs since new cross-references
        exist bidirectionally -->
   <rule-set load-condition="runtime-query">
      <post-rules>
         <rule>ooLangImp != null and ooLangImp
            <action>createImport("com.goldencode.p2j.oo.lang.*")</action>
         </rule>

         <rule>persist()</rule>
         <rule>persistJavaFile()</rule>
      </post-rules>
   </rule-set>
</cfg>
