Attached please find the patch that makes method's newFile work with compiled 
Rexx scripts, but has
a problem at runtime when trying to invoke a method that got restored from the 
compiled form.

---rony


On 06.08.2020 13:54, Rony G. Flatscher wrote:
>
> As a first step I have been trying to correct the code to accept compiled 
> Rexx scripts as method
> code (using the .method's newFile).
>
> This seems to have been successful, decoding now works.
>
> However, when assigning the method object to a class and then sending an 
> object of that class the
> message to execute the method, I get the runtime error message (Rexx test 
> script at the end):
>
>         15 *-*   say .context~name", return value:" o~aha(1,2,3)
>     Error 97 running G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin\testrgf.rex 
> line 15:  Object method not found.
>     Error 97.3:  Object "a TEST" cannot accept package scope message "AHA" 
> from a different package caller.
>
> The compiled Rexx code for the method gets successfully processed in a new 
> method defined in
> ProgramMetaData.cpp:
>
>     MethodClass *ProgramMetaData::restoreMethod(RexxString *name, BufferClass 
> *buffer)
>     {
>         ProgramMetaData *metaData;
>
>         // check to see if this is already translated
>         if (!processRestoreData(name, buffer, metaData))
>         {
>             // nope, can't restore this
>             return OREF_NULL;
>         }
>
>         // make sure this is valid for interpreter
>         if (!metaData->validate(name))
>         {
>             return OREF_NULL;
>         }
>
>         // this should be valid...try to restore.
>         Protected<MethodClass> method = MethodClass::restore(buffer, 
> metaData->getImageData(), metaData->getImageSize());
>         // change the program name to match the file this was restored from
>         method->getPackageObject()->setProgramName(name);
>         return method;
>     }
>
> The question is, how can I inhibit the runtime error 97.3, what do I need to 
> do to the method object?
>
> The starting point is in LanguageParser the new method:
>
>     MethodClass* LanguageParser::createMethod(RexxString *name, PackageClass 
> *sourceContext)
>     {
>         // load the file into a buffer
>         Protected<BufferClass> program_buffer = 
> FileProgramSource::readProgram(name->getStringData());
>         // if this failed, report an error now.
>         if (program_buffer == (BufferClass *)OREF_NULL)
>         {
>             reportException(Error_Program_unreadable_name, name);
>         }
>
>         // try to restore a flattened program first
>         Protected<MethodClass> method = MethodClass::restore(name, 
> program_buffer);
>         if (method != (MethodClass *)OREF_NULL)
>         {
>
>             return method;
>         }
>
>         // create the appropriate program source, then the parser, then 
> generate the
>         // code.
>         Protected<ProgramSource> programSource = new 
> BufferProgramSource(program_buffer);
>         Protected<LanguageParser> parser = new LanguageParser(name, 
> programSource);
>         return parser->generateMethod(sourceContext);
>     }
>
> Hence it would be possible to pass the sourceContext as the third arguemtn 
> via the new method
> MethodClass::restore() to ProgramMetaData::restoreMethod(...). But then, how 
> can I set the scope
> from the sourceContext which is a PackageClass, bet MethodClass::setScope 
> expects a RexxClass?
>
> ---rony
>
> P.S.: Here the Rexx test script that generates the above runtime error:
>
>     fnames="testmethod.rex", "testmethod-compiled.rex", 
> "testmethod-compiled-encoded.rex"
>     say "testing routine code from external files:"
>     do fn over fnames
>        o=.routine~newFile(fn)
>        say .context~name", return value:" o[1,2,3]
>        say
>     end
>
>     say "--------------------"
>
>     say "testing method code from external files:"
>     do fn over fnames
>        o=.test~new~~addMethod("aha", .method~newFile(fn))
>        say .context~name", return value:" o~aha(1,2,3)    /* <--- line # 15 */
>        say
>     end
>
>
>     ::class test
>     ::method addMethod
>       use strict arg name, method
>       self~setmethod(name, method, "object")
>
> Here the three external files:
>
>     testmethod-compiled.rex ... copmiled with rexxc
>     testmethod-compiled-encoded.rex  ... compiled with the "/e" switch of 
> rexxc.exe
>     testmethod.rex ... source code:
>
>         parse source s
>         say .dateTime~new": number of args:" arg()
>         say .dateTime~new": args          :" arg(1,'A')~toString(,",")
>         say .dateTime~new": parse source  :" s
>         say .dateTime~new": .context~name :" .context~name
>         return .dateTime~new
>
> Here the output of running the above test script including the runtime error:
>
>     G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin>rexx testrgf.rex
>     testing routine code from external files:
>     2020-08-06T13:53:14.998000: number of args: 3
>     2020-08-06T13:53:14.998000: args          : 1,2,3
>     2020-08-06T13:53:14.998000: parse source  : WindowsNT SUBROUTINE 
> testmethod.rex
>     2020-08-06T13:53:14.998000: .context~name : testmethod.rex
>     G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin\testrgf.rex, return value: 
> 2020-08-06T13:53:14.998000
>
>     2020-08-06T13:53:14.998000: number of args: 3
>     2020-08-06T13:53:14.998000: args          : 1,2,3
>     2020-08-06T13:53:14.998000: parse source  : WindowsNT SUBROUTINE 
> testmethod-compiled.rex
>     2020-08-06T13:53:14.998000: .context~name : 
> G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin\testmethod.rex
>     G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin\testrgf.rex, return value: 
> 2020-08-06T13:53:14.998000
>
>     2020-08-06T13:53:15.014000: number of args: 3
>     2020-08-06T13:53:15.014000: args          : 1,2,3
>     2020-08-06T13:53:15.014000: parse source  : WindowsNT SUBROUTINE 
> testmethod-compiled-encoded.rex
>     2020-08-06T13:53:15.014000: .context~name : 
> G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin\testmethod.rex
>     G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin\testrgf.rex, return value: 
> 2020-08-06T13:53:15.014000
>
>     --------------------
>     testing method code from external files:
>     2020-08-06T13:53:15.014000: number of args: 3
>     2020-08-06T13:53:15.014000: args          : 1,2,3
>     2020-08-06T13:53:15.014000: parse source  : WindowsNT METHOD 
> testmethod.rex
>     2020-08-06T13:53:15.014000: .context~name : AHA
>     G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin\testrgf.rex, return value: 
> 2020-08-06T13:53:15.014000
>
>         15 *-*   say .context~name", return value:" o~aha(1,2,3)
>     Error 97 running G:\oorexx.tmp\oorexxBuild\debug32.trunk\bin\testrgf.rex 
> line 15:  Object method not found.
>     Error 97.3:  Object "a TEST" cannot accept package scope message "AHA" 
> from a different package caller.
>
>

Index: interpreter/classes/MethodClass.cpp
===================================================================
--- interpreter/classes/MethodClass.cpp (revision 12101)
+++ interpreter/classes/MethodClass.cpp (working copy)
@@ -53,6 +53,7 @@
 #include "DirectoryClass.hpp"
 #include "ProtectedObject.hpp"
 #include "BufferClass.hpp"
+#include "ProgramMetaData.hpp"
 #include "RexxInternalApis.h"
 #include "RoutineClass.hpp"
 #include "PackageClass.hpp"
@@ -413,7 +414,48 @@
 }
 
 
