Files
crosslang/src/vm/vm.cpp
T

3003 lines
109 KiB
C++

#include "CrossLang.hpp"
#include "TessesFramework/Serialization/BitConverter.hpp"
#include "TessesFramework/Streams/ByteReader.hpp"
#include "TessesFramework/Uuid.hpp"
#include <cmath>
#include <cstddef>
#include <cstring>
#include <exception>
#include <iostream>
#include <sstream>
#include <variant>
namespace Tesses::CrossLang {
TObject ExecuteFunction(GCList &ls, TCallable *callable,
std::vector<TObject> args) {
return callable->Call(ls, args);
}
void InterperterThread::Mark() {
if (this->marked)
return;
this->marked = true;
for (auto item : this->call_stack_entries) {
item->Mark();
}
}
#define TVM_HANDLER(hndl) \
if (hndl(gc)) \
goto execute
typedef bool (InterperterThread::*opcode)(std::shared_ptr<GC> gc);
bool InterperterThread::InterperterThread::Breakpoint(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto res = cse.back()->Pop(ls);
auto env = cse.back()->env;
if (!env->GetRootEnvironment()->HandleBreakpoint(gc, env, res)) {
throw std::runtime_error("Breakpoint unhandled");
}
return false;
}
bool InterperterThread::PushPrivateExpression(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto fn = cse.back();
auto re = fn->env->GetRootEnvironment();
if (re) {
fn->Push(gc, re->GetPrivateFromFile(gc, fn->callable->file));
} else {
throw VMException("No root environment for private expression");
}
return false;
}
bool InterperterThread::Times(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) * std::get<int64_t>(right));
}
else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<double>(left) * std::get<double>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<double>(left) * std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) * std::get<double>(right));
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator*");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator*", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator*");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator*", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Divide(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<std::string>(left) &&
std::holds_alternative<std::string>(right)) {
cse.back()->Push(gc, Tesses::Framework::Filesystem::VFSPath(
std::get<std::string>(left)) /
std::get<std::string>(right));
} else if (std::holds_alternative<std::string>(left) &&
std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(
right)) {
cse.back()->Push(
gc, std::get<std::string>(left) /
std::get<Tesses::Framework::Filesystem::VFSPath>(right));
}
else if (std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(
left) &&
std::holds_alternative<std::string>(right)) {
cse.back()->Push(
gc, std::get<Tesses::Framework::Filesystem::VFSPath>(left) /
std::get<std::string>(right));
}
else if (std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(
left) &&
std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(
right)) {
cse.back()->Push(
gc, std::get<Tesses::Framework::Filesystem::VFSPath>(left) /
std::get<Tesses::Framework::Filesystem::VFSPath>(right));
}
else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) / std::get<int64_t>(right));
}
else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<double>(left) / std::get<double>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<double>(left) / std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) / std::get<double>(right));
}
else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator/");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator/", {right}));
return false;
} else
if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator/", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator/");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator/", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Mod(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) % std::get<int64_t>(right));
}
else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc,
fmod(std::get<double>(left), std::get<double>(right)));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(
gc, fmod(std::get<double>(left), std::get<int64_t>(right)));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(
gc, fmod(std::get<int64_t>(left), std::get<double>(right)));
}
else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator%");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator%", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator%");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator%", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Neg(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left)) {
cse.back()->Push(gc, -std::get<int64_t>(left));
} else if (std::holds_alternative<double>(left)) {
cse.back()->Push(gc, -std::get<double>(left));
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator-");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator-", {}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject negfn = dict->GetValue("operator-");
gc->BarrierEnd();
return InvokeOne(ls, negfn, left);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator-", {}));
return false;
} else {
cse.back()->Push(gc, nullptr);
}
} else {
cse.back()->Push(gc, nullptr);
}
return false;
}
bool InterperterThread::LNot(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<Undefined>(left)) {
cse.back()->Push(gc, true);
} else if (std::holds_alternative<std::nullptr_t>(left)) {
cse.back()->Push(gc, true);
}
else if (std::holds_alternative<int64_t>(left)) {
cse.back()->Push(gc, !std::get<int64_t>(left));
}
else if (std::holds_alternative<bool>(left)) {
cse.back()->Push(gc, !std::get<bool>(left));
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator!");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, !natObj->ToBool());
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject negfn = dict->GetValue("operator!");
gc->BarrierEnd();
return InvokeOne(ls, negfn, left);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator!", {}));
return false;
}
else {
cse.back()->Push(gc, !ToBool(left));
}
} else {
cse.back()->Push(gc, !ToBool(left));
}
return false;
}
bool InterperterThread::BNot(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left)) {
cse.back()->Push(gc, ~std::get<int64_t>(left));
}
else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator~");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator~", {}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject negfn = dict->GetValue("operator~");
gc->BarrierEnd();
return InvokeOne(ls, negfn, left);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator~", {}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Lt(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) < std::get<int64_t>(right));
}
else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<double>(left) < std::get<double>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<double>(left) < std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) < std::get<double>(right));
}
else if (std::holds_alternative<char>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<char>(left) < std::get<int64_t>(right));
} else if (std::holds_alternative<char>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<char>(left) < std::get<char>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) < std::get<char>(right));
} else if (std::holds_alternative<TVMVersion>(left) &&
std::holds_alternative<TVMVersion>(right)) {
auto lver = std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r < 0);
} else if (std::holds_alternative<std::string>(left) &&
std::holds_alternative<std::string>(right)) {
cse.back()->Push(gc, std::get<std::string>(left) <
std::get<std::string>(right));
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
cse.back()->Push(gc, l->ToEpoch() < r->ToEpoch());
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
cse.back()->Push(gc, l->TotalSeconds() < r->TotalSeconds());
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator<");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator<", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator<");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator<", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Gt(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) > std::get<int64_t>(right));
}
else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<double>(left) > std::get<double>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<double>(left) > std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) > std::get<double>(right));
}
else if (std::holds_alternative<char>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<char>(left) > std::get<int64_t>(right));
} else if (std::holds_alternative<char>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<char>(left) > std::get<char>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) > std::get<char>(right));
} else if (std::holds_alternative<TVMVersion>(left) &&
std::holds_alternative<TVMVersion>(right)) {
auto lver = std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r > 0);
} else if (std::holds_alternative<std::string>(left) &&
std::holds_alternative<std::string>(right)) {
cse.back()->Push(gc, std::get<std::string>(left) >
std::get<std::string>(right));
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
cse.back()->Push(gc, l->ToEpoch() > r->ToEpoch());
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
cse.back()->Push(gc, l->TotalSeconds() > r->TotalSeconds());
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator>");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator>", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator>");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator>", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Lte(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) <= std::get<int64_t>(right));
}
else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<double>(left) <= std::get<double>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<double>(left) <= std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) <= std::get<double>(right));
} else if (std::holds_alternative<char>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<char>(left) <= std::get<char>(right));
} else if (std::holds_alternative<char>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<char>(left) <= std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) <= std::get<char>(right));
} else if (std::holds_alternative<TVMVersion>(left) &&
std::holds_alternative<TVMVersion>(right)) {
auto lver = std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r <= 0);
} else if (std::holds_alternative<std::string>(left) &&
std::holds_alternative<std::string>(right)) {
cse.back()->Push(gc, std::get<std::string>(left) <=
std::get<std::string>(right));
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
cse.back()->Push(gc, l->ToEpoch() <= r->ToEpoch());
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
cse.back()->Push(gc, l->TotalSeconds() <= r->TotalSeconds());
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator<=");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator<=", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator<=");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
} else if (dynDict != nullptr) {
cse.back()->Push(gc,
dynDict->CallMethod(ls, "operator<=", {right}));
return false;
}
else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Gte(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) >= std::get<int64_t>(right));
}
else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<double>(left) >= std::get<double>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<double>(left) >= std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) >= std::get<double>(right));
}
else if (std::holds_alternative<char>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<char>(left) >= std::get<int64_t>(right));
} else if (std::holds_alternative<char>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<char>(left) >= std::get<char>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) >= std::get<char>(right));
} else if (std::holds_alternative<TVMVersion>(left) &&
std::holds_alternative<TVMVersion>(right)) {
auto lver = std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r >= 0);
} else if (std::holds_alternative<std::string>(left) &&
std::holds_alternative<std::string>(right)) {
cse.back()->Push(gc, std::get<std::string>(left) >=
std::get<std::string>(right));
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
cse.back()->Push(gc, l->ToEpoch() >= r->ToEpoch());
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
cse.back()->Push(gc, l->TotalSeconds() >= r->TotalSeconds());
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator>=");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator>=", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator>=");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
} else if (dynDict != nullptr) {
cse.back()->Push(gc,
dynDict->CallMethod(ls, "operator>=", {right}));
return false;
}
else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Eq(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<std::nullptr_t>(left) &&
std::holds_alternative<std::nullptr_t>(right)) {
cse.back()->Push(gc, true);
return false;
}
else if (std::holds_alternative<Undefined>(left) &&
std::holds_alternative<Undefined>(right)) {
cse.back()->Push(gc, true);
return false;
}
else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) == std::get<int64_t>(right));
}
else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<double>(left) == std::get<double>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<double>(left) == std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) == std::get<double>(right));
}
else if (std::holds_alternative<std::string>(left) &&
std::holds_alternative<std::string>(right)) {
cse.back()->Push(gc, std::get<std::string>(left) ==
std::get<std::string>(right));
}
else if (std::holds_alternative<bool>(left) &&
std::holds_alternative<bool>(right)) {
cse.back()->Push(gc, std::get<bool>(left) == std::get<bool>(right));
}
else if (std::holds_alternative<char>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<char>(left) == std::get<char>(right));
} else if (std::holds_alternative<char>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<char>(left) == std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) == std::get<char>(right));
} else if (std::holds_alternative<TVMVersion>(left) &&
std::holds_alternative<TVMVersion>(right)) {
auto lver = std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r == 0);
} else if (std::holds_alternative<Tesses::Framework::Uuid>(left) &&
std::holds_alternative<Tesses::Framework::Uuid>(right)) {
auto l = std::get<Tesses::Framework::Uuid>(left);
auto r = std::get<Tesses::Framework::Uuid>(right);
return l == r;
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
cse.back()->Push(gc, (l->ToEpoch() == r->ToEpoch()) &&
(l->IsLocal() == r->IsLocal()));
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
cse.back()->Push(gc, l->TotalSeconds() == r->TotalSeconds());
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto native = dynamic_cast<TNative *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator==");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->Equals(gc, right));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator==");
gc->BarrierEnd();
if (!std::holds_alternative<Undefined>(fn))
return InvokeTwo(ls, fn, left, right);
}
else if (dynDict != nullptr) {
auto res = dynDict->CallMethod(ls, "operator==", {right});
if (!std::holds_alternative<std::nullptr_t>(res) &&
std::holds_alternative<Undefined>(res)) {
cse.back()->Push(gc, res);
return false;
}
}
else if (native != nullptr &&
std::holds_alternative<std::nullptr_t>(right)) {
cse.back()->Push(gc, native->GetDestroyed());
return false;
}
if (std::holds_alternative<THeapObjectHolder>(right)) {
cse.back()->Push(gc, obj == std::get<THeapObjectHolder>(right).obj);
return false;
}
else if (std::holds_alternative<std::nullptr_t>(right)) {
cse.back()->Push(gc, false);
return false;
} else if (std::holds_alternative<Undefined>(right)) {
cse.back()->Push(gc, false);
return false;
} else {
cse.back()->Push(gc, Undefined());
}
}
else if (std::holds_alternative<std::nullptr_t>(right)) {
cse.back()->Push(gc, false);
return false;
} else if (std::holds_alternative<Undefined>(right)) {
cse.back()->Push(gc, false);
return false;
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::NEq(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<std::nullptr_t>(left) &&
std::holds_alternative<std::nullptr_t>(right)) {
cse.back()->Push(gc, false);
return false;
} else if (std::holds_alternative<Undefined>(left) &&
std::holds_alternative<Undefined>(right)) {
cse.back()->Push(gc, false);
return false;
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) != std::get<int64_t>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc, std::get<double>(left) != std::get<double>(right));
} else if (std::holds_alternative<double>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<double>(left) != std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<double>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) != std::get<double>(right));
} else if (std::holds_alternative<std::string>(left) &&
std::holds_alternative<std::string>(right)) {
cse.back()->Push(gc, std::get<std::string>(left) !=
std::get<std::string>(right));
} else if (std::holds_alternative<bool>(left) &&
std::holds_alternative<bool>(right)) {
cse.back()->Push(gc, std::get<bool>(left) != std::get<bool>(right));
} else if (std::holds_alternative<char>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<char>(left) != std::get<char>(right));
} else if (std::holds_alternative<char>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<char>(left) != std::get<int64_t>(right));
} else if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<char>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) != std::get<char>(right));
} else if (std::holds_alternative<TVMVersion>(left) &&
std::holds_alternative<TVMVersion>(right)) {
auto lver = std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r != 0);
} else if (std::holds_alternative<Tesses::Framework::Uuid>(left) &&
std::holds_alternative<Tesses::Framework::Uuid>(right)) {
auto l = std::get<Tesses::Framework::Uuid>(left);
auto r = std::get<Tesses::Framework::Uuid>(right);
return l != r;
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::DateTime>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::DateTime>>(right);
cse.back()->Push(gc, !((l->ToEpoch() == r->ToEpoch()) &&
(l->IsLocal() == r->IsLocal())));
} else if (std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left) &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right)) {
auto &l =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(left);
auto &r =
std::get<std::shared_ptr<Tesses::Framework::Date::TimeSpan>>(right);
cse.back()->Push(gc, l->TotalSeconds() != r->TotalSeconds());
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto native = dynamic_cast<TNative *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator!=");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, !natObj->Equals(gc, right));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator!=");
gc->BarrierEnd();
if (!std::holds_alternative<Undefined>(fn))
return InvokeTwo(ls, fn, left, right);
}
else if (dynDict != nullptr) {
auto res = dynDict->CallMethod(ls, "operator!=", {right});
if (!std::holds_alternative<std::nullptr_t>(res) &&
std::holds_alternative<Undefined>(res)) {
cse.back()->Push(gc, res);
return false;
}
}
else if (native != nullptr &&
std::holds_alternative<std::nullptr_t>(right)) {
cse.back()->Push(gc, !native->GetDestroyed());
return false;
}
if (std::holds_alternative<THeapObjectHolder>(right)) {
cse.back()->Push(gc, obj != std::get<THeapObjectHolder>(right).obj);
return false;
} else if (std::holds_alternative<std::nullptr_t>(right)) {
cse.back()->Push(gc, true);
return false;
} else if (std::holds_alternative<Undefined>(right)) {
cse.back()->Push(gc, true);
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else if (std::holds_alternative<Undefined>(right)) {
cse.back()->Push(gc, true);
return false;
} else if (std::holds_alternative<std::nullptr_t>(right)) {
cse.back()->Push(gc, true);
return false;
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::LShift(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left)
<< (int)std::get<int64_t>(right));
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator<<");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator<<", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator<<");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
}
else if (dynDict != nullptr) {
cse.back()->Push(gc,
dynDict->CallMethod(ls, "operator<<", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::RShift(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc, std::get<int64_t>(left) >>
(int)std::get<int64_t>(right));
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator>>");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator>>", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator>>");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
}
else if (dynDict != nullptr) {
cse.back()->Push(gc,
dynDict->CallMethod(ls, "operator>>", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::BOr(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) | std::get<int64_t>(right));
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator|");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator|", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator|");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
}
else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator|", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::XOr(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) ^ std::get<int64_t>(right));
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator^");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator^", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator^");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
}
else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator^", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::BAnd(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto right = cse.back()->Pop(ls);
auto left = cse.back()->Pop(ls);
if (std::holds_alternative<int64_t>(left) &&
std::holds_alternative<int64_t>(right)) {
cse.back()->Push(gc,
std::get<int64_t>(left) & std::get<int64_t>(right));
} else if (std::holds_alternative<THeapObjectHolder>(left)) {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary *>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary *>(obj);
auto natObj = dynamic_cast<TNativeObject *>(obj);
auto cls = dynamic_cast<TClassObject *>(obj);
if (cls != nullptr) {
gc->BarrierBegin();
auto obj =
cls->GetValue(cse.back()->callable->className, "operator&");
gc->BarrierEnd();
TClosure *clos;
TCallable *callable;
if (GetObjectHeap(obj, clos)) {
this->AddCallStackEntry(ls, clos, {right});
return true;
} else if (GetObjectHeap(obj, callable)) {
cse.back()->Push(gc, callable->Call(ls, {right}));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
} else if (natObj != nullptr) {
cse.back()->Push(gc, natObj->CallMethod(ls, "operator&", {right}));
return false;
} else if (dict != nullptr) {
gc->BarrierBegin();
TObject fn = dict->GetValue("operator&");
gc->BarrierEnd();
return InvokeTwo(ls, fn, left, right);
} else if (dynDict != nullptr) {
cse.back()->Push(gc, dynDict->CallMethod(ls, "operator&", {right}));
return false;
} else {
cse.back()->Push(gc, Undefined());
}
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::InvokeOne(GCList &ls, TObject fn, TObject arg) {
if (std::holds_alternative<THeapObjectHolder>(fn)) {
auto obj =
dynamic_cast<TCallable *>(std::get<THeapObjectHolder>(fn).obj);
if (obj != nullptr) {
auto closure = dynamic_cast<TClosure *>(obj);
if (closure != nullptr) {
if (!closure->closure->args.empty() &&
closure->closure->args[0] == "this") {
this->AddCallStackEntry(ls, closure, {arg});
} else {
this->AddCallStackEntry(ls, closure, {});
}
} else {
auto val = obj->Call(ls, {});
this->call_stack_entries.back()->Push(ls.GetGC(), val);
return false;
}
return true;
}
}
return false;
}
bool InterperterThread::ExecuteFunction(std::shared_ptr<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;
GCList ls(gc);
auto res = stk->Pop(ls);
if (std::holds_alternative<int64_t>(res)) {
uint32_t n = (uint32_t)std::get<int64_t>(res);
std::vector<TObject> args;
for (size_t i = 0; i < n; i++) {
args.insert(args.begin(), {stk->Pop(ls)});
}
TObject fn = stk->Pop(ls);
if (std::holds_alternative<MethodInvoker>(fn)) {
if (args.size() == 3) {
if (std::holds_alternative<std::string>(args[1]) &&
std::holds_alternative<THeapObjectHolder>(args[2])) {
std::string key = std::get<std::string>(args[1]);
TList *ls = dynamic_cast<TList *>(
std::get<THeapObjectHolder>(args[2]).obj);
if (ls != nullptr)
return ExecuteMethod2(gc, args[0], key, ls->items);
}
}
stk->Push(gc, Undefined());
return false;
}
if (std::holds_alternative<THeapObjectHolder>(fn)) {
auto obj = dynamic_cast<TCallable *>(
std::get<THeapObjectHolder>(fn).obj);
if (obj != nullptr) {
auto closure = dynamic_cast<TClosure *>(obj);
if (closure != nullptr) {
this->AddCallStackEntry(ls, closure, args);
return true;
} else {
auto val = obj->Call(ls, args);
this->call_stack_entries.back()->Push(ls.GetGC(), val);
return false;
}
return true;
}
stk->Push(gc, Undefined());
return false;
}
stk->Push(gc, Undefined());
} else
stk->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::Yield(std::shared_ptr<GC> gc) {
GCList ls(gc);
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
if (!cse.empty()) {
gc->BarrierBegin();
cse.back()->mustReturn = true;
cse.back()->Push(gc, cse.back());
gc->BarrierEnd();
}
return false;
}
bool InterperterThread::ExecuteMethod(std::shared_ptr<GC> gc) {
GCList ls(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;
auto cnt = stk->Pop(ls);
if (std::holds_alternative<int64_t>(cnt)) {
uint32_t n = (uint32_t)std::get<int64_t>(cnt);
std::vector<TObject> args;
for (size_t i = 0; i < n; i++) {
args.insert(args.begin(), {stk->Pop(ls)});
}
TObject key = stk->Pop(ls);
TObject instance = stk->Pop(ls);
if (std::holds_alternative<std::string>(key)) {
return ExecuteMethod2(gc, instance, std::get<std::string>(key),
args);
}
stk->Push(gc, Undefined());
return false;
}
}
return false;
}
bool InterperterThread::GetVariable(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
if (!cse.empty()) {
auto stk = cse.back();
GCList ls(gc);
auto key = stk->Pop(ls);
if (std::holds_alternative<std::string>(key)) {
gc->BarrierBegin();
stk->Push(gc,
stk->env->GetVariable(ls, std::get<std::string>(key)));
gc->BarrierEnd();
} else {
throw VMException("[GETVARIABLE] Can't pop string.");
}
}
return false;
}
bool InterperterThread::SetVariable(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
if (!cse.empty()) {
auto stk = cse.back();
GCList ls(gc);
auto value = stk->Pop(ls);
auto key = stk->Pop(ls);
TList *mls;
if (std::holds_alternative<std::string>(key)) {
gc->BarrierBegin();
if (stk->env->HasConstForSet(std::get<std::string>(key))) {
gc->BarrierEnd();
ThrowConstError(std::get<std::string>(key));
}
stk->Push(gc, stk->env->SetVariable(ls, std::get<std::string>(key),
value));
gc->BarrierEnd();
} else if (GetObjectHeap(key, mls)) {
gc->BarrierBegin();
TList *valueLs;
TDynamicList *valueDynList;
TDictionary *valueDict;
TDynamicDictionary *valueDynDict;
if (GetObjectHeap(value, valueLs)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = std::min(valueLs->Count(), mls->Count());
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
auto val = valueLs->Get(i);
result->SetValue(mkey, val);
if (stk->env->HasConstForSet(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->SetVariable(ls, mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDynList)) {
TDictionary *result = TDictionary::Create(ls);
gc->BarrierEnd();
int64_t len = std::min(valueDynList->Count(ls), mls->Count());
gc->BarrierBegin();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
gc->BarrierEnd();
auto val = valueDynList->GetAt(ls, i);
gc->BarrierBegin();
result->SetValue(mkey, val);
if (stk->env->HasConstForSet(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->SetVariable(ls, mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDict)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
auto val = valueDict->GetValue(mkey);
result->SetValue(mkey, val);
if (stk->env->HasConstForSet(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->SetVariable(ls, mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDynDict)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
gc->BarrierEnd();
auto val = valueDynDict->GetField(ls, mkey);
gc->BarrierBegin();
result->SetValue(mkey, val);
if (stk->env->HasConstForSet(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->SetVariable(ls, mkey, val);
}
}
stk->Push(gc, result);
} else {
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
if (stk->env->HasConstForSet(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->SetVariable(ls, mkey, value);
}
}
stk->Push(gc, value);
}
gc->BarrierEnd();
} else {
throw VMException("[SETVARIABLE] Can't pop string.");
}
}
return false;
}
bool InterperterThread::DeclareVariable(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
if (!cse.empty()) {
auto stk = cse.back();
GCList ls(gc);
auto value = stk->Pop(ls);
auto key = stk->Pop(ls);
TList *mls;
if (std::holds_alternative<std::string>(key)) {
gc->BarrierBegin();
if (stk->env->HasConstForDeclare(std::get<std::string>(key))) {
gc->BarrierEnd();
ThrowConstError(std::get<std::string>(key));
}
stk->env->DeclareVariable(std::get<std::string>(key), value);
stk->Push(gc, value);
gc->BarrierEnd();
} else if (GetObjectHeap(key, mls)) {
gc->BarrierBegin();
TList *valueLs;
TDynamicList *valueDynList;
TDictionary *valueDict;
TDynamicDictionary *valueDynDict;
if (GetObjectHeap(value, valueLs)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = std::min(valueLs->Count(), mls->Count());
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
auto val = valueLs->Get(i);
result->SetValue(mkey, val);
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareVariable(mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDynList)) {
TDictionary *result = TDictionary::Create(ls);
gc->BarrierEnd();
int64_t len = std::min(valueDynList->Count(ls), mls->Count());
gc->BarrierBegin();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
gc->BarrierEnd();
auto val = valueDynList->GetAt(ls, i);
gc->BarrierBegin();
result->SetValue(mkey, val);
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareVariable(mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDict)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
auto val = valueDict->GetValue(mkey);
result->SetValue(mkey, val);
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareVariable(mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDynDict)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
gc->BarrierEnd();
auto val = valueDynDict->GetField(ls, mkey);
gc->BarrierBegin();
result->SetValue(mkey, val);
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareVariable(mkey, val);
}
}
stk->Push(gc, result);
} else {
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareVariable(mkey, value);
}
}
stk->Push(gc, value);
}
gc->BarrierEnd();
} else {
throw VMException("[DECLAREVARIABLE] Can't pop string, got type " +
GetObjectTypeString(key) + " = " +
ToString(gc, key) + ".");
}
}
return false;
}
bool InterperterThread::DeclareConstVariable(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
if (!cse.empty()) {
auto stk = cse.back();
GCList ls(gc);
auto value = stk->Pop(ls);
auto key = stk->Pop(ls);
TList *mls;
if (std::holds_alternative<std::string>(key)) {
gc->BarrierBegin();
if (stk->env->HasConstForDeclare(std::get<std::string>(key))) {
gc->BarrierEnd();
ThrowConstError(std::get<std::string>(key));
}
stk->env->DeclareConstVariable(std::get<std::string>(key), value);
stk->Push(gc, value);
gc->BarrierEnd();
} else if (GetObjectHeap(key, mls)) {
gc->BarrierBegin();
TList *valueLs;
TDynamicList *valueDynList;
TDictionary *valueDict;
TDynamicDictionary *valueDynDict;
if (GetObjectHeap(value, valueLs)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = std::min(valueLs->Count(), mls->Count());
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
auto val = valueLs->Get(i);
result->SetValue(mkey, val);
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareConstVariable(mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDynList)) {
TDictionary *result = TDictionary::Create(ls);
gc->BarrierEnd();
int64_t len = std::min(valueDynList->Count(ls), mls->Count());
gc->BarrierBegin();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
gc->BarrierEnd();
auto val = valueDynList->GetAt(ls, i);
gc->BarrierBegin();
result->SetValue(mkey, val);
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareConstVariable(mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDict)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
auto val = valueDict->GetValue(mkey);
result->SetValue(mkey, val);
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareConstVariable(mkey, val);
}
}
stk->Push(gc, result);
} else if (GetObjectHeap(value, valueDynDict)) {
TDictionary *result = TDictionary::Create(ls);
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
gc->BarrierEnd();
auto val = valueDynDict->GetField(ls, mkey);
gc->BarrierBegin();
result->SetValue(mkey, val);
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareConstVariable(mkey, val);
}
}
stk->Push(gc, result);
} else {
int64_t len = mls->Count();
for (int64_t i = 0; i < len; i++) {
std::string mkey;
auto item = mls->Get(i);
if (GetObject(item, mkey)) {
if (stk->env->HasConstForDeclare(mkey)) {
gc->BarrierEnd();
ThrowConstError(mkey);
}
stk->env->DeclareConstVariable(mkey, value);
}
}
stk->Push(gc, value);
}
gc->BarrierEnd();
} else {
throw VMException(
"[DECLARECONSTVARIABLE] Can't pop string, got type " +
GetObjectTypeString(key) + " = " + ToString(gc, key) + ".");
}
}
return false;
}
bool InterperterThread::PushResourceStream(std::shared_ptr<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->resources.size())
throw VMException("Can't read resource.");
stk->ip = stk->ip + 4;
gc->BarrierBegin();
GCList ls(gc);
// TByteArray* arr = TByteArray::Create(ls);
// arr->data = stk->callable->file->resources[n];
stk->Push(
gc, std::make_shared<EmbedStream>(gc, stk->callable->file, n));
gc->BarrierEnd();
} else {
throw VMException("Can't read chunk.");
}
}
return false;
}
bool InterperterThread::PushResource(std::shared_ptr<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->resources.size())
throw VMException("Can't read resource.");
stk->ip = stk->ip + 4;
gc->BarrierBegin();
GCList ls(gc);
TByteArray *arr = TByteArray::Create(ls);
arr->data = stk->callable->file->resources[n];
stk->Push(gc, arr);
gc->BarrierEnd();
} else {
throw VMException("Can't read chunk.");
}
}
return false;
}
bool InterperterThread::Throw(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto _res2 = cse.back()->Pop(ls);
if (!std::holds_alternative<Undefined>(_res2)) {
auto env = cse.back()->env;
if (!env->GetRootEnvironment()->HandleException(gc, env, _res2)) {
TNativeException *nex;
if (GetObjectHeap(_res2, nex)) {
nex->ThrowIt();
}
throw VMByteCodeException(gc, _res2, cse.back());
}
}
return false;
}
bool InterperterThread::PushResourceDirectory(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
GCList ls(gc);
auto _res2 = cse.back()->Pop(ls);
TDictionary *dict;
if (GetObjectHeap(_res2, dict)) {
cse.back()->Push(gc, std::make_shared<EmbedDirectory>(gc, dict));
} else {
cse.back()->Push(gc, Undefined());
}
return false;
}
bool InterperterThread::JumpIfDefined(std::shared_ptr<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]);
GCList ls(gc);
auto _res2 = stk->Pop(ls);
stk->ip = stk->ip + 4;
if (!std::holds_alternative<Undefined>(_res2) &&
!std::holds_alternative<std::nullptr_t>(_res2)) {
stk->ip = n;
stk->Push(gc, _res2);
}
} else
throw VMException("Can't read jmpifdefined pc.");
return false;
}
bool InterperterThread::JumpIfBreak(std::shared_ptr<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]);
GCList ls(gc);
auto _res2 = stk->Pop(ls);
stk->ip = stk->ip + 4;
if (std::holds_alternative<TBreak>(_res2))
stk->ip = n;
else
stk->Push(gc, _res2);
} else
throw VMException("Can't read jmpifbreak pc.");
return false;
}
bool InterperterThread::JumpIfContinue(std::shared_ptr<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]);
GCList ls(gc);
auto _res2 = stk->Pop(ls);
stk->ip = stk->ip + 4;
if (std::holds_alternative<TContinue>(_res2))
stk->ip = n;
else
stk->Push(gc, _res2);
} else
throw VMException("Can't read jmpifcontinue pc.");
return false;
}
bool InterperterThread::JumpUndefined(std::shared_ptr<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]);
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(std::shared_ptr<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;
}
bool InterperterThread::PushNull(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
stk->Push(gc, nullptr);
return false;
}
bool InterperterThread::PushBreak(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
stk->Push(gc, TBreak());
return false;
}
bool InterperterThread::PushContinue(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
stk->Push(gc, TContinue());
return false;
}
bool InterperterThread::PushUndefined(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
stk->Push(gc, Undefined());
return false;
}
bool InterperterThread::LineInfo(std::shared_ptr<GC> gc) {
GCList ls(gc);
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
auto file = stk->Pop(ls);
auto line = stk->Pop(ls);
// Set the fields in this cse
GetObject(file, stk->srcfile);
GetObject(line, stk->srcline);
// TODO: implement lines (this will make the language work until we get it
// rigged up)
return false;
}
bool InterperterThread::PushFalse(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
stk->Push(gc, false);
return false;
}
bool InterperterThread::PushTrue(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
stk->Push(gc, true);
return false;
}
bool InterperterThread::CreateDictionary(std::shared_ptr<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(std::shared_ptr<GC> gc) { return false; }
bool InterperterThread::AppendList(std::shared_ptr<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(std::shared_ptr<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);
auto cls = dynamic_cast<TClassObject *>(
std::get<THeapObjectHolder>(objhold).obj);
if (dict != nullptr) {
dict->SetValue(std::get<std::string>(k), value);
} else if (cls != nullptr) {
auto obj = cls->GetValue(cse.back()->callable->className,
"set" + std::get<std::string>(k));
TCallable *callable;
if (GetObjectHeap(obj, callable)) {
gc->BarrierEnd();
callable->Call(ls, {value});
gc->BarrierBegin();
} else {
cls->SetValue(cse.back()->callable->className,
std::get<std::string>(k), value);
}
}
}
stk->Push(gc, objhold);
gc->BarrierEnd();
return false;
}
bool InterperterThread::CreateArray(std::shared_ptr<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(std::shared_ptr<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(std::shared_ptr<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);
TCallable *tryC;
TCallable *catchC;
if (GetObjectHeap(tryFn, tryC) && GetObjectHeap(catchFn, catchC)) {
try {
stk->Push(gc, tryC->Call(ls, {}));
} catch (std::bad_alloc &ex) {
std::cerr
<< "CrossLang has failed to allocate, sorry for termination."
<< std::endl;
std::exit(1);
} catch (const std::string &ex) {
stk->Push(gc, catchC->Call(ls, {ex}));
} catch (const char *ex) {
stk->Push(gc,
catchC->Call(ls, {std::string{ex != nullptr ? ex : ""}}));
} catch (std::runtime_error &ex) {
stk->Push(
gc, catchC->Call(ls, {TNativeObject::Create<TException>(
ls, ex.what(), "RuntimeException")}));
} catch (VMException &ex) {
stk->Push(
gc, catchC->Call(ls, {TNativeObject::Create<TException>(
ls, ex.GetMessage(), "VMException")}));
} catch (VMByteCodeException &ex) {
stk->Push(gc, catchC->Call(ls, {ex.exception}));
} catch (std::exception &ex) {
stk->Push(gc,
catchC->Call(
ls, {TNativeObject::Create<TNativeException>(
ls, ex.what(), std::current_exception())}));
} catch (...) {
stk->Push(gc,
catchC->Call(ls, {TNativeObject::Create<TNativeException>(
ls, "<No Message>",
std::current_exception())}));
}
}
return false;
}
bool InterperterThread::JumpConditional(std::shared_ptr<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]);
GCList ls2(gc);
auto _res2 = stk->Pop(ls2);
auto _res = ToBool(_res2);
stk->ip = stk->ip + 4;
if (_res)
stk->ip = n;
} else
throw VMException("Can't read jmpc pc.");
return false;
}
bool InterperterThread::PushClosure(std::shared_ptr<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);
closure->className = cse.back()->callable->className;
stk->Push(gc, closure);
gc->BarrierEnd();
} else {
throw VMException("Can't read chunk.");
}
}
return false;
}
bool InterperterThread::PushScopelessClosure(std::shared_ptr<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);
closure->className = stk->callable->className;
stk->Push(gc, closure);
gc->BarrierEnd();
} else {
throw VMException("Can't read chunk.");
}
}
return false;
}
bool InterperterThread::PushString(std::shared_ptr<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(std::shared_ptr<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(std::shared_ptr<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(std::shared_ptr<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(std::shared_ptr<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(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
gc->BarrierBegin();
GCList ls(gc);
stk->env = stk->env->GetSubEnvironment(ls);
stk->scopes++;
gc->BarrierEnd();
return false;
}
bool InterperterThread::Defer(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
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();
return false;
}
bool InterperterThread::Dup(std::shared_ptr<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(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
gc->BarrierBegin();
GCList ls(gc);
std::vector<TCallable *> callable;
std::vector<uint8_t> &code = stk->callable->closure->code;
if (stk->ip + 4 <= code.size()) {
uint32_t n = BitConverter::ToUint32BE(code[stk->ip]);
stk->ip += 4;
for (uint32_t i = 0; i < n; i++) {
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::ScopeEnd(std::shared_ptr<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();
gc->BarrierEnd();
for (auto item : callable) {
GCList ls2(gc);
item->Call(ls2, {});
}
return false;
}
bool InterperterThread::PushRelativePath(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
auto p = Framework::Filesystem::VFSPath();
p.relative = true;
p.path = {};
stk->Push(gc, p);
return false;
}
bool InterperterThread::PushRootPath(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
auto stk = cse.back();
auto p = Framework::Filesystem::VFSPath();
p.relative = false;
p.path = {};
stk->Push(gc, p);
return false;
}
bool InterperterThread::Illegal(std::shared_ptr<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[stk->ip - 1]);
throw VMException("Illegal instruction: 0x" + std::string(chr) + ".");
}
void InterperterThread::Execute(std::shared_ptr<GC> gc) {
std::vector<CallStackEntry *> &cse = this->call_stack_entries;
#define VM_OPCODE_TABLE_INLINE
#include "vm_opcode_table.def"
#undef VM_OPCODE_TABLE_INLINE
execute:
if (!cse.empty()) {
auto stk = cse.back();
GC::SetCurrentFunction(stk);
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 (stk->mustReturn) {
stk->mustReturn = false;
if (cse.size() > 1) {
GCList ls(gc);
TObject o = cse[cse.size() - 1]->Pop(ls);
cse[cse.size() - 2]->Push(gc, o);
cse.erase(cse.end() - 1);
GC::SetCurrentFunction(cse.back());
gc->BarrierEnd();
goto execute;
} else {
return;
}
}
if (gc->UsingNullThreads()) {
std::vector<THeapObject *> objs;
gc->Collect(objs);
for (auto &item : objs) {
delete item;
}
}
}
stk->mustReturn = false;
} catch (...) {
{
gc->BarrierBegin();
GCList ls(gc);
std::vector<TCallable *> callable;
while (!cse.empty()) {
auto r = cse.back();
auto e = r->env;
for (uint32_t i = 0; i < r->scopes; i++) {
if (!e->defers.empty()) {
ls.Add(e);
callable.insert(callable.end(), e->defers.begin(),
e->defers.end());
}
e = e->GetParentEnvironment();
}
cse.erase(cse.end() - 1);
}
gc->BarrierEnd();
for (auto item : callable) {
GCList ls2(gc);
item->Call(ls2, {});
}
}
std::rethrow_exception(std::current_exception());
}
if (cse.size() == 1) {
GC::SetCurrentFunction(nullptr);
{
gc->BarrierBegin();
GCList ls(gc);
std::vector<TCallable *> callable;
auto r = cse.back();
auto e = r->env;
for (uint32_t i = 0; i < r->scopes; i++) {
if (!e->defers.empty()) {
ls.Add(e);
callable.insert(callable.end(), e->defers.begin(),
e->defers.end());
}
e = e->GetParentEnvironment();
}
gc->BarrierEnd();
for (auto item : callable) {
GCList ls2(gc);
item->Call(ls2, {});
}
}
return;
} else {
{
gc->BarrierBegin();
GCList ls(gc);
std::vector<TCallable *> callable;
auto r = cse.back();
auto e = r->env;
for (uint32_t i = 0; i < r->scopes; i++) {
if (!e->defers.empty()) {
ls.Add(e);
callable.insert(callable.end(), e->defers.begin(),
e->defers.end());
}
e = e->GetParentEnvironment();
}
TObject o = cse[cse.size() - 1]->Pop(ls);
cse[cse.size() - 2]->Push(gc, o);
cse.erase(cse.end() - 1);
GC::SetCurrentFunction(cse.back());
gc->BarrierEnd();
for (auto item : callable) {
GCList ls2(gc);
item->Call(ls2, {});
}
}
goto execute;
}
}
}
void CallStackEntry::Mark() {
if (this->marked)
return;
this->marked = true;
this->env->Mark();
this->callable->Mark();
for (auto item : this->stack)
GC::Mark(item);
}
void CallStackEntry::Push(std::shared_ptr<GC> gc, TObject o) {
gc->BarrierBegin();
this->stack.push_back(o);
gc->BarrierEnd();
}
TObject CallStackEntry::Resume(GCList &ls) {
auto cse = GC::GetCurrentFunction();
InterperterThread *thrd = InterperterThread::Create(ls);
ls.GetGC()->BarrierBegin();
thrd->call_stack_entries.push_back(this);
ls.GetGC()->BarrierEnd();
thrd->Execute(ls.GetGC());
TObject v = thrd->call_stack_entries[0]->Pop(ls);
GC::SetCurrentFunction(cse);
return v;
}
TObject CallStackEntry::Pop(GCList &gc) {
if (this->stack.empty())
return Undefined();
gc.GetGC()->BarrierBegin();
TObject o = this->stack[this->stack.size() - 1];
gc.Add(o);
this->stack.erase(this->stack.begin() + this->stack.size() - 1);
gc.GetGC()->BarrierEnd();
return o;
}
InterperterThread *InterperterThread::Create(GCList &ls) {
return ls.Create<InterperterThread>();
}
InterperterThread *InterperterThread::Create(GCList *ls) {
return ls->Create<InterperterThread>();
}
CallStackEntry *CallStackEntry::Create(GCList &ls) {
return ls.Create<CallStackEntry>();
}
CallStackEntry *CallStackEntry::Create(GCList *ls) {
return ls->Create<CallStackEntry>();
}
void InterperterThread::AddCallStackEntry(GCList &ls, TClosure *closure,
std::vector<TObject> args) {
ls.GetGC()->BarrierBegin();
CallStackEntry *cse = CallStackEntry::Create(ls);
cse->thread = this;
cse->callable = closure;
cse->env = closure->chunkId == 0 ? closure->env
: closure->ownScope ? closure->env->GetSubEnvironment(ls)
: closure->env;
cse->ip = 0;
if (closure->closure->args.empty() && closure->chunkId != 0) {
TList *list = TList::Create(ls);
list->items = args;
cse->env->DeclareVariable("arguments", list);
} else {
auto requiredArguments = [closure]() -> size_t {
for (size_t i = 0; i < closure->closure->args.size(); i++) {
if (closure->closure->args[i].find("$") == 0) {
return i;
}
}
return closure->closure->args.size();
};
auto optionalArguments = [closure](size_t argLen) -> size_t {
for (size_t i = 0; i < closure->closure->args.size(); i++) {
if (closure->closure->args[i].find("$$") == 0) {
return std::min(argLen, i);
}
}
return std::min(argLen, closure->closure->args.size());
};
auto trimStart = [](std::string txt) -> std::string {
if (txt.empty())
return {};
if (txt[0] != '$')
return txt;
auto idx = txt.find_first_not_of('$');
if (idx == std::string::npos)
return {};
return txt.substr(idx);
};
size_t required = requiredArguments();
if (args.size() < required) {
throw VMException("Called a function that expected at least " +
std::to_string(required) + " args but got " +
std::to_string(args.size()));
}
size_t i;
for (i = 0; i < optionalArguments(args.size()); i++) {
cse->env->DeclareVariable(trimStart(closure->closure->args[i]),
args[i]);
}
for (; i < closure->closure->args.size(); i++) {
auto &a = closure->closure->args[i];
if (a.size() > 1 && a[0] == '$') {
if (a[1] == '$') {
break;
}
cse->env->DeclareVariable(trimStart(a), Undefined());
} else {
break;
}
}
std::string back = closure->closure->args.empty()
? std::string()
: closure->closure->args.back();
if (i == closure->closure->args.size() - 1 && back.size() > 2 &&
back[0] == '$' && back[1] == '$') {
auto argName = closure->closure->args[i];
auto lsArgs = TList::Create(ls);
for (; i < args.size(); i++)
lsArgs->Add(args[i]);
cse->env->DeclareVariable(trimStart(argName), lsArgs);
i = args.size();
}
if (i < args.size())
throw VMException("Too many arguments");
}
GC::SetCurrentFunction(cse);
this->call_stack_entries.push_back(cse);
ls.GetGC()->BarrierEnd();
}
} // namespace Tesses::CrossLang