Added FS.MemoryFilesystem
This commit is contained in:
		
							parent
							
								
									82bf80ba06
								
							
						
					
					
						commit
						f0a7c77134
					
				|  | @ -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": [], | ||||
|  |  | |||
|  | @ -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 <tesses@tesses.net>") | ||||
|  |  | |||
|  | @ -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() | ||||
|  | @ -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::pair<std::string,TVMVersion>,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); | ||||
|  |  | |||
|  | @ -0,0 +1,291 @@ | |||
| #include "CrossLang.hpp" | ||||
| #include <iostream> | ||||
| 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<uint8_t> 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<std::string> 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<std::string> 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<void(Tesses::Framework::Filesystem::VFSPath)> walkFS = [vfs,&ensureString,&ensureResource,&ms,&walkFS,&writeInt](Tesses::Framework::Filesystem::VFSPath path)->void { | ||||
|             | ||||
|             if(vfs->DirectoryExists(path)) | ||||
|             { | ||||
| 
 | ||||
|                 ms.WriteByte(1); | ||||
|                 std::vector<std::string> 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::pair<std::string,TVMVersion>,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<std::string> 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<void(Tesses::Framework::Filesystem::VFSPath)> 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::pair<std::string,TVMVersion>,std::string>(std::pair<std::string,TVMVersion>(name,v2),info); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,83 @@ | |||
| #include <CrossLang.hpp> | ||||
| #include <iostream> | ||||
| using namespace Tesses::CrossLang; | ||||
| using namespace Tesses::Framework::Filesystem; | ||||
| using namespace Tesses::Framework::Streams; | ||||
| void Help(const char* filename) | ||||
| { | ||||
|     printf("USAGE: %s [OPTIONS] <dirasroot> <archive.crvm>\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<std::string> 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; | ||||
| } | ||||
|  | @ -0,0 +1,34 @@ | |||
| #include <CrossLang.hpp> | ||||
| #include <iostream> | ||||
| 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 <archive.crvm> <dirasroot>\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; | ||||
| } | ||||
|  | @ -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<LexToken> tokens; | ||||
|  |  | |||
|  | @ -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;arg<argc;arg++) | ||||
|         args->Add(std::string(argv[arg])); | ||||
|  |  | |||
|  | @ -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<TlsClientStream*>(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<int64_t>(res)) | ||||
|                 { | ||||
|                     auto num = std::get<int64_t>(res); | ||||
|                     return (int)num; | ||||
|                 } | ||||
|                 return -1; | ||||
|             } | ||||
|             static int strm_recv(void* ctx,unsigned char* buf,size_t len) | ||||
|             { | ||||
|                 TlsClientStream* strm = static_cast<TlsClientStream*>(ctx); | ||||
|                 strm->readBuffer->data.resize(len); | ||||
|                  | ||||
|                 auto res = strm->read->Call(*strm->ls,{strm->readBuffer}); | ||||
|                 if(std::holds_alternative<int64_t>(res)) | ||||
|                 { | ||||
|                     auto num = std::get<int64_t>(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<void*>(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<TlsServerStream*>(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<int64_t>(res)) | ||||
|                 { | ||||
|                     auto num = std::get<int64_t>(res); | ||||
|                      | ||||
|                     return (int)num; | ||||
|                 } | ||||
|                 return -1; | ||||
|             } | ||||
|             static int strm_recv(void* ctx,unsigned char* buf,size_t len) | ||||
|             { | ||||
|                 TlsServerStream* strm = static_cast<TlsServerStream*>(ctx); | ||||
|                 strm->readBuffer->data.resize(len); | ||||
|                  | ||||
|                 auto res = strm->read->Call(*strm->ls,{strm->readBuffer}); | ||||
|                 if(std::holds_alternative<int64_t>(res)) | ||||
|                 { | ||||
|                     auto num = std::get<int64_t>(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<void*>(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<TObject> 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<std::string>(args[0]) && std::holds_alternative<std::string>(args[1]) && std::holds_alternative<bool>(args[2]) && std::holds_alternative<THeapObjectHolder>(args[3]) && std::holds_alternative<THeapObjectHolder>(args[4]) && std::holds_alternative<THeapObjectHolder>(args[5])) | ||||
|         { | ||||
|             std::string domain = std::get<std::string>(args[0]); | ||||
|             std::string chain = std::get<std::string>(args[1]); | ||||
|             bool verify = std::get<bool>(args[2]); | ||||
|             TCallable* read = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[3]).obj); | ||||
| 
 | ||||
|             TCallable* write = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[4]).obj); | ||||
| 
 | ||||
|             TCallable* close = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(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<void*>(serverStream),[](void* ptr)->void { | ||||
|                     if(ptr == nullptr) return; | ||||
|                     TlsClientStream* strm = static_cast<TlsClientStream*>(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<TObject> args2)->TObject { | ||||
|                     if(args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2])) | ||||
|                     { | ||||
|                         auto byteArray = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj); | ||||
|                         size_t offset = (size_t)std::get<int64_t>(args2[1]); | ||||
|                         size_t length = (size_t)std::get<int64_t>(args2[2]); | ||||
| 
 | ||||
|                         if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size())) | ||||
|                         { | ||||
|                             auto strm = static_cast<TlsClientStream*>(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<TObject> args2)->TObject { | ||||
|                     if(args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2])) | ||||
|                     { | ||||
|                         auto byteArray = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj); | ||||
|                         size_t offset = (size_t)std::get<int64_t>(args2[1]); | ||||
|                         size_t length = (size_t)std::get<int64_t>(args2[2]); | ||||
| 
 | ||||
|                         if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size())) | ||||
|                         { | ||||
|                             auto strm = static_cast<TlsClientStream*>(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<TObject> args2)->TObject { | ||||
|                      | ||||
|                         if(!native->GetDestroyed()) | ||||
|                         { | ||||
|                             native->Destroy(); | ||||
|                         } | ||||
|                      | ||||
|                     return Undefined(); | ||||
|                 }); | ||||
|                 return dict; | ||||
|             } | ||||
|         } | ||||
|         return Undefined(); | ||||
|     } | ||||
|    | ||||
|     static TObject Crypto_TlsServer(GCList& ls, std::vector<TObject> 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<std::string>(args[0]) && std::holds_alternative<std::string>(args[1]) && std::holds_alternative<std::string>(args[2]) && std::holds_alternative<THeapObjectHolder>(args[3]) && std::holds_alternative<THeapObjectHolder>(args[4]) && std::holds_alternative<THeapObjectHolder>(args[5])) | ||||
|         { | ||||
|             std::string cert = std::get<std::string>(args[0]); | ||||
|             std::string chain = std::get<std::string>(args[1]); | ||||
|             std::string privkey = std::get<std::string>(args[2]); | ||||
|             TCallable* read = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[3]).obj); | ||||
| 
 | ||||