+
+
 /**
+ * Unflatten a saved Method object.
+ *
+ * @param buffer The buffer containing the saved data.
+ * @param startPointer
+ *               The pointer to the start of the flattened data.
+ * @param length The length of the flattened data.
+ *
+ * @return A restored Method object.
+ */
+MethodClass *MethodClass::restore(BufferClass *buffer, char *startPointer, 
size_t length)
+{
+    // get an envelope and puff up the object
+    Protected<Envelope> envelope  = new Envelope;
+    envelope->puff(buffer, startPointer, length);
+    // the envelope receiver object is our return value.
+    return (MethodClass *)envelope->getReceiver();
+}
+
+
+/**
+ * Restore a program from a simple buffer.
+ *
+ * @param fileName The file name of the program we're restoring from.
+ * @param buffer   The source buffer.  This contains all of the saved metadata
+ *                 ahead of the the flattened object.
+ *
+ * @return The inflated Method object, if valid.
+ */
+MethodClass* MethodClass::restore(RexxString *fileName, BufferClass *buffer)
+{
+    // ProgramMetaData handles all of the details here
+    return ProgramMetaData::restoreMethod(fileName, buffer);
+}
+
+
+
+
+
+/**
  * Static method used for constructing new method objects in
  * various contexts (such as the define method on the Class class).
  *
@@ -519,6 +561,9 @@
     // go create a method from filename
     Protected<MethodClass> newMethod = LanguageParser::createMethod(filename, 
sourceContext);
 
+    // cannot coerce PackageClass to RexxClass
+    // newMethod->setScope(sourceContext);
+
     classThis->completeNewObject(newMethod);
     return newMethod;
 }
Index: interpreter/classes/MethodClass.hpp
===================================================================
--- interpreter/classes/MethodClass.hpp (revision 12101)
+++ interpreter/classes/MethodClass.hpp (working copy)
@@ -139,6 +139,10 @@
     inline bool  isScope(RexxClass *s) {return scope == s;}
 
     inline BaseCode  *getCode()     { return code; }
+
+    static MethodClass* restore(BufferClass *buffer, char *startPointer, 
size_t length);
+    static MethodClass* restore(RexxString *fileName, BufferClass *buffer);
+
     MethodClass  *newRexx(RexxObject **, size_t);
     MethodClass  *newFileRexx(RexxString *, PackageClass *);
     MethodClass  *loadExternalMethod(RexxString *methodName, RexxString 
*descriptor);
Index: interpreter/classes/RoutineClass.cpp
===================================================================
--- interpreter/classes/RoutineClass.cpp        (revision 12101)
+++ interpreter/classes/RoutineClass.cpp        (working copy)
@@ -406,7 +406,7 @@
 RoutineClass* RoutineClass::restore(RexxString *fileName, BufferClass *buffer)
 {
     // ProgramMetaData handles all of the details here
-    return ProgramMetaData::restore(fileName, buffer);
+    return ProgramMetaData::restoreRoutine(fileName, buffer);
 }
 
 
@@ -424,7 +424,7 @@
     Protected<BufferClass> buffer = new_buffer(inData->strptr, 
inData->strlength);
 
     // ProgramMetaData handles all of the details here
-    return ProgramMetaData::restore(name, buffer);
+    return ProgramMetaData::restoreRoutine(name, buffer);
 }
 
 
Index: interpreter/classes/support/ProgramMetaData.cpp
===================================================================
--- interpreter/classes/support/ProgramMetaData.cpp     (revision 12101)
+++ interpreter/classes/support/ProgramMetaData.cpp     (working copy)
@@ -168,7 +168,7 @@
  *
  * @return The restored Routine object, or NULL if this was not a saved 
program image.
  */
