diff --git a/.vscode/launch.json b/.vscode/launch.json index 1b95120..68c6be3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,8 +8,8 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/builds/linux/crosslang", - "args": [], + "program": "${workspaceFolder}/builds/linux/crossvm", + "args": ["builds/linux/out-1.0.0.0-prod.crvm"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], diff --git a/CMakeLists.txt b/CMakeLists.txt index 336d829..9735576 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,7 @@ src/vm/gc.cpp src/vm/gclist.cpp src/vm/vm.cpp src/bitconverter.cpp +src/archive.cpp ) if(CROSSLANG_ENABLE_SQLITE) @@ -163,37 +164,72 @@ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesCrossLang) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/TessesCrossLangConfig.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesCrossLang) +else() +if(CROSSLANG_ENABLE_SHARED) +install(TARGETS crosslang_shared + EXPORT TessesCrossLangTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) +endif() endif() if(CROSSLANG_ENABLE_BINARIES) -if(CROSSLANG_ENABLE_STATIC) +if(CROSSLANG_ENABLE_SHARED) +set(CMAKE_MACOSX_RPATH 1) +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +add_executable(crossc src/crosslangcompiler.cpp) +add_executable(crossvm src/crosslangvm.cpp) +add_executable(crossint src/crosslanginterperter.cpp) +add_executable(crossdump src/crosslangdump.cpp) +add_executable(crosslang src/crosslang.cpp) +add_executable(crossarchiveextract src/crossarchiveextract.cpp) +add_executable(crossarchivecreate src/crossarchivecreate.cpp) +target_link_libraries(crossc PUBLIC crosslang_shared) +target_link_libraries(crossvm PUBLIC crosslang_shared) +target_link_libraries(crossint PUBLIC crosslang_shared) +target_link_libraries(crossdump PUBLIC crosslang_shared) +target_link_libraries(crosslang PUBLIC crosslang_shared) +target_link_libraries(crossarchiveextract PUBLIC crosslang_shared) +target_link_libraries(crossarchivecreate PUBLIC crosslang_shared) +elseif(CROSSLANG_ENABLE_STATIC) add_executable(crossc src/crosslangcompiler.cpp) add_executable(crossvm src/crosslangvm.cpp) add_executable(crossint src/crosslanginterperter.cpp) add_executable(crossdump src/crosslangdump.cpp) add_executable(crosslang src/crosslang.cpp) +add_executable(crossarchiveextract src/crossarchiveextract.cpp) +add_executable(crossarchivecreate src/crossarchivecreate.cpp) target_link_libraries(crossc PUBLIC crosslang_static) target_link_libraries(crossvm PUBLIC crosslang_static) target_link_libraries(crossint PUBLIC crosslang_static) target_link_libraries(crossdump PUBLIC crosslang_static) target_link_libraries(crosslang PUBLIC crosslang_static) +target_link_libraries(crossarchiveextract PUBLIC crosslang_static) +target_link_libraries(crossarchivecreate PUBLIC crosslang_static) else() add_executable(crossc src/crosslangcompiler.cpp ${CROSSLANG_SOURCE}) add_executable(crossvm src/crosslangvm.cpp ${CROSSLANG_SOURCE}) add_executable(crossint src/crosslanginterperter.cpp ${CROSSLANG_SOURCE}) add_executable(crossdump src/crosslangdump.cpp ${CROSSLANG_SOURCE}) add_executable(crosslang src/crosslang.cpp ${CROSSLANG_SOURCE}) +add_executable(crossarchiveextract src/crossarchiveextract.cpp ${CROSSLANG_SOURCE}) +add_executable(crossarchivecreate src/crossarchivecreate.cpp ${CROSSLANG_SOURCE}) CROSSLANG_LINK_DEPS(crossc) CROSSLANG_LINK_DEPS(crossvm) CROSSLANG_LINK_DEPS(crossint) CROSSLANG_LINK_DEPS(crosslang) CROSSLANG_LINK_DEPS(crossdump) +CROSSLANG_LINK_DEPS(crossarchiveextract) +CROSSLANG_LINK_DEPS(crossarchivecreate) endif() install(TARGETS crossc DESTINATION bin) install(TARGETS crossvm DESTINATION bin) install(TARGETS crossint DESTINATION bin) install(TARGETS crossdump DESTINATION bin) install(TARGETS crosslang DESTINATION bin) +install(TARGETS crossarchiveextract DESTINATION bin) +install(TARGETS crossarchivecreate DESTINATION bin) endif() include(InstallRequiredSystemLibraries) set(CPACK_PACKAGE_CONTACT "Mike Nolan ") diff --git a/Config.cmake.in b/Config.cmake.in index e3b6488..3db5823 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -3,3 +3,13 @@ include("${CMAKE_CURRENT_LIST_DIR}/TessesCrossLangTargets.cmake") check_required_components(TessesCrossLang) +find_package(TessesFramework REQUIRED) +if(@CROSSLANG_ENABLE_SDL2@) +find_package(SDL2 REQUIRED) +find_package(SDL2_ttf REQUIRED) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube") + +else() +find_package(SDL2_image REQUIRED) +endif() +endif() \ No newline at end of file diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index 8516c65..39b0ef9 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -232,6 +232,7 @@ namespace Tesses::CrossLang { return true; } + std::string ToString() { std::string str={}; @@ -263,6 +264,9 @@ namespace Tesses::CrossLang { }; + void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name,TVMVersion version,std::string info); + std::pair,std::string> CrossArchiveExtract(Tesses::Framework::Streams::Stream* strm,Tesses::Framework::Filesystem::VFS* vfs); + @@ -1162,19 +1166,42 @@ class GC { bool BAnd(GC* gc); bool ExecuteFunction(GC* gc); bool ExecuteMethod(GC* gc); - void GetVariable(GC* gc); - void SetVariable(GC* gc); + bool GetVariable(GC* gc); + bool SetVariable(GC* gc); bool GetField(GC* gc); bool SetField(GC* gc); bool GetArray(GC* gc); bool SetArray(GC* gc); - void DeclareVariable(GC* gc); - void PushLong(GC* gc); - void PushDouble(GC* gc); - void PushChar(GC* gc); - void PushString(GC* gc); - void PushClosure(GC* gc,bool ownScope=true); - void PushResource(GC* gc); + bool DeclareVariable(GC* gc); + bool PushLong(GC* gc); + bool PushDouble(GC* gc); + bool PushChar(GC* gc); + bool PushString(GC* gc); + bool PushClosure(GC* gc); + bool PushScopelessClosure(GC* gc); + bool PushResource(GC* gc); + bool Illegal(GC* gc); + bool Throw(GC* gc); + bool Jump(GC* gc); + bool JumpConditional(GC* gc); + bool JumpUndefined(GC* gc); + bool Defer(GC* gc); + bool TryCatch(GC* gc); + bool Return(GC* gc); + bool ScopeBegin(GC* gc); + bool ScopeEnd(GC* gc); + bool ScopeEndTimes(GC* gc); + bool PushTrue(GC* gc); + bool PushFalse(GC* gc); + bool PushNull(GC* gc); + bool PushUndefined(GC* gc); + bool CreateDictionary(GC* gc); + bool CreateArray(GC* gc); + bool AppendList(GC* gc); + bool AppendDictionary(GC* gc); + bool Pop(GC* gc); + bool Dup(GC* gc); + bool Nop(GC* gc); public: static InterperterThread* Create(GCList* ls); static InterperterThread* Create(GCList& ls); diff --git a/src/archive.cpp b/src/archive.cpp new file mode 100644 index 0000000..fe7e8fc --- /dev/null +++ b/src/archive.cpp @@ -0,0 +1,291 @@ +#include "CrossLang.hpp" +#include +namespace Tesses::CrossLang +{ + + void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name, TVMVersion version, std::string info) + { + static std::vector error_message_byte_code = { + PUSHSTRING, + 0, + 0, + 0, + 2, + GETVARIABLE, + PUSHSTRING, + 0, + 0, + 0, + 3, + PUSHSTRING, + 0, + 0, + 0, + 4, + PUSHLONG, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + CALLMETHOD, + RET + }; + auto writeInt = [](Tesses::Framework::Streams::Stream* strm,uint32_t number)->void{ + uint8_t buff[4]; + BitConverter::FromUint32BE(buff[0],number); + strm->WriteBlock(buff,4); + }; + auto writeStr = [&writeInt](Tesses::Framework::Streams::Stream* strm,std::string text)->void { + writeInt(strm,(uint32_t)text.size()); + strm->WriteBlock((const uint8_t*)text.c_str(),text.size()); + }; + + std::vector strs; + strs.push_back(name); + strs.push_back(info); + strs.push_back("Console"); + strs.push_back("WriteLine"); + strs.push_back("You are trying to run a crvm archive, stop it you won't get anywhere!\nUse crossarchiveextract instead."); + + std::vector resources; + + auto ensureResource = [&resources](std::string path)->uint32_t { + for(uint32_t i = 0; i < (uint32_t)resources.size(); i++) + { + if(resources[i] == path) return i; + } + uint32_t index = (uint32_t)resources.size(); + resources.push_back(path); + return index; + }; + auto ensureString = [&strs](std::string str)->uint32_t { + for(uint32_t i = 0; i < (uint32_t)strs.size(); i++) + { + if(strs[i] == str) return i; + } + uint32_t index = (uint32_t)strs.size(); + strs.push_back(str); + return index; + }; + Tesses::Framework::Streams::MemoryStream ms(true); + + std::function walkFS = [vfs,&ensureString,&ensureResource,&ms,&walkFS,&writeInt](Tesses::Framework::Filesystem::VFSPath path)->void { + + if(vfs->DirectoryExists(path)) + { + + ms.WriteByte(1); + std::vector paths; + for(auto item : vfs->EnumeratePaths(path)) + { + if(!item.relative && item.path.size() == 1 && item.path[0] == "__resdir_tmp") continue; + if(vfs->DirectoryExists(item) || vfs->RegularFileExists(item)) + paths.push_back(item.GetFileName()); + } + writeInt(&ms,(uint32_t)paths.size()); + for(auto item : paths) + { + writeInt(&ms,ensureString(item)); + walkFS(path / item); + } + } + else if(vfs->RegularFileExists(path)) + { + ms.WriteByte(0); + writeInt(&ms,ensureResource(path.ToString())); + } + }; + + walkFS(std::string("/")); + + uint8_t main_header[18]; + memcpy(main_header,"TCROSSVM",8); + TVMVersion rtVersion(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE); + rtVersion.ToArray(main_header+8); + version.ToArray(main_header+13); + strm->WriteBlock(main_header,sizeof(main_header)); + writeInt(strm,(uint32_t)(5+resources.size())); + strm->WriteBlock((const uint8_t*)"STRS",4); + uint32_t sz=4; + for(auto str : strs) + sz += (uint32_t)(4 + str.size()); + writeInt(strm,sz); + writeInt(strm,(uint32_t)strs.size()); + for(auto str : strs) + { + writeStr(strm,str); + } + strm->WriteBlock((const uint8_t*)"NAME",4); + writeInt(strm,4); + writeInt(strm,0); + strm->WriteBlock((const uint8_t*)"INFO",4); + writeInt(strm,4); + writeInt(strm,1); + strm->WriteBlock((const uint8_t*)"CHKS",4); + writeInt(strm,(uint32_t)(12+error_message_byte_code.size())); + writeInt(strm,1); + writeInt(strm,0); + writeInt(strm,(uint32_t)error_message_byte_code.size()); + strm->WriteBlock(error_message_byte_code.data(),error_message_byte_code.size()); + + + + for(auto res : resources) + { + strm->WriteBlock((const uint8_t*)"RESO",4); + auto strm2 = vfs->OpenFile(res,"rb"); + writeInt(strm,(uint32_t)strm2->GetLength()); + strm2->CopyTo(strm); + delete strm2; + } + strm->WriteBlock((const uint8_t*)"ARCV",4); + writeInt(strm,(uint32_t)ms.GetLength()); + ms.Seek(0,Tesses::Framework::Streams::SeekOrigin::Begin); + ms.CopyTo(strm); + } + std::pair,std::string> CrossArchiveExtract(Tesses::Framework::Streams::Stream* strm,Tesses::Framework::Filesystem::VFS* vfs) + { + auto ensure = [strm](uint8_t* buffer,size_t count)->void{ + + size_t read = strm->ReadBlock(buffer, count); + if(read < count) throw VMException("End of file, could not read " + std::to_string((int64_t)count) + " byte(s)., offset=" + std::to_string(strm->GetLength())); + }; + auto ensureInt = [&ensure]()->uint32_t { + uint8_t buffer[4]; + ensure(buffer,4); + return BitConverter::ToUint32BE(buffer[0]); + }; + auto ensureStr = [&ensure,&ensureInt]()-> std::string { + auto len = ensureInt(); + if(len == 0) return {}; + std::string str={}; + str.resize((size_t)len); + ensure((uint8_t*)str.data(),str.size()); + return str; + }; + std::vector strs; + auto getStr = [&ensure,&ensureInt,&strs]()-> std::string { + auto index = ensureInt(); + if(index > strs.size()) throw VMException("String does not exist in TCrossVM file, expected string index: " + std::to_string(index) + ", total strings: " + std::to_string(strs.size())); + return strs[index]; + }; + uint8_t main_header[18]; + ensure(main_header,sizeof(main_header)); + if(strncmp((const char*)main_header,"TCROSSVM",8) != 0) throw VMException("Invalid TCrossVM image."); + TVMVersion version(main_header+8); + if(version.CompareToRuntime() == 1) + { + throw VMException("Runtime is too old."); + } + TVMVersion v2(main_header+13); + std::string name; + std::string info; + + + size_t _len = (size_t)ensureInt(); + + char table_name[4]; + + uint32_t resource_id = 0; + + Tesses::Framework::Filesystem::VFSPath tmpDir("/__resdir_tmp"); + + vfs->CreateDirectory(tmpDir); + for(size_t i = 0;i < _len; i++) + { + ensure((uint8_t*)table_name,sizeof(table_name)); + size_t tableLen = (size_t)ensureInt(); + if(strncmp(table_name,"NAME",4) == 0) + { + name = getStr(); + } + else if(strncmp(table_name,"INFO",4) == 0) + { + info = getStr(); + + } + + else if(strncmp(table_name,"RESO",4) == 0) //resources (using embed) + { + + auto path = tmpDir /std::to_string(resource_id); + + auto strm2 = vfs->OpenFile(path,"wb"); + size_t read = 0; + size_t offset = 0; + uint8_t buff[1024]; + do { + read = std::min(std::min(tableLen-offset,tableLen), sizeof(buff)); + read = strm->Read(buff,read); + if(read > 0) + strm2->WriteBlock(buff,read); + offset+=read; + } while(read > 0); + delete strm2; + resource_id++; + } + + else if(strncmp(table_name,"STRS",4) == 0) //strings + { + size_t strsLen = (size_t)ensureInt(); + for(size_t j = 0;j < strsLen;j++) + { + strs.push_back(ensureStr()); + } + } + else if(strncmp(table_name,"ARCV",4) == 0) + { + size_t offset = 0; + + std::function walkEntry = [strm,vfs,&getStr,&ensureInt,&tmpDir,&tableLen,&offset,&walkEntry](Tesses::Framework::Filesystem::VFSPath path)->void { + if(offset + 1 > tableLen) return; + uint8_t type = strm->ReadByte(); + offset++; + if(type == 1) + { + //ISDIR + vfs->CreateDirectory(path); + if(offset + 4 > tableLen) return; + uint32_t count = ensureInt(); + offset +=4; + for(uint32_t i = 0; i < count; i++) + { + if(offset + 4 > tableLen) return; + std::string name = getStr(); + offset +=4; + walkEntry(path / name); + } + } + else if(type == 0) + { + if(offset + 4 > tableLen) return; + uint32_t index = ensureInt(); + auto fSrc = tmpDir /std::to_string(index); + vfs->MoveFile(fSrc, path); + } + }; + + walkEntry(std::string("/")); + } + else + { + if(strm->CanSeek()) + { + strm->Seek((int64_t)tableLen,Tesses::Framework::Streams::SeekOrigin::Current); + } + else{ + uint8_t* buffer=new uint8_t[tableLen]; + ensure(buffer,tableLen); + delete buffer; + } + } + } + vfs->DeleteDirectoryRecurse(tmpDir); + + return std::pair,std::string>(std::pair(name,v2),info); + } +} \ No newline at end of file diff --git a/src/crossarchivecreate.cpp b/src/crossarchivecreate.cpp new file mode 100644 index 0000000..d01f684 --- /dev/null +++ b/src/crossarchivecreate.cpp @@ -0,0 +1,83 @@ +#include +#include +using namespace Tesses::CrossLang; +using namespace Tesses::Framework::Filesystem; +using namespace Tesses::Framework::Streams; +void Help(const char* filename) +{ + printf("USAGE: %s [OPTIONS] \n", filename); + printf("OPTIONS:\n"); + printf(" -i: Set info (ex {\"maintainer\": \"Mike Nolan\", \"repo\": \"https://example.com/\", \"homepage\": \"https://example.com/\",\"license\":\"MIT\"})\n"); + printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n"); + printf(" -n: Set name (MyAppOrLibName defaults to out)\n"); + printf(" -h, --help: Prints help\n"); + printf("Options except for help have flag with arg like this: -F ARG\n"); + exit(1); +} +int main(int argc, char** argv) +{ + std::string name="out"; + std::string info="{}"; + TVMVersion version; + std::vector args; + for(int i = 1; i < argc; i++) + { + if(strcmp(argv[i],"--help") == 0 || strcmp(argv[i],"-h")==0) + { + Help(argv[0]); + } + else if(strcmp(argv[i], "-i") == 0) + { + i++; + if(i < argc) + { + info = argv[i]; + } + } + else if(strcmp(argv[i], "-n") == 0) + { + i++; + if(i < argc) + { + name = argv[i]; + } + } + else if(strcmp(argv[i], "-v") == 0) + { + i++; + if(i < argc) + { + + if(!TVMVersion::TryParse(argv[i],version)) + { + printf("ERROR: Invalid syntax for version\n"); + printf("Expected MAJOR[.MINOR[.PATCH[.BUILD[-dev,-alpha,-beta,-prod]]]]\n"); + exit(1); + } + } + } + else { + args.push_back(argv[i]); + } + } + + if(args.size() < 2) Help(argv[0]); + + + LocalFilesystem fs; + auto path = fs.SystemToVFSPath(args[0]); + fs.CreateDirectory(path); + SubdirFilesystem sdfs(&fs,path,false); + + FILE* f = fopen(args[1].c_str(),"wb"); + if(f == NULL) + { + printf("ERROR: could not open %s\n", args[1].c_str()); + return 1; + } + + FileStream strm(f,true,"wb",true); + CrossArchiveCreate(&sdfs,&strm,name,version,info); + + return 0; +} \ No newline at end of file diff --git a/src/crossarchiveextract.cpp b/src/crossarchiveextract.cpp new file mode 100644 index 0000000..b4fb27a --- /dev/null +++ b/src/crossarchiveextract.cpp @@ -0,0 +1,34 @@ +#include +#include +using namespace Tesses::CrossLang; +using namespace Tesses::Framework::Filesystem; +using namespace Tesses::Framework::Streams; + +int main(int argc, char** argv) +{ + if(argc < 3) + { + printf("USAGE: %s \n", argv[0]); + return 1; + } + + LocalFilesystem fs; + SubdirFilesystem sdfs(&fs,std::string(argv[2]),false); + + FILE* f = fopen(argv[1],"rb"); + if(f == NULL) + { + printf("ERROR: could not open %s\n", argv[1]); + return 1; + } + + FileStream strm(f,true,"rb",true); + + auto res = CrossArchiveExtract(&strm,&sdfs); + + std::cout << "Crvm Name: " << res.first.first << std::endl; + std::cout << "Crvm Version: " << res.first.second.ToString() << std::endl; + std::cout << "Crvm Info: " << std::endl << res.second << std::endl; + + return 0; +} \ No newline at end of file diff --git a/src/crosslangcompiler.cpp b/src/crosslangcompiler.cpp index 7c22327..2c19c91 100644 --- a/src/crosslangcompiler.cpp +++ b/src/crosslangcompiler.cpp @@ -40,10 +40,7 @@ int main(int argc, char** argv) std::string name="out"; std::string info="{}"; TVMVersion version; - if(argc < 2) - { - Help(argv[0]); - } + for(int i = 1; i < argc; i++) { @@ -135,7 +132,10 @@ int main(int argc, char** argv) source.push_back(argv[i]); } } - + if(source.empty()) + { + Help(argv[0]); + } std::vector tokens; diff --git a/src/crosslangvm.cpp b/src/crosslangvm.cpp index edae70d..76d1140 100644 --- a/src/crosslangvm.cpp +++ b/src/crosslangvm.cpp @@ -17,8 +17,9 @@ int main(int argc, char** argv) GCList ls(gc); TRootEnvironment* env = TRootEnvironment::Create(ls, TDictionary::Create(ls)); Tesses::Framework::Filesystem::LocalFilesystem fs; - env->LoadFileWithDependencies(&gc, &fs, fs.SystemToVFSPath(argv[1])); TStd::RegisterStd(&gc,env); + env->LoadFileWithDependencies(&gc, &fs, fs.SystemToVFSPath(argv[1])); + TList* args = TList::Create(ls); for(int arg=1;argAdd(std::string(argv[arg])); diff --git a/src/runtime_methods/crypto.cpp b/src/runtime_methods/crypto.cpp index 1b7d719..a43e889 100644 --- a/src/runtime_methods/crypto.cpp +++ b/src/runtime_methods/crypto.cpp @@ -19,558 +19,8 @@ namespace Tesses::CrossLang { #if defined(CROSSLANG_ENABLE_MBED) - static void my_debug(void *ctx, int level, - const char *file, int line, - const char *str) -{ - ((void) level); + - fprintf(stderr, "%s:%04d: %s", file, line, str); - fflush(stderr); -} - class TlsClientStream { - GCList* ls; - TCallable* read; - TCallable* write; - TCallable* close; - TByteArray* readBuffer; - TByteArray* writeBuffer; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_ssl_context ssl; - mbedtls_ssl_config conf; - mbedtls_x509_crt cachain; - - - static int strm_send(void* ctx,const unsigned char* buf,size_t len) - { - TlsClientStream* strm = static_cast(ctx); - strm->writeBuffer->data.resize(len); - memcpy(strm->writeBuffer->data.data(),buf,len); - - auto res = strm->write->Call(*strm->ls,{strm->writeBuffer}); - if(std::holds_alternative(res)) - { - auto num = std::get(res); - return (int)num; - } - return -1; - } - static int strm_recv(void* ctx,unsigned char* buf,size_t len) - { - TlsClientStream* strm = static_cast(ctx); - strm->readBuffer->data.resize(len); - - auto res = strm->read->Call(*strm->ls,{strm->readBuffer}); - if(std::holds_alternative(res)) - { - auto num = std::get(res); - if(num < 0) return (int)num; - size_t read = (size_t)num; - if(read > len) read = len; - memcpy(buf,strm->readBuffer->data.data(), read); - return read; - } - return -1; - - //return (int)strm->Read((uint8_t*)buf,len); - } - public: - void Close() - { - close->Call(*ls,{}); - } - bool success=false; - bool isDoneReading = false; - int64_t Read(uint8_t* buffer, size_t len) - { - if(isDoneReading) return 0; - int64_t r = (int64_t)mbedtls_ssl_read(&ssl,buffer,len); - if(r == 0) isDoneReading=true; - if(r == -30848) - { - isDoneReading = true; - return 0; - } - return r; - } - int64_t Write(uint8_t* buffer, size_t len) - { - return (int64_t)mbedtls_ssl_write(&ssl,buffer,len); - } - - TlsClientStream(GC* gc,std::string domain,std::string chain,bool verify, TCallable* read, TCallable* write, TCallable* close) - { - ls = new GCList(gc); - ls->Add(read); - ls->Add(write); - ls->Add(close); - this->read = read; - this->write = write; - this->close = close; - readBuffer = TByteArray::Create(ls); - writeBuffer = TByteArray::Create(ls); - - mbedtls_ssl_init(&ssl); - mbedtls_ssl_config_init(&conf); - mbedtls_x509_crt_init(&cachain); - mbedtls_ctr_drbg_init(&ctr_drbg); - mbedtls_entropy_init(&entropy); - - const char* pers = "CrossLangTLS"; - - int ret=0; - - - -#if defined(MBEDTLS_USE_PSA_CRYPTO) - psa_status_t status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n", - (int) status); - return; - } -#endif - - if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, - (const unsigned char *) pers, - strlen(pers))) != 0) - { - printf("FAILED mbedtls_ctr_drbg_seed\n"); - return; - } - - if(ret != 0) { printf("FAILED mbedtls_x509_crt_parse cert %i\n",ret); return;} - ret = mbedtls_x509_crt_parse(&cachain, (const unsigned char *) chain.c_str(), - chain.size()+1); - - if(ret != 0) {printf("FAILED mbedtls_x509_crt_parse chain %i\n",ret); return;} - - - - if((ret = mbedtls_ssl_config_defaults(&conf, - MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT)) != 0) - { - char buffer[100]; - mbedtls_strerror(ret,buffer,sizeof(buffer)); - printf("FAILED mbedtls_ssl_conf_defaults %s\n",buffer); - return; - } - - - - - mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); - mbedtls_ssl_conf_dbg(&conf,my_debug,stdout); - /* #if defined(MBEDTLS_SSL_CACHE_C) - mbedtls_ssl_conf_session_cache(&conf, &cache, - mbedtls_ssl_cache_get, - mbedtls_ssl_cache_set); -#endif*/ - mbedtls_ssl_conf_authmode(&conf, verify ? MBEDTLS_SSL_VERIFY_REQUIRED: MBEDTLS_SSL_VERIFY_OPTIONAL); - mbedtls_ssl_conf_ca_chain(&conf, &cachain, NULL); - - - mbedtls_ssl_set_bio(&ssl, static_cast(this),strm_send,strm_recv, NULL); - if((ret=mbedtls_ssl_setup(&ssl,&conf) != 0)) - { - printf("FAILED mbedtls_ssl_setup %i\n",ret); - return; - } - if((ret=mbedtls_ssl_set_hostname(&ssl,domain.c_str()) != 0)) - { - printf("FAILED mbedtls_ssl_set_hostname %i\n",ret); - return; - } - if((ret = mbedtls_ssl_handshake(&ssl)) != 0) - { - char buffer[100]; - mbedtls_strerror(ret,buffer,sizeof(buffer)); - printf("FAILED mbedtls_ssl_handshake %s\n",buffer); - return; - } - uint32_t flags; - if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { -#if !defined(MBEDTLS_X509_REMOVE_INFO) - char vrfy_buf[512]; -#endif - - - -#if !defined(MBEDTLS_X509_REMOVE_INFO) - mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); - - -#endif - if(verify) - return; - } - - success=true; - - } - ~TlsClientStream() - { - - mbedtls_ctr_drbg_free(&ctr_drbg); - mbedtls_entropy_free(&entropy); - mbedtls_ssl_config_free(&conf); - -#if defined(MBEDTLS_USE_PSA_CRYPTO) - mbedtls_psa_crypto_free(); -#endif /* MBEDTLS_USE_PSA_CRYPTO */ - - delete ls; - } - }; - - class TlsServerStream { - GCList* ls; - TCallable* read; - TCallable* write; - TCallable* close; - TByteArray* readBuffer; - TByteArray* writeBuffer; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_ssl_context ssl; - mbedtls_ssl_config conf; - mbedtls_x509_crt srvcert; - mbedtls_x509_crt cachain; - mbedtls_pk_context pkey; - - - - static int strm_send(void* ctx,const unsigned char* buf,size_t len) - { - TlsServerStream* strm = static_cast(ctx); - strm->writeBuffer->data.resize(len); - memcpy(strm->writeBuffer->data.data(),buf,len); - - auto res = strm->write->Call(*strm->ls,{strm->writeBuffer}); - if(std::holds_alternative(res)) - { - auto num = std::get(res); - - return (int)num; - } - return -1; - } - static int strm_recv(void* ctx,unsigned char* buf,size_t len) - { - TlsServerStream* strm = static_cast(ctx); - strm->readBuffer->data.resize(len); - - auto res = strm->read->Call(*strm->ls,{strm->readBuffer}); - if(std::holds_alternative(res)) - { - auto num = std::get(res); - if(num < 0) return num; - size_t read = (size_t)num; - if(read > len) read = len; - memcpy(buf,strm->readBuffer->data.data(), read); - return read; - } - return -1; - - //return (int)strm->Read((uint8_t*)buf,len); - } - public: - void Close() - { - close->Call(*ls,{}); - } - bool success=false; - bool isDoneReading =false; - int64_t Read(uint8_t* buffer, size_t len) - { - if(isDoneReading) return 0; - int64_t r = (int64_t)mbedtls_ssl_read(&ssl,buffer,len); - if(r == 0) isDoneReading=true; - if(r == -30848) - { - isDoneReading = true; - return 0; - } - return r; - } - int64_t Write(uint8_t* buffer, size_t len) - { - return mbedtls_ssl_write(&ssl,buffer,len); - } - - TlsServerStream(GC* gc,std::string cert, std::string chain, std::string privkey, TCallable* read, TCallable* write, TCallable* close) - { - ls = new GCList(gc); - ls->Add(read); - ls->Add(write); - ls->Add(close); - readBuffer = TByteArray::Create(ls); - writeBuffer = TByteArray::Create(ls); - this->read = read; - this->write = write; - this->close = close; - - mbedtls_ssl_init(&ssl); - mbedtls_ssl_config_init(&conf); - mbedtls_x509_crt_init(&srvcert); - mbedtls_x509_crt_init(&cachain); - mbedtls_ctr_drbg_init(&ctr_drbg); - mbedtls_entropy_init(&entropy); - mbedtls_pk_init(&pkey); - - const char* pers = "CrossLangTLS"; - int ret=0; - - - -#if defined(MBEDTLS_USE_PSA_CRYPTO) - psa_status_t status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n", - (int) status); - return; - } -#endif - - if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, - (const unsigned char *) pers, - strlen(pers))) != 0) - { - printf("FAILED mbedtls_ctr_drbg_seed\n"); - return; - } - ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) cert.c_str(), - cert.size()+1); - if(ret != 0) { printf("FAILED mbedtls_x509_crt_parse cert %i\n",ret); return;} - ret = mbedtls_x509_crt_parse(&cachain, (const unsigned char *) chain.c_str(), - chain.size()+1); - - if(ret != 0) {printf("FAILED mbedtls_x509_crt_parse chain %i\n",ret); return;} - - - ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) privkey.c_str(), - privkey.size()+1, NULL, 0); - if(ret != 0) {printf("FAILED mbedtls_pk_parse_key %i\n",ret); return;} - if((ret = mbedtls_ssl_config_defaults(&conf, - MBEDTLS_SSL_IS_SERVER, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT)) != 0) - { - char buffer[100]; - mbedtls_strerror(ret,buffer,sizeof(buffer)); - printf("FAILED mbedtls_ssl_conf_defaults %s\n",buffer); - return; - } - - - - - mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); - - /* #if defined(MBEDTLS_SSL_CACHE_C) - mbedtls_ssl_conf_session_cache(&conf, &cache, - mbedtls_ssl_cache_get, - mbedtls_ssl_cache_set); -#endif*/ - mbedtls_ssl_conf_own_cert(&conf,&srvcert,&pkey); - mbedtls_ssl_conf_ca_chain(&conf, &cachain, NULL); - - mbedtls_ssl_set_bio(&ssl, static_cast(this),strm_send,strm_recv, NULL); - - if((ret=mbedtls_ssl_setup(&ssl,&conf) != 0)) - { - printf("FAILED mbedtls_ssl_setup %i\n",ret); - return; - } - - if((ret = mbedtls_ssl_handshake(&ssl)) != 0) - { - char buffer[100]; - mbedtls_strerror(ret,buffer,sizeof(buffer)); - printf("FAILED mbedtls_ssl_handshake %s\n",buffer); - return; - } - - success=true; - - } - ~TlsServerStream() - { - mbedtls_x509_crt_free(&srvcert); - mbedtls_pk_free(&pkey); - - mbedtls_ctr_drbg_free(&ctr_drbg); - mbedtls_entropy_free(&entropy); - mbedtls_ssl_config_free(&conf); - -#if defined(MBEDTLS_USE_PSA_CRYPTO) - mbedtls_psa_crypto_free(); -#endif /* MBEDTLS_USE_PSA_CRYPTO */ - - delete ls; - } - }; - static TObject Crypto_TlsClient(GCList& ls, std::vector args) - { - //TlsServerStream(GC* gc,std::string domain, std::string chain, bool verify, TCallable* read, TCallable* write, TCallable* close) - if(args.size() == 6 && std::holds_alternative(args[0]) && std::holds_alternative(args[1]) && std::holds_alternative(args[2]) && std::holds_alternative(args[3]) && std::holds_alternative(args[4]) && std::holds_alternative(args[5])) - { - std::string domain = std::get(args[0]); - std::string chain = std::get(args[1]); - bool verify = std::get(args[2]); - TCallable* read = dynamic_cast(std::get(args[3]).obj); - - TCallable* write = dynamic_cast(std::get(args[4]).obj); - - TCallable* close = dynamic_cast(std::get(args[5]).obj); - - if(read != nullptr && write != nullptr && close != nullptr) - { - auto serverStream = new TlsClientStream(ls.GetGC(),domain,chain,verify,read,write,close); - if(!serverStream->success) - { - serverStream->Close(); - delete serverStream; - return nullptr; - } - TNative* native = TNative::Create(ls,static_cast(serverStream),[](void* ptr)->void { - if(ptr == nullptr) return; - TlsClientStream* strm = static_cast(ptr); - strm->Close(); - delete strm; - }); - - TDictionary* dict = TDictionary::Create(ls); - ls.GetGC()->BarrierBegin(); - dict->SetValue("_native",native); - ls.GetGC()->BarrierEnd(); - dict->DeclareFunction(ls.GetGC(),"Read","Read data from Tls Connection",{"buffer","offset","length"},[native](GCList& ls2, std::vector args2)->TObject { - if(args2.size() == 3 && std::holds_alternative(args2[0]) && std::holds_alternative(args2[1]) && std::holds_alternative(args2[2])) - { - auto byteArray = dynamic_cast(std::get(args2[0]).obj); - size_t offset = (size_t)std::get(args2[1]); - size_t length = (size_t)std::get(args2[2]); - - if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size())) - { - auto strm = static_cast(native->GetPointer()); - return strm->Read(byteArray->data.data()+offset, length); - } - } - return Undefined(); - }); - dict->DeclareFunction(ls.GetGC(),"Write","Write data to Tls Connection",{"buffer","offset","length"},[native](GCList& ls2, std::vector args2)->TObject { - if(args2.size() == 3 && std::holds_alternative(args2[0]) && std::holds_alternative(args2[1]) && std::holds_alternative(args2[2])) - { - auto byteArray = dynamic_cast(std::get(args2[0]).obj); - size_t offset = (size_t)std::get(args2[1]); - size_t length = (size_t)std::get(args2[2]); - - if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size())) - { - auto strm = static_cast(native->GetPointer()); - return strm->Write(byteArray->data.data()+offset, length); - } - } - return Undefined(); - }); - dict->DeclareFunction(ls.GetGC(),"Close","Close Tls Connection",{},[native](GCList& ls2, std::vector args2)->TObject { - - if(!native->GetDestroyed()) - { - native->Destroy(); - } - - return Undefined(); - }); - return dict; - } - } - return Undefined(); - } - - static TObject Crypto_TlsServer(GCList& ls, std::vector args) - { - //TlsServerStream(GC* gc,std::string cert, std::string chain, std::string privkey, TCallable* read, TCallable* write, TCallable* close) - if(args.size() == 6 && std::holds_alternative(args[0]) && std::holds_alternative(args[1]) && std::holds_alternative(args[2]) && std::holds_alternative(args[3]) && std::holds_alternative(args[4]) && std::holds_alternative(args[5])) - { - std::string cert = std::get(args[0]); - std::string chain = std::get(args[1]); - std::string privkey = std::get(args[2]); - TCallable* read = dynamic_cast(std::get(args[3]).obj); - - TCallable* write = dynamic_cast(std::get(args[4]).obj); - - TCallable* close = dynamic_cast(std::get(args[5]).obj); - - if(read != nullptr && write != nullptr && close != nullptr) - { - auto serverStream = new TlsServerStream(ls.GetGC(),cert,chain,privkey,read,write,close); - if(!serverStream->success) - { - serverStream->Close(); - delete serverStream; - return nullptr; - } - TNative* native = TNative::Create(ls,static_cast(serverStream),[](void* ptr)->void { - if(ptr == nullptr) return; - TlsServerStream* strm = static_cast(ptr); - strm->Close(); - delete strm; - }); - - TDictionary* dict = TDictionary::Create(ls); - ls.GetGC()->BarrierBegin(); - dict->SetValue("_native",native); - ls.GetGC()->BarrierEnd(); - dict->DeclareFunction(ls.GetGC(),"Read","Read data from Tls Connection",{"buffer","offset","length"},[native](GCList& ls2, std::vector args2)->TObject { - if(args2.size() == 3 && std::holds_alternative(args2[0]) && std::holds_alternative(args2[1]) && std::holds_alternative(args2[2])) - { - auto byteArray = dynamic_cast(std::get(args2[0]).obj); - size_t offset = (size_t)std::get(args2[1]); - size_t length = (size_t)std::get(args2[2]); - if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size())) - { - auto strm = static_cast(native->GetPointer()); - return strm->Read(byteArray->data.data()+offset, length); - } - } - return Undefined(); - }); - dict->DeclareFunction(ls.GetGC(),"Write","Write data to Tls Connection",{"buffer","offset","length"},[native](GCList& ls2, std::vector args2)->TObject { - if(args2.size() == 3 && std::holds_alternative(args2[0]) && std::holds_alternative(args2[1]) && std::holds_alternative(args2[2])) - { - auto byteArray = dynamic_cast(std::get(args2[0]).obj); - size_t offset = (size_t)std::get(args2[1]); - size_t length = (size_t)std::get(args2[2]); - - - if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size())) - { - auto strm = static_cast(native->GetPointer()); - return strm->Write(byteArray->data.data()+offset, length); - } - } - return Undefined(); - }); - dict->DeclareFunction(ls.GetGC(),"Close","Close Tls Connection",{},[native](GCList& ls2, std::vector args2)->TObject { - - if(!native->GetDestroyed()) - { - native->Destroy(); - } - - return Undefined(); - }); - return dict; - } - } - return Undefined(); - } - static TObject Crypto_Sha1(GCList& ls, std::vector args) { @@ -750,6 +200,60 @@ namespace Tesses::CrossLang return dict; } + static TObject Crypto_Base64Encode(GCList& ls, std::vector args) + { + TByteArray* byteArray; + int64_t offset; + int64_t length; + if(GetArgumentHeap(args,0,byteArray) && GetArgument(args,1,offset) && GetArgument(args,2,length)) + { + std::string str={}; + 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; + } + + + } + + return ""; + + } + } + static TObject Crypto_Base64Decode(GCList& ls, std::vector args) + { + std::string str; + if(GetArgument(args,0,str)) + { + size_t olen; + + TByteArray* bArray = TByteArray::Create(ls); + + + 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; + } + + + } + } #endif void TStd::RegisterCrypto(GC* gc,TRootEnvironment* env) { @@ -759,14 +263,10 @@ namespace Tesses::CrossLang GCList ls(gc); TDictionary* dict = TDictionary::Create(ls); - //dict->DeclareFunction(gc, "Decode","Deserialize Json",{"Json string"},Json_Decode); - //dict->DeclareFunction(gc, "Encode","Serialize Json",{"any","$indent"},Json_Encode); dict->DeclareFunction(gc, "Sha1","Sha1 Algorithm (needed for WebSocket handshake/BitTorrent etc) (don't use unless you have no other choice)",{},Crypto_Sha1); dict->DeclareFunction(gc, "Sha256","Sha256 Algorithm",{"$is224"},Crypto_Sha256); dict->DeclareFunction(gc, "Sha512","Sha512 Algorithm",{"$is384"},Crypto_Sha512); - dict->DeclareFunction(gc, "TlsClient", "Create TLS client for HTTPS client",{"domain","chain","verify","read","write","close"},Crypto_TlsClient); - - dict->DeclareFunction(gc, "TlsServer", "Create TLS server for HTTPS server",{"cert","chain","privkey","read","write","close"},Crypto_TlsServer); + dict->DeclareFunction(gc, "Base64Encode","Sha512 Algorithm",{"data"},Crypto_Base64Encode); gc->BarrierBegin(); env->DeclareVariable("Crypto", dict); gc->BarrierEnd(); diff --git a/src/runtime_methods/dictionary.cpp b/src/runtime_methods/dictionary.cpp index a24abe6..a16947e 100644 --- a/src/runtime_methods/dictionary.cpp +++ b/src/runtime_methods/dictionary.cpp @@ -8,7 +8,6 @@ namespace Tesses::CrossLang TDictionary* dict; - dict->items.begin(); if(args.size() == 1 && std::holds_alternative(args[0])) { auto item = dynamic_cast(std::get(args[0]).obj); diff --git a/src/runtime_methods/io.cpp b/src/runtime_methods/io.cpp index 602b521..a3f89cb 100644 --- a/src/runtime_methods/io.cpp +++ b/src/runtime_methods/io.cpp @@ -35,6 +35,10 @@ namespace Tesses::CrossLang } return nullptr; } + static TObject FS_CreateMemoryFilesystem(GCList& ls, std::vector args) + { + return TVFSHeapObject::Create(ls, new Tesses::Framework::Filesystem::MemoryFilesystem()); + } static TObject FS_CreateFilesystem(GCList& ls, std::vector args) { @@ -71,6 +75,41 @@ namespace Tesses::CrossLang } return nullptr; } + static TObject FS_CreateArchive(GCList& ls, std::vector args) + { + TVFSHeapObject* vfs; + TStreamHeapObject* strm; + std::string name; + std::string version; + std::string info; + TVMVersion version2; + + if(GetArgumentHeap(args,0,vfs) && GetArgumentHeap(args,1,strm) && GetArgument(args,2,name) && GetArgument(args,3,version) && GetArgument(args,4,info) && TVMVersion::TryParse(version,version2)) + { + CrossArchiveCreate(vfs->vfs,strm->stream,name,version2,info); + } + return nullptr; + } + static TObject FS_ExtractArchive(GCList& ls, std::vector args) + { + TVFSHeapObject* vfs; + TStreamHeapObject* strm; + + if(GetArgumentHeap(args,0,strm) && GetArgumentHeap(args,1,vfs)) + { + auto res = CrossArchiveExtract(strm->stream,vfs->vfs); + + TDictionary* dict = TDictionary::Create(ls); + ls.GetGC()->BarrierBegin(); + dict->SetValue("Name",res.first.first); + dict->SetValue("Version",res.first.second.ToString()); + dict->SetValue("Info",res.second); + ls.GetGC()->BarrierEnd(); + return dict; + } + return nullptr; + } + void TStd::RegisterIO(GC* gc,TRootEnvironment* env,bool enableLocalFilesystem) { @@ -93,6 +132,10 @@ namespace Tesses::CrossLang dict->DeclareFunction(gc, "MemoryStream","Create a memory stream",{"writable"}, FS_MemoryStream); dict->DeclareFunction(gc, "CreateStream","Create stream", {"strm"},FS_CreateStream); dict->DeclareFunction(gc, "CreateFilesystem","Create filesystem", {"fs"},FS_CreateFilesystem); + + dict->DeclareFunction(gc, "CreateMemoryFilesystem","Create in memory filesystem", {},FS_CreateMemoryFilesystem); + dict->DeclareFunction(gc, "CreateArchive", "Create a crvm archive",{"fs","strm","name","version","info"},FS_CreateArchive); + dict->DeclareFunction(gc,"ExtractArchive", "Extract a crvm archive",{"strm","vfs"},FS_ExtractArchive); env->DeclareVariable("FS", dict); gc->BarrierEnd(); } diff --git a/src/runtime_methods/json.cpp b/src/runtime_methods/json.cpp index 874e681..4ca15d8 100644 --- a/src/runtime_methods/json.cpp +++ b/src/runtime_methods/json.cpp @@ -12,6 +12,31 @@ namespace Tesses::CrossLang { #if defined(CROSSLANG_ENABLE_JSON) + static bool IsValidForJson(TObject v) + { + if(std::holds_alternative(v)) return true; + + if(std::holds_alternative(v)) return true; + + if(std::holds_alternative(v)) return true; + + + if(std::holds_alternative(v)) return true; + + + if(std::holds_alternative(v)) return true; + + + if(std::holds_alternative(v)) + { + auto res = std::get(v); + auto ls = dynamic_cast(res.obj); + auto dict = dynamic_cast(res.obj); + if(ls != nullptr) return true; + if(dict != nullptr) return true; + } + return false; + } static json_t* JsonSerialize(TObject v) { if(std::holds_alternative(v)) return json_null(); @@ -34,7 +59,9 @@ namespace Tesses::CrossLang json_t* items=json_array(); for(int64_t i = 0; i < ls->Count(); i++) { - json_array_append_new(items,JsonSerialize(ls->Get(i))); + auto val = ls->Get(i); + if(IsValidForJson(val)) + json_array_append_new(items,JsonSerialize(val)); } return items; } @@ -44,6 +71,7 @@ namespace Tesses::CrossLang json_t* obj = json_object(); for(auto item : dict->items) { + if(IsValidForJson(item.second)) json_object_setn_new(obj, item.first.c_str(), item.first.size(),JsonSerialize(item.second)); } return obj; diff --git a/src/runtime_methods/net.cpp b/src/runtime_methods/net.cpp index 398441a..f2a258f 100644 --- a/src/runtime_methods/net.cpp +++ b/src/runtime_methods/net.cpp @@ -329,6 +329,14 @@ namespace Tesses::CrossLang } return Undefined(); } + static TObject Net_HtmlEncode(GCList& ls, std::vector args) + { + if(args.size() == 1 && std::holds_alternative(args[0])) + { + return HttpUtils::HtmlEncode(std::get(args[0])); + } + return Undefined(); + } static TObject Net_UrlEncode(GCList& ls, std::vector args) { if(args.size() == 1 && std::holds_alternative(args[0])) @@ -530,6 +538,8 @@ namespace Tesses::CrossLang TDictionary* dict = TDictionary::Create(ls); TDictionary* http = TDictionary::Create(ls); + http->DeclareFunction(gc, "HtmlEncode","Html encode",{"param"}, Net_HtmlEncode); + http->DeclareFunction(gc, "UrlEncode","Url encode query param",{"param"}, Net_UrlEncode); http->DeclareFunction(gc, "UrlDecode","Url decode query param",{"param"}, Net_UrlDecode); http->DeclareFunction(gc, "UrlPathEncode","Url encode path",{"path"}, Net_UrlPathEncode); diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index f6fe302..1bb8e23 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -80,6 +80,14 @@ namespace Tesses::CrossLang { #define TVM_HANDLER(hndl) if(hndl(gc)) goto execute + typedef bool (InterperterThread::*opcode)(GC* gc); + + + + + + + bool InterperterThread::InvokeTwo(GCList& ls, TObject fn, TObject left, TObject right) { if(std::holds_alternative(fn)) @@ -3146,6 +3154,20 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, r); return false; } + if(key == "Length") + { + int64_t r = strm->stream != nullptr ? strm->stream->GetLength() : 0; + + cse.back()->Push(gc, r); + return false; + } + if(key == "Position") + { + int64_t r = strm->stream != nullptr ? strm->stream->GetPosition() : 0; + + cse.back()->Push(gc, r); + return false; + } cse.back()->Push(gc, nullptr); @@ -3337,7 +3359,7 @@ namespace Tesses::CrossLang { return false; } - void InterperterThread::GetVariable(GC* gc) + bool InterperterThread::GetVariable(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) @@ -3357,8 +3379,9 @@ namespace Tesses::CrossLang { throw VMException("[GETVARIABLE] Can't pop string."); } } + return false; } - void InterperterThread::SetVariable(GC* gc) + bool InterperterThread::SetVariable(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) @@ -3379,8 +3402,9 @@ namespace Tesses::CrossLang { throw VMException("[SETVARIABLE] Can't pop string."); } } + return false; } - void InterperterThread::DeclareVariable(GC* gc) + bool InterperterThread::DeclareVariable(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) @@ -3402,10 +3426,11 @@ namespace Tesses::CrossLang { throw VMException("[DECLAREVARIABLE] Can't pop string."); } } + return false; } - void InterperterThread::PushResource(GC* gc) + bool InterperterThread::PushResource(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) @@ -3432,154 +3457,193 @@ namespace Tesses::CrossLang { throw VMException("Can't read chunk."); } } + return false; } - - void InterperterThread::PushClosure(GC* gc,bool ownScope) + bool InterperterThread::Throw(GC* gc) { std::vector& cse=this->call_stack_entries; - if(!cse.empty()) - { - auto stk = cse.back(); - std::vector& code = stk->callable->closure->code; - if(stk->ip + 4 <= code.size()) - { - uint32_t n=BitConverter::ToUint32BE(code[stk->ip]); - if(n >= stk->callable->file->chunks.size()) - throw VMException("Can't read chunk."); - stk->ip = stk->ip + 4; + GCList ls(gc); + auto _res2 = cse.back()->Pop(ls); - gc->BarrierBegin(); - GCList ls(gc); - TClosure* closure = TClosure::Create(ls,stk->env,stk->callable->file,n,ownScope); - stk->Push(gc,closure); - gc->BarrierEnd(); - } - else - { - throw VMException("Can't read chunk."); - } + if(!std::holds_alternative(_res2)) + { + throw VMByteCodeException(gc,_res2); } + return false; } - void InterperterThread::PushString(GC* gc) + bool InterperterThread::JumpUndefined(GC* gc) { std::vector& cse=this->call_stack_entries; - if(!cse.empty()) - { - auto stk = cse.back(); - std::vector& code = stk->callable->closure->code; - if(stk->ip + 4 <= code.size()) - { - uint32_t n=BitConverter::ToUint32BE(code[stk->ip]); - if(n < stk->callable->file->strings.size()) - stk->Push(gc,stk->callable->file->strings[n]); - else - throw VMException("Can't read string."); - stk->ip = stk->ip + 4; - } - } - } - - void InterperterThread::PushLong(GC* gc) - { - std::vector& cse=this->call_stack_entries; - if(!cse.empty()) - { - auto stk = cse.back(); - std::vector& code = stk->callable->closure->code; - if(stk->ip + 8 <= code.size()) - { - uint64_t n=BitConverter::ToUint64BE(code[stk->ip]); - stk->Push(gc,(int64_t)n); - stk->ip = stk->ip + 8; - } - } - } - void InterperterThread::PushChar(GC* gc) - { - std::vector& cse=this->call_stack_entries; - if(!cse.empty()) - { - auto stk = cse.back(); - std::vector& code = stk->callable->closure->code; - if(stk->ip + 1 <= code.size()) - { - char c = (char)code[stk->ip]; - stk->Push(gc,c); - stk->ip = stk->ip + 1; - } - } - } - void InterperterThread::PushDouble(GC* gc) - { - std::vector& cse=this->call_stack_entries; - if(!cse.empty()) - { - auto stk = cse.back(); - std::vector& code = stk->callable->closure->code; - if(stk->ip + 8 <= code.size()) - { - double dbl = BitConverter::ToDoubleBE(code[stk->ip]); - stk->Push(gc,dbl); - stk->ip = stk->ip + 8; - } - } - } - + auto stk = cse.back(); - void InterperterThread::Execute(GC* gc) + if(stk->ip + 4 <= stk->callable->closure->code.size()) + { + uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); + + GCList ls(gc); + auto _res2 = stk->Pop(ls); + + stk->ip = stk->ip + 4; + if(std::holds_alternative(_res2)) + stk->ip = n; + else + stk->Push(gc,_res2); + + + } + else + throw VMException("Can't read jmpundefined pc."); + return false; + } + bool InterperterThread::Jump(GC* gc) { - std::vector& cse=this->call_stack_entries; - - execute: + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); - if(!cse.empty()) + if(stk->ip + 4 <= stk->callable->closure->code.size()) { - auto stk = cse.back(); - try{ - while(stk->ip < 0xFFFFFFFF && stk->ip < stk->callable->closure->code.size()) - { - - uint32_t ip = stk->ip; - stk->ip = ip + 1; - switch(stk->callable->closure->code[ip]) - { - case JMP: - { - if(stk->ip + 4 <= stk->callable->closure->code.size()) + uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); + stk->ip = n; + } + else + throw VMException("Can't read jmp pc."); + return false; + } + bool InterperterThread::PushNull(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + + stk->Push(gc,nullptr); + return false; + } + bool InterperterThread::PushUndefined(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + + stk->Push(gc,Undefined()); + return false; + } + bool InterperterThread::PushFalse(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + + stk->Push(gc,false); + return false; + } + bool InterperterThread::PushTrue(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + + stk->Push(gc,true); + return false; + } + bool InterperterThread::CreateDictionary(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + GCList ls(gc); + TDictionary* dict = TDictionary::Create(ls); + stk->Push(gc,dict); + return false; + } + bool InterperterThread::Nop(GC* gc) + { + return false; + } + bool InterperterThread::AppendList(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + + GCList ls(gc); + gc->BarrierBegin(); + auto obj = stk->Pop(ls); + auto objhold= stk->Pop(ls); + if(std::holds_alternative(objhold)) { - uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); - - - stk->ip = n; + auto list= dynamic_cast(std::get(objhold).obj); + if(list != nullptr) + { + list->Add(obj); + } + /* + if(dict != nullptr) + { + auto potential_str = stk->Pop(ls); + if(std::holds_alternative(potential_str)) + { + dict->SetValue(std::get(potential_str), stk->Pop(ls)); + } + }*/ } - else - throw VMException("Can't read jmp pc."); - } - break; - case JMPC: - { - if(stk->ip + 4 <= stk->callable->closure->code.size()) + + stk->Push(gc, objhold); + + gc->BarrierEnd(); + return false; + } + bool InterperterThread::AppendDictionary(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + GCList ls(gc); + gc->BarrierBegin(); + auto value = stk->Pop(ls); + auto k = stk->Pop(ls); + auto objhold= stk->Pop(ls); + if(std::holds_alternative(objhold) && std::holds_alternative(k)) { - uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); - - GCList ls2(gc); - auto _res2 = stk->Pop(ls2); - auto _res = ToBool(_res2); - stk->ip = stk->ip + 4; - if(_res) - stk->ip = n; - - + auto dict= dynamic_cast(std::get(objhold).obj); + + if(dict != nullptr) + { + dict->SetValue(std::get(k), value); + } } - else - throw VMException("Can't read jmpc pc."); - } - break; - case TRYCATCH: - { + + stk->Push(gc, objhold); + + gc->BarrierEnd(); + return false; + } + bool InterperterThread::CreateArray(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + GCList ls(gc); + TList* dict = TList::Create(ls); + stk->Push(gc,dict); + return false; + } + bool InterperterThread::Pop(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + GCList ls(gc); + stk->Pop(ls); + return false; + } + bool InterperterThread::TryCatch(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); GCList ls(gc); auto catchFn = stk->Pop(ls); auto tryFn = stk->Pop(ls); @@ -3621,178 +3685,214 @@ namespace Tesses::CrossLang { stk->Push(gc, catchC->Call(ls,{dict})); } } - } - break; - case THROW: - { + return false; + } + bool InterperterThread::JumpConditional(GC* gc) + { - GCList ls2(gc); - auto _res2 = stk->Pop(ls2); + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + if(stk->ip + 4 <= stk->callable->closure->code.size()) + { + uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); + + GCList ls2(gc); + auto _res2 = stk->Pop(ls2); + auto _res = ToBool(_res2); + stk->ip = stk->ip + 4; + if(_res) + stk->ip = n; + + + + } + else + throw VMException("Can't read jmpc pc."); + return false; + } + bool InterperterThread::PushClosure(GC* gc) + { + std::vector& cse=this->call_stack_entries; + if(!cse.empty()) + { + auto stk = cse.back(); + std::vector& code = stk->callable->closure->code; + if(stk->ip + 4 <= code.size()) + { + uint32_t n=BitConverter::ToUint32BE(code[stk->ip]); + if(n >= stk->callable->file->chunks.size()) + throw VMException("Can't read chunk."); + stk->ip = stk->ip + 4; + + gc->BarrierBegin(); + GCList ls(gc); + TClosure* closure = TClosure::Create(ls,stk->env,stk->callable->file,n,true); + stk->Push(gc,closure); + gc->BarrierEnd(); + } + else + { + throw VMException("Can't read chunk."); + } + } + return false; + } + bool InterperterThread::PushScopelessClosure(GC* gc) + { + std::vector& cse=this->call_stack_entries; + if(!cse.empty()) + { + auto stk = cse.back(); + std::vector& code = stk->callable->closure->code; + if(stk->ip + 4 <= code.size()) + { + uint32_t n=BitConverter::ToUint32BE(code[stk->ip]); + if(n >= stk->callable->file->chunks.size()) + throw VMException("Can't read chunk."); + stk->ip = stk->ip + 4; + + gc->BarrierBegin(); + GCList ls(gc); + TClosure* closure = TClosure::Create(ls,stk->env,stk->callable->file,n,false); + stk->Push(gc,closure); + gc->BarrierEnd(); + } + else + { + throw VMException("Can't read chunk."); + } + } + return false; + } + + bool InterperterThread::PushString(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + if(!cse.empty()) + { + auto stk = cse.back(); + std::vector& code = stk->callable->closure->code; + if(stk->ip + 4 <= code.size()) + { + uint32_t n=BitConverter::ToUint32BE(code[stk->ip]); + if(n < stk->callable->file->strings.size()) + stk->Push(gc,stk->callable->file->strings[n]); + else + throw VMException("Can't read string."); + stk->ip = stk->ip + 4; + } + } + return false; + } + + bool InterperterThread::PushLong(GC* gc) + { + std::vector& cse=this->call_stack_entries; + if(!cse.empty()) + { + auto stk = cse.back(); + std::vector& code = stk->callable->closure->code; + if(stk->ip + 8 <= code.size()) + { + uint64_t n=BitConverter::ToUint64BE(code[stk->ip]); + stk->Push(gc,(int64_t)n); + stk->ip = stk->ip + 8; + } + } + return false; + } + bool InterperterThread::PushChar(GC* gc) + { + std::vector& cse=this->call_stack_entries; + if(!cse.empty()) + { + auto stk = cse.back(); + std::vector& code = stk->callable->closure->code; + if(stk->ip + 1 <= code.size()) + { + char c = (char)code[stk->ip]; + stk->Push(gc,c); + stk->ip = stk->ip + 1; + } + } + return false; + } + bool InterperterThread::PushDouble(GC* gc) + { + std::vector& cse=this->call_stack_entries; + if(!cse.empty()) + { + auto stk = cse.back(); + std::vector& code = stk->callable->closure->code; + if(stk->ip + 8 <= code.size()) + { + double dbl = BitConverter::ToDoubleBE(code[stk->ip]); + stk->Push(gc,dbl); + stk->ip = stk->ip + 8; + } + } + return false; + } + bool InterperterThread::Return(GC* gc) + { + + + std::vector& cse=this->call_stack_entries; + + auto stk = cse.back(); + stk->ip = (uint32_t)stk->callable->closure->code.size(); + return false; + } + bool InterperterThread::ScopeBegin(GC* gc) + { + std::vector& cse=this->call_stack_entries; + + auto stk = cse.back(); + + gc->BarrierBegin(); + GCList ls(gc); + stk->env = stk->env->GetSubEnvironment(ls); + stk->scopes++; + gc->BarrierEnd(); + + return false; + } + bool InterperterThread::Defer(GC* gc) + { + std::vector& cse=this->call_stack_entries; + + auto stk = cse.back(); - if(!std::holds_alternative(_res2)) - { - throw VMByteCodeException(gc,_res2); - } - } - break; - case JMPUNDEFINED: - { - if(stk->ip + 4 <= stk->callable->closure->code.size()) - { - uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); - - GCList ls2(gc); - auto _res2 = stk->Pop(ls2); - - stk->ip = stk->ip + 4; - if(std::holds_alternative(_res2)) - stk->ip = n; - else - stk->Push(gc,_res2); - - - } - else - throw VMException("Can't read jmpundefined pc."); - } - break; - - case ADD: - TVM_HANDLER(Add); - break; - case SUB: - TVM_HANDLER(Sub); - break; - case TIMES: - TVM_HANDLER(Times); - break; - case DIVIDE: - TVM_HANDLER(Divide); - break; - case MODULO: - TVM_HANDLER(Mod); - break; - case LEFTSHIFT: - TVM_HANDLER(LShift); - break; - case RIGHTSHIFT: - TVM_HANDLER(RShift); - break; - case LESSTHAN: - TVM_HANDLER(Lt); - break; - case LESSTHANEQ: - TVM_HANDLER(Lte); - break; - case GREATERTHAN: - TVM_HANDLER(Gt); - break; - case GREATERTHANEQ: - TVM_HANDLER(Gte); - break; - case NEQ: - TVM_HANDLER(NEq); - break; - case EQ: - TVM_HANDLER(Eq); - break; - case NEGATIVE: - TVM_HANDLER(Neg); - break; - case BITWISEOR: - TVM_HANDLER(BOr); - break; - case BITWISEAND: - TVM_HANDLER(BAnd); - break; - case BITWISENOT: - TVM_HANDLER(BNot); - break; - case NOT: - TVM_HANDLER(LNot); - break; - case XOR: - TVM_HANDLER(XOr); - break; - case CALLFUNCTION: - TVM_HANDLER(ExecuteFunction); - break; - case CALLMETHOD: - TVM_HANDLER(ExecuteMethod); - break; - case GETVARIABLE: - GetVariable(gc); - break; - case SETVARIABLE: - SetVariable(gc); - break; - case GETFIELD: - TVM_HANDLER(GetField); - break; - case SETFIELD: - TVM_HANDLER(SetField); - break; - case DECLAREVARIABLE: - DeclareVariable(gc); - break; - case PUSHRESOURCE: - PushResource(gc); - break; - case PUSHCLOSURE: - PushClosure(gc); - break; - case PUSHSCOPELESSCLOSURE: - PushClosure(gc,false); - break; - case PUSHLONG: - PushLong(gc); - break; - case PUSHDOUBLE: - PushDouble(gc); - break; - case PUSHSTRING: - PushString(gc); - break; - case PUSHCHAR: - PushChar(gc); - break; - case SCOPEBEGIN: - { gc->BarrierBegin(); GCList ls(gc); - stk->env = stk->env->GetSubEnvironment(ls); - stk->scopes++; - gc->BarrierEnd(); - } - break; - case SCOPEEND: - { - gc->BarrierBegin(); - GCList ls(gc); - std::vector callable; - - if(!stk->env->defers.empty()) - { - ls.Add(stk->env); - callable.insert(callable.end(), stk->env->defers.begin(),stk->env->defers.end()); - } - - stk->scopes--; - stk->env = stk->env->GetParentEnvironment(); + auto item = stk->Pop(ls); + TCallable* call; + if(GetObjectHeap(item,call)) + cse.back()->env->defers.insert(cse.back()->env->defers.begin(), {call}); gc->BarrierEnd(); + + return false; + } + bool InterperterThread::Dup(GC* gc) + { + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + GCList ls(gc); + auto res = stk->Pop(ls); + stk->Push(gc,res); + stk->Push(gc,res); - for(auto item : callable) - { - GCList ls2(gc); - item->Call(ls2,{}); - } - - } - break; - case SCOPEENDTIMES: - { - gc->BarrierBegin(); + return false; + } + bool InterperterThread::ScopeEndTimes(GC* gc) + { + std::vector& cse=this->call_stack_entries; + + auto stk = cse.back(); + + gc->BarrierBegin(); GCList ls(gc); std::vector callable; std::vector& code = stk->callable->closure->code; @@ -3818,130 +3918,79 @@ namespace Tesses::CrossLang { GCList ls2(gc); item->Call(ls2,{}); } - } - break; - case PUSHFALSE: - { - GCList ls(gc); - stk->Push(gc,false); - } - break; - case PUSHTRUE: - { - GCList ls(gc); - stk->Push(gc,true); - } - break; - case PUSHNULL: - { - GCList ls(gc); - stk->Push(gc,nullptr); - } - break; - case PUSHUNDEFINED: - { - GCList ls(gc); - stk->Push(gc,Undefined()); - } - break; - case CREATEDICTIONARY: - { - GCList ls(gc); - TDictionary* dict = TDictionary::Create(ls); - stk->Push(gc,dict); - } - break; - case POP: - { - GCList ls(gc); - stk->Pop(ls); - } - break; - - case CREATEARRAY: - { - GCList ls(gc); - TList* myList = TList::Create(ls); - stk->Push(gc,myList); - } - break; - - case APPENDLIST: - { - GCList ls(gc); + + return false; + } + bool InterperterThread::ScopeEnd(GC* gc) + { + std::vector& cse=this->call_stack_entries; + + auto stk = cse.back(); + + gc->BarrierBegin(); - auto obj = stk->Pop(ls); - auto objhold= stk->Pop(ls); - if(std::holds_alternative(objhold)) + GCList ls(gc); + std::vector callable; + + if(!stk->env->defers.empty()) { - auto list= dynamic_cast(std::get(objhold).obj); - if(list != nullptr) - { - list->Add(obj); - } - /* - if(dict != nullptr) - { - auto potential_str = stk->Pop(ls); - if(std::holds_alternative(potential_str)) - { - dict->SetValue(std::get(potential_str), stk->Pop(ls)); - } - }*/ + ls.Add(stk->env); + callable.insert(callable.end(), stk->env->defers.begin(),stk->env->defers.end()); } - - stk->Push(gc, objhold); - - gc->BarrierEnd(); - } - break; - case APPENDDICT: - { - GCList ls(gc); - gc->BarrierBegin(); - auto value = stk->Pop(ls); - auto k = stk->Pop(ls); - auto objhold= stk->Pop(ls); - if(std::holds_alternative(objhold) && std::holds_alternative(k)) - { - auto dict= dynamic_cast(std::get(objhold).obj); - - if(dict != nullptr) - { - dict->SetValue(std::get(k), value); - } + stk->scopes--; + stk->env = stk->env->GetParentEnvironment(); + gc->BarrierEnd(); + + + for(auto item : callable) + { + GCList ls2(gc); + item->Call(ls2,{}); } + + return false; + } + bool InterperterThread::Illegal(GC* gc) + { - stk->Push(gc, objhold); - gc->BarrierEnd(); - } - break; - case NOP: - //this does nothing - break; - case RET: - stk->ip = (uint32_t)stk->callable->closure->code.size(); - break; - case DEFER: - { - gc->BarrierBegin(); - GCList ls(gc); - auto item = stk->Pop(ls); - TCallable* call; - if(GetObjectHeap(item,call)) - cse.back()->env->defers.insert(cse.back()->env->defers.begin(), {call}); - gc->BarrierEnd(); - } - break; - default: - { - char chr[3]; - snprintf(chr,3,"%02X",stk->callable->closure->code[ip]); - throw VMException("Illegal instruction: 0x" + std::string(chr) + "."); - } - } + std::vector& cse=this->call_stack_entries; + + auto stk = cse.back(); + char chr[3]; + snprintf(chr,3,"%02X",stk->callable->closure->code[stk->ip-1]); + throw VMException("Illegal instruction: 0x" + std::string(chr) + "."); + + } + + void InterperterThread::Execute(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + #define VM_OPCODE_TABLE_INLINE + #include "vm_opcode_table.h" + #undef VM_OPCODE_TABLE_INLINE + + execute: + + if(!cse.empty()) + { + auto stk = cse.back(); + + + + + try{ + while(stk->ip < 0xFFFFFFFF && stk->ip < stk->callable->closure->code.size()) + { + + uint32_t ip = stk->ip; + stk->ip = ip + 1; + + if(((*this).*(opcodes[stk->callable->closure->code[ip]]))(gc)) + goto execute; + if(gc->UsingNullThreads()) gc->Collect(); diff --git a/src/vm/vm_opcode_table.h b/src/vm/vm_opcode_table.h new file mode 100644 index 0000000..46f2feb --- /dev/null +++ b/src/vm/vm_opcode_table.h @@ -0,0 +1,3 @@ +#if defined(VM_OPCODE_TABLE_INLINE) +static opcode opcodes[256]={&InterperterThread::Add, &InterperterThread::Sub, &InterperterThread::Times, &InterperterThread::Divide, &InterperterThread::Mod, &InterperterThread::LShift, &InterperterThread::RShift, &InterperterThread::BOr, &InterperterThread::BAnd, &InterperterThread::BNot, &InterperterThread::Lt, &InterperterThread::Gt, &InterperterThread::Lte, &InterperterThread::Gte, &InterperterThread::Eq, &InterperterThread::NEq, &InterperterThread::LNot, &InterperterThread::Neg, &InterperterThread::XOr, &InterperterThread::Pop, &InterperterThread::Dup,&InterperterThread::Nop, &InterperterThread::PushClosure, &InterperterThread::CreateDictionary, &InterperterThread::CreateArray, &InterperterThread::AppendList, &InterperterThread::AppendDictionary, &InterperterThread::PushResource, &InterperterThread::PushLong, &InterperterThread::PushChar, &InterperterThread::PushDouble, &InterperterThread::PushString, &InterperterThread::PushNull, &InterperterThread::PushUndefined, &InterperterThread::ScopeBegin, &InterperterThread::ScopeEnd, &InterperterThread::ScopeEndTimes, &InterperterThread::PushFalse, &InterperterThread::PushTrue, &InterperterThread::SetVariable, &InterperterThread::GetVariable, &InterperterThread::DeclareVariable, &InterperterThread::SetField, &InterperterThread::GetField, &InterperterThread::ExecuteFunction, &InterperterThread::ExecuteMethod, &InterperterThread::Return, &InterperterThread::JumpConditional, &InterperterThread::Jump, &InterperterThread::JumpUndefined, &InterperterThread::Defer, &InterperterThread::TryCatch, &InterperterThread::Throw, &InterperterThread::PushScopelessClosure, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal}; +#endif \ No newline at end of file