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,557 +19,7 @@
|
|||
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);
|
||||
|
|
807
src/vm/vm.cpp
807
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;
|
||||
|
||||
gc->BarrierBegin();
|
||||
GCList ls(gc);
|
||||
TClosure* closure = TClosure::Create(ls,stk->env,stk->callable->file,n,ownScope);
|
||||
stk->Push(gc,closure);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
else
|
||||
auto _res2 = cse.back()->Pop(ls);
|
||||
|
||||
if(!std::holds_alternative<Undefined>(_res2))
|
||||
{
|
||||
throw VMException("Can't read chunk.");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InterperterThread::Execute(GC* gc)
|
||||
{
|
||||
|
||||
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
|
||||
|
||||
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;
|
||||
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]);
|
||||
|
||||
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;
|
||||
auto stk = cse.back();
|
||||
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case JMPC:
|
||||
bool InterperterThread::PushNull(GC* gc)
|
||||
{
|
||||
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;
|
||||
|
||||
|
||||
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
|
||||
auto stk = cse.back();
|
||||
|
||||
stk->Push(gc,nullptr);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
throw VMException("Can't read jmpc pc.");
|
||||
}
|
||||
break;
|
||||
case TRYCATCH:
|
||||
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))
|
||||
{
|
||||
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));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
auto dict= dynamic_cast<TDictionary*>(std::get<THeapObjectHolder>(objhold).obj);
|
||||
|
||||
|
||||
if(dict != nullptr)
|
||||
{
|
||||
dict->SetValue(std::get<std::string>(k), value);
|
||||
}
|
||||
}
|
||||
|
||||
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,177 +3685,213 @@ namespace Tesses::CrossLang {
|
|||
stk->Push(gc, catchC->Call(ls,{dict}));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case THROW:
|
||||
bool InterperterThread::JumpConditional(GC* gc)
|
||||
{
|
||||
|
||||
GCList ls2(gc);
|
||||
auto _res2 = stk->Pop(ls2);
|
||||
|
||||
if(!std::holds_alternative<Undefined>(_res2))
|
||||
{
|
||||
throw VMByteCodeException(gc,_res2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JMPUNDEFINED:
|
||||
{
|
||||
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(std::holds_alternative<Undefined>(_res2))
|
||||
if(_res)
|
||||
stk->ip = n;
|
||||
else
|
||||
stk->Push(gc,_res2);
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
throw VMException("Can't read jmpundefined pc.");
|
||||
throw VMException("Can't read jmpc pc.");
|
||||
return false;
|
||||
}
|
||||
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:
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case SCOPEEND:
|
||||
bool InterperterThread::Defer(GC* gc)
|
||||
{
|
||||
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
|
||||
|
||||
auto stk = cse.back();
|
||||
|
||||
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();
|
||||
|
||||
|
||||
for(auto item : callable)
|
||||
{
|
||||
GCList ls2(gc);
|
||||
item->Call(ls2,{});
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case SCOPEENDTIMES:
|
||||
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);
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
bool InterperterThread::ScopeEnd(GC* gc)
|
||||
{
|
||||
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
|
||||
|
||||
case APPENDLIST:
|
||||
{
|
||||
GCList ls(gc);
|
||||
gc->BarrierBegin();
|
||||
auto obj = stk->Pop(ls);
|
||||
auto objhold= stk->Pop(ls);
|
||||
if(std::holds_alternative<THeapObjectHolder>(objhold))
|
||||
{
|
||||
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));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
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);
|
||||
auto stk = cse.back();
|
||||
|
||||
|
||||
if(dict != nullptr)
|
||||
{
|
||||
dict->SetValue(std::get<std::string>(k), value);
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
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();
|
||||
gc->BarrierEnd();
|
||||
|
||||
|
||||
for(auto item : callable)
|
||||
{
|
||||
GCList ls2(gc);
|
||||
item->Call(ls2,{});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool InterperterThread::Illegal(GC* gc)
|
||||
{
|
||||
|
||||
|
||||
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
|
||||
|
||||
auto stk = cse.back();
|
||||
char chr[3];
|
||||
snprintf(chr,3,"%02X",stk->callable->closure->code[ip]);
|
||||
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