-RoutineClass *ProgramMetaData::restore(RexxString *name, BufferClass *buffer)
+RoutineClass *ProgramMetaData::restoreRoutine(RexxString *name, BufferClass 
*buffer)
 {
     ProgramMetaData *metaData;
 
@@ -194,6 +194,39 @@
 
 
 /**
+ * Restore a saved program from the metadata.
+ *
+ * @param name   The program name being restored
+ * @param buffer A buffer object that contains the image data
+ *
+ * @return The restored Routine object, or NULL if this was not a saved 
program image.
+ */
+MethodClass *ProgramMetaData::restoreMethod(RexxString *name, BufferClass 
*buffer)
+{
+    ProgramMetaData *metaData;
+
+    // check to see if this is already translated
+    if (!processRestoreData(name, buffer, metaData))
+    {
+        // nope, can't restore this
+        return OREF_NULL;
+    }
+
+    // make sure this is valid for interpreter
+    if (!metaData->validate(name))
+    {
+        return OREF_NULL;
+    }
+
+    // this should be valid...try to restore.
+    Protected<MethodClass> method = MethodClass::restore(buffer, 
metaData->getImageData(), metaData->getImageSize());
+    // change the program name to match the file this was restored from
+    method->getPackageObject()->setProgramName(name);
+    return method;
+}
+
+
+/**
  * Validate that this saved program image is valid for this
  * interpreter.
  *
Index: interpreter/classes/support/ProgramMetaData.hpp
===================================================================
--- interpreter/classes/support/ProgramMetaData.hpp     (revision 12101)
+++ interpreter/classes/support/ProgramMetaData.hpp     (working copy)
@@ -62,7 +62,8 @@
     bool validate(RexxString *fileName);
     void write(SysFile &target, BufferClass *program, bool encode);
 
-    static RoutineClass* restore(RexxString *fileName, BufferClass *buffer);
+    static MethodClass*  restoreMethod(RexxString *name, BufferClass *buffer);
+    static RoutineClass* restoreRoutine(RexxString *fileName, BufferClass 
*buffer);
     static bool processRestoreData(RexxString *fileName, BufferClass *data, 
ProgramMetaData *&metaData);
 
     static const size_t encodingChunkLength = 72;    // the chunking to use 
with encoded data
Index: interpreter/parser/LanguageParser.cpp
===================================================================
--- interpreter/parser/LanguageParser.cpp       (revision 12101)
+++ interpreter/parser/LanguageParser.cpp       (working copy)
@@ -123,6 +123,7 @@
 }
 
 
+
 /**
  * Static method for creating a new MethodClass instance from a
  * file.
@@ -134,16 +135,36 @@
  *
  * @return An executable method object.
  */
-MethodClass *LanguageParser::createMethod(RexxString *name, PackageClass 
*sourceContext)
+MethodClass* LanguageParser::createMethod(RexxString *name, PackageClass 
*sourceContext)
 {
+    // load the file into a buffer
+    Protected<BufferClass> program_buffer = 
FileProgramSource::readProgram(name->getStringData());
+    // if this failed, report an error now.
+    if (program_buffer == (BufferClass *)OREF_NULL)
+    {
+        reportException(Error_Program_unreadable_name, name);
+    }
+
+    // try to restore a flattened program first
+    Protected<MethodClass> method = MethodClass::restore(name, program_buffer);
+    if (method != (MethodClass *)OREF_NULL)
+    {
+
+        return method;
+    }
+
     // create the appropriate program source, then the parser, then generate 
the
     // code.
-    Protected<ProgramSource> programSource = new FileProgramSource(name);
+    Protected<ProgramSource> programSource = new 
BufferProgramSource(program_buffer);
     Protected<LanguageParser> parser = new LanguageParser(name, programSource);
     return parser->generateMethod(sourceContext);
 }
 
 
+
+
+
+
 /**
  * Static method for creating a new RoutineClass instance.
  *
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to