Files
Mike Nolan c1c3d02bf0
All checks were successful
Build and Deploy on Tag / 🔨 Build for PowerPC (push) Successful in 32s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-riscv64:latest, riscv64-linux-gnu, riscv64) (push) Successful in 3m33s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-x64:latest, x86_64-linux-gnu, amd64) (push) Successful in 3m42s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-arm64:latest, aarch64-linux-gnu, arm64) (push) Successful in 4m1s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-arm:latest, arm-linux-gnueabihf, arm7) (push) Successful in 4m1s
Build and Deploy on Tag / update-tap (push) Successful in 3m55s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-x86:latest, i386-linux-gnu, 386) (push) Successful in 59s
Replace time-based GC with allocation-count trigger, migrate all Create factories to GCList::Create(), fix VFSPath root path, reorder TObject variant
2026-09-01 06:04:58 -05:00

1637 lines
61 KiB
C++

#include "CrossLang.hpp"
#include "TessesFramework/Streams/ByteReader.hpp"
#include "TessesFramework/Streams/Stream.hpp"
#include "TessesFramework/Uuid.hpp"
#include <memory>
#include <variant>
#include <vector>
#if !defined(CROSSLANG_STATIC)
#if defined(CROSSLANG_ENABLE_FFI)
#include <ffi.h>
#endif
#if !defined(_WIN32)
#include <dlfcn.h>
#include <unistd.h>
#endif
#else
#if !defined(_WIN32)
#include <unistd.h>
#endif
#endif
namespace Tesses::CrossLang {
#if defined(_WIN32)
std::string SharedExtension = ".dll";
#elif defined(__APPLE__)
std::string SharedExtension = ".dylib";
#else
std::string SharedExtension = ".so";
#endif
class TMuxex : public TNativeObject {
public:
Tesses::Framework::Threading::Mutex mtx;
std::string TypeName() { return "Mutex"; }
TObject CallMethod(GCList &ls, std::string key, std::vector<TObject> args) {
if (key == "Lock") {
mtx.Lock();
} else if (key == "Unlock") {
mtx.Unlock();
} else if (key == "TryLock") {
return mtx.TryLock();
}
return Undefined();
}
};
#if !defined(CROSSLANG_STATIC)
class DL {
void *handle;
public:
DL(Tesses::Framework::Filesystem::VFSPath p) {
Tesses::Framework::Filesystem::LocalFilesystem lfs;
std::string str = lfs.VFSPathToSystem(p);
#if defined(_WIN32)
throw std::runtime_error("I removed support on this platform");
// handle =LoadLibraryExA(str.c_str(), NULL,
// LOAD_WITH_ALTERED_SEARCH_PATH);
#else
handle = dlopen(str.c_str(), RTLD_LAZY);
#endif
}
template <typename T> T Resolve(std::string name) {
#if defined(_WIN32)
throw std::runtime_error("I removed support on this platform");
// return (T)GetProcAddress((HMODULE)handle, name.c_str());
#else
return (T)dlsym(handle, name.c_str());
#endif
}
~DL() {
#if defined(_WIN32)
throw std::runtime_error("I removed support on this platform");
// FreeLibrary((HMODULE)handle);
#else
dlclose(handle);
#endif
}
};
#endif
#if defined(CROSSLANG_ENABLE_FFI)
typedef union {
ffi_arg v_arg;
ffi_sarg v_sarg;
uint64_t v_u64;
int64_t v_i64;
double v_f64;
void *v_ptr;
} ffi_tmp_type_t;
template <typename T> class ffi_my_struct_t {
char ffi_my_struct_chr;
T ffi_my_struct_val;
public:
static int64_t GetPadding() {
ffi_my_struct_t<T> s;
return ((int64_t)&s.ffi_my_struct_val - (int64_t)&s.ffi_my_struct_chr);
}
};
ffi_tmp_type_t FFI_ConvertTObjectToFFIType(TObject &arg, std::string t) {
if (std::holds_alternative<char>(arg)) {
if (t == "char" || t == "i8" || t == "i16" || t == "i32") {
return (ffi_tmp_type_t){.v_sarg = std::get<char>(arg)};
} else if (t == "u8" || t == "u16" || t == "u32") {
return (ffi_tmp_type_t){.v_arg = (uint8_t)std::get<char>(arg)};
} else if (t == "u64") {
return (ffi_tmp_type_t){.v_u64 = (uint8_t)std::get<char>(arg)};
} else if (t == "i64") {
return (ffi_tmp_type_t){.v_i64 = std::get<char>(arg)};
}
} else if (std::holds_alternative<int64_t>(arg)) {
if (t == "u8" || t == "u16" || t == "u32") {
return (ffi_tmp_type_t){
.v_arg = (ffi_arg)(uint64_t)std::get<int64_t>(arg)};
} else if (t == "char" || t == "i8" || t == "i16" || t == "i32") {
return (ffi_tmp_type_t){.v_sarg = (ffi_sarg)std::get<int64_t>(arg)};
} else if (t == "u64") {
return (ffi_tmp_type_t){.v_u64 = (uint64_t)std::get<int64_t>(arg)};
} else if (t == "i64") {
return (ffi_tmp_type_t){.v_i64 = std::get<int64_t>(arg)};
} else if (t == "pointer" || t == "string") {
return (ffi_tmp_type_t){.v_ptr = (void *)std::get<int64_t>(arg)};
}
} else if (std::holds_alternative<double>(arg)) {
if (t == "f64") {
return (ffi_tmp_type_t){.v_f64 = std::get<double>(arg)};
}
} else if (std::holds_alternative<std::string>(arg)) {
if (t == "pointer" || t == "string") {
return (ffi_tmp_type_t){
.v_ptr = (void *)std::get<std::string>(arg).c_str()};
}
} else if (std::holds_alternative<THeapObjectHolder>(arg)) {
auto obj = std::get<THeapObjectHolder>(arg).obj;
auto bA = dynamic_cast<TByteArray *>(obj);
auto nat = dynamic_cast<TNative *>(obj);
if (bA != nullptr) {
if (t == "pointer" || t == "string") {
return (ffi_tmp_type_t){.v_ptr = (void *)bA->data.data()};
}
}
if (nat != nullptr) {
if (t == "pointer" || t == "string") {
return (ffi_tmp_type_t){.v_ptr = nat->GetPointer()};
}
}
}
return {0};
}
ffi_type *FFI_ConvertStringToFFIType(std::string t) {
if (t == "char") {
return &ffi_type_schar;
} else if (t == "i8") {
return &ffi_type_sint8;
} else if (t == "u8") {
return &ffi_type_uint8;
} else if (t == "i16") {
return &ffi_type_sint16;
} else if (t == "u16") {
return &ffi_type_uint16;
} else if (t == "i32") {
return &ffi_type_sint32;
} else if (t == "u32") {
return &ffi_type_uint32;
} else if (t == "i64") {
return &ffi_type_sint64;
} else if (t == "u64") {
return &ffi_type_uint64;
} else if (t == "float") {
return &ffi_type_float;
} else if (t == "double") {
return &ffi_type_double;
} else if (t == "void") {
return &ffi_type_void;
} else if (t == "pointer" || t == "string") {
return &ffi_type_pointer;
}
return nullptr;
}
TExternalMethod *FFI_CreateFunction(GCList &ls, TNative *native,
std::string retVal,
std::vector<std::string> listArgs,
ffi_abi abi, bool freeRet) {
ffi_type *retTypeT = FFI_ConvertStringToFFIType(retVal);
std::vector<ffi_type *> argTypes;
argTypes.resize(listArgs.size());
for (size_t i = 0; i < listArgs.size(); i++) {
argTypes[i] = FFI_ConvertStringToFFIType(listArgs[i]);
}
auto cb = TExternalMethod::Create(
ls, "FFI Generated function, returns: " + retVal, listArgs,
[retVal, listArgs, abi, native, freeRet, argTypes,
retTypeT](GCList &ls, std::vector<TObject> args) -> TObject {
if (args.size() != listArgs.size())
throw VMException("Args must be " +
std::to_string(listArgs.size()) + "but got " +
std::to_string(args.size()) + ".");
ffi_cif cif;
std::vector<void *> argVals;
std::vector<ffi_tmp_type_t> tmpTypes;
argVals.resize(listArgs.size());
tmpTypes.resize(listArgs.size());
for (size_t i = 0; i < argTypes.size(); i++) {
tmpTypes[i] = FFI_ConvertTObjectToFFIType(args[i], listArgs[i]);
if (listArgs[i] == "char" || listArgs[i] == "i8" ||
listArgs[i] == "i16" || listArgs[i] == "i32" ||
listArgs[i] == "u8" || listArgs[i] == "u16" ||
listArgs[i] == "u32") {
argVals[i] = (void *)&(tmpTypes[i].v_arg);
}
else if (listArgs[i] == "u64" || listArgs[i] == "i64") {
argVals[i] = (void *)&(tmpTypes[i].v_u64);
} else if (listArgs[i] == "pointer" ||
listArgs[i] == "string") {
argVals[i] = (void *)&(tmpTypes[i].v_ptr);
} else if (listArgs[i] == "f64") {
argVals[i] = (void *)&(tmpTypes[i].v_f64);
}
}
ffi_prep_cif(&cif, abi, (unsigned int)listArgs.size(), retTypeT,
(ffi_type **)argTypes.data());
ffi_tmp_type_t retObj;
void *retPtr = NULL;
if (retVal == "char" || retVal == "i8" || retVal == "u8" ||
retVal == "i16" || retVal == "u16" || retVal == "i32" ||
retVal == "u32") {
retPtr = (void *)&(retObj.v_arg);
} else if (retVal == "i64" || retVal == "u64") {
retPtr = (void *)&(retObj.v_u64);
} else if (retVal == "f64") {
retPtr = (void *)&(retObj.v_f64);
} else if (retVal == "pointer" || retVal == "string") {
retPtr = (void *)&(retObj.v_ptr);
}
ffi_call(&cif, (void (*)())native->GetPointer(), retPtr,
argVals.data());
if (retVal == "char")
return (char)retObj.v_sarg;
if (retVal == "i8" || retVal == "i16" || retVal == "i32")
return (int64_t)retObj.v_sarg;
if (retVal == "u8" || retVal == "u16" || retVal == "u32")
return (int64_t)retObj.v_arg;
if (retVal == "i64" || retVal == "u64")
return retObj.v_i64;
if (retVal == "f64")
return retObj.v_f64;
if (retVal == "string") {
std::string res = (char *)retObj.v_ptr;
if (freeRet)
free(retObj.v_ptr);
return res;
}
if (retVal == "pointer") {
TNative *native3 = TNative::Create(
ls, retObj.v_ptr, [freeRet](void *_ptr) -> void {
if (freeRet)
free(_ptr);
});
native3->other = native;
return native3;
}
return nullptr;
});
cb->watch.push_back(native);
return cb;
}
void RegisterFFI(std::shared_ptr<GC> gc, TDictionary *dict) {
dict->SetValue("SizeOfChar", (int64_t)sizeof(char));
dict->SetValue("SizeOfShort", (int64_t)sizeof(short));
dict->SetValue("SizeOfInt", (int64_t)sizeof(int));
dict->SetValue("SizeOfLong", (int64_t)sizeof(long));
dict->SetValue("SizeOfLongLong", (int64_t)sizeof(long long));
dict->SetValue("SizeOfInt8", (int64_t)sizeof(int8_t));
dict->SetValue("SizeOfInt16", (int64_t)sizeof(int16_t));
dict->SetValue("SizeOfInt32", (int64_t)sizeof(int32_t));
dict->SetValue("SizeOfInt64", (int64_t)sizeof(int64_t));
dict->SetValue("SizeOfFloat", (int64_t)sizeof(float));
dict->SetValue("SizeOfDouble", (int64_t)sizeof(double));
dict->SetValue("SizeOfPointer", (int64_t)sizeof(void *));
dict->SetValue("PaddingOfShort", ffi_my_struct_t<short>::GetPadding());
dict->SetValue("PaddingOfInt", ffi_my_struct_t<int>::GetPadding());
dict->SetValue("PaddingOfLong", ffi_my_struct_t<long>::GetPadding());
dict->SetValue("PaddingOfLongLong",
ffi_my_struct_t<long long>::GetPadding());
dict->SetValue("PaddingOfInt16", ffi_my_struct_t<int16_t>::GetPadding());
dict->SetValue("PaddingOfInt32", ffi_my_struct_t<int32_t>::GetPadding());
dict->SetValue("PaddingOfInt64", ffi_my_struct_t<int64_t>::GetPadding());
dict->SetValue("PaddingOfFloat", ffi_my_struct_t<float>::GetPadding());
dict->SetValue("PaddingOfDouble", ffi_my_struct_t<double>::GetPadding());
dict->SetValue("PaddingOfPointer", ffi_my_struct_t<void *>::GetPadding());
union {
uint8_t c[2];
uint16_t num;
} endian;
endian.c[0] = 0x01;
endian.c[1] = 0xA4;
dict->SetValue("IsLittleEndian", (bool)(endian.num != 420));
dict->DeclareFunction(
gc, "Open", "Open a shared object", {"path"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
Tesses::Framework::Filesystem::VFSPath path;
if (GetArgumentAsPath(args, 0, path)) {
return TNative::Create(
ls, static_cast<void *>(new DL(path)),
[](void *ptr) -> void { delete static_cast<DL *>(ptr); });
}
return nullptr;
});
dict->DeclareFunction(
gc, "Symbol", "Get current symbol", {"sharedObj", "name"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
TNative *native;
std::string name;
if (GetArgumentHeap(args, 0, native) &&
GetArgument(args, 1, name)) {
if (native->GetDestroyed())
return nullptr;
DL *dl = static_cast<DL *>(native->GetPointer());
auto native2 = TNative::Create(ls, dl->Resolve<void *>(name),
[](void *_e) -> void {});
native2->other = native;
return native2;
}
return nullptr;
});
dict->DeclareFunction(gc, "Close", "Closes the shared object",
{"sharedObj"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
TNative *native;
if (GetArgumentHeap(args, 0, native))
native->Destroy();
return nullptr;
});
dict->DeclareFunction(
gc, "CreateFunction", "Create a function",
{"functionPtr", "returnVal", "args", "$abi", "$freeRet"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
TNative *native;
std::string retVal;
TList *listArgsO;
int64_t abi = (int64_t)FFI_DEFAULT_ABI;
bool freeRet = false;
if (GetArgumentHeap(args, 0, native) &&
GetArgument(args, 1, retVal) &&
GetArgumentHeap(args, 2, listArgsO)) {
GetArgument(args, 3, abi);
GetArgument(args, 4, freeRet);
std::vector<std::string> listArgs;
for (int64_t i = 0; i < listArgsO->Count(); i++) {
auto item = listArgsO->Get(i);
std::string typ;
if (GetObject(item, typ))
listArgs.push_back(typ);
}
return FFI_CreateFunction(ls, native, retVal, listArgs,
(ffi_abi)abi, freeRet);
}
return nullptr;
});
}
#endif
Tesses::Framework::Filesystem::VFSPath
GetPluginPath(Tesses::Framework::Filesystem::VFSPath path) {
using namespace Tesses::Framework::Filesystem;
if (!path.relative)
return path;
auto pluginConfigDir = GetCrossLangConfigDir() / "Plugins";
if (LocalFS->DirectoryExists(pluginConfigDir)) {
if (LocalFS->FileExists(pluginConfigDir / path + SharedExtension))
return pluginConfigDir / path + SharedExtension;
auto path2 = pluginConfigDir / path.GetParent() / "lib" +
path.GetFileName() + SharedExtension;
if (LocalFS->FileExists(path2))
return path2;
}
return path;
}
void LoadPlugin(std::shared_ptr<GC> gc, TRootEnvironment *env,
Tesses::Framework::Filesystem::VFSPath sharedObjectPath) {
#if !defined(CROSSLANG_STATIC)
auto ptr = std::make_shared<DL>(GetPluginPath(sharedObjectPath));
auto cb = ptr->Resolve<PluginFunction>("CrossLangPluginInit");
if (cb == nullptr)
return;
gc->RegisterEverythingCallback(
[ptr, cb](std::shared_ptr<GC> gc, TRootEnvironment *env) -> void {
cb(gc, env);
});
cb(gc, env);
#endif
}
static TObject TypeIsClass(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
if (args.empty())
return nullptr;
TClassObject *co;
return GetArgumentHeap(args, 0, co);
}
static TObject TypeIsDefined(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
return (!std::holds_alternative<std::nullptr_t>(args[0]) &&
!std::holds_alternative<Undefined>(args[0]));
}
static TObject TypeIsHeap(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
return std::holds_alternative<THeapObjectHolder>(args[0]);
}
static TObject TypeIsNumber(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
return std::holds_alternative<int64_t>(args[0]) ||
std::holds_alternative<double>(args[0]);
}
static TObject TypeIsLong(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
return std::holds_alternative<int64_t>(args[0]);
}
static TObject TypeIsDouble(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
return std::holds_alternative<double>(args[0]);
}
static TObject TypeIsString(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
return std::holds_alternative<std::string>(args[0]);
}
static TObject TypeIsCallable(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
TCallable *call;
return GetArgumentHeap(args, 0, call);
}
static TObject TypeIsDictionary(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
TDictionary *dict;
TDynamicDictionary *dynDict;
return GetArgumentHeap(args, 0, dict) || GetArgumentHeap(args, 0, dynDict);
}
static TObject TypeIsList(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
TList *list;
TDynamicList *dynList;
return GetArgumentHeap(args, 0, list) || GetArgumentHeap(args, 0, dynList);
}
static TObject TypeIsStream(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
return GetArgument(args, 0, strm);
}
static TObject TypeIsTextReader(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<Tesses::Framework::TextStreams::TextReader> strm;
return GetArgument(args, 0, strm);
}
static TObject TypeIsTextWriter(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<Tesses::Framework::TextStreams::TextWriter> strm;
return GetArgument(args, 0, strm);
}
static TObject TypeIsByteReader(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<Tesses::Framework::Streams::ByteReader> strm;
return GetArgument(args, 0, strm);
}
static TObject TypeIsByteWriter(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<Tesses::Framework::Streams::ByteWriter> strm;
return GetArgument(args, 0, strm);
}
static TObject TypeIsUuid(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
return std::holds_alternative<Tesses::Framework::Uuid>(args[0]);
}
static TObject TypeIsVFS(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
return GetArgument(args, 0, vfs);
}
static TObject TypeIsDateTime(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<Tesses::Framework::Date::DateTime> dt;
return GetArgument(args, 0, dt);
}
static TObject TypeIsTimeSpan(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<Tesses::Framework::Date::TimeSpan> dt;
return GetArgument(args, 0, dt);
}
static TObject TypeIsQueryable(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return nullptr;
TQueryable *queryable;
return GetArgumentHeap(args, 0, queryable);
}
static TObject New_SubdirFilesystem(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
Tesses::Framework::Filesystem::VFSPath path;
if (GetArgument(args, 0, vfs) && GetArgumentAsPath(args, 1, path)) {
return std::make_shared<
Tesses::Framework::Filesystem::SubdirFilesystem>(vfs, path);
}
return nullptr;
}
static TObject New_MountableFilesystem(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
if (GetArgument(args, 0, vfs)) {
return std::make_shared<
Tesses::Framework::Filesystem::MountableFilesystem>(vfs);
}
return nullptr;
}
static TObject New_MemoryStream(GCList &ls, std::vector<TObject> args) {
bool writable;
if (GetArgument(args, 0, writable)) {
return std::make_shared<Tesses::Framework::Streams::MemoryStream>(
writable);
}
return nullptr;
}
static TObject New_Filesystem(GCList &ls, std::vector<TObject> args) {
TDictionary *dict;
if (GetArgumentHeap(args, 0, dict)) {
return std::make_shared<TObjectVFS>(ls.GetGC(), dict);
}
return nullptr;
}
static TObject New_TempFS(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
if (GetArgument(args, 0, vfs)) {
bool deleteOnDispose = true;
GetArgument(args, 1, deleteOnDispose);
return std::make_shared<Tesses::Framework::Filesystem::TempFS>(
vfs, deleteOnDispose);
} else {
bool deleteOnDispose;
if (GetArgument(args, 0, deleteOnDispose)) {
return std::make_shared<Tesses::Framework::Filesystem::TempFS>(
deleteOnDispose);
}
}
return std::make_shared<Tesses::Framework::Filesystem::TempFS>();
}
static TObject New_Stream(GCList &ls, std::vector<TObject> args) {
TDictionary *dict;
if (GetArgumentHeap(args, 0, dict)) {
return std::make_shared<TObjectStream>(ls.GetGC(), dict);
}
return nullptr;
}
static TObject New_DateTime(GCList &ls, std::vector<TObject> args) {
int64_t year;
if (GetArgument(args, 0, year)) {
if (args.size() == 1) {
return std::make_shared<Tesses::Framework::Date::DateTime>(year);
} else {
int64_t month = 1;
int64_t day = 1;
int64_t hour = 0;
int64_t minute = 0;
int64_t second = 0;
bool isLocal = true;
GetArgument(args, 1, month);
GetArgument(args, 2, day);
GetArgument(args, 3, hour);
GetArgument(args, 4, minute);
GetArgument(args, 5, second);
GetArgument(args, 6, isLocal);
return std::make_shared<Tesses::Framework::Date::DateTime>(
(int)year, (int)month, (int)day, (int)hour, (int)minute,
(int)second, isLocal);
}
}
return nullptr;
}
static TObject New_TimeSpan(GCList &ls, std::vector<TObject> args) {
int64_t arg1;
if (GetArgument(args, 0, arg1)) {
if (args.size() == 1) {
return std::make_shared<Tesses::Framework::Date::TimeSpan>(arg1);
} else if (args.size() >= 3) {
int64_t arg2;
int64_t arg3;
if (GetArgument(args, 1, arg2) && GetArgument(args, 2, arg3)) {
int64_t arg4;
if (GetArgument(args, 3, arg4)) {
return std::make_shared<Tesses::Framework::Date::TimeSpan>(
(int)arg1, (int)arg2, (int)arg3, (int)arg4);
} else {
return std::make_shared<Tesses::Framework::Date::TimeSpan>(
(int)arg1, (int)arg2, (int)arg3);
;
}
}
}
}
return nullptr;
}
std::string GetObjectTypeString(TObject _obj) {
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::TF_Timer_Handle>>(_obj))
return "Timer";
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Http::ServerSentEvents>>(_obj))
return "ServerSentEvents";
if (std::holds_alternative<std::regex>(_obj))
return "Regex";
if (std::holds_alternative<Undefined>(_obj))
return "Undefined";
if (std::holds_alternative<std::nullptr_t>(_obj))
return "Null";
if (std::holds_alternative<bool>(_obj))
return "Boolean";
if (std::holds_alternative<int64_t>(_obj))
return "Long";
if (std::holds_alternative<double>(_obj))
return "Double";
if (std::holds_alternative<char>(_obj))
return "Char";
if (std::holds_alternative<MethodInvoker>(_obj))
return "MethodInvoker";
if (std::holds_alternative<std::string>(_obj))
return "String";
if (std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(_obj))
return "Path";
if (std::holds_alternative<TVMVersion>(_obj))
return "Version";
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(_obj))
return "DateTime";
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(_obj))
return "TimeSpan";
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Streams::ByteReader>>(_obj))
return "ByteReader";
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Streams::ByteWriter>>(_obj))
return "ByteWriter";
if (std::holds_alternative<Tesses::Framework::Uuid>(_obj))
return "Uuid";
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Streams::Stream>>(_obj)) {
auto strm =
std::get<std::shared_ptr<Tesses::Framework::Streams::Stream>>(_obj);
if (strm != nullptr) {
auto netStrm = std::dynamic_pointer_cast<
Tesses::Framework::Streams::NetworkStream>(strm);
if (netStrm != nullptr) {
return "NetworkStream";
}
}
return "Stream";
}
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Http::IHttpServer>>(_obj)) {
auto svr =
std::get<std::shared_ptr<Tesses::Framework::Http::IHttpServer>>(
_obj);
if (svr != nullptr) {
auto fileServer =
std::dynamic_pointer_cast<Tesses::Framework::Http::FileServer>(
svr);
auto mountableServer = std::dynamic_pointer_cast<
Tesses::Framework::Http::MountableServer>(svr);
auto routableServer =
std::dynamic_pointer_cast<Tesses::Framework::Http::RouteServer>(
svr);
if (fileServer != nullptr) {
return "FileServer";
}
if (mountableServer != nullptr) {
return "MountableServer";
}
if (routableServer != nullptr) {
return "RoutableServer";
}
}
return "HttpServer";
}
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::TextStreams::TextReader>>(
_obj)) {
auto textReader = std::get<
std::shared_ptr<Tesses::Framework::TextStreams::TextReader>>(_obj);
if (textReader != nullptr) {
auto stringReader = std::dynamic_pointer_cast<
Tesses::Framework::TextStreams::StringReader>(textReader);
auto streamReader = std::dynamic_pointer_cast<
Tesses::Framework::TextStreams::StreamReader>(textReader);
auto consoleReader = std::dynamic_pointer_cast<
Tesses::Framework::TextStreams::ConsoleReader>(textReader);
if (stringReader != nullptr) {
return "StringReader";
}
if (streamReader != nullptr) {
return "StreamReader";
}
if (consoleReader != nullptr) {
return "ConsoleReader";
}
}
return "TextReader";
}
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(
_obj)) {
auto textWriter = std::get<
std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(_obj);
if (textWriter != nullptr) {
auto stringWriter = std::dynamic_pointer_cast<
Tesses::Framework::TextStreams::StringWriter>(textWriter);
auto streamWriter = std::dynamic_pointer_cast<
Tesses::Framework::TextStreams::StreamWriter>(textWriter);
auto consoleWriter = std::dynamic_pointer_cast<
Tesses::Framework::TextStreams::ConsoleReader>(textWriter);
if (stringWriter != nullptr) {
return "StringWriter";
}
if (streamWriter != nullptr) {
return "StreamWriter";
}
if (consoleWriter != nullptr) {
return "ConsoleWriter";
}
}
return "TextReader";
}
if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Filesystem::VFS>>(_obj)) {
auto vfs =
std::get<std::shared_ptr<Tesses::Framework::Filesystem::VFS>>(_obj);
if (vfs != nullptr) {
auto rfs = std::dynamic_pointer_cast<
Tesses::Framework::Filesystem::RelativeFilesystem>(vfs);
auto localVFS = std::dynamic_pointer_cast<
Tesses::Framework::Filesystem::LocalFilesystem>(vfs);
auto mountableVFS = std::dynamic_pointer_cast<
Tesses::Framework::Filesystem::MountableFilesystem>(vfs);
auto subFS = std::dynamic_pointer_cast<
Tesses::Framework::Filesystem::SubdirFilesystem>(vfs);
auto tempFS = std::dynamic_pointer_cast<
Tesses::Framework::Filesystem::TempFS>(vfs);
if (rfs)
return "RelativeFilesystem";
if (localVFS != nullptr)
return "LocalFilesystem";
if (subFS != nullptr)
return "SubdirFilesystem";
if (mountableVFS != nullptr)
return "MountableFilesystem";
if (tempFS != nullptr)
return "TempFS";
}
return "VFS";
}
if (std::holds_alternative<THeapObjectHolder>(_obj)) {
auto obj = std::get<THeapObjectHolder>(_obj).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto list = dynamic_cast<TList *>(obj);
auto dynList = dynamic_cast<TDynamicList *>(obj);
auto argWrapper = dynamic_cast<TArgWrapper *>(obj);
auto closure = dynamic_cast<TClosure *>(obj);
auto externalMethod = dynamic_cast<TExternalMethod *>(obj);
auto byteArray = dynamic_cast<TByteArray *>(obj);
auto native = dynamic_cast<TNative *>(obj);
auto any = dynamic_cast<TAny *>(obj);
auto cse = dynamic_cast<CallStackEntry *>(obj);
auto rootEnv = dynamic_cast<TRootEnvironment *>(obj);
auto subEnv = dynamic_cast<TSubEnvironment *>(obj);
auto env = dynamic_cast<TEnvironment *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cobj = dynamic_cast<TClassObject *>(obj);
auto aarray = dynamic_cast<TAssociativeArray *>(obj);
auto file = dynamic_cast<TFile *>(obj);
auto queryable = dynamic_cast<TQueryable *>(obj);
if (rootEnv != nullptr)
return "RootEnvironment";
if (subEnv != nullptr)
return "SubEnvironment";
if (env != nullptr)
return "Environment";
if (cobj != nullptr)
return cobj->TypeName();
if (cse != nullptr)
return "YieldedClosure";
if (dynDict != nullptr)
return "DynamicDictionary";
if (dynList != nullptr)
return "DynamicList";
if (aarray != nullptr)
return "AssociativeArray";
if (natObj != nullptr)
return natObj->TypeName();
if (dict != nullptr)
return "Dictionary";
if (list != nullptr)
return "List";
if (argWrapper != nullptr)
return "ArgWrapper";
if (closure != nullptr)
return "Closure";
if (externalMethod != nullptr)
return "ExternalMethod";
if (byteArray != nullptr)
return "ByteArray";
if (native != nullptr)
return "Native";
if (any != nullptr)
return "Any";
if (file != nullptr)
return "File";
if (queryable != nullptr)
return "Queryable";
return "HeapObject";
}
return "Object";
}
static TObject TypeOf(GCList &ls, std::vector<TObject> args) {
if (args.size() < 1)
return "Undefined";
return GetObjectTypeString(args[0]);
}
TObject ByteArray(GCList &ls, std::vector<TObject> args) {
auto res = TByteArray::Create(ls);
if (args.size() == 1) {
if (std::holds_alternative<int64_t>(args[0]))
res->data.resize((size_t)std::get<int64_t>(args[0]));
else if (std::holds_alternative<std::string>(args[0])) {
std::string &txt = std::get<std::string>(args[0]);
res->data.insert(res->data.end(), txt.begin(), txt.end());
}
}
return res;
}
TObject ParseLong(GCList &ls, std::vector<TObject> args) {
if (args.size() >= 1) {
int base = 10;
if (args.size() == 2 && std::holds_alternative<int64_t>(args[1])) {
base = (int)std::get<int64_t>(args[1]);
}
size_t pos;
std::string str = ToString(ls.GetGC(), args[0]);
try {
int64_t v = std::stoll(str, &pos, base);
if (pos < str.size())
return nullptr;
return v;
} catch (std::exception &ex) {
return nullptr;
}
}
return nullptr;
}
TObject ParseDouble(GCList &ls, std::vector<TObject> args) {
if (args.size() == 1) {
size_t pos;
std::string str = ToString(ls.GetGC(), args[0]);
try {
double v = std::stod(str, &pos);
if (pos < str.size())
return nullptr;
return v;
} catch (std::exception &ex) {
return nullptr;
}
}
return nullptr;
}
EnvironmentPermissions::EnvironmentPermissions() {
this->canRegisterConsole = false;
this->canRegisterCrypto = false;
this->canRegisterDictionary = false;
this->canRegisterEnv = false;
this->canRegisterIO = false;
this->canRegisterJSON = false;
this->canRegisterNet = false;
this->canRegisterOGC = false;
this->canRegisterPath = false;
this->canRegisterProcess = false;
this->canRegisterRoot = false;
this->canRegisterSqlite = false;
this->canRegisterVM = false;
this->locked = false;
this->sqlite3Scoped = false;
}
static TObject YieldEnumerableFunc(GCList &ls, std::vector<TObject> args) {
TClosure *closure;
if (GetArgumentHeap(args, 0, closure)) {
TDictionary *enumerableItem = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
auto fn = TExternalMethod::Create(
ls, "Get Enumerator for yield", {},
[closure](GCList &ls2, std::vector<TObject> args) -> TObject {
return TYieldEnumerator::Create(ls2, closure);
});
fn->watch.push_back(closure);
enumerableItem->SetValue("GetEnumerator", fn);
ls.GetGC()->BarrierEnd();
return enumerableItem;
}
return Undefined();
}
static TObject DateTime_Sleep(GCList &ls, std::vector<TObject> args) {
int64_t msec;
if (GetArgument(args, 0, msec)) {
Tesses::Framework::TF_Sleep(msec);
}
return nullptr;
}
static TObject DateTime_getNow(GCList &ls, std::vector<TObject> args) {
return std::make_shared<Tesses::Framework::Date::DateTime>(
Tesses::Framework::Date::DateTime::Now());
}
static TObject DateTime_getNowUTC(GCList &ls, std::vector<TObject> args) {
return std::make_shared<Tesses::Framework::Date::DateTime>(
Tesses::Framework::Date::DateTime::NowUTC());
}
static TObject DateTime_getNowEpoch(GCList &ls, std::vector<TObject> args) {
return (int64_t)time(NULL);
}
static TObject DateTime_TryParseHttpDate(GCList &ls,
std::vector<TObject> args) {
std::string d;
Tesses::Framework::Date::DateTime dt;
if (GetArgument(args, 0, d) &&
Tesses::Framework::Date::DateTime::TryParseHttpDate(d, dt)) {
return std::make_shared<Tesses::Framework::Date::DateTime>(dt);
}
return nullptr;
}
static TObject New_Promise(GCList &ls, std::vector<TObject> args) {
TCallable *call;
if (GetArgumentHeap(args, 0, call)) {
TTask *task = TTask::Create(ls);
TExternalMethod *resolve = TExternalMethod::Create(
ls, "fulfill the promise", {"arg"},
[task](GCList &ls, std::vector<TObject> args) -> TObject {
if (!args.empty()) {
task->SetSucceeded(args[0]);
}
return Undefined();
});
resolve->watch.push_back(task);
TExternalMethod *reject = TExternalMethod::Create(
ls, "reject the promise", {"arg"},
[task](GCList &ls, std::vector<TObject> args) -> TObject {
if (!args.empty()) {
auto item = args[0];
if (!std::holds_alternative<Undefined>(item)) {
try {
VMByteCodeException ex(ls.GetGC(), item, nullptr);
throw ex;
} catch (...) {
task->SetFailed(std::current_exception());
}
}
}
return Undefined();
});
reject->watch.push_back(task);
call->Call(ls, {resolve, reject});
return task;
}
return nullptr;
}
static TObject TimeSpan_Parse(GCList &ls, std::vector<TObject> args) {
std::string t;
Tesses::Framework::Date::TimeSpan ts;
if (GetArgument(args, 0, t) &&
Tesses::Framework::Date::TimeSpan::TryParse(t, ts)) {
return std::make_shared<Tesses::Framework::Date::TimeSpan>(ts);
}
return nullptr;
}
static TObject TimeSpan_FromSeconds(GCList &ls, std::vector<TObject> args) {
int64_t n;
if (GetArgument(args, 0, n)) {
return std::make_shared<Tesses::Framework::Date::TimeSpan>(n);
}
return nullptr;
}
static TObject TimeSpan_FromMinutes(GCList &ls, std::vector<TObject> args) {
int64_t n;
if (GetArgument(args, 0, n)) {
return std::make_shared<Tesses::Framework::Date::TimeSpan>(n * 60);
}
return nullptr;
}
static TObject TimeSpan_FromHours(GCList &ls, std::vector<TObject> args) {
int64_t n;
if (GetArgument(args, 0, n)) {
return std::make_shared<Tesses::Framework::Date::TimeSpan>(n * 3600);
}
return nullptr;
}
static TObject TimeSpan_FromDays(GCList &ls, std::vector<TObject> args) {
int64_t n;
if (GetArgument(args, 0, n)) {
return std::make_shared<Tesses::Framework::Date::TimeSpan>(n * 86400);
}
return nullptr;
}
static TObject New_StreamReader(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
Tesses::Framework::Filesystem::VFSPath path;
if (GetArgument(args, 0, strm)) {
return std::make_shared<Tesses::Framework::TextStreams::StreamReader>(
strm);
} else if (GetArgument(args, 0, vfs) && GetArgumentAsPath(args, 1, path)) {
strm = vfs->OpenFile(path, "rb");
return std::make_shared<Tesses::Framework::TextStreams::StreamReader>(
strm);
}
return nullptr;
}
static TObject New_StreamWriter(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
Tesses::Framework::Filesystem::VFSPath path;
if (GetArgument(args, 0, strm)) {
return std::make_shared<Tesses::Framework::TextStreams::StreamWriter>(
strm);
} else if (GetArgument(args, 0, vfs) && GetArgumentAsPath(args, 1, path)) {
bool append = false;
GetArgument(args, 2, append);
strm = vfs->OpenFile(path, append ? "ab" : "wb");
return std::make_shared<Tesses::Framework::TextStreams::StreamWriter>(
strm);
}
return nullptr;
}
static TObject New_StringReader(GCList &ls, std::vector<TObject> args) {
std::string str;
if (GetArgument(args, 0, str)) {
return std::make_shared<Tesses::Framework::TextStreams::StringReader>(
str);
}
return nullptr;
}
static TObject New_StringWriter(GCList &ls, std::vector<TObject> args) {
std::string str;
if (GetArgument(args, 0, str)) {
return std::make_shared<Tesses::Framework::TextStreams::StringWriter>(
str);
}
return std::make_shared<Tesses::Framework::TextStreams::StringWriter>();
}
static TObject Task_FromResult(GCList &ls, std::vector<TObject> args) {
if (!args.empty()) {
return TTask::FromResult(ls, args[0]);
}
return nullptr;
}
static TObject New_ByteReader(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
if (GetArgument(args, 0, strm))
return std::make_shared<Tesses::Framework::Streams::ByteReader>(strm);
return nullptr;
}
static TObject New_ByteWriter(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
if (GetArgument(args, 0, strm))
return std::make_shared<Tesses::Framework::Streams::ByteWriter>(strm);
return nullptr;
}
static void empty() {}
static TObject New_Timer(GCList &ls, std::vector<TObject> args) {
TCallable *callable;
if (GetArgumentHeap(args, 0, callable)) {
int64_t interval = 1000;
bool enabled = true;
GetArgument(args, 1, interval);
GetArgument(args, 2, enabled);
auto obj = CreateMarkedTObject(ls.GetGC(), callable);
return Tesses::Framework::TF_Timer(
[obj]() -> void {
TCallable *callable;
if (GetObjectHeap(obj->GetObject(), callable)) {
GCList ls(obj->GetGC());
callable->Call(ls, {});
}
},
interval, enabled);
}
return Tesses::Framework::TF_Timer(empty, 1000L, false);
}
static TObject New_RelativeFilesystem(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
Tesses::Framework::Filesystem::VFSPath path;
if (GetArgument(args, 0, vfs) && GetArgumentAsPath(args, 1, path) &&
!path.relative) {
return std::make_shared<
Tesses::Framework::Filesystem::RelativeFilesystem>(vfs, path);
}
return nullptr;
}
static TObject New_Queryable(GCList &ls, std::vector<TObject> args) {
if (!args.empty()) {
return TQueryable::Create(ls, args.front());
}
return nullptr;
}
void TStd::RegisterRoot(std::shared_ptr<GC> gc, TRootEnvironment *env) {
GCList ls(gc);
gc->BarrierBegin();
env->permissions.canRegisterRoot = true;
RegisterHelpers(gc, env);
RegisterUuid(gc, env);
auto date = env->EnsureDictionary(gc, "DateTime");
date->DeclareFunction(gc, "Sleep",
"Sleep for a specified amount of milliseconds "
"(multiply seconds by 1000 to get milliseconds)",
{"ms"}, DateTime_Sleep);
date->DeclareFunction(gc, "getNow", "Get the current time", {},
DateTime_getNow);
date->DeclareFunction(gc, "getNowUTC", "Get the current time in UTC", {},
DateTime_getNowUTC);
date->DeclareFunction(gc, "getNowEpoch", "Get the time_t time now", {},
DateTime_getNowEpoch);
date->DeclareFunction(gc, "TryParseHttpDate", "Parse the http date", {},
DateTime_TryParseHttpDate);
date->SetValue("Zone", (int64_t)Tesses::Framework::Date::GetTimeZone());
date->SetValue("SupportsDaylightSavings",
Tesses::Framework::Date::TimeZoneSupportDST());
auto ts = env->EnsureDictionary(gc, "TimeSpan");
ts->DeclareFunction(gc, "Parse", "Parse timespan", {"tsStr"},
TimeSpan_Parse);
ts->DeclareFunction(gc, "FromSeconds", "Create timespan from seconds",
{"seconds"}, TimeSpan_FromSeconds);
ts->DeclareFunction(gc, "FromMinutes", "Create timespan from minutes",
{"minutes"}, TimeSpan_FromMinutes);
ts->DeclareFunction(gc, "FromHours", "Create timespan from hours",
{"hours"}, TimeSpan_FromHours);
ts->DeclareFunction(gc, "FromDays", "Create timespan from days", {"days"},
TimeSpan_FromDays);
auto task = env->EnsureDictionary(gc, "Task");
task->DeclareFunction(
gc, "AsyncClosure",
"Create async closure (internal for compiler to generate calls to)",
{"closure"}, [](GCList &ls, std::vector<TObject> args) -> TObject {
TClosure *closure;
if (GetArgumentHeap(args, 0, closure))
return TTask::FromClosure(ls, closure);
return nullptr;
});
task->DeclareFunction(gc, "Run", "Run code async", {"callable"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
TCallable *closure;
if (GetArgumentHeap(args, 0, closure))
return TTask::Run(ls, closure);
return nullptr;
});
task->DeclareFunction(gc, "FromResult", "async from result", {"result"},
Task_FromResult);
TDictionary *newTypes = env->EnsureDictionary(gc, "New");
newTypes->DeclareFunction(gc, "ByteReader", "Read binary data from stream",
{"stream"}, New_ByteReader);
newTypes->DeclareFunction(gc, "ByteWriter", "Write binary data to stream",
{"stream"}, New_ByteWriter);
// newTypes->DeclareFunction(gc,)
newTypes->DeclareFunction(gc, "Promise", "Create an async object",
{"resolve", "reject"}, New_Promise);
newTypes->DeclareFunction(
gc, "DateTime",
"Create a DateTime object, if only one arg is provided year is epoch, "
"isLocal defaults to true unless epoch",
{"year", "$month", "$day", "$hour", "$minute", "$second", "$isLocal"},
New_DateTime);
newTypes->DeclareFunction(
gc, "TimeSpan",
"Create a DateTime object, if only one arg is provided days is "
"totalSeconds, if there are only three arguments days will be hours, "
"hours will be minutes, minutes will be seconds (according to the "
"argument documentation)",
{"days", "$hours", "$minutes", "$seconds"}, New_TimeSpan);
newTypes->DeclareFunction(gc, "MountableFilesystem",
"Create a mountable filesystem", {"root"},
New_MountableFilesystem);
newTypes->DeclareFunction(gc, "SubdirFilesystem",
"Create a subdir filesystem", {"fs", "subdir"},
New_SubdirFilesystem);
newTypes->DeclareFunction(gc, "MemoryStream", "Create a memory stream",
{"writable"}, New_MemoryStream);
newTypes->DeclareFunction(gc, "Filesystem", "Create filesystem", {"fs"},
New_Filesystem);
newTypes->DeclareFunction(gc, "RelativeFilesystem", "Create relativefs",
{"parent", "absoluteDir"},
New_RelativeFilesystem);
newTypes->DeclareFunction(gc, "TempFS", "Create a temp directory", {"", ""},
New_TempFS);
newTypes->DeclareFunction(gc, "Timer", "Create a timer",
{"$cb", "$interval", "$enabled"}, New_Timer);
newTypes->DeclareFunction(gc, "Stream", "Create stream", {"strm"},
New_Stream);
newTypes->DeclareFunction(
gc, "Version", "Create a version object",
{"$major", "$minor", "$patch", "$build", "$stage"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
int64_t major = 1;
int64_t minor = 0;
int64_t patch = 0;
int64_t build = 0;
std::string stageS = "prod";
TVMVersionStage stage = TVMVersionStage::ProductionVersion;
GetArgument(args, 0, major);
GetArgument(args, 1, minor);
GetArgument(args, 2, patch);
GetArgument(args, 3, build);
GetArgument(args, 4, stageS);
if (stageS == "dev")
stage = TVMVersionStage::DevVersion;
else if (stageS == "alpha")
stage = TVMVersionStage::AlphaVersion;
else if (stageS == "beta")
stage = TVMVersionStage::BetaVersion;
return TVMVersion((uint8_t)major, (uint8_t)minor, (uint8_t)patch,
(uint16_t)build, stage);
});
newTypes->DeclareFunction(
gc, "Random", "Create random number generator", {"$seed"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
int64_t seed;
if (GetArgument(args, 0, seed)) {
return TNativeObject::Create<TRandom>(ls, (uint64_t)seed);
}
return TNativeObject::Create<TRandom>(ls);
});
newTypes->DeclareFunction(gc, "StreamReader", "Create a StreamReader",
{"strmOrVFS", "$pathIfVFS"}, New_StreamReader);
newTypes->DeclareFunction(gc, "StreamWriter", "Create a StreamWriter",
{"strmOrVFS", "$pathIfVFS", "$appendIfVFS"},
New_StreamWriter);
newTypes->DeclareFunction(gc, "StringReader", "Create a StringReader",
{"str"}, New_StringReader);
newTypes->DeclareFunction(gc, "StringWriter", "Create a StringWriter",
{"$str"}, New_StringWriter);
env->DeclareFunction(gc, "ParseLong", "Parse Long from String",
{"arg", "$base"}, ParseLong);
env->DeclareFunction(gc, "ParseDouble", "Parse Double from String", {"arg"},
ParseDouble);
env->DeclareFunction(gc, "YieldEmumerable",
"Turn yield in function into enumerable", {"closure"},
YieldEnumerableFunc);
env->DeclareFunction(gc, "TypeOf", "Get type of object", {"object"},
TypeOf);
env->DeclareFunction(gc, "TypeIsDefined",
"Get whether object is not null or undefined",
{"object"}, TypeIsDefined);
env->DeclareFunction(
gc, "TypeIsHeap",
"Get whether object is susceptible to garbage collection", {"object"},
TypeIsHeap);
env->DeclareFunction(gc, "TypeIsNumber", "Get whether object is a number",
{"object"}, TypeIsNumber);
env->DeclareFunction(gc, "TypeIsLong",
"Get whether object is a long (not a double)",
{"object"}, TypeIsLong);
env->DeclareFunction(gc, "TypeIsDouble",
"Get whether object is a double (not a long)",
{"object"}, TypeIsDouble);
env->DeclareFunction(gc, "TypeIsString", "Get whether object is a string",
{"object"}, TypeIsString);
env->DeclareFunction(gc, "TypeIsCallable", "Get whether object is callable",
{"object"}, TypeIsCallable);
env->DeclareFunction(gc, "TypeIsClass",
"Get whether object is class instance", {"object"},
TypeIsClass);
env->DeclareFunction(
gc, "TypeIsDictionary",
"Get whether object is a dictionary or dynamic dictionary", {"object"},
TypeIsDictionary);
env->DeclareFunction(gc, "TypeIsList",
"Get whether object is a list or dynamic list",
{"object"}, TypeIsList);
env->DeclareFunction(gc, "TypeIsStream", "Get whether object is a stream",
{"object"}, TypeIsStream);
env->DeclareFunction(gc, "TypeIsVFS",
"Get whether object is a virtual filesystem",
{"object"}, TypeIsVFS);
env->DeclareFunction(gc, "TypeIsDateTime",
"Get whether object is a DateTime", {"object"},
TypeIsDateTime);
env->DeclareFunction(gc, "TypeIsTimeSpan",
"Get whether object is a TimeSpan", {"object"},
TypeIsTimeSpan);
env->DeclareFunction(gc, "TypeIsTextReader",
"Get whether object is a TextReader", {"object"},
TypeIsTextReader);
env->DeclareFunction(gc, "TypeIsTextWriter",
"Get whether object is a TextWriter", {"object"},
TypeIsTextWriter);
env->DeclareFunction(gc, "TypeIsByteReader",
"Get whether object is a ByteReader", {"object"},
TypeIsByteReader);
env->DeclareFunction(gc, "TypeIsByteWriter",
"Get whether object is a ByteWriter", {"object"},
TypeIsByteWriter);
env->DeclareFunction(gc, "TypeIsUuid", "Get whether object is a Uuid",
{"object"}, TypeIsUuid);
env->DeclareFunction(gc, "TypeIsQueryable",
"Get whether object is a Queryable", {"object"},
TypeIsQueryable);
newTypes->DeclareFunction(
gc, "Regex", "Create regex object", {"regex"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
std::string str;
if (GetArgument(args, 0, str)) {
std::regex regex(str);
return regex;
}
return nullptr;
});
newTypes->DeclareFunction(
gc, "Mutex", "Create mutex", {},
[](GCList &ls, std::vector<TObject> args) -> TObject {
return TNativeObject::Create<TMuxex>(ls);
});
newTypes->DeclareFunction(
gc, "Thread", "Create thread", {"callback"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
if (args.size() == 1 &&
std::holds_alternative<THeapObjectHolder>(args[0])) {
auto cb = dynamic_cast<TCallable *>(
std::get<THeapObjectHolder>(args[0]).obj);
if (cb != nullptr) {
return CreateThread(ls, cb, false);
}
}
return Undefined();
});
newTypes->DeclareFunction(
gc, "DynamicList", "Create a dynamic list", {},
[](GCList &ls, std::vector<TObject> args) -> TObject {
TCallable *callable;
if (GetArgumentHeap(args, 0, callable))
return TDynamicList::Create(ls, callable);
return nullptr;
});
newTypes->DeclareFunction(
gc, "DynamicDictionary", "Create a dynamic dictionary", {},
[](GCList &ls, std::vector<TObject> args) -> TObject {
TCallable *callable;
if (GetArgumentHeap(args, 0, callable))
return TDynamicDictionary::Create(ls, callable);
return nullptr;
});
newTypes->DeclareFunction(
gc, "AssociativeArray", "Create a new AssociativeArray", {},
[](GCList &ls, std::vector<TObject> args) -> TObject {
return TAssociativeArray::Create(ls);
});
newTypes->DeclareFunction(
gc, "AArray", "alias for new AssociativeArray", {},
[](GCList &ls, std::vector<TObject> args) -> TObject {
return TAssociativeArray::Create(ls);
});
newTypes->DeclareFunction(
gc, "ByteArray",
"Create bytearray, with optional either size (to size it) or string "
"argument (to fill byte array)",
{"$data"}, ByteArray);
newTypes->DeclareFunction(gc, "Queryable", "Create a queryable",
{"enumerable"}, New_Queryable);
env->DeclareVariable(
"Version",
TDictionary::Create(
ls,
{TDItem("Parse",
TExternalMethod::Create(
ls, "Parse version from string", {"versionStr"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
std::string str;
TVMVersion v;
if (GetArgument(args, 0, v))
return v;
if (GetArgument(args, 0, str)) {
TVMVersion version;
if (TVMVersion::TryParse(str, version)) {
return version;
}
}
return nullptr;
})),
TDItem("FromByteArray",
TExternalMethod::Create(
ls, "Create from ByteArray", {"byteArray", "$offset"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
TByteArray *ba;
if (GetArgumentHeap(args, 0, ba)) {
int64_t offset = 0;
GetArgument(args, 1, offset);
if (ba->data.size() < 5)
throw VMException("ByteArray too small");
size_t o = (size_t)offset;
if ((o + 5) > ba->data.size() || (o + 5) < 5)
throw VMException("ByteArray too small");
return TVMVersion(ba->data.data() + o);
}
return nullptr;
})),
TDItem("FromLong",
TExternalMethod::Create(
ls, "Create from long", {"longBasedVersion"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
int64_t num;
if (GetArgument(args, 0, num)) {
return TVMVersion((uint64_t)num);
}
return nullptr;
}))}));
env->DeclareVariable("InvokeMethod", MethodInvoker());
gc->BarrierEnd();
}
void TStd::RegisterStd(std::shared_ptr<GC> gc, TRootEnvironment *env) {
RegisterStd(
gc, env,
std::make_shared<Tesses::Framework::Filesystem::RelativeFilesystem>(
Tesses::Framework::Filesystem::LocalFS,
Tesses::Framework::Filesystem::VFSPath::
GetAbsoluteCurrentDirectory()));
}
void TStd::RegisterStd(
std::shared_ptr<GC> gc, TRootEnvironment *env,
std::shared_ptr<Tesses::Framework::Filesystem::RelativeFilesystem>
localfs) {
env->permissions.canRegisterEverything = true;
RegisterEnv(gc, env);
RegisterRoot(gc, env);
RegisterPath(gc, env);
RegisterConsole(gc, env);
RegisterIO(gc, env, localfs);
RegisterNet(gc, env);
RegisterSqlite(gc, env);
RegisterVM(gc, env);
RegisterJson(gc, env);
RegisterDictionary(gc, env);
RegisterCrypto(gc, env);
RegisterOGC(gc, env);
RegisterProcess(gc, env);
RegisterZeClass(gc, env);
gc->RegisterEverything(env);
GCList ls(gc);
TDictionary *dict = TDictionary::Create(ls);
TDictionary *gc_dict = TDictionary::Create(ls);
#if defined(CROSSLANG_ENABLE_FFI)
TDictionary *ffi = TDictionary::Create(ls);
RegisterFFI(gc, ffi);
#endif
dict->DeclareFunction(
gc, "LoadNativePlugin",
"Load a native plugin, requires a dynamic linker and shared build of "
"libcrosslang",
{"path"}, [gc, env](GCList &ls, std::vector<TObject> args) -> TObject {
Tesses::Framework::Filesystem::VFSPath path;
if (GetArgumentAsPath(args, 0, path)) {
LoadPlugin(gc, env, path);
}
return nullptr;
});
gc_dict->DeclareFunction(
gc, "Collect", "Collect garbage", {},
[](GCList &ls, std::vector<TObject> args) -> TObject {
std::vector<THeapObject *> to_delete;
ls.GetGC()->BarrierBegin();
ls.GetGC()->Collect(to_delete);
ls.GetGC()->BarrierEnd();
for (auto item : to_delete)
delete item;
return nullptr;
});
gc_dict->DeclareFunction(
gc, "BarrierBegin", "Lock globally", {},
[](GCList &ls, std::vector<TObject> args) -> TObject {
ls.GetGC()->BarrierBegin();
return nullptr;
});
gc_dict->DeclareFunction(
gc, "BarrierEnd", "Unlock globally", {},
[](GCList &ls, std::vector<TObject> args) -> TObject {
ls.GetGC()->BarrierEnd();
return nullptr;
});
gc->BarrierBegin();
#if defined(CROSSLANG_ENABLE_FFI)
env->SetVariable("FFI", ffi);
#endif
env->SetVariable("Reflection", dict);
env->SetVariable("GC", gc_dict);
gc->BarrierEnd();
env->permissions.locked = true;
}
} // namespace Tesses::CrossLang