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