Y_Less

OOPS - Object Oriented PAWN Script.

Apr 28th, 2013
577
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 6.69 KB | None | 0 0
  1. // This is a VERY rough proof-of-concept for a few ideas I've been working on,
  2. // much of this is implementation details, and other bits will be wrapped up in
  3. // macros.
  4. //
  5. // ========================================================================== //
  6. // ========================================================================== //
  7. // ||                                                                      || //
  8. // ||                    SCROLL DOWN FOR THE USER CODE.                    || //
  9. // ||                                                                      || //
  10. // ========================================================================== //
  11. // ========================================================================== //
  12. //
  13.  
  14. #include <a_samp>
  15.  
  16. #define YSI_MAX_STRING (144)
  17. #define string:
  18.  
  19. #define strcpy(%0,%1) strcat((%0[0] = 0, %0), %1)
  20.  
  21. enum e_RET_DATA_STRUCT
  22. {
  23.     e_RET_DATA_VAL,
  24.     e_RET_DATA_STR,
  25.     e_RET_DATA:e_RET_DATA_RET[YSI_MAX_STRING] = 0,
  26.     e_RET_DATA_PAD
  27. }
  28.  
  29. new
  30.     YSI_g_sSearchClass = 0,
  31.     YSI_gReturnAddr,
  32.     YSI_gReturnData[e_RET_DATA_STRUCT];
  33.  
  34. // Only defined for classes that exist.
  35. stock _CLASS_TAG:operator=(CObjects:n) return YSI_g_sSearchClass=0x1010,_CLASS_TAG:n;
  36.  
  37. // Unique class number (constructor address)?  Used to find the correct classes.
  38. stock _CLASS_TAG:operator=(CPlayers:n) return YSI_g_sSearchClass=0x2020,_CLASS_TAG:n;
  39.  
  40. // Define for all valid return tags.
  41. stock Float:operator=(e_RET_DATA:n) return Float:n;
  42.  
  43. // The "o:" macro - sadly this is still the best way I can find to code "OOPS".
  44. #define o:%0->%1(%2) (CallMethod((%0), (_METHOD_NAME:#%1), %2),YSI_gReturnData[e_RET_DATA_RET])
  45. // Define macros.  This is done in two stages to not incorrectly detect colons.
  46. #define method%0(%1) forward _METHOD_DO(%0|||%1);public _METHOD_DO(%0|||%1)
  47. #define _METHOD_DO(%0|||%1) _METHOD_RET:%0(_THIS_TAG:this,%1)
  48. // Consume empty parameter lists.
  49. #define _METHOD_NAME:#%1),) _METHOD_NAME:#%1))
  50. // "this" won't be an inline function parameter but a container class variable.
  51. #define _THIS_TAG:this,) _THIS_TAG:this)
  52. // Consume return tags and suffix names.
  53. #define _METHOD_RET:%5:%0(%1) _METHOD_TAG%5:%0(%1)
  54. #define _METHOD_TAG%9\32;%5:%0(%1) _METHOD_TAG%5:%0(%1)
  55. #define _METHOD_TAGstring:%0(%1) %0@s(%1)
  56. #define _METHOD_TAGFloat:%0(%1) %0@f(%1)
  57. #define _METHOD_TAG_:%0(%1) %0@i(%1)
  58.  
  59. CallMethod(_CLASS_TAG:object, const _METHOD_NAME:name[], {Float, _}:...)
  60. {
  61.     static
  62.         sToCall[32];
  63.     new
  64.         bool:isString;
  65.     // Only set this up once in reality.
  66.     #emit CONST.pri      YSI_gReturnData
  67.     #emit ADD.C          4
  68.     #emit STOR.pri       YSI_gReturnAddr
  69.     // Update for more parameters later.
  70.     assert(numargs() == 3); // Just for now.
  71.     // HACK HACK HACK.
  72.     if (strcmp(_:name, !"StrReturn"))
  73.     {
  74.         format(sToCall, sizeof (sToCall), "%s@s", _:name);
  75.         if (funcidx(sToCall) != -1) { isString = true; goto CallMethod_alt_1; }
  76.         format(sToCall, sizeof (sToCall), "%s@i", _:name);
  77.         if (funcidx(sToCall) != -1) goto CallMethod_alt_1;
  78.         format(sToCall, sizeof (sToCall), "%s@f", _:name);
  79.         if (funcidx(sToCall) != -1) goto CallMethod_alt_1;
  80.         sToCall[0] = '\0';
  81.         strcat(sToCall, _:name);
  82. CallMethod_alt_1:
  83.         CallLocalFunction(sToCall, "ii", object, getarg(2));
  84.     }
  85.     else
  86.     {
  87.         static const
  88.             szType[] = "is";
  89.         // Make passing the string work without implementing the full system.
  90.         // All this code does is correctly passes the string's address to
  91.         // "CallLocalFunction", but that will be corrected better later.
  92.         format(sToCall, sizeof (sToCall), "%s@s", _:name);
  93.         if (funcidx(sToCall) != -1) { isString = true; goto CallMethod_alt_2; }
  94.         format(sToCall, sizeof (sToCall), "%s@i", _:name);
  95.         if (funcidx(sToCall) != -1) goto CallMethod_alt_2;
  96.         format(sToCall, sizeof (sToCall), "%s@f", _:name);
  97.         if (funcidx(sToCall) != -1) goto CallMethod_alt_2;
  98.         strcpy(sToCall, _:name);
  99. CallMethod_alt_2:
  100.         #emit LOAD.S.pri 20
  101.         #emit PUSH.pri
  102.         #emit ADDR.pri   object
  103.         #emit PUSH.pri
  104.         #emit PUSH.C     szType
  105.         #emit PUSH.C     sToCall
  106.         #emit PUSH.C     16
  107.         #emit SYSREQ.C   CallLocalFunction
  108.         #emit STACK      20
  109.     }
  110.     if (isString)
  111.     {
  112.         // Move the data slightly.
  113.         memcpy(YSI_gReturnData[e_RET_DATA_STR], YSI_gReturnData[e_RET_DATA_VAL], 0, YSI_MAX_STRING * 4, YSI_MAX_STRING);
  114.         YSI_gReturnData[e_RET_DATA_VAL] = YSI_gReturnAddr;
  115.     }
  116. }
  117.  
  118. stock _Return()
  119. {
  120.     // Manipulate the stack to end an inline early and simulate a real "return".
  121. }
  122.  
  123. #define _return%0; (YSI_gReturnData[e_RET_DATA_RET] = e_RET_DATA:(%0),_Return());
  124.  
  125. //
  126. // ========================================================================== //
  127. // ========================================================================== //
  128. // ||                                                                      || //
  129. // ||                        THIS IS THE USER CODE.                        || //
  130. // ||                                                                      || //
  131. // ========================================================================== //
  132. // ========================================================================== //
  133. //
  134.  
  135. method IntReturn(n)
  136. {
  137.     printf("IntReturn called for class %x", YSI_g_sSearchClass);
  138.     _return n;
  139. }
  140.  
  141. method Float:FltReturn(Float:n)
  142. {
  143.     printf("FltReturn called for class %x", YSI_g_sSearchClass);
  144.     _return n;
  145. }
  146.  
  147. method string:StrReturn(string:n[])
  148. {
  149.     printf("StrReturn called for class %x", YSI_g_sSearchClass);
  150.     // You can't return a string parameter directly (plus unknown size).
  151.     new
  152.         str[YSI_MAX_STRING];
  153.     strcpy(str, n);
  154.     _return str;
  155. }
  156.  
  157. //
  158. // ========================================================================== //
  159. // ========================================================================== //
  160. // ||                                                                      || //
  161. // ||                      HERE IS IT SORT OF IN USE.                      || //
  162. // ||                                                                      || //
  163. // ========================================================================== //
  164. // ========================================================================== //
  165. //
  166.  
  167. public OnFilterScriptInit()
  168. {
  169.     new
  170.         CObjects:obj1,
  171.         CPlayers:obj2,
  172.         CWorlds:obj3,
  173.         var,
  174.         Float:flt,
  175.         str[YSI_MAX_STRING];
  176.     // With returns.
  177.     var = o:obj1->IntReturn(88);
  178.     str = o:obj1->StrReturn("Woop");
  179.     flt = o:obj1->FltReturn(8.6);
  180.     printf("%d, \"%s\", %.2f", var, str, flt);
  181.     // Without returns.
  182.     printf("%d", o:obj2->IntReturn(50));
  183.     // Don't do this - it prints the first character too (the bad address).
  184.     printf("%s", o:obj1->StrReturn("Yeah"));
  185.     printf("%f", o:obj2->FltReturn(9.9));
  186.     // With warnings (gives the wrong results).
  187.     o:obj3->IntReturn(88);
  188.     o:obj3->StrReturn("Woop");
  189.     o:obj3->FltReturn(8.6);
  190.     return 1;
  191. }
Advertisement
Add Comment
Please, Sign In to add comment