|             TCallable* write = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(args[4]).obj); | ||||
| 
 | ||||
|             TCallable* close = dynamic_cast<TCallable*>(std::get<THeapObjectHolder>(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<void*>(serverStream),[](void* ptr)->void { | ||||
|                     if(ptr == nullptr) return; | ||||
|                     TlsServerStream* strm = static_cast<TlsServerStream*>(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<TObject> args2)->TObject { | ||||
|                     if(args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2])) | ||||
|                     { | ||||
|                         auto byteArray = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj); | ||||
|                         size_t offset = (size_t)std::get<int64_t>(args2[1]); | ||||
|                         size_t length = (size_t)std::get<int64_t>(args2[2]); | ||||
|                         if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size())) | ||||
|                         { | ||||
|                             auto strm = static_cast<TlsServerStream*>(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<TObject> args2)->TObject { | ||||
|                     if(args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2])) | ||||
|                     { | ||||
|                         auto byteArray = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj); | ||||
|                         size_t offset = (size_t)std::get<int64_t>(args2[1]); | ||||
|                         size_t length = (size_t)std::get<int64_t>(args2[2]); | ||||
| 
 | ||||
| 
 | ||||
|                         if(!native->GetDestroyed() && byteArray != nullptr && ((offset + length) <= byteArray->data.size())) | ||||
|                         { | ||||
|                             auto strm = static_cast<TlsServerStream*>(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<TObject> args2)->TObject { | ||||
|                      | ||||
|                         if(!native->GetDestroyed()) | ||||
|                         { | ||||
|                             native->Destroy(); | ||||
|                         } | ||||
|                      | ||||
|                     return Undefined(); | ||||
|                 }); | ||||
|                 return dict; | ||||
|             } | ||||
|         } | ||||
|         return Undefined(); | ||||
|     } | ||||
|    | ||||
|     static TObject Crypto_Sha1(GCList& ls, std::vector<TObject> args) | ||||
|     { | ||||
|          | ||||
|  | @ -750,6 +200,60 @@ namespace Tesses::CrossLang | |||
|          | ||||
|         return dict; | ||||
|     } | ||||
|     static TObject Crypto_Base64Encode(GCList& ls, std::vector<TObject> 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<TObject> 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(); | ||||
|  |  | |||
|  | @ -8,7 +8,6 @@ namespace Tesses::CrossLang | |||
|          | ||||
|         TDictionary* dict; | ||||
|         | ||||
|         dict->items.begin(); | ||||
|         if(args.size() == 1 && std::holds_alternative<THeapObjectHolder>(args[0])) | ||||
|         { | ||||
|             auto item = dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(args[0]).obj); | ||||
|  |  | |||
|  | @ -35,6 +35,10 @@ namespace Tesses::CrossLang | |||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
|     static TObject FS_CreateMemoryFilesystem(GCList& ls, std::vector<TObject> args) | ||||
|     { | ||||
|         return TVFSHeapObject::Create(ls, new Tesses::Framework::Filesystem::MemoryFilesystem()); | ||||
|     } | ||||
| 
 | ||||
|     static TObject FS_CreateFilesystem(GCList& ls, std::vector<TObject> args) | ||||
|     { | ||||
|  | @ -71,6 +75,41 @@ namespace Tesses::CrossLang | |||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
|     static TObject FS_CreateArchive(GCList& ls, std::vector<TObject> 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<TObject> 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(); | ||||
|     } | ||||
|  |  | |||
|  | @ -12,6 +12,31 @@ namespace Tesses::CrossLang | |||
| { | ||||
| 
 | ||||
| #if defined(CROSSLANG_ENABLE_JSON) | ||||
|     static bool IsValidForJson(TObject v) | ||||
|     { | ||||
|         if(std::holds_alternative<std::nullptr_t>(v)) return true; | ||||
| 
 | ||||
|         if(std::holds_alternative<int64_t>(v)) return true; | ||||
| 
 | ||||
|         if(std::holds_alternative<double>(v)) return true; | ||||
| 
 | ||||
| 
 | ||||
|         if(std::holds_alternative<bool>(v)) return true; | ||||
| 
 | ||||
| 
 | ||||
|         if(std::holds_alternative<std::string>(v)) return true; | ||||
| 
 | ||||
| 
 | ||||
|         if(std::holds_alternative<THeapObjectHolder>(v)) | ||||
|         { | ||||
|             auto res = std::get<THeapObjectHolder>(v); | ||||
|             auto ls = dynamic_cast<TList*>(res.obj); | ||||
|             auto dict = dynamic_cast<TDictionary*>(res.obj); | ||||
|             if(ls != nullptr) return true; | ||||
|             if(dict != nullptr) return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     static json_t* JsonSerialize(TObject v) | ||||
|     { | ||||
|         if(std::holds_alternative<std::nullptr_t>(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; | ||||
|  |  | |||
|  | @ -329,6 +329,14 @@ namespace Tesses::CrossLang | |||
|         } | ||||
|         return Undefined(); | ||||
|     } | ||||
|     static TObject Net_HtmlEncode(GCList& ls, std::vector<TObject> args) | ||||
|     { | ||||
|         if(args.size() == 1 && std::holds_alternative<std::string>(args[0])) | ||||
|         {    | ||||
|             return  HttpUtils::HtmlEncode(std::get<std::string>(args[0])); | ||||
|         } | ||||
|         return Undefined(); | ||||
|     } | ||||
|     static TObject Net_UrlEncode(GCList& ls, std::vector<TObject> args) | ||||
|     { | ||||
|         if(args.size() == 1 && std::holds_alternative<std::string>(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); | ||||
|  |  | |||
							
								
								
									
										879
									
								
								src/vm/vm.cpp
								
								
								
								
							
							
						
						
									
										879
									
								
								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<THeapObjectHolder>(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<CallStackEntry*>& 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<CallStackEntry*>& 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<CallStackEntry*>& 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<CallStackEntry*>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<Undefined>(_res2)) | ||||
|         { | ||||
|             throw VMByteCodeException(gc,_res2); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     void InterperterThread::PushString(GC* gc) | ||||
|     bool InterperterThread::JumpUndefined(GC* gc) | ||||
|     { | ||||
|          | ||||
|         std::vector<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<Undefined>(_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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|      | ||||
|         execute: | ||||
|         std::vector<CallStackEntry*>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         auto stk = cse.back(); | ||||
|         | ||||
|         stk->Push(gc,nullptr); | ||||
|         return false; | ||||
|     } | ||||
|      bool InterperterThread::PushUndefined(GC* gc) | ||||
|     { | ||||
| 
 | ||||
|         std::vector<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         auto stk = cse.back(); | ||||
|         | ||||
|         stk->Push(gc,Undefined()); | ||||
|         return false; | ||||
|     } | ||||
|       bool InterperterThread::PushFalse(GC* gc) | ||||
|     { | ||||
| 
 | ||||
|         std::vector<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         auto stk = cse.back(); | ||||
|         | ||||
|         stk->Push(gc,false); | ||||
|         return false; | ||||
|     } | ||||
|       bool InterperterThread::PushTrue(GC* gc) | ||||
|     { | ||||
| 
 | ||||
|         std::vector<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         auto stk = cse.back(); | ||||
|         | ||||
|         stk->Push(gc,true); | ||||
|         return false; | ||||
|     } | ||||
|     bool InterperterThread::CreateDictionary(GC* gc) | ||||
|     { | ||||
| 
 | ||||
|         std::vector<CallStackEntry*>& 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<CallStackEntry*>& 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<THeapObjectHolder>(objhold)) | ||||
|                         { | ||||
|                             uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); | ||||
|                              | ||||
|                              | ||||
|                              stk->ip = n; | ||||
|                             auto list= dynamic_cast<TList*>(std::get<THeapObjectHolder>(objhold).obj); | ||||
|                             if(list != nullptr) | ||||
|                             { | ||||
|                                 list->Add(obj); | ||||
|                             } | ||||
|                             /*
 | ||||
|                             if(dict != nullptr) | ||||
|                             { | ||||
|                                 auto potential_str = stk->Pop(ls); | ||||
|                                 if(std::holds_alternative<std::string>(potential_str)) | ||||
|                                 { | ||||
|                                     dict->SetValue(std::get<std::string>(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<CallStackEntry*>& 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<THeapObjectHolder>(objhold) && std::holds_alternative<std::string>(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<TDictionary*>(std::get<THeapObjectHolder>(objhold).obj); | ||||
|                             | ||||
|                              | ||||
|                             if(dict != nullptr) | ||||
|                             { | ||||
|                                 dict->SetValue(std::get<std::string>(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<CallStackEntry*>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         auto stk = cse.back(); | ||||
|         GCList ls(gc); | ||||
|         stk->Pop(ls); | ||||
|         return false; | ||||
|     } | ||||
|     bool InterperterThread::TryCatch(GC* gc) | ||||
|     { | ||||
| 
 | ||||
|         std::vector<CallStackEntry*>& 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<CallStackEntry*>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
|         if(!cse.empty()) | ||||
|         { | ||||
|             auto stk = cse.back(); | ||||
|             std::vector<uint8_t>& 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<CallStackEntry*>& 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<CallStackEntry*>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
| 
 | ||||
|         auto stk = cse.back(); | ||||
| 
 | ||||
|                         if(!std::holds_alternative<Undefined>(_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<Undefined>(_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<TCallable*> 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<CallStackEntry*>& 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<CallStackEntry*>& cse=this->call_stack_entries; | ||||
| 
 | ||||
|         auto stk = cse.back(); | ||||
| 
 | ||||
|         gc->BarrierBegin(); | ||||
|                         GCList ls(gc); | ||||
|                         std::vector<TCallable*> callable; | ||||
|                         std::vector<uint8_t>& 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<CallStackEntry*>& 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<THeapObjectHolder>(objhold)) | ||||
|                         GCList ls(gc); | ||||
|                         std::vector<TCallable*> callable; | ||||
|                      | ||||
|                         if(!stk->env->defers.empty()) | ||||
|                         { | ||||
|                             auto list= dynamic_cast<TList*>(std::get<THeapObjectHolder>(objhold).obj); | ||||
|                             if(list != nullptr) | ||||
|                             { | ||||
|                                 list->Add(obj); | ||||
|                             } | ||||
|                             /*
 | ||||
|                             if(dict != nullptr) | ||||
|                             { | ||||
|                                 auto potential_str = stk->Pop(ls); | ||||
|                                 if(std::holds_alternative<std::string>(potential_str)) | ||||
|                                 { | ||||
|                                     dict->SetValue(std::get<std::string>(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<THeapObjectHolder>(objhold) && std::holds_alternative<std::string>(k)) | ||||
|                         { | ||||
|                             auto dict= dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(objhold).obj); | ||||
|                             | ||||
|                              | ||||
|                             if(dict != nullptr) | ||||
|                             { | ||||
|                                 dict->SetValue(std::get<std::string>(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<CallStackEntry*>& 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<CallStackEntry*>& 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(); | ||||
|                  | ||||
|  |  | |||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
		Reference in New Issue