From 43591bb8af4d6a391bed277ccd9522d7ab8b876f Mon Sep 17 00:00:00 2001 From: Olly Date: Tue, 12 Sep 2023 22:20:32 +0100 Subject: [PATCH] Some plugin docs. --- DocGen/build/plugins/Plugins.html | 410 +++++++++++++++ DocGen/build/plugins/c++.html | 501 +++++++++++++++++++ DocGen/build/plugins/index.html | 310 ++++++++++++ DocGen/source/conf.py | 5 +- DocGen/source/index.rst | 1 + DocGen/source/plugins/Plugins.rst | 113 +++++ DocGen/source/plugins/c++.rst | 201 ++++++++ DocGen/source/plugins/index.rst | 8 + DocGen/source/tutorials/index.rst | 3 +- Source/Simba.lpi | 6 +- Source/script/simba.script_plugin.pas | 307 +----------- Source/script/simba.script_pluginmethods.pas | 248 +++++++++ 12 files changed, 1824 insertions(+), 289 deletions(-) create mode 100644 DocGen/build/plugins/Plugins.html create mode 100644 DocGen/build/plugins/c++.html create mode 100644 DocGen/build/plugins/index.html create mode 100644 DocGen/source/plugins/Plugins.rst create mode 100644 DocGen/source/plugins/c++.rst create mode 100644 DocGen/source/plugins/index.rst create mode 100644 Source/script/simba.script_pluginmethods.pas diff --git a/DocGen/build/plugins/Plugins.html b/DocGen/build/plugins/Plugins.html new file mode 100644 index 000000000..e9d04ee48 --- /dev/null +++ b/DocGen/build/plugins/Plugins.html @@ -0,0 +1,410 @@ + + + + + + + + + Writing Plugins - Simba + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Simba
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

Writing Plugins#

+

Simba scripts can be extended with plugins. +Plugins are libraries (dll/so/dylib) which can be written in virtually every low-level language.

+
+

Note

+

The cdecl calling convention is used for 32bit, otherwise the default systems calling convention is used.

+
+
+
+

Importing functions#

+

To import functions the following methods must be exported to provide information to Simba.

+
function GetFunctionInfo(Index: Integer; var Address: Pointer; var Header: PChar): Integer; cdecl;
+function GetFunctionCount: Integer; cdecl;
+
+
+
+

Note

+
+
Appending native; to the header cause parameters and result passed in the lape wrapper format.
+
This is the preferred way, otherwise libffi is used.
+
+

The Lape wrapper format is:

+
procedure(const Params: PParamArray; const Result: Pointer);
+
+
+
+
+
+
+

Importing types#

+

To import types the following methods must be exported to provide information to Simba.

+
function GetTypeInfo(Index: Integer; var Name: PChar; var Str: PChar): Integer; cdecl;
+function GetTypeCount: Integer; cdecl;
+
+
+
+

Note

+

These methods are imported before GetFunctionInfo & GetFunctionCount so these types will be available when adding functions.

+
+
+
+
+

Importing code#

+

Code can be imported in the script with the following methods exported.

+
procedure GetCode(var Code: PChar); cdecl;
+function GetCodeLength: Integer; cdecl;
+
+
+
+
+
+

RegisterSimbaPlugin#

+

A plugin can export RegisterSimbaPlugin which provides access to various Simba’s infomation & methods.

+
procedure RegisterSimbaPlugin(Infomation: PSimbaInfomation; Methods: PSimbaMethods); cdecl;
+
+
+

These pointers are provided to these structures:

+
TSimbaInfomation = packed record
+  SimbaVersion: Integer;
+  SimbaMajor: Integer;
+
+  FileName: PChar;
+
+  Compiler: Pointer;
+end;
+
+TSimbaMethods = packed record
+  RunOnMainThread: procedure(Method: TMainThreadMethod; Data: Pointer = nil); cdecl;
+
+  GetMem: function(Size: NativeUInt): Pointer; cdecl;
+  FreeMem: function(P: Pointer): NativeUInt; cdecl;
+  AllocMem: function(Size: NativeUInt): Pointer; cdecl;
+  ReAllocMem: function(var P: Pointer; Size: NativeUInt): Pointer; cdecl;
+  MemSize: function(P: Pointer): NativeUInt; cdecl;
+
+  RaiseException: procedure(Message: PChar); cdecl;
+
+  GetTypeInfo: function(Compiler: Pointer; Typ: PChar): Pointer; cdecl;
+  GetTypeInfoSize: function(TypeInfo: Pointer): NativeInt; cdecl;
+  GetTypeInfoFieldOffset: function(TypeInfo: Pointer; FieldName: PChar): NativeInt; cdecl;
+
+  AllocateArray: function(TypeInfo: Pointer; Len: NativeInt): Pointer; cdecl;
+  AllocateString: function(Data: PChar): Pointer; cdecl;
+  AllocateUnicodeString: function(Data: PUnicodeChar): Pointer; cdecl;
+  AllocateIntegerArray: function(Len: NativeInt): Pointer; cdecl;
+  AllocateStringArray: function(Len: NativeInt): Pointer; cdecl;
+  AllocatePointArray: function(Len: NativeInt): Pointer; cdecl;
+
+  SetArrayLength: procedure(TypeInfo: Pointer; var AVar: Pointer; NewLen: NativeInt); cdecl;
+  GetArrayLength: function(AVar: Pointer): NativeInt; cdecl;
+end;
+
+
+

See the Example C++ plugin to see how TypeInfo is used to allocate custom records & arrays.

+
+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/DocGen/build/plugins/c++.html b/DocGen/build/plugins/c++.html new file mode 100644 index 000000000..f393ba9a6 --- /dev/null +++ b/DocGen/build/plugins/c++.html @@ -0,0 +1,501 @@ + + + + + + + + + Example C++ plugin - Simba + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Simba
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+
+
+

Example C++ plugin#

+
+

main.h#

