Add native plugin support, remove SDL2

This commit is contained in:
2025-01-23 13:36:15 -06:00
parent ea3e01bdb2
commit 3ebdab9401
12 changed files with 421 additions and 373 deletions

View File

@ -72,6 +72,8 @@
"mutex": "cpp", "mutex": "cpp",
"semaphore": "cpp", "semaphore": "cpp",
"stop_token": "cpp", "stop_token": "cpp",
"thread": "cpp" "thread": "cpp",
"bitset": "cpp",
"regex": "cpp"
} }
} }

View File

@ -14,9 +14,9 @@ option(CROSSLANG_ENABLE_THREADING "Enable Tesses CrossLang threading" ON)
option(CROSSLANG_ENABLE_SQLITE "Enable sqlite (Embedded database, supports Wii)" ON) option(CROSSLANG_ENABLE_SQLITE "Enable sqlite (Embedded database, supports Wii)" ON)
option(CROSSLANG_ENABLE_JSON "Enable JSON" ON) option(CROSSLANG_ENABLE_JSON "Enable JSON" ON)
option(CROSSLANG_ENABLE_PROCESS "Enable process" ON) option(CROSSLANG_ENABLE_PROCESS "Enable process" ON)
option(CROSSLANG_ENABLE_SDL2 "Enable SDL2 (For Drawing)" ON)
option(CROSSLANG_ENABLE_TERMIOS "Enable termios (For changing terminal options)" ON) option(CROSSLANG_ENABLE_TERMIOS "Enable termios (For changing terminal options)" ON)
option(CROSSLANG_ENABLE_PLATFORM_FOLDERS "Enable platform folders" ON) option(CROSSLANG_ENABLE_PLATFORM_FOLDERS "Enable platform folders" ON)
option(CROSSLANG_SHARED_EXECUTABLES "Link with libcrosslang_shared" ON)
option(CROSSLANG_CUSTOM_CONSOLE "Enable custom Console" OFF) option(CROSSLANG_CUSTOM_CONSOLE "Enable custom Console" OFF)
@ -59,22 +59,9 @@ endif()
if(CROSSLANG_ENABLE_PLATFORM_FOLDERS) if(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_PLATFORM_FOLDERS) target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_PLATFORM_FOLDERS)
endif() endif()
if(CROSSLANG_ENABLE_SHARED)
target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_SHARED)
if(CROSSLANG_ENABLE_SDL2)
target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_SDL2)
find_package(SDL2 REQUIRED)
find_package(SDL2_ttf REQUIRED)
target_include_directories(${CROSSLANG_TARGET_NAME} PUBLIC ${SDL2_INCLUDE_DIRS})
target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC SDL2::SDL2)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube")
target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC SDL2_image png jpeg z)
else()
find_package(SDL2_image REQUIRED)
target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC ${SDL2_image_LIBRARIES})
endif()
target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC ${SDL2_ttf_LIBRARIES})
endif() endif()
if("${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube") if("${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube")
target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC fat) target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC fat)
@ -94,7 +81,6 @@ src/compiler/codegen.cpp
src/compiler/lexer.cpp src/compiler/lexer.cpp
src/compiler/parser.cpp src/compiler/parser.cpp
src/compiler/ast.cpp src/compiler/ast.cpp
src/runtime_methods/sdl2.cpp
src/runtime_methods/console.cpp src/runtime_methods/console.cpp
src/runtime_methods/io.cpp src/runtime_methods/io.cpp
src/runtime_methods/std.cpp src/runtime_methods/std.cpp
@ -204,7 +190,7 @@ endif()
if(CROSSLANG_ENABLE_BINARIES) if(CROSSLANG_ENABLE_BINARIES)
if(CROSSLANG_ENABLE_SHARED) if(CROSSLANG_ENABLE_SHARED AND CROSSLANG_SHARED_EXECUTABLES)
set(CMAKE_MACOSX_RPATH 1) set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_WIN32_EXE_SRC}) add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_WIN32_EXE_SRC})

View File

@ -1,7 +1,7 @@
FROM onedev.site.tesses.net/tesses-framework/tesses-framework:latest FROM onedev.site.tesses.net/tesses-framework/tesses-framework:latest
RUN apt update -y && \ RUN apt update -y && \
apt install -y --no-install-recommends \ apt install -y --no-install-recommends \
libjansson-dev wget libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev && \ libjansson-dev wget && \
apt clean -y && \ apt clean -y && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
RUN mkdir /src && cd /src && git clone https://onedev.site.tesses.net/crosslang . && cd /src && mkdir build && cd build && cmake -S .. -B . && make -j4 && make install && cd / && rm -r /src RUN mkdir /src && cd /src && git clone https://onedev.site.tesses.net/crosslang . && cd /src && mkdir build && cd build && cmake -S .. -B . && make -j4 && make install && cd / && rm -r /src

View File

