gnue / NEWT0

NewtonScript
http://gnue.github.io/NEWT0
34 stars 13 forks source link

Apply()/Perform()/PerformIfDefined()/ProtoPerform()/ProtoPerformIfDefined() global functions not implemented #2

Closed morgant closed 12 years ago

morgant commented 12 years ago

I'm attempting to write & test some NewtonScript with NEWT/0 which sends messages to dynamic method names in frames, but the Apply(), Perform(), PerformIfDefined(), ProtoPerform(), ProtoPerformIfDefined() global functions aren't implemented. I'd like to be able to call something like Perform(self, slotName, nil).

morgant commented 12 years ago

While I'm starting to get more familiar with the NEWT/0 source, I believe I've hit a wall in trying to implement this and would like some assistance or pointers, if possible.

Starting with Perform(), I've currently got a new function NsPerform() added to src/newt_core/NewtFns.c (and defined in NewtFns.h, of course): https://gist.github.com/3173823. Unfortunately, it currently throws an exception (I'll have to run it through the debugger again to determine exactly which one) in NcLookupSymbol() so I'm definitely not converting the method name correctly.

To expose my new Perform() function as a global function to NewtonScript, I'm calling the following in NVMInitGlobalFns1() in src/newt_core/NewtVM.c:

NewtDefGlobalFunc(NSSYM(Perform),          NsPerform,                      3, "Perform(frame, message, params)");

That part does seem to work correctly.

Thanks for any assistance you can provide helping me fix NsPerform() to work correctly.

morgant commented 12 years ago

I've been running this through the debugger and I'm getting closer to understanding what's happening. When NewtLookupSymbolArray() calls NewtLookupSymbol() (a few steps into my call to NcLookupSymbol() in NcPerform()), the name it's passing in (sym->name) is missing the first part/four characters. For example, if the message I pass into Perform() is "TestNothing" (or "SomeMethod") then the string passed to NewtLookupSymbol() is "Nothing" (or "Method" in the second case).

Here's my current NewtonScript test of this: https://gist.github.com/3173823#file_perform.newt

gnue commented 12 years ago

NcLookupSymbol() first parameter is not receiver object. first parameter is symbol table.

NcLookupSymbol(NcGetSymTable(), message)

but, NcLookupSymbol() is no need to use for NsPerform().

newtRef NsPerform(newtRefArg rcvr, newtRefArg frame, newtRefArg message, newtRefArg params)
{
     return NcSendWithArgArray(frame, message, false, params);                                                                                                                        
}
morgant commented 12 years ago

Thanks for helping with this! I hope it's not an inconvenience.

Your suggestion is was what I was initially hoping, but when I use just return NcSendWithArgArray(frame, message, false, params); it fails the NewtRefIsSymbol() check in NcSendWithArgArray() and throws kNErrNotASymbol (hence thinking I needed to look up the symbol for the slot/method name).

gnue commented 12 years ago

The following code will pass your NewtonScript test code.

newtRef NsPerform(newtRefArg rcvr, newtRefArg frame, newtRefArg message, newtRefArg params)
{
    newtRef sym = NewtRefIsString(message)?NcMakeSymbol(message):message;
    newtRef ary = NewtRefIsNIL(params)?NewtMakeArray(kNewtRefUnbind, 0):params;

    return NcSendWithArgArray(frame, sym, false, ary);
}

but, "The NewtonScript Programming Language" 6-74

Perform(frame, message, parameterArray)

…

message       A symbol naming the message to send.

…

Here’s an example of using this function in the Inspector:

f:={multiply: func(x,y) x*y};
perform(f, 'multiply, [10,2]);
morgant commented 12 years ago

Thanks, that implementation makes sense and helps me understand NcMakeSymbol() & NcMakeArray() usage.

Regarding the definition of Perform(), I agree that it looks like I misread it. One thing that was confusing to me was the following example from "The NewtonScript Programming Language" 2-27:

Perform(x,kConst,[42]);

However both that example and the one you mentioned above (perform(f, 'multiply, [10,2]);) are both constants (a regular constant and a quoted constant), so I definitely misunderstood.

I'll have to re-research my options. Unless you know of a way to convert a string to a symbol on the NewtonScript side (not internal to NEWT/0. However, I think you've given me enough help to implement Apply(), Perform(), etc. correctly.

morgant commented 12 years ago

Okay, Perform() & its tests seem to now be implemented in accordance to the spec: https://gist.github.com/3173823. I'll whip up the others soon.

morgant commented 12 years ago

Apply() is also implemented & test written. My next question is best practice for implementing PerformIfDefined(): is there a way to catch an exception from NcSendWithArgArray() (I'm not seeing a precedent for this) or should I just re-implement it to return nil instead of throw the exception (I personally don't like duplicating code like that).

gnue commented 12 years ago

NcSendWithArgArray(receiver, sym, ignore, args): The third argument ignore is set to true. Undefined method exception ignored and return #UNBIND.

morgant commented 12 years ago

I can't believe I missed that. Thanks and sorry for bothering you again.