+
#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#include <cstdint>
+
+#if defined(_WIN32) || defined(_WIN64)
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT [[gnu::visibility("default")]]
+#endif
+
+#if INTPTR_MAX == INT32_MAX
+    typedef int32_t NativeInt;
+    typedef uint32_t NativeUInt;
+#else
+    typedef int64_t NativeInt;
+    typedef uint64_t NativeUInt;
+#endif
+
+struct __attribute__((__packed__)) TSimbaInfo
+{
+    int SimbaVersion;
+    int SimbaMajor;
+
+    char* FileName;
+
+    void* Compiler;
+};
+
+struct __attribute__((__packed__)) TSimbaMethods
+{
+    void (*RunOnMainThread)(void(*Method)(void*), void* data);
+
+    void* (*GetMem)(NativeUInt size);
+    void  (*FreeMem)(void* ptr);
+    void* (*AllocMem)(NativeUInt Size);
+    void* (*ReAllocMem)(void** ptr, NativeUInt size);
+    NativeUInt (*MemSize)(void* ptr);
+
+    void  (*RaiseException)(char* Message);
+    void* (*GetTypeInfo)(void* Compiler, char* Typ);
+    NativeUInt (*GetTypeInfoSize)(void* TypeInfo);
+    NativeInt  (*GetTypeInfoFieldOffset)(void* TypeInfo, char* FieldName);
+
+    void* (*AllocateArray)(void* TypeInfo, NativeUInt Len);
+    void* (*AllocateString)(void* Data);
+    void* (*AllocateUnicodeString)(void* Data);
+    void* (*AllocateIntegerArray)(NativeInt Len);
+    void* (*AllocateStringArray)(NativeInt Len);
+    void* (*AllocatePointArray)(NativeInt Len);
+
+    void (*SetArrayLength)(void* TypeInfo, void**ptr, NativeInt NewLen);
+    NativeInt (*GetArrayLength)(void* AVar);
+};
+
+TSimbaInfo* SIMBA_INFO = {0};
+TSimbaMethods* SIMBA_METHODS = {0};
+
+extern "C"
+{
+  EXPORT int GetTypeCount();
+  EXPORT int GetTypeInfo(int Index, char** Name, char** Definition);
+  EXPORT int GetFunctionCount();
+  EXPORT int GetFunctionInfo(int Index, void** Address, char** Definition);
+  EXPORT void RegisterSimbaPlugin(TSimbaInfo* Information, TSimbaMethods* Methods);
+}
+
+#endif // __MAIN_H__
+
+
+
+
+

main.cpp#