@ -7,7 +7,6 @@ Tesses Cross Language
- [TessesFramework](https://onedev.site.tesses.net/tesses-framework) - [TessesFramework](https://onedev.site.tesses.net/tesses-framework)
- Jansson (but can be turned off but is strongly recommended otherwise many programs will not work) - Jansson (but can be turned off but is strongly recommended otherwise many programs will not work)
- CMake - CMake
- SDL2 (but can be turned off)
## Use in docker (use my container) ## Use in docker (use my container)
```bash ```bash

View File

@ -13,6 +13,7 @@
#include <memory> #include <memory>
#include <cstring> #include <cstring>
#include <TessesFramework/TessesFramework.hpp> #include <TessesFramework/TessesFramework.hpp>
#include <regex>
#define TVM_MAJOR 1 #define TVM_MAJOR 1
#define TVM_MINOR 0 #define TVM_MINOR 0
#define TVM_PATCH 0 #define TVM_PATCH 0
@ -650,7 +651,7 @@ class Parser {
class MethodInvoker { class MethodInvoker {
}; };
using TObject = std::variant<int64_t,double,char,bool,std::string,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder>; using TObject = std::variant<int64_t,double,char,bool,std::string,std::regex,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder>;
class TRootEnvironment; class TRootEnvironment;
class GC; class GC;
class GC { class GC {
@ -842,7 +843,6 @@ class GC {
bool canRegisterDictionary; bool canRegisterDictionary;
bool canRegisterJSON; bool canRegisterJSON;
bool canRegisterCrypto; bool canRegisterCrypto;
bool canRegisterSDL2;
bool canRegisterRoot; bool canRegisterRoot;
bool canRegisterProcess; bool canRegisterProcess;
bool canRegisterPath; bool canRegisterPath;
@ -889,7 +889,6 @@ class GC {
static void RegisterDictionary(GC* gc, TRootEnvironment* env); static void RegisterDictionary(GC* gc, TRootEnvironment* env);
static void RegisterJson(GC* gc, TRootEnvironment* env); static void RegisterJson(GC* gc, TRootEnvironment* env);
static void RegisterCrypto(GC* gc,TRootEnvironment* env); static void RegisterCrypto(GC* gc,TRootEnvironment* env);
static void RegisterSDL2(GC* gc, TRootEnvironment* env);
static void RegisterRoot(GC* gc, TRootEnvironment* env); static void RegisterRoot(GC* gc, TRootEnvironment* env);
static void RegisterPath(GC* gc, TRootEnvironment* env); static void RegisterPath(GC* gc, TRootEnvironment* env);
static void RegisterOGC(GC* gc, TRootEnvironment* env); static void RegisterOGC(GC* gc, TRootEnvironment* env);
@ -1436,6 +1435,13 @@ class GC {
} }
bool GetObjectAsPath(TObject& obj, Tesses::Framework::Filesystem::VFSPath& path, bool allowString=true); bool GetObjectAsPath(TObject& obj, Tesses::Framework::Filesystem::VFSPath& path, bool allowString=true);
bool GetArgumentAsPath(std::vector<TObject>& args, size_t index, Tesses::Framework::Filesystem::VFSPath& path,bool allowString=true); bool GetArgumentAsPath(std::vector<TObject>& args, size_t index, Tesses::Framework::Filesystem::VFSPath& path,bool allowString=true);
typedef void (*PluginFunction)(GC* gc,TRootEnvironment* env);
#if !defined(_WIN32)
#define DLLEXPORT
#else
#define DLLEXPORT __declspec(dllexport)
#endif
#define CROSSLANG_PLUGIN(plugin) DLLEXPORT extern "C" void CrossLangPluginInit(GC* gc, TRootEnvironment* env) { plugin(gc,env); }
void LoadPlugin(GC* gc, TRootEnvironment* env, Tesses::Framework::Filesystem::VFSPath sharedObjectPath);
}; };

View File

@ -451,8 +451,7 @@ namespace Tesses::CrossLang
} }
else else
{ {
Flush(); buffer.push_back('$');
Symbol({read});
} }
break; break;
case '\"': case '\"':
@ -529,7 +528,6 @@ namespace Tesses::CrossLang
while(true) while(true)
{ {
int r = Read(); int r = Read();
std::cout << r <<std::endl;
lineInfo.Add(r); lineInfo.Add(r);
if(r == -1) if(r == -1)
{ {

View File

@ -32,7 +32,7 @@ namespace Tesses::CrossLang
mbedtls_entropy_init(&entropy); mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_ctr_drbg_init(&ctr_drbg);
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) "personalization_string", strlen("personalization_string")); int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) personalStr.c_str(), personalStr.size());
if(ret != 0) if(ret != 0)
{ {
mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_ctr_drbg_free(&ctr_drbg);
@ -290,30 +290,10 @@ namespace Tesses::CrossLang
static TObject Crypto_Base64Encode(GCList& ls, std::vector<TObject> args) static TObject Crypto_Base64Encode(GCList& ls, std::vector<TObject> args)
{ {
TByteArray* byteArray; TByteArray* byteArray;
int64_t offset;
int64_t length; if(GetArgumentHeap(args,0,byteArray))
if(GetArgumentHeap(args,0,byteArray) && GetArgument(args,1,offset) && GetArgument(args,2,length))
{ {
std::string str={}; return Tesses::Framework::Crypto::Base64_Encode(byteArray->data);
size_t olen;
size_t off = (size_t)offset;
size_t len = (size_t)length;
len = std::min(std::min(byteArray->data.size(),len-off),len);
if(len > 0)
{
mbedtls_base64_encode((uint8_t*)str.data(), 0, &olen, byteArray->data.data()+offset,len);
str.resize(olen);
if(mbedtls_base64_encode((uint8_t*)str.data(), olen, &olen, byteArray->data.data()+offset,len)==0)
{
return str;
}
}
} }
@ -324,23 +304,13 @@ namespace Tesses::CrossLang
std::string str; std::string str;
if(GetArgument(args,0,str)) if(GetArgument(args,0,str))
{ {
size_t olen;
TByteArray* bArray = TByteArray::Create(ls); TByteArray* bArray = TByteArray::Create(ls);
bArray->data = Tesses::Framework::Crypto::Base64_Decode(str);
return bArray;
mbedtls_base64_decode(bArray->data.data(), 0, &olen, (const uint8_t*)str.data(),str.size());
str.resize(olen);
if(mbedtls_base64_decode(bArray->data.data(), olen, &olen, (const uint8_t*)str.data(),str.size())==0)
{
return str;
}
} }
return ""; return nullptr;
} }
#endif #endif
void TStd::RegisterCrypto(GC* gc,TRootEnvironment* env) void TStd::RegisterCrypto(GC* gc,TRootEnvironment* env)

View File

@ -206,8 +206,60 @@ namespace Tesses::CrossLang
return nullptr; return nullptr;
}); });
// dict->DeclareFunction(gc,"getUrlWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->GetUrlWithQuery();}); // dict->DeclareFunction(gc,"getUrlWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->GetUrlWithQuery();});
dict->DeclareFunction(gc,"StartWebSocketSession","Start websocket session",{"dict"}, [ctx](GCList& ls,std::vector<TObject> args)->TObject {
TDictionary* dict;
if(GetArgumentHeap(args,0,dict))
{
ctx->StartWebSocketSession([dict,&ls](std::function<void(WebSocketMessage&)> sendMessage,std::function<void()> ping)->void{
GCList ls2(ls.GetGC());
dict->CallMethod(ls2,"Open",{
TExternalMethod::Create(ls2,"Send a message",{"messageTextOrByteArray"},[sendMessage](GCList& ls,std::vector<TObject> args)->TObject{
std::string str;
TByteArray* bArray;
if(GetArgument(args,0,str))
{
WebSocketMessage msg(str);
sendMessage(msg);
}
else if(GetArgumentHeap(args,0,bArray))
{
WebSocketMessage msg(bArray->data);
sendMessage(msg);
}
return nullptr;
}),
TExternalMethod::Create(ls2, "Ping client", {},[ping](GCList& ls,std::vector<TObject> args)->TObject {
ping();
return nullptr;
})
});
}, [dict,&ls](WebSocketMessage& msg)->void {
GCList ls2(ls.GetGC());
TObject v;
if(msg.isBinary)
{
auto r = TByteArray::Create(ls2);
r->data = msg.data;
v = r;
}
else
{
v = msg.ToString();
}
dict->CallMethod(ls2,"Receive",{v});
}, [dict,&ls](bool close)->void {
GCList ls2(ls.GetGC());
dict->CallMethod(ls2,"Close",{close});
});
}
return nullptr;
});
//dict->DeclareFunction(gc,"getOriginalPathWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->GetOriginalPathWithQuery();}); //dict->DeclareFunction(gc,"getOriginalPathWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->GetOriginalPathWithQuery();});
dict->DeclareFunction(gc,"getPath","Get path",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->path;}); dict->DeclareFunction(gc,"getPath","Get path",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->path;});
dict->DeclareFunction(gc,"setPath","Set path",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject { dict->DeclareFunction(gc,"setPath","Set path",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {
@ -247,6 +299,7 @@ namespace Tesses::CrossLang
TObjectHttpServer::TObjectHttpServer(GC* gc,TObject obj) TObjectHttpServer::TObjectHttpServer(GC* gc,TObject obj)
{ {
this->ls=new GCList(gc); this->ls=new GCList(gc);
this->ls->Add(obj);
this->obj = obj; this->obj = obj;
} }
@ -550,7 +603,28 @@ namespace Tesses::CrossLang
//http->DeclareFunction(gc, "ProcessServer","Process HTTP server connection",{"networkstream","server","ip","port","encrypted"},, Net_ProcessServer); //http->DeclareFunction(gc, "ProcessServer","Process HTTP server connection",{"networkstream","server","ip","port","encrypted"},, Net_ProcessServer);
http->DeclareFunction(gc, "MakeRequest", "Create an http request", {"url","$extra"}, Net_Http_MakeRequest); http->DeclareFunction(gc, "MakeRequest", "Create an http request", {"url","$extra"}, Net_Http_MakeRequest);
http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop); http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop);
//FileServer svr()
http->DeclareFunction(gc, "FileServer","Create a file server",{"path","allowlisting","spa"}, [](GCList& ls, std::vector<TObject> args)->TObject{
bool allowlisting;
bool spa;
if(GetArgument(args,1,allowlisting) && GetArgument(args,2,spa))
{
auto fserver = new FileServer(new TObjectVFS(ls.GetGC(),args[0]),true,allowlisting,spa);
return TServerHeapObject::Create(ls,fserver);
}
return nullptr;
});
http->DeclareFunction(gc, "MountableServer","Create a server you can mount to, must mount parents before child",{"root"}, [](GCList& ls, std::vector<TObject> args)->TObject{
if(args.size() > 0)
{
auto svr = new TObjectHttpServer(ls.GetGC(), args[0]);
auto svr2 = new MountableServer(svr,true);
return TServerHeapObject::Create(ls,svr2);
}
return nullptr;
});
dict->DeclareFunction(gc, "NetworkStream","Create a network stream",{"ipv6","datagram"},Net_NetworkStream); dict->DeclareFunction(gc, "NetworkStream","Create a network stream",{"ipv6","datagram"},Net_NetworkStream);
gc->BarrierBegin(); gc->BarrierBegin();
dict->SetValue("Http", http); dict->SetValue("Http", http);

View File

@ -1,281 +0,0 @@
#include "CrossLang.hpp"
#if defined(CROSSLANG_ENABLE_SDL2)
#include <SDL2/SDL.h>
#endif
namespace Tesses::CrossLang
{
#if defined(CROSSLANG_ENABLE_SDL2)
static void TObjectToRect(TDictionary* dict, SDL_Rect& rect)
{
int64_t number;
auto obj = dict->GetValue("x");
if(GetObject(obj,number)) rect.x = (int)number;
obj = dict->GetValue("y");
if(GetObject(obj,number)) rect.y = (int)number;
obj = dict->GetValue("w");
if(GetObject(obj,number)) rect.w = (int)number;
obj = dict->GetValue("h");
if(GetObject(obj,number)) rect.h = (int)number;
}
static TObject SDL2_RenderDrawRect(GCList& ls, std::vector<TObject> args)
{
TNative* nat;
TDictionary* dict;
if(GetArgumentHeap(args,0, nat) && GetArgumentHeap(args,1,dict))
{
SDL_Rect rect;
TObjectToRect(dict,rect);
return (int64_t)SDL_RenderDrawRect((SDL_Renderer*)nat->GetPointer(), &rect);
}
return nullptr;
}
static TObject SDL2_RenderFillRect(GCList& ls, std::vector<TObject> args)
{
TNative* nat;
TDictionary* dict;
if(GetArgumentHeap(args,0, nat) && GetArgumentHeap(args,1,dict))
{
SDL_Rect rect;
TObjectToRect(dict,rect);
return (int64_t)SDL_RenderFillRect((SDL_Renderer*)nat->GetPointer(), &rect);
}
return nullptr;
}
static TObject SDL2_PollEvent(GCList& ls, std::vector<TObject> args)
{
SDL_Event event;
if(SDL_PollEvent(&event))
{
TDictionary* dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Type",(int64_t)event.common.type);
dict->SetValue("Timestamp",(int64_t)event.common.timestamp);
switch(event.type)
{
case SDL_DROPBEGIN:
case SDL_DROPCOMPLETE:
dict->SetValue("WindowId",(int64_t)event.drop.windowID);
break;
case SDL_DROPFILE:
dict->SetValue("File", Tesses::Framework::Filesystem::VFSPath(std::string(event.drop.file)));
SDL_free(event.drop.file);
break;
case SDL_DROPTEXT:
dict->SetValue("WindowId",(int64_t)event.drop.windowID);
dict->SetValue("Text", std::string(event.drop.file));
SDL_free(event.drop.file);
break;
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN:
dict->SetValue("WindowId",(int64_t)event.button.windowID);
dict->SetValue("Which",(int64_t)event.button.which);
dict->SetValue("Button",(int64_t)event.button.button);
dict->SetValue("State",(int64_t)event.button.state);
dict->SetValue("Clicks",(int64_t)event.button.clicks);
dict->SetValue("X",(int64_t)event.button.x);
dict->SetValue("Y",(int64_t)event.button.y);
break;
case SDL_MOUSEMOTION:
dict->SetValue("WindowId",(int64_t)event.motion.windowID);
dict->SetValue("Which",(int64_t)event.motion.which);
dict->SetValue("State",(int64_t)event.motion.state);
dict->SetValue("X",(int64_t)event.motion.x);
dict->SetValue("Y",(int64_t)event.motion.y);
dict->SetValue("XRel",(int64_t)event.motion.xrel);
dict->SetValue("YRel",(int64_t)event.motion.yrel);
break;
case SDL_MOUSEWHEEL:
dict->SetValue("Direction", (int64_t)event.wheel.direction);
dict->SetValue("MouseX",(int64_t)event.wheel.mouseX);
dict->SetValue("MouseY",(int64_t)event.wheel.mouseY);
dict->SetValue("PreciseX",(double)event.wheel.preciseX);
dict->SetValue("PreciseY",(double)event.wheel.preciseY);
dict->SetValue("Which",(int64_t)event.wheel.which);
dict->SetValue("WindowId",(int64_t)event.wheel.windowID);
dict->SetValue("X",(int64_t)event.wheel.x);
dict->SetValue("Y",(int64_t)event.wheel.y);
break;
case SDL_KEYUP:
case SDL_KEYDOWN:
dict->SetValue("WindowId",(int64_t)event.key.windowID);
dict->SetValue("Repeat",(int64_t)event.key.repeat);
dict->SetValue("State",(int64_t)event.key.state);
{
TDictionary* dict2=TDictionary::Create(ls);
dict2->SetValue("Mod",(int64_t)event.key.keysym.mod);
dict2->SetValue("Scancode",(int64_t)event.key.keysym.scancode);
dict2->SetValue("Sym",(int64_t)event.key.keysym.sym);
dict->SetValue("Keysym",dict2);
}
break;
case SDL_EventType::SDL_FINGERMOTION:
dict->SetValue("Dx",event.tfinger.dx);
dict->SetValue("Dy",event.tfinger.dy);
//falls into SDL_FINGERUP/DOWN due to having same props
case SDL_EventType::SDL_FINGERUP:
case SDL_EventType::SDL_FINGERDOWN:
dict->SetValue("X",event.tfinger.x);
dict->SetValue("Y",event.tfinger.y);
dict->SetValue("FingerId",(int64_t)event.tfinger.fingerId);
dict->SetValue("Pressure",event.tfinger.pressure);
dict->SetValue("TouchId",(int64_t)event.tfinger.touchId);
dict->SetValue("WindowId",(int64_t)event.tfinger.windowID);
break;
case SDL_EventType::SDL_TEXTINPUT:
dict->SetValue("Text",event.text.text);
dict->SetValue("WindowId",(int64_t)event.text.windowID);
break;
case SDL_EventType::SDL_TEXTEDITING:
dict->SetValue("Text",event.edit.text);
dict->SetValue("Length",(int64_t)event.edit.length);
dict->SetValue("Start",(int64_t)event.edit.start);
dict->SetValue("WindowId",(int64_t)event.edit.windowID);
break;
case SDL_EventType::SDL_TEXTEDITING_EXT:
{
dict->SetValue("Text",event.editExt.text);
dict->SetValue("Length",(int64_t)event.editExt.length);
dict->SetValue("Start",(int64_t)event.editExt.start);
dict->SetValue("WindowId",(int64_t)event.editExt.windowID);
SDL_free(event.editExt.text);
}
break;
case SDL_EventType::SDL_WINDOWEVENT:
{
dict->SetValue("WindowId",(int64_t)event.window.windowID);
dict->SetValue("Event",(int64_t)event.window.event);
dict->SetValue("Data1",(int64_t)event.window.data1);
dict->SetValue("Data2",(int64_t)event.window.data2);
}
break;
}
ls.GetGC()->BarrierEnd();
return dict;
}
return nullptr;
}
static TObject SDL2_RenderPresent(GCList& ls, std::vector<TObject> args)
{
TNative* renderer;
if(GetArgumentHeap<TNative*>(args,0,renderer) && !renderer->GetDestroyed())
{
SDL_RenderPresent((SDL_Renderer*)renderer->GetPointer());
}
return Undefined();
}
static TObject SDL2_RenderClear(GCList& ls, std::vector<TObject> args)
{
TNative* renderer;
if(GetArgumentHeap<TNative*>(args,0,renderer) && !renderer->GetDestroyed())
{
return SDL_RenderClear((SDL_Renderer*)renderer->GetPointer())==0;
}
return Undefined();
}
static TObject SDL2_SetRenderDrawColor(GCList& ls, std::vector<TObject> args)
{
TNative* renderer;
int64_t r;
int64_t g;
int64_t b;
int64_t a;
if(GetArgumentHeap<TNative*>(args,0,renderer) && !renderer->GetDestroyed() && GetArgument<int64_t>(args,1,r) && GetArgument<int64_t>(args,2,g) && GetArgument<int64_t>(args,3,b) && GetArgument<int64_t>(args,4,a))
{
return SDL_SetRenderDrawColor((SDL_Renderer*)renderer->GetPointer(),(Uint8)r,(Uint8)g,(Uint8)b,(Uint8)a) == 0;
}
return Undefined();
}
static TObject SDL2_Init(GCList& ls, std::vector<TObject> args)
{
return (int64_t)SDL_Init(SDL_INIT_EVERYTHING);
}
static TObject SDL2_CreateRenderer(GCList& ls, std::vector<TObject> args)
{
TNative* window;
int64_t index;
int64_t flags;
if(GetArgumentHeap<TNative*>(args,0,window) && !window->GetDestroyed() && GetArgument<int64_t>(args,1,index) && GetArgument<int64_t>(args,2,flags))
{
SDL_Renderer* _renderer= SDL_CreateRenderer((SDL_Window*)window->GetPointer(),(int)index, (Uint32)flags);
if(_renderer == nullptr) return nullptr;
return TNative::Create(ls,_renderer,[](void* _ptr)-> void{
SDL_DestroyRenderer((SDL_Renderer*)_ptr);
});
}
return Undefined();
}
static TObject SDL2_CreateWindow(GCList& ls, std::vector<TObject> args)
{
if(args.size() == 6 && std::holds_alternative<std::string>(args[0]) && std::holds_alternative<int64_t>(args[1]) && std::holds_alternative<int64_t>(args[2]) && std::holds_alternative<int64_t>(args[3]) && std::holds_alternative<int64_t>(args[4]) && std::holds_alternative<int64_t>(args[5]))
{
SDL_Window* window = SDL_CreateWindow(std::get<std::string>(args[0]).c_str(),(int)std::get<int64_t>(args[1]),(int)std::get<int64_t>(args[2]),(int)std::get<int64_t>(args[3]),(int)std::get<int64_t>(args[4]),(uint32_t)std::get<int64_t>(args[5]));
if(window == nullptr) return nullptr;
return TNative::Create(ls,window,[](void* _ptr)->void {
SDL_Window* win = (SDL_Window*)_ptr;
if(win != nullptr) SDL_DestroyWindow(win);
});
}
return Undefined();
}
#endif
void TStd::RegisterSDL2(GC* gc, TRootEnvironment* env)
{
env->permissions.canRegisterSDL2=true;
#if defined(CROSSLANG_ENABLE_SDL2)
GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc, "RenderDrawRect","Draw a rectangle using SDL",{"renderer","dictionary_with_x_y_w_h"}, SDL2_RenderDrawRect);
dict->DeclareFunction(gc, "RenderFillRect","Fill a rectangle using SDL",{"renderer","dictionary_with_x_y_w_h"}, SDL2_RenderFillRect);
dict->DeclareFunction(gc, "RenderPresent","Present frame (you are finished with the frame)",{"renderer"},SDL2_RenderPresent);
dict->DeclareFunction(gc, "RenderClear","Clear renderer with renderer draw color",{"renderer"},SDL2_RenderClear);
dict->DeclareFunction(gc, "SetRenderDrawColor","Set SDL2 Renderer Draw Color",{"renderer","r","g","b","a"},SDL2_SetRenderDrawColor);
dict->DeclareFunction(gc, "CreateWindow","Create a SDL2 Window",{"title","x","y","w","h","flags"},SDL2_CreateWindow);
dict->DeclareFunction(gc, "CreateRenderer","Create a SDL2 Renderer",{"window",""},SDL2_CreateRenderer);
dict->DeclareFunction(gc, "PollEvent", "Get events",{},SDL2_PollEvent);
dict->DeclareFunction(gc, "Init", "Init SDL2",{},SDL2_Init);
gc->BarrierBegin();
dict->SetValue("DROPBEGIN",(int64_t)SDL_DROPBEGIN);
dict->SetValue("DROPCOMPLETE",(int64_t)SDL_DROPCOMPLETE);
dict->SetValue("DROPFILE",(int64_t)SDL_DROPFILE);
dict->SetValue("DROPTEXT",(int64_t)SDL_DROPTEXT);
dict->SetValue("MOUSEBUTTONUP",(int64_t)SDL_MOUSEBUTTONUP);
dict->SetValue("MOUSEBUTTONDOWN",(int64_t)SDL_MOUSEBUTTONDOWN);
dict->SetValue("MOUSEMOTION",(int64_t)SDL_MOUSEMOTION);
dict->SetValue("KEYUP",(int64_t)SDL_KEYUP);
dict->SetValue("KEYDOWN",(int64_t)SDL_KEYDOWN);
dict->SetValue("FINGERMOTION",(int64_t)SDL_FINGERMOTION);
dict->SetValue("FINGERUP",(int64_t)SDL_FINGERUP);
dict->SetValue("FINGERDOWN",(int64_t)SDL_FINGERDOWN);
dict->SetValue("TEXTINPUT",(int64_t)SDL_TEXTINPUT);
dict->SetValue("TEXTEDITING",(int64_t)SDL_TEXTEDITING);
dict->SetValue("TEXTEDITING_EXT",(int64_t)SDL_TEXTEDITING_EXT);
dict->SetValue("WINDOWEVENT",(int64_t)SDL_WINDOWEVENT);
dict->SetValue("QUIT",(int64_t)SDL_QUIT);
dict->SetValue("WINDOW_RESIZABLE",(int64_t)SDL_WINDOW_RESIZABLE);
dict->SetValue("WINDOW_BORDERLESS",(int64_t)SDL_WINDOW_BORDERLESS);
dict->SetValue("WINDOW_FULLSCREEN",(int64_t)SDL_WINDOW_FULLSCREEN);
dict->SetValue("WINDOW_MAXIMIZED",(int64_t)SDL_WINDOW_MAXIMIZED);
env->DeclareVariable("SDL2", dict);
gc->BarrierEnd();
#endif
}
}

View File

@ -39,7 +39,6 @@ namespace Tesses::CrossLang {
std::string name = p.ToString(); std::string name = p.ToString();
sqlite3* sqlite; sqlite3* sqlite;
std::cout << name << std::endl;
int rc =sqlite3_open(name.c_str(),&sqlite); int rc =sqlite3_open(name.c_str(),&sqlite);
if(rc) if(rc)
{ {

View File

@ -1,7 +1,61 @@
#include "CrossLang.hpp" #include "CrossLang.hpp"
#if defined(CROSSLANG_ENABLE_SHARED)
#if defined(_WIN32)
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#endif
namespace Tesses::CrossLang namespace Tesses::CrossLang
{ {
#if defined(CROSSLANG_ENABLE_SHARED)
class DL {
void* handle;
public:
DL(Tesses::Framework::Filesystem::VFSPath p)
{
Tesses::Framework::Filesystem::LocalFilesystem lfs;
std::string str = lfs.VFSPathToSystem(p);
#if defined(_WIN32)
handle = LoadLibraryExA(str.c_str() , NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
#else
handle = dlopen(str.c_str(), RTLD_LAZY);
#endif
}
template<typename T>
T Resolve(std::string name)
{
#if defined(_WIN32)
return (T)GetProcAddress(handle,name.c_str());
#else
return (T)dlsym(handle,name.c_str());
#endif
}
~DL()
{
#if defined(_WIN32)
FreeLibrary(handle);
#else
dlclose(handle);
#endif
}
};
#endif
void LoadPlugin(GC* gc, TRootEnvironment* env, Tesses::Framework::Filesystem::VFSPath sharedObjectPath)
{
#if defined(CROSSLANG_ENABLE_SHARED)
auto ptr = std::make_shared<DL>(sharedObjectPath);
auto cb = ptr->Resolve<PluginFunction>("CrossLangPluginInit");
if(cb == nullptr) return;
gc->RegisterEverythingCallback([ptr,cb](GC* gc, TRootEnvironment* env)-> void{
cb(gc,env);
});
cb(gc,env);
#endif
}
static TObject TypeIsDefined(GCList& ls,std::vector<TObject> args) static TObject TypeIsDefined(GCList& ls,std::vector<TObject> args)
{ {
if(args.empty()) return nullptr; if(args.empty()) return nullptr;
@ -67,6 +121,7 @@ namespace Tesses::CrossLang
static TObject TypeOf(GCList& ls, std::vector<TObject> args) static TObject TypeOf(GCList& ls, std::vector<TObject> args)
{ {
if(args.size() < 1) return "Undefined"; if(args.size() < 1) return "Undefined";
if(std::holds_alternative<std::regex>(args[0])) return "Regex";
if(std::holds_alternative<Undefined>(args[0])) return "Undefined"; if(std::holds_alternative<Undefined>(args[0])) return "Undefined";
if(std::holds_alternative<std::nullptr_t>(args[0])) return "Null"; if(std::holds_alternative<std::nullptr_t>(args[0])) return "Null";
if(std::holds_alternative<bool>(args[0])) return "Boolean"; if(std::holds_alternative<bool>(args[0])) return "Boolean";
@ -91,6 +146,7 @@ namespace Tesses::CrossLang
auto native = dynamic_cast<TNative*>(obj); auto native = dynamic_cast<TNative*>(obj);
auto vfs = dynamic_cast<TVFSHeapObject*>(obj); auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto strm = dynamic_cast<TStreamHeapObject*>(obj); auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto svr = dynamic_cast<TServerHeapObject*>(obj);
if(dynDict != nullptr) return "DynamicDictionary"; if(dynDict != nullptr) return "DynamicDictionary";
if(dynList != nullptr) return "DynamicList"; if(dynList != nullptr) return "DynamicList";
if(strm != nullptr) if(strm != nullptr)
@ -104,6 +160,20 @@ namespace Tesses::CrossLang
return "Stream"; return "Stream";
} }
if(svr != nullptr)
{
auto fileServer = dynamic_cast<Tesses::Framework::Http::FileServer*>(svr->server);
auto mountableServer = dynamic_cast<Tesses::Framework::Http::MountableServer*>(svr->server);
if(fileServer != nullptr)
{
return "FileServer";
}
if(mountableServer != nullptr)
{
return "MountableServer";
}
return "HttpServer";
}
if(vfs != nullptr) if(vfs != nullptr)
{ {
auto localVFS = dynamic_cast<Tesses::Framework::Filesystem::LocalFilesystem*>(vfs->vfs); auto localVFS = dynamic_cast<Tesses::Framework::Filesystem::LocalFilesystem*>(vfs->vfs);
@ -127,6 +197,7 @@ namespace Tesses::CrossLang
if(byteArray != nullptr) return "ByteArray"; if(byteArray != nullptr) return "ByteArray";
if(native != nullptr) return "Native"; if(native != nullptr) return "Native";
return "HeapObject"; return "HeapObject";
} }
@ -222,7 +293,6 @@ namespace Tesses::CrossLang
this->canRegisterPath=false; this->canRegisterPath=false;
this->canRegisterProcess=false; this->canRegisterProcess=false;
this->canRegisterRoot=false; this->canRegisterRoot=false;
this->canRegisterSDL2=false;
this->canRegisterSqlite=false; this->canRegisterSqlite=false;
this->canRegisterVM = false; this->canRegisterVM = false;
this->locked=false; this->locked=false;
@ -250,7 +320,59 @@ namespace Tesses::CrossLang
env->DeclareFunction(gc, "TypeIsVFS","Get whether object is a virtual filesystem",{"object"},TypeIsVFS); env->DeclareFunction(gc, "TypeIsVFS","Get whether object is a virtual filesystem",{"object"},TypeIsVFS);
env->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector<TObject> args)->TObject {
std::string str;
if(GetArgument(args,0,str))
{
std::regex regex(str);
return regex;
}
return nullptr;
});
env->DeclareFunction(gc, "Mutex", "Create mutex",{}, [](GCList& ls,std::vector<TObject> args)->TObject {
ls.GetGC()->BarrierBegin();
auto mtx = TDictionary::Create(ls);
auto native = TNative::Create(ls, new Tesses::Framework::Threading::Mutex(),[](void* ptr)->void{
delete static_cast<Tesses::Framework::Threading::Mutex*>(ptr);
});
auto lock = TExternalMethod::Create(ls,"Lock the mutex",{},[native](GCList& ls, std::vector<TObject> args)->TObject {
if(native->GetDestroyed()) return nullptr;
auto r = static_cast<Tesses::Framework::Threading::Mutex*>(native->GetPointer());
r->Lock();
return nullptr;
});
lock->watch.push_back(native);
mtx->SetValue("Lock",lock);
auto unlock = TExternalMethod::Create(ls,"Unlock the mutex",{},[native](GCList& ls, std::vector<TObject> args)->TObject {
if(native->GetDestroyed()) return nullptr;
auto r = static_cast<Tesses::Framework::Threading::Mutex*>(native->GetPointer());
r->Unlock();
return nullptr;
});
unlock->watch.push_back(native);
mtx->SetValue("Unlock",unlock);
auto trylock = TExternalMethod::Create(ls,"Try to lock the mutex, returns true if we aquire the lock, false if we can't due to another thread owning it",{},[native](GCList& ls, std::vector<TObject> args)->TObject {
if(native->GetDestroyed()) return true;
auto r = static_cast<Tesses::Framework::Threading::Mutex*>(native->GetPointer());
return r->TryLock();
});
trylock->watch.push_back(native);
mtx->SetValue("TryLock",trylock);
ls.GetGC()->BarrierEnd();
auto close = TExternalMethod::Create(ls,"Try to lock the mutex, returns true if we aquire the lock, false if we can't due to another thread owning it",{},[native](GCList& ls, std::vector<TObject> args)->TObject {
native->Destroy();
return nullptr;
});
close->watch.push_back(native);
mtx->SetValue("Close",close);
ls.GetGC()->BarrierEnd();
return mtx;
});
env->DeclareFunction(gc, "Thread","Create thread",{"callback"},[](GCList& ls, std::vector<TObject> args)-> TObject env->DeclareFunction(gc, "Thread","Create thread",{"callback"},[](GCList& ls, std::vector<TObject> args)-> TObject
{ {
if(args.size() == 1 && std::holds_alternative<THeapObjectHolder>(args[0])) if(args.size() == 1 && std::holds_alternative<THeapObjectHolder>(args[0]))
@ -282,7 +404,6 @@ namespace Tesses::CrossLang
RegisterJson(gc, env); RegisterJson(gc, env);
RegisterDictionary(gc, env); RegisterDictionary(gc, env);
RegisterCrypto(gc,env); RegisterCrypto(gc,env);
RegisterSDL2(gc, env);
RegisterOGC(gc, env); RegisterOGC(gc, env);
RegisterProcess(gc,env); RegisterProcess(gc,env);
@ -291,6 +412,14 @@ namespace Tesses::CrossLang
GCList ls(gc); GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls); TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc,"LoadNativePlugin","Load a native plugin, requires a dynamic linker and shared build of libcrosslang",{"path"},[gc,env](GCList& ls, std::vector<TObject> args)->TObject {
Tesses::Framework::Filesystem::VFSPath path;
if(GetArgumentAsPath(args,0,path))
{
LoadPlugin(gc,env,path);
}
return nullptr;
});
gc->BarrierBegin(); gc->BarrierBegin();
env->SetVariable("Reflection",dict); env->SetVariable("Reflection",dict);
gc->BarrierEnd(); gc->BarrierEnd();

View File

@ -1372,7 +1372,42 @@ namespace Tesses::CrossLang {
if(!cse.empty()) if(!cse.empty())
{ {
GCList ls(gc); GCList ls(gc);
if(std::holds_alternative<bool>(instance)) std::regex regex;
if(GetObject(instance,regex))
{
if(key == "Search")
{
std::string str;
if(GetArgument(args,0,str))
{
std::smatch m;
if(std::regex_search(str,m,regex))
{
auto myLs = TList::Create(ls);
gc->BarrierBegin();
for(auto item : m)
{
auto itm = TDictionary::Create(ls);
itm->SetValue("Offset", (int64_t)(item.first-str.begin()));
itm->SetValue("Length",(int64_t)item.length());
itm->SetValue("Matched",item.matched);
itm->SetValue("Text",item.str());
myLs->Add(itm);
}
cse.back()->Push(gc, myLs);
gc->BarrierEnd();
return false;
}
}
}
cse.back()->Push(gc, nullptr);
return false;
}
else if(std::holds_alternative<bool>(instance))
{ {
bool flag = std::get<bool>(instance); bool flag = std::get<bool>(instance);
if(key == "ToString") if(key == "ToString")
@ -1709,8 +1744,23 @@ namespace Tesses::CrossLang {
std::string str = std::get<std::string>(instance); std::string str = std::get<std::string>(instance);
if(key == "IndexOf") if(key == "IndexOf")
{ {
char c; std::string str2;
if(GetArgument<char>(args,0,c)) char c;
if(GetArgument(args,0,str2))
{
int64_t index = str.size();
GetArgument(args,1,index);
auto res = str.find(str2,(std::size_t)index);
if(res == std::string::npos)
cse.back()->Push(gc, (int64_t)-1);
else
cse.back()->Push(gc, (int64_t)res);
return false;
}
else if(GetArgument<char>(args,0,c))
{ {
int64_t index = 0; int64_t index = 0;
GetArgument(args,1,index); GetArgument(args,1,index);
@ -1727,8 +1777,22 @@ namespace Tesses::CrossLang {
} }
if(key == "LastIndexOf") if(key == "LastIndexOf")
{ {
std::string str2;
char c; char c;
if(GetArgument<char>(args,0,c)) if(GetArgument(args,0,str2))
{
int64_t index = str.size();
GetArgument(args,1,index);
auto res = str.rfind(str2,(std::size_t)index);
if(res == std::string::npos)
cse.back()->Push(gc, (int64_t)-1);
else
cse.back()->Push(gc, (int64_t)res);
return false;
}
else if(GetArgument<char>(args,0,c))
{ {
int64_t index = str.size(); int64_t index = str.size();
GetArgument(args,1,index); GetArgument(args,1,index);
@ -1914,7 +1978,71 @@ namespace Tesses::CrossLang {
auto env = dynamic_cast<TEnvironment*>(obj); auto env = dynamic_cast<TEnvironment*>(obj);
auto rootEnv = dynamic_cast<TRootEnvironment*>(obj); auto rootEnv = dynamic_cast<TRootEnvironment*>(obj);
auto callable = dynamic_cast<TCallable*>(obj); auto callable = dynamic_cast<TCallable*>(obj);
auto svr = dynamic_cast<TServerHeapObject*>(obj);
if(svr != nullptr)
{
auto mountable = dynamic_cast<Tesses::Framework::Http::MountableServer*>(svr->server);
if(mountable != nullptr)
{
if(key == "Mount")
{
Tesses::Framework::Filesystem::VFSPath p;
if(args.size() > 1 && GetArgumentAsPath(args,0,p))
{
mountable->Mount(p.ToString(),new TObjectHttpServer(gc,args[1]),true);
cse.back()->Push(gc,nullptr);
return false;
}
}
if(key == "Unmount")
{
Tesses::Framework::Filesystem::VFSPath p;
if(GetArgumentAsPath(args,0,p))
{
mountable->Unmount(p.ToString());
cse.back()->Push(gc,nullptr);
return false;
}
}
}
if(key == "Handle")
{
if(GetArgumentHeap(args,0,dict))
{
gc->BarrierBegin();
auto nat = dict->GetValue("native");
gc->BarrierEnd();
TNative* nat2;
if(GetObjectHeap(nat,nat2))
{
if(!nat2->GetDestroyed())
{
auto ctx = static_cast<Tesses::Framework::Http::ServerContext*>(nat2->GetPointer());
if(ctx != nullptr)
{
cse.back()->Push(gc,svr->server->Handle(*ctx));
return false;
}
}
}
}
cse.back()->Push(gc,false);
return false;
}
if(key == "Close")
{
svr->Close();
cse.back()->Push(gc, nullptr);
return false;
}
cse.back()->Push(gc,Undefined());
return false;
}
if(rootEnv != nullptr) if(rootEnv != nullptr)
{ {
//TStd::RegisterCrypto //TStd::RegisterCrypto
@ -1968,8 +2096,6 @@ namespace Tesses::CrossLang {
if(myEnv->permissions.canRegisterRoot && !rootEnv->permissions.locked) if(myEnv->permissions.canRegisterRoot && !rootEnv->permissions.locked)
TStd::RegisterRoot(gc, rootEnv); TStd::RegisterRoot(gc, rootEnv);
if(myEnv->permissions.canRegisterSDL2 && !rootEnv->permissions.locked)
TStd::RegisterSDL2(gc, rootEnv);
if(myEnv->permissions.canRegisterSqlite && !rootEnv->permissions.locked) if(myEnv->permissions.canRegisterSqlite && !rootEnv->permissions.locked)
TStd::RegisterSqlite(gc, rootEnv); TStd::RegisterSqlite(gc, rootEnv);
@ -2066,13 +2192,6 @@ namespace Tesses::CrossLang {
return false; return false;
} }
if(key == "RegisterSDL2")
{
if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterSDL2) && !rootEnv->permissions.locked)
TStd::RegisterSDL2(gc, rootEnv);
cse.back()->Push(gc,nullptr);
return false;
}
if(key == "RegisterSqlite") if(key == "RegisterSqlite")
{ {
if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterSqlite) && !rootEnv->permissions.locked) if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterSqlite) && !rootEnv->permissions.locked)
@ -4457,10 +4576,57 @@ namespace Tesses::CrossLang {
} }
else else
{ {
for(size_t i = 0; i < std::min(args.size(),closure->closure->args.size()); i++) auto requiredArguments = [closure]()->size_t
{ {
cse->env->DeclareVariable(closure->closure->args[i], args[i]); for(size_t i =0;i<closure->closure->args.size();i++)
{
if(closure->closure->args[i].find("$") == 0)
{
return i;
}
}
return closure->closure->args.size();
};
auto optionalArguments = [closure](size_t argLen)->size_t
{
for(size_t i =0;i<closure->closure->args.size();i++)
{
if(closure->closure->args[i].find("$$") == 0)
{
return std::min(argLen,i);
}
}
return std::min(argLen,closure->closure->args.size());
};
auto trimStart = [](std::string txt)->std::string {
if(txt.empty()) return {};
if(txt[0] != '$') return txt;
auto idx = txt.find_first_not_of('$');
if(idx == std::string::npos) return {};
return txt.substr(idx);
};
size_t required = requiredArguments();
if(args.size() < requiredArguments())
{
throw VMException("Called a function that expected at least " + std::to_string(required) + " args but got " + std::to_string(args.size()));
} }
size_t i;
for( i = 0; i < optionalArguments(args.size()); i++)
{
cse->env->DeclareVariable(trimStart(closure->closure->args[i]), args[i]);
}
if(i == closure->closure->args.size()-1)
{
auto lsArgs = TList::Create(ls);
for(;i<args.size(); i++)
lsArgs->Add(args[i]);
cse->env->DeclareVariable(trimStart(closure->closure->args[i]), lsArgs);
i = args.size();
}
if(i<args.size())
throw VMException("Too many arguments");
} }
current_function = cse; current_function = cse;