+
#include "main.h"
+#include "stdio.h"
+#include <cstring>
+
+template<typename T>
+void MemWrite(void* ptr, int offset, T item) noexcept
+{
+    memcpy((char*)ptr+offset, &item, sizeof(T));
+}
+
+template<typename T>
+T MemRead(void* ptr) noexcept
+{
+    T result;
+    memcpy(&result, ptr, sizeof(T));
+    return result;
+}
+
+void* ARR_TYPEINFO = 0;
+void* REC_TYPEINFO = 0;
+NativeUInt REC_SIZE = 0;
+NativeUInt REC_STR_OFFSET = 0;
+
+void GetIntArray(void** Params, void** Result)
+{
+    int Count = MemRead<int>(*Params);
+    void* Arr = SIMBA_METHODS->AllocateIntegerArray(Count);
+    for (int i=0; i<Count; i++) {
+        MemWrite(Arr, i*sizeof(int), i);
+    }
+    MemWrite<void*>(Result, 0, Arr);
+}
+
+void GetRecord(void** Params, void** Result)
+{
+    MemWrite<int>(Result, 0, 123456);
+    MemWrite<void*>(Result, REC_STR_OFFSET, SIMBA_METHODS->AllocateString((char*)"Hello world"));
+}
+
+void GetArrayOfRecord(void** Params, void** Result)
+{
+    char str0[] = "Hello in array index 0";
+    char str1[] = "Hola in array index 1";
+    char str2[] = "Bonjour in array index 2";
+
+    void* mem = SIMBA_METHODS->AllocateArray(ARR_TYPEINFO, 3);
+    for (int i=0; i<3; i++) {
+        void* str = nullptr;
+        switch (i) {
+            case 0: str = SIMBA_METHODS->AllocateString((void*)str0); break;
+            case 1: str = SIMBA_METHODS->AllocateString((void*)str1); break;
+            case 2: str = SIMBA_METHODS->AllocateString((void*)str2); break;
+        }
+
+        // write arr[i].i
+        MemWrite<int>(mem, i*REC_SIZE, i);
+        // write  arr[i].str
+        MemWrite<void*>(mem, (i*REC_SIZE)+REC_STR_OFFSET, str);
+    }
+
+    MemWrite<void*>(Result, 0, mem);
+}
+
+void RegisterSimbaPlugin(TSimbaInfo* Info, TSimbaMethods* Methods)
+{
+    SIMBA_INFO = Info;
+    SIMBA_METHODS = Methods;
+
+    REC_TYPEINFO = SIMBA_METHODS->GetTypeInfo(SIMBA_INFO->Compiler, (char*)"TMyRecord");
+    REC_SIZE = SIMBA_METHODS->GetTypeInfoSize(REC_TYPEINFO);
+    REC_STR_OFFSET = SIMBA_METHODS->GetTypeInfoFieldOffset(REC_TYPEINFO, (char*)"str");
+
+    ARR_TYPEINFO = SIMBA_METHODS->GetTypeInfo(SIMBA_INFO->Compiler, (char*)"array of TMyRecord");
+}
+
+int GetTypeCount()
+{
+    return 1;
+}
+
+int GetTypeInfo(int Index, char** Name, char** Definition)
+{
+    switch(Index) {
+        case 0:
+            strcpy(*Name, "TMyRecord");
+            strcpy(*Definition, "record i: Int32; str: String; end;");
+            break;
+    }
+    return Index;
+}
+
+int GetFunctionCount()
+{
+    return 3;
+}
+
+int GetFunctionInfo(int Index, void** Address, char** Definition)
+{
+    switch(Index) {
+        case 0:
+            strcpy(*Definition, "function GetIntArray(Count: Int32): array of Int32; native;");
+            *Address = (void*)GetIntArray;
+            break;
+
+        case 1:
+            strcpy(*Definition, "function GetRecord: TMyRecord; native;");
+            *Address = (void*)GetRecord;
+            break;
+
+        case 2:
+            strcpy(*Definition, "function GetArrayOfRecord: array of TMyRecord; native;");
+            *Address = (void*)GetArrayOfRecord;
+            break;
+    }
+
+    return Index;
+}
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/DocGen/build/plugins/index.html b/DocGen/build/plugins/index.html new file mode 100644 index 000000000..56c2b8d68 --- /dev/null +++ b/DocGen/build/plugins/index.html @@ -0,0 +1,310 @@ + + + + + + + + + Plugins - Simba + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Simba
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+ +
+ +
+ +
+ +
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/DocGen/source/conf.py b/DocGen/source/conf.py index 014eff0f4..3b337f811 100644 --- a/DocGen/source/conf.py +++ b/DocGen/source/conf.py @@ -13,5 +13,6 @@ html_css_files = ['custom.css'] extensions = [ 'sphinx.ext.githubpages', - 'sphinx.ext.mathjax' -] \ No newline at end of file + 'sphinx.ext.mathjax', + 'sphinx.ext.autosectionlabel' +] diff --git a/DocGen/source/index.rst b/DocGen/source/index.rst index d9bbea31b..501d0c9ff 100644 --- a/DocGen/source/index.rst +++ b/DocGen/source/index.rst @@ -7,3 +7,4 @@ Simba tutorials/index api/index + plugins/index diff --git a/DocGen/source/plugins/Plugins.rst b/DocGen/source/plugins/Plugins.rst new file mode 100644 index 000000000..e34b63659 --- /dev/null +++ b/DocGen/source/plugins/Plugins.rst @@ -0,0 +1,113 @@ +############### +Writing Plugins +############### + +Simba scripts can be extended with plugins. +Plugins are libraries (dll/so/dylib) which can be written in virtually every low-level language. + +.. note:: + + For 32bit the **cdecl** calling convention is used for methods plugin related. Otherwise the default systems calling convention is used. + +----- + +Importing functions +------------------- + +To import functions the following methods must be exported to provide information to Simba. + +.. code-block:: + + function GetFunctionInfo(Index: Integer; var Address: Pointer; var Header: PChar): Integer; cdecl; + function GetFunctionCount: Integer; cdecl; + +.. note:: + + | Appending :code:`native;` to the header cause parameters and result passed in the lape wrapper format. + | This is the preferred way, otherwise libffi is used. + + The Lape wrapper format is: + + .. code-block:: + + procedure(const Params: PParamArray; const Result: Pointer); + +----- + +Importing types +--------------- + +To import types the following methods must be exported to provide information to Simba. + +.. code-block:: + + function GetTypeInfo(Index: Integer; var Name: PChar; var Str: PChar): Integer; cdecl; + function GetTypeCount: Integer; cdecl; + +.. note:: + + These methods are imported before GetFunctionInfo & GetFunctionCount so these types will be available when adding functions. + +----- + +Importing code +-------------- + +Code can be imported in the script with the following methods exported. + +.. code-block:: + + procedure GetCode(var Code: PChar); cdecl; + function GetCodeLength: Integer; cdecl; + +----- + +RegisterSimbaPlugin +------------------- + +A plugin can export `RegisterSimbaPlugin` which provides access to various Simba's infomation & methods. + +.. code-block:: + + procedure RegisterSimbaPlugin(Infomation: PSimbaInfomation; Methods: PSimbaMethods); cdecl; + +These pointers are provided to these structures: + +.. code-block:: + + TSimbaInfomation = packed record + SimbaVersion: Integer; + SimbaMajor: Integer; + + FileName: PChar; + + Compiler: Pointer; + end; + + TSimbaMethods = packed record + RunOnMainThread: procedure(Method: TMainThreadMethod; Data: Pointer = nil); cdecl; + + GetMem: function(Size: NativeUInt): Pointer; cdecl; + FreeMem: function(P: Pointer): NativeUInt; cdecl; + AllocMem: function(Size: NativeUInt): Pointer; cdecl; + ReAllocMem: function(var P: Pointer; Size: NativeUInt): Pointer; cdecl; + MemSize: function(P: Pointer): NativeUInt; cdecl; + + RaiseException: procedure(Message: PChar); cdecl; + + GetTypeInfo: function(Compiler: Pointer; Typ: PChar): Pointer; cdecl; + GetTypeInfoSize: function(TypeInfo: Pointer): NativeInt; cdecl; + GetTypeInfoFieldOffset: function(TypeInfo: Pointer; FieldName: PChar): NativeInt; cdecl; + + AllocateArray: function(TypeInfo: Pointer; Len: NativeInt): Pointer; cdecl; + AllocateString: function(Data: PChar): Pointer; cdecl; + AllocateUnicodeString: function(Data: PUnicodeChar): Pointer; cdecl; + AllocateIntegerArray: function(Len: NativeInt): Pointer; cdecl; + AllocateStringArray: function(Len: NativeInt): Pointer; cdecl; + AllocatePointArray: function(Len: NativeInt): Pointer; cdecl; + + SetArrayLength: procedure(TypeInfo: Pointer; var AVar: Pointer; NewLen: NativeInt); cdecl; + GetArrayLength: function(AVar: Pointer): NativeInt; cdecl; + end; + +See the :ref:`Example C++ plugin` to see how TypeInfo is used to allocate custom records & arrays. \ No newline at end of file diff --git a/DocGen/source/plugins/c++.rst b/DocGen/source/plugins/c++.rst new file mode 100644 index 000000000..3871c5dd4 --- /dev/null +++ b/DocGen/source/plugins/c++.rst @@ -0,0 +1,201 @@ +################## +Example C++ plugin +################## + +main.h +------ + +.. code-block:: c++ + + #ifndef __MAIN_H__ + #define __MAIN_H__ + + #include + + #if defined(_WIN32) || defined(_WIN64) + #define EXPORT __declspec(dllexport) + #else + #define EXPORT [[gnu::visibility("default")]] + #endif + + #if INTPTR_MAX == INT32_MAX + typedef int32_t NativeInt; + typedef uint32_t NativeUInt; + #else + typedef int64_t NativeInt; + typedef uint64_t NativeUInt; + #endif + + struct __attribute__((__packed__)) TSimbaInfo + { + int SimbaVersion; + int SimbaMajor; + + char* FileName; + + void* Compiler; + }; + + struct __attribute__((__packed__)) TSimbaMethods + { + void (*RunOnMainThread)(void(*Method)(void*), void* data); + + void* (*GetMem)(NativeUInt size); + void (*FreeMem)(void* ptr); + void* (*AllocMem)(NativeUInt Size); + void* (*ReAllocMem)(void** ptr, NativeUInt size); + NativeUInt (*MemSize)(void* ptr); + + void (*RaiseException)(char* Message); + void* (*GetTypeInfo)(void* Compiler, char* Typ); + NativeUInt (*GetTypeInfoSize)(void* TypeInfo); + NativeInt (*GetTypeInfoFieldOffset)(void* TypeInfo, char* FieldName); + + void* (*AllocateArray)(void* TypeInfo, NativeUInt Len); + void* (*AllocateString)(void* Data); + void* (*AllocateUnicodeString)(void* Data); + void* (*AllocateIntegerArray)(NativeInt Len); + void* (*AllocateStringArray)(NativeInt Len); + void* (*AllocatePointArray)(NativeInt Len); + + void (*SetArrayLength)(void* TypeInfo, void**ptr, NativeInt NewLen); + NativeInt (*GetArrayLength)(void* AVar); + }; + + TSimbaInfo* SIMBA_INFO = {0}; + TSimbaMethods* SIMBA_METHODS = {0}; + + extern "C" + { + EXPORT int GetTypeCount(); + EXPORT int GetTypeInfo(int Index, char** Name, char** Definition); + EXPORT int GetFunctionCount(); + EXPORT int GetFunctionInfo(int Index, void** Address, char** Definition); + EXPORT void RegisterSimbaPlugin(TSimbaInfo* Information, TSimbaMethods* Methods); + } + + #endif // __MAIN_H__ + +main.cpp +-------- + +.. code-block:: c++ + + #include "main.h" + #include "stdio.h" + #include + + template + void MemWrite(void* ptr, int offset, T item) noexcept + { + memcpy((char*)ptr+offset, &item, sizeof(T)); + } + + template + T MemRead(void* ptr) noexcept + { + T result; + memcpy(&result, ptr, sizeof(T)); + return result; + } + + void* ARR_TYPEINFO = 0; + void* REC_TYPEINFO = 0; + NativeUInt REC_SIZE = 0; + NativeUInt REC_STR_OFFSET = 0; + + void GetIntArray(void** Params, void** Result) + { + int Count = MemRead(*Params); + void* Arr = SIMBA_METHODS->AllocateIntegerArray(Count); + for (int i=0; i(Result, 0, Arr); + } + + void GetRecord(void** Params, void** Result) + { + MemWrite(Result, 0, 123456); + MemWrite(Result, REC_STR_OFFSET, SIMBA_METHODS->AllocateString((char*)"Hello world")); + } + + void GetArrayOfRecord(void** Params, void** Result) + { + char str0[] = "Hello in array index 0"; + char str1[] = "Hola in array index 1"; + char str2[] = "Bonjour in array index 2"; + + void* mem = SIMBA_METHODS->AllocateArray(ARR_TYPEINFO, 3); + for (int i=0; i<3; i++) { + void* str = nullptr; + switch (i) { + case 0: str = SIMBA_METHODS->AllocateString((void*)str0); break; + case 1: str = SIMBA_METHODS->AllocateString((void*)str1); break; + case 2: str = SIMBA_METHODS->AllocateString((void*)str2); break; + } + + // write arr[i].i + MemWrite(mem, i*REC_SIZE, i); + // write arr[i].str + MemWrite(mem, (i*REC_SIZE)+REC_STR_OFFSET, str); + } + + MemWrite(Result, 0, mem); + } + + void RegisterSimbaPlugin(TSimbaInfo* Info, TSimbaMethods* Methods) + { + SIMBA_INFO = Info; + SIMBA_METHODS = Methods; + + REC_TYPEINFO = SIMBA_METHODS->GetTypeInfo(SIMBA_INFO->Compiler, (char*)"TMyRecord"); + REC_SIZE = SIMBA_METHODS->GetTypeInfoSize(REC_TYPEINFO); + REC_STR_OFFSET = SIMBA_METHODS->GetTypeInfoFieldOffset(REC_TYPEINFO, (char*)"str"); + + ARR_TYPEINFO = SIMBA_METHODS->GetTypeInfo(SIMBA_INFO->Compiler, (char*)"array of TMyRecord"); + } + + int GetTypeCount() + { + return 1; + } + + int GetTypeInfo(int Index, char** Name, char** Definition) + { + switch(Index) { + case 0: + strcpy(*Name, "TMyRecord"); + strcpy(*Definition, "record i: Int32; str: String; end;"); + break; + } + return Index; + } + + int GetFunctionCount() + { + return 3; + } + + int GetFunctionInfo(int Index, void** Address, char** Definition) + { + switch(Index) { + case 0: + strcpy(*Definition, "function GetIntArray(Count: Int32): array of Int32; native;"); + *Address = (void*)GetIntArray; + break; + + case 1: + strcpy(*Definition, "function GetRecord: TMyRecord; native;"); + *Address = (void*)GetRecord; + break; + + case 2: + strcpy(*Definition, "function GetArrayOfRecord: array of TMyRecord; native;"); + *Address = (void*)GetArrayOfRecord; + break; + } + + return Index; + } + diff --git a/DocGen/source/plugins/index.rst b/DocGen/source/plugins/index.rst new file mode 100644 index 000000000..bf6f0114d --- /dev/null +++ b/DocGen/source/plugins/index.rst @@ -0,0 +1,8 @@ +Plugins +======= + +.. toctree:: + :maxdepth: 2 + + Plugins.rst + c++.rst \ No newline at end of file diff --git a/DocGen/source/tutorials/index.rst b/DocGen/source/tutorials/index.rst index 9674bd4c8..5f1769fce 100644 --- a/DocGen/source/tutorials/index.rst +++ b/DocGen/source/tutorials/index.rst @@ -1,4 +1,3 @@ - Simba ===== @@ -6,4 +5,4 @@ Simba :maxdepth: 2 Color Finding.rst - Sleep Until.rst + Sleep Until.rst \ No newline at end of file diff --git a/Source/Simba.lpi b/Source/Simba.lpi index 5929d2458..80d11cdfa 100644 --- a/Source/Simba.lpi +++ b/Source/Simba.lpi @@ -341,7 +341,7 @@ - + @@ -983,6 +983,10 @@ + + + + diff --git a/Source/script/simba.script_plugin.pas b/Source/script/simba.script_plugin.pas index 8a458f249..fe4160586 100644 --- a/Source/script/simba.script_plugin.pas +++ b/Source/script/simba.script_plugin.pas @@ -5,119 +5,28 @@ } unit simba.script_plugin; -(* - - // procedure Test1(out test: TIntegerArray); native; - procedure Test1(const Params: PParamArray); cdecl; - var - Arr, Element: Pointer; - TypeInfo: Pointer; - Index: Integer; - begin - Arr := nil; - - TypeInfo := MyMethods^.GetTypeInfo('TIntegerArray'); - - MyMethods^.SetArrayLength(TypeInfo, Arr, 10); - for Index := 0 to MyMethods^.GetArrayLength(Arr) - 1 do - begin - Element := MyMethods^.GetArrayElement(TypeInfo, Arr, Index); - Integer(Element^) := Index; - end; - - PPointer(Params^[0])^ := Arr; - end; - -*) - -(* - - // function Test2: array of record Int: Integer; Str: String; end; native; - procedure Test2(const Params: PParamArray; const Result: Pointer); cdecl; - var - TestInteger: Integer = 123456; - TestString: String = 'Hello World'; - var - Arr, Field: Pointer; - ArrInfo, RecInfo, StrInfo: Pointer; - begin - Arr := nil; - - ArrInfo := MyMethods^.GetTypeInfo('array of record Int: Integer; Str: String; end'); - RecInfo := MyMethods^.GetTypeInfo('record Int: Integer; Str: String; end'); - StrInfo := MyMethods^.GetTypeInfo('String'); - - MyMethods^.SetArrayLength(ArrInfo, Arr, 3); - - // Result[1].Int := testInt; - Field := MyMethods^.GetArrayElement(ArrInfo, Arr, 1) + MyMethods^.GetFieldOffset(RecInfo, 'Int'); - Move(TestInteger, Field^, SizeOf(Integer)); - - // SetLength(Result[1].Str, Length(TestString)); - Field := MyMethods^.GetArrayElement(ArrInfo, Arr, 1) + MyMethods^.GetFieldOffset(RecInfo, 'Str'); - MyMethods^.SetFieldArrayLength(StrInfo, Field, Length(TestString)); - - // Result[1].Str := TestString; - Field := MyMethods^.GetFieldArrayElement(StrInfo, Field, 0); - Move(TestString[1], Field^, Length(TestString)); - - PPointer(Result)^ := Arr; - end; - -*) - {$i simba.inc} interface uses - classes, sysutils, dynlibs, lpcompiler, - simba.mufasatypes, simba.script_compiler; + Classes, SysUtils, DynLibs, + simba.mufasatypes, simba.script_compiler, simba.script_pluginmethods; type - TSimbaSynchronizeMethod = procedure(Data: Pointer); cdecl; - - PSimbaInfomation = ^TSimbaInfomation; - TSimbaInfomation = packed record + PSimbaPluginInfo = ^TSimbaPluginInfo; + TSimbaPluginInfo = packed record SimbaVersion: Integer; SimbaMajor: Integer; FileName: PChar; - // Extend this as much as you want, do not remove, reorder or change datatypes. - end; - - PSimbaMethods = ^TSimbaMethods; - TSimbaMethods = packed record - Synchronize: procedure(Method: TSimbaSynchronizeMethod; Data: Pointer = nil); cdecl; - - GetMem: function(Size: PtrUInt): Pointer; cdecl; - FreeMem: function(P: Pointer): PtrUInt; cdecl; - AllocMem: function(Size: PtrUInt): Pointer; cdecl; - ReAllocMem: function(var P: Pointer; Size: PtrUInt): Pointer; cdecl; - MemSize: function(P: Pointer): PtrUInt; cdecl; - - RaiseException: procedure(Message: PChar); cdecl; - - GetTypeInfo: function(Str: PChar): Pointer; cdecl; - GetTypeSize: function(TypeInfo: Pointer): Integer; cdecl; - GetTypeBaseType: function(TypeInfo: Pointer): Integer; cdecl; - GetTypeClassName: function(TypeInfo: Pointer; Buffer: PChar): Integer; cdecl; - - GetArrayElement: function(TypeInfo: Pointer; AVar: Pointer; Index: Integer): Pointer; cdecl; - GetArrayLength: function(AVar: Pointer): Integer; cdecl; - SetArrayLength: procedure(TypeInfo: Pointer; var AVar: Pointer; Len: Integer); cdecl; + Compiler: Pointer; - GetFieldOffset: function(TypeInfo: Pointer; FieldName: PChar): Integer; cdecl; - GetFieldArrayLength: function(AVar: Pointer): Integer; cdecl; - SetFieldArrayLength: procedure(TypeInfo: Pointer; var AVar: Pointer; Len: Integer); cdecl; - GetFieldArrayElement: function(TypeInfo: Pointer; AVar: Pointer; Index: Integer): Pointer; cdecl; - - // Extend this as much as you want, do not remove, reorder or change datatypes. + // Extend this but do not remove, reorder or change datatypes. end; TSimbaPluginExports = packed record - GetPluginABIVersion: function: Integer; cdecl; GetFunctionInfo: function(Index: Integer; var Address: Pointer; var Header: PChar): Integer; cdecl; GetFunctionCount: function: Integer; cdecl; GetTypeInfo: function(Index: Integer; var Name: PChar; var Str: PChar): Integer; cdecl; @@ -126,7 +35,7 @@ interface GetCodeLength: function: Integer; cdecl; SetPluginMemManager: procedure(MemoryManager: TMemoryManager); cdecl; - RegisterSimbaPlugin: procedure(Infomation: PSimbaInfomation; Methods: PSimbaMethods); cdecl; + RegisterSimbaPlugin: procedure(Info: PSimbaPluginInfo; Methods: PSimbaPluginMethods); cdecl; OnAttach: procedure(Data: Pointer); cdecl; OnDetach: procedure; cdecl; @@ -147,16 +56,12 @@ TSimbaScriptPluginType = record end; TSimbaScriptPlugin = class - protected - class var - FBaseCompiler: TSimbaScript_Compiler; // Type info.. Use script compiler. protected FFileName: String; FHandle: TLibHandle; - FSimbaInfomation: TSimbaInfomation; - FSimbaMethods: TSimbaMethods; - FSimbaMemoryManager: TMemoryManager; + FInfo: TSimbaPluginInfo; + FMemoryManager: TMemoryManager; FExports: TSimbaPluginExports; @@ -184,142 +89,7 @@ TSimbaScriptPlugin = class implementation uses - ffi, lptypes, lpvartypes, lpvartypes_array, lpvartypes_record; - -function _GetMem(Size: PtrUInt): Pointer; cdecl; -begin - Result := GetMem(Size); -end; - -function _FreeMem(Ptr: Pointer): PtrUInt; cdecl; -begin - Result := FreeMem(Ptr); -end; - -function _AllocMem(Size: PtrUInt): Pointer; cdecl; -begin - Result := AllocMem(Size); -end; - -function _ReAllocMem(var P: Pointer; Size: PtrUInt): Pointer; cdecl; -begin - Result := ReAllocMem(P, Size); -end; - -function _MemSize(P: Pointer): PtrUInt; cdecl; -begin - Result := MemSize(P); -end; - -procedure _RaiseException(Message: PChar); cdecl; -begin - raise Exception.Create(Message); -end; - -function _GetTypeInfo(Str: PChar): Pointer; cdecl; -var - Typ: TLapeType absolute Result; -begin - Result := nil; - - with TSimbaScriptPlugin.FBaseCompiler do - try - Typ := getGlobalType(Str); - if (Typ <> nil) then - Exit; - - Typ := addGlobalType(Str, '_GetTypeInfo'); - if (Typ <> nil) then - Typ.Name := Str; - except - end; -end; - -function _GetFieldOffset(TypeInfo: Pointer; Name: PChar): Integer; cdecl; -begin - Result := TLapeType_Record(TypeInfo).FieldMap[Name].Offset; -end; - -procedure _SetArrayLength(TypeInfo: Pointer; var AVar: Pointer; Len: Integer); cdecl; -begin - TLapeType_DynArray(TypeInfo).VarSetLength(AVar, Len); -end; - -function _GetArrayLength(AVar: Pointer): Integer; cdecl; -begin - Result := DynArraySize(AVar); -end; - -function _GetArrayElement(TypeInfo: Pointer; AVar: Pointer; Index: Integer): Pointer; cdecl; -begin - Result := AVar + (Index * TLapeType_DynArray(TypeInfo).PType.Size); -end; - -function _GetFieldArrayLength(AVar: Pointer): Integer; cdecl; -begin - Result := DynArraySize(PPointer(AVar)^); -end; - -procedure _SetFieldArrayLength(TypeInfo: Pointer; var AVar: Pointer; Len: Integer); cdecl; -begin - with TLapeType_DynArray(TypeInfo) do - VarSetLength(PPointer(AVar)^, Len); -end; - -function _GetFieldArrayElement(TypeInfo: Pointer; AVar: Pointer; Index: Integer): Pointer; cdecl; -begin - with TLapeType_DynArray(TypeInfo) do - Result := PPointer(AVar + (Index * PType.Size))^; -end; - -function _GetTypeSize(TypeInfo: Pointer): Integer; cdecl; -begin - with TLapeType(TypeInfo) do - Result := Size; -end; - -function _GetTypeClassName(TypeInfo: Pointer; Buffer: PChar): Integer; cdecl; -begin - with TLapeType(TypeInfo) do - begin - Result := Length(ClassName); - if (Result > 0) then - Move(ClassName[1], Buffer^, Result); - end; -end; - -function _GetTypeBaseType(TypeInfo: Pointer): Integer; cdecl; -begin - with TLapeType(TypeInfo) do - Result := Ord(BaseType); -end; - -// Sync wrapper which includes a data parameter -type - TSync = class - Data: Pointer; - Method: TSimbaSynchronizeMethod; - - procedure Execute; - end; - -procedure TSync.Execute; -begin - Method(Data); -end; - -procedure _Synchronize(Method: TSimbaSynchronizeMethod; Data: Pointer = nil); cdecl; -var - Sync: TSync; -begin - Sync := TSync.Create(); - Sync.Data := Data; - Sync.Method := Method; - - TThread.Synchronize(TThread.CurrentThread, @Sync.Execute); - - Sync.Free(); -end; + ffi; procedure TSimbaScriptPlugin.Load; @@ -395,7 +165,6 @@ procedure TSimbaScriptPlugin.Load; begin with FExports do begin - Pointer(GetPluginABIVersion) := GetProcedureAddress(FHandle, 'GetPluginABIVersion'); Pointer(GetFunctionInfo) := GetProcedureAddress(FHandle, 'GetFunctionInfo'); Pointer(GetFunctionCount) := GetProcedureAddress(FHandle, 'GetFunctionCount'); Pointer(GetTypeInfo) := GetProcedureAddress(FHandle, 'GetTypeInfo'); @@ -411,9 +180,6 @@ procedure TSimbaScriptPlugin.Load; Pointer(RegisterSimbaPlugin) := GetProcedureAddress(FHandle, 'RegisterSimbaPlugin'); end; - if Assigned(FExports.SetPluginMemManager) then FExports.SetPluginMemManager(FSimbaMemoryManager); - if Assigned(FExports.RegisterSimbaPlugin) then FExports.RegisterSimbaPlugin(@FSimbaInfomation, @FSimbaMethods); - // Methods if Assigned(FExports.GetFunctionCount) and Assigned(FExports.GetFunctionInfo) then begin @@ -465,23 +231,29 @@ procedure TSimbaScriptPlugin.Import(Compiler: TSimbaScript_Compiler); if FMethods[I].Native then Compiler.addGlobalFunc(FMethods[I].Header, FMethods[I].Address) else - Compiler.addGlobalFunc(FMethods[I].Header, FMethods[I].Address, {$IF DECLARED(FFI_CDECL)}FFI_CDECL{$ELSE}FFI_DEFAULT_ABI{$ENDIF}); + Compiler.addGlobalFunc(FMethods[I].Header, FMethods[I].Address, FFI_DEFAULT_ABI); end; if (FCode <> '') then Compiler.addDelayedCode(FCode, '!' + FFileName, False); + + GetMemoryManager(FMemoryManager); + if Assigned(FExports.SetPluginMemManager) then + FExports.SetPluginMemManager(FMemoryManager); + + FInfo.SimbaMajor := SIMBA_MAJOR; + FInfo.SimbaVersion := SIMBA_VERSION; + FInfo.FileName := PChar(FFileName); + FInfo.Compiler := Compiler; + + if Assigned(FExports.RegisterSimbaPlugin) then + FExports.RegisterSimbaPlugin(@FInfo, @SimbaPluginMethods); end; constructor TSimbaScriptPlugin.Create(FileName: String); begin inherited Create(); - if (FBaseCompiler = nil) then - begin - FBaseCompiler := TSimbaScript_Compiler.Create(nil); - FBaseCompiler.Import(); - end; - FFileName := FileName; if (not FileExists(FFileName)) then raise Exception.CreateFmt('Loading plugin: File "%s" does not exist', [FFileName]); @@ -496,35 +268,6 @@ constructor TSimbaScriptPlugin.Create(FileName: String); raise Exception.Create('Loading plugin failed. Architecture mismatch? (expected a ' + {$IFDEF CPU32}'32'{$ELSE}'64'{$ENDIF} + ' bit plugin)'); end; - FSimbaMethods.Synchronize := @_Synchronize; - FSimbaMethods.GetMem := @_GetMem; - FSimbaMethods.FreeMem := @_FreeMem; - FSimbaMethods.AllocMem := @_AllocMem; - FSimbaMethods.MemSize := @_MemSize; - FSimbaMethods.ReAllocMem := @_ReAllocMem; - - FSimbaMethods.RaiseException := @_RaiseException; - - FSimbaMethods.GetTypeInfo := @_GetTypeInfo; - FSimbaMethods.GetTypeSize := @_GetTypeSize; - FSimbaMethods.GetTypeBaseType := @_GetTypeBaseType; - FSimbaMethods.GetTypeClassName := @_GetTypeClassName; - - FSimbaMethods.GetArrayElement := @_GetArrayElement; - FSimbaMethods.GetArrayLength := @_GetArrayLength; - FSimbaMethods.SetArrayLength := @_SetArrayLength; - - FSimbaMethods.GetFieldOffset := @_GetFieldOffset; - FSimbaMethods.GetFieldArrayLength := @_GetFieldArrayLength; - FSimbaMethods.SetFieldArrayLength := @_SetFieldArrayLength; - FSimbaMethods.GetFieldArrayElement := @_GetFieldArrayElement; - - FSimbaInfomation.FileName := PChar(FFileName); - FSimbaInfomation.SimbaMajor := SIMBA_MAJOR; - FSimbaInfomation.SimbaVersion := SIMBA_VERSION; - - GetMemoryManager(FSimbaMemoryManager); - Load(); end; @@ -569,9 +312,5 @@ procedure TSimbaScriptPluginArrayHelper.CallOnStop; Self[I].FExports.OnStop(); end; -finalization - if (TSimbaScriptPlugin.FBaseCompiler <> nil) then - FreeAndNil(TSimbaScriptPlugin.FBaseCompiler); - end. diff --git a/Source/script/simba.script_pluginmethods.pas b/Source/script/simba.script_pluginmethods.pas new file mode 100644 index 000000000..27daf7fd1 --- /dev/null +++ b/Source/script/simba.script_pluginmethods.pas @@ -0,0 +1,248 @@ +{ + Author: Raymond van Venetië and Merlijn Wajer + Project: Simba (https://github.com/MerlijnWajer/Simba) + License: GNU General Public License (https://www.gnu.org/licenses/gpl-3.0) + + Functions passed to plugins in RegisterSimbaPlugin +} +unit simba.script_pluginmethods; + +{$i simba.inc} + +interface + +uses + Classes, SysUtils, + lpcompiler; + +type + TMainThreadMethod = procedure(Data: Pointer); cdecl; + + PSimbaPluginMethods = ^TSimbaPluginMethods; + TSimbaPluginMethods = packed record + RunOnMainThread: procedure(Method: TMainThreadMethod; Data: Pointer = nil); cdecl; + + GetMem: function(Size: NativeUInt): Pointer; cdecl; + FreeMem: function(P: Pointer): NativeUInt; cdecl; + AllocMem: function(Size: NativeUInt): Pointer; cdecl; + ReAllocMem: function(var P: Pointer; Size: NativeUInt): Pointer; cdecl; + MemSize: function(P: Pointer): NativeUInt; cdecl; + + RaiseException: procedure(Message: PChar); cdecl; + + GetTypeInfo: function(Compiler: Pointer; Typ: PChar): Pointer; cdecl; + GetTypeInfoSize: function(TypeInfo: Pointer): NativeInt; cdecl; + GetTypeInfoFieldOffset: function(TypeInfo: Pointer; FieldName: PChar): NativeInt; cdecl; + + AllocateArray: function(TypeInfo: Pointer; Len: NativeInt): Pointer; cdecl; + AllocateString: function(Data: PChar): Pointer; cdecl; + AllocateUnicodeString: function(Data: PUnicodeChar): Pointer; cdecl; + AllocateIntegerArray: function(Len: NativeInt): Pointer; cdecl; + AllocateStringArray: function(Len: NativeInt): Pointer; cdecl; + AllocatePointArray: function(Len: NativeInt): Pointer; cdecl; + + SetArrayLength: procedure(TypeInfo: Pointer; var AVar: Pointer; NewLen: NativeInt); cdecl; + GetArrayLength: function(AVar: Pointer): NativeInt; cdecl; + + // Extend this but do not remove, reorder or change datatypes. + end; + +var + SimbaPluginMethods: TSimbaPluginMethods; + +implementation + +uses + simba.mufasatypes, + lpvartypes, lpvartypes_record, lpvartypes_array, lpffiwrappers; + +// Sync wrapper which includes a data parameter +type + TSync = class + Data: Pointer; + Method: TMainThreadMethod; + + procedure Execute; + end; + +procedure TSync.Execute; +begin + Method(Data); +end; + +procedure _RunOnMainThread(Method: TMainThreadMethod; Data: Pointer = nil); cdecl; +var + Sync: TSync; +begin + Sync := TSync.Create(); + Sync.Data := Data; + Sync.Method := Method; + + TThread.Synchronize(TThread.CurrentThread, @Sync.Execute); + + Sync.Free(); +end; + +procedure _RaiseException(Message: PChar); cdecl; +begin + raise Exception.Create(Message); +end; + +function Plugin_GetMem(Size: NativeUInt): Pointer; cdecl; +begin + Result := GetMem(Size); +end; + +function Plugin_FreeMem(Ptr: Pointer): NativeUInt; cdecl; +begin + Result := FreeMem(Ptr); +end; + +function Plugin_AllocMem(Size: NativeUInt): Pointer; cdecl; +begin + Result := AllocMem(Size); +end; + +function Plugin_ReAllocMem(var P: Pointer; Size: NativeUInt): Pointer; cdecl; +begin + Result := ReAllocMem(P, Size); +end; + +function Plugin_MemSize(P: Pointer): NativeUInt; cdecl; +begin + Result := MemSize(P); +end; + +function Plugin_GetTypeInfo(Compiler: Pointer; Str: PChar): Pointer; cdecl; +var + Typ: TLapeType absolute Result; +begin + Result := nil; + + with TLapeCompiler(Compiler) do + try + Typ := getGlobalType(Str); + + // Check if plugin already added this + if (Typ = nil) then + Typ := getGlobalType('GetTypeInfo::' + Str); + + // Add it + if (Typ = nil) then + begin + Typ := addGlobalType(Str, '_GetTypeInfo'); + if (Typ <> nil) then + Typ.Name := 'GetTypeInfo::' + Str; + end; + except + if (Typ <> nil) then + Typ.Free(); + Result := nil; + end; +end; + +function Plugin_GetTypeInfoSize(TypeInfo: Pointer): NativeInt; cdecl; +begin + Result := -1; + if (TypeInfo <> nil) and (TObject(TypeInfo) is TLapeType) then + Result := TLapeType(TypeInfo).Size; +end; + +function Plugin_GetTypeInfoFieldOffset(TypeInfo: Pointer; FieldName: PChar): NativeInt; cdecl; +begin + Result := -1; + if (TypeInfo <> nil) and (TObject(TypeInfo) is TLapeType_Record) then + Result := TLapeType_Record(TypeInfo).FieldMap[FieldName].Offset; +end; + +function Plugin_AllocateArray(TypeInfo: Pointer; Len: NativeInt): Pointer; cdecl; +begin + Result := nil; + + TLapeType_DynArray(TypeInfo).VarSetLength(Result, Len); +end; + +function Plugin_AllocateString(Data: PChar): Pointer; cdecl; +var + Len: SizeInt; +begin + Result := nil; + + Len := StrLen(Data); + SetLength(String(Result), Len); + if (Len > 0) then + Move(Data^, String(Result)[1], Len); +end; + +function Plugin_AllocateUnicodeString(Data: PUnicodeChar): Pointer; cdecl; +var + Len: SizeInt; +begin + Result := nil; + + Len := StrLen(Data); + SetLength(UnicodeString(Result), Len); + if (Len > 0) then + Move(Data^, UnicodeString(Result)[1], Len * SizeOf(UnicodeChar)); +end; + +function Plugin_AllocateIntegerArray(Len: NativeInt): Pointer; cdecl; +begin + Result := nil; + + SetLength(TIntegerArray(Result), Len); +end; + +function Plugin_AllocateStringArray(Len: NativeInt): Pointer; cdecl; +begin + Result := nil; + + SetLength(TStringArray(Result), Len); +end; + +function Plugin_AllocatePointArray(Len: NativeInt): Pointer; cdecl; +begin + Result := nil; + + SetLength(TPointArray(Result), Len); +end; + +procedure Plugin_SetArrayLength(TypeInfo: Pointer; var Arr: Pointer; Len: NativeInt); cdecl; +begin + TLapeType_DynArray(TypeInfo).VarSetLength(Arr, Len); +end; + +function Plugin_GetArrayLength(Arr: Pointer): NativeInt; cdecl; +begin + Result := DynArraySize(Arr); +end; + +initialization + + with SimbaPluginMethods do + begin + RunOnMainThread := @_RunOnMainThread; + RaiseException := @_RaiseException; + + GetMem := @Plugin_GetMem; + FreeMem := @Plugin_FreeMem; + AllocMem := @Plugin_AllocMem; + MemSize := @Plugin_MemSize; + ReAllocMem := @Plugin_ReAllocMem; + + GetTypeInfo := @Plugin_GetTypeInfo; + GetTypeInfoSize := @Plugin_GetTypeInfoSize; + GetTypeInfoFieldOffset := @Plugin_GetTypeInfoFieldOffset; + AllocateArray := @Plugin_AllocateArray; + AllocateString := @Plugin_AllocateString; + AllocateUnicodeString := @Plugin_AllocateUnicodeString; + AllocateIntegerArray := @Plugin_AllocateIntegerArray; + AllocateStringArray := @Plugin_AllocateStringArray; + AllocatePointArray := @Plugin_AllocatePointArray; + + SetArrayLength := @Plugin_SetArrayLength; + GetArrayLength := @Plugin_GetArrayLength; + end; + +end. +