#include "CrossLang.hpp" #include #include #include namespace Tesses::CrossLang { thread_local CallStackEntry* current_function=nullptr; bool ToBool(TObject obj) { if(std::holds_alternative(obj)) { return true; } if(std::holds_alternative(obj)) { return !std::get(obj).empty(); } else if(std::holds_alternative(obj)) { return std::get(obj) != 0; } else if(std::holds_alternative(obj)) { return std::get(obj); } else if(std::holds_alternative(obj)) { return std::get(obj); } else if(std::holds_alternative(obj)) { return std::get(obj) != 0; } else if(std::holds_alternative(obj)) { auto o = std::get(obj).obj; auto ls = dynamic_cast(o); auto dict = dynamic_cast(o); auto ba = dynamic_cast(o); auto nat = dynamic_cast(o); auto thrd = dynamic_cast(o); if(ls != nullptr) { return ls->Count() != 0; } else if(dict != nullptr) { return !dict->items.empty(); } else if(ba != nullptr) { return !ba->data.empty(); } else if(nat != nullptr) { return !nat->GetDestroyed(); } else if(thrd != nullptr) { return !thrd->hasReturned; } } return false; } TObject ExecuteFunction(GCList& ls,TCallable* callable, std::vector 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 bool InterperterThread::InvokeTwo(GCList& ls, TObject fn, TObject left, TObject right) { if(std::holds_alternative(fn)) { auto obj = dynamic_cast(std::get(fn).obj); if(obj != nullptr) { auto closure = dynamic_cast(obj); if(closure != nullptr) { if(!closure->closure->args.empty() && closure->closure->args[0] == "this") { this->AddCallStackEntry(ls,closure,{left,right}); } else { this->AddCallStackEntry(ls,closure,{right}); } } else { this->call_stack_entries[this->call_stack_entries.size()-1]->Push(ls.GetGC(), obj->Call(ls,{right})); return false; } return true; } } return false; } bool InterperterThread::InvokeMethod(GCList& ls, TObject fn, TObject instance, std::vector args) { if(std::holds_alternative(fn)) { auto obj = dynamic_cast(std::get(fn).obj); if(obj != nullptr) { auto closure = dynamic_cast(obj); if(closure != nullptr) { if(!closure->closure->args.empty() && closure->closure->args[0] == "this") { std::vector args2; args2.push_back(instance); args2.insert(args2.end(), args.begin(),args.end()); this->AddCallStackEntry(ls,closure,args2); } else { this->AddCallStackEntry(ls,closure,args); } } else { auto val = obj->Call(ls,args); this->call_stack_entries.back()->Push(ls.GetGC(), val); return false; } return true; } } return false; } bool InterperterThread::Sub(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) - std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) - std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) - std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) - std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator-"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Times(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) * std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) * std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) * std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) * std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator*"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Divide(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) / std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) / std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) / std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) / std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) / std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) / std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) / std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator/"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Mod(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) % std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,fmod(std::get(left), std::get(right))); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,fmod(std::get(left), std::get(right))); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,fmod(std::get(left), std::get(right))); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator%"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Neg(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left)) { cse.back()->Push(gc,-std::get(left)); } else if(std::holds_alternative(left)) { cse.back()->Push(gc,-std::get(left)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator-"); gc->BarrierEnd(); return InvokeOne(ls,negfn,left); } else { cse.back()->Push(gc,nullptr); } } else { cse.back()->Push(gc,nullptr); } return false; } bool InterperterThread::LNot(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left)) { cse.back()->Push(gc,true); } else if(std::holds_alternative(left)) { cse.back()->Push(gc,true); } else if(std::holds_alternative(left)) { cse.back()->Push(gc,!std::get(left)); } else if(std::holds_alternative(left)) { cse.back()->Push(gc,!std::get(left)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator!"); gc->BarrierEnd(); return InvokeOne(ls,negfn,left); } else { cse.back()->Push(gc, !ToBool(left)); } } else { cse.back()->Push(gc, !ToBool(left)); } return false; } bool InterperterThread::BNot(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left)) { cse.back()->Push(gc,~std::get(left)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject negfn = dict->GetValue("operator~"); gc->BarrierEnd(); return InvokeOne(ls,negfn,left); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Lt(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) < std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) < std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) < std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) < std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Gt(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) > std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) > std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) > std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) > std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Lte(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) <= std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) <= std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) <= std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) <= std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<="); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Gte(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) >= std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) >= std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) >= std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) >= std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>="); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::Eq(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { return true; } else if(std::holds_alternative(left) && std::holds_alternative(right)) { return true; } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) == std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) == std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) == std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) == std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) == std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) == std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) == std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator=="); gc->BarrierEnd(); if(!std::holds_alternative(fn)) return InvokeTwo(ls,fn,left,right); } if(std::holds_alternative(right)) { cse.back()->Push(gc,obj == std::get(right).obj); return false; } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::NEq(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { return false; } else if(std::holds_alternative(left) && std::holds_alternative(right)) { return false; } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) != std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) != std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) != std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) != std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) != std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) != std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) != std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator!="); gc->BarrierEnd(); if(!std::holds_alternative(fn)) return InvokeTwo(ls,fn,left,right); } if(std::holds_alternative(right)) { cse.back()->Push(gc,obj != std::get(right).obj); return false; } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::LShift(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) << (int)std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator<<"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::RShift(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) >> (int)std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator>>"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::BOr(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) || std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator||"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::XOr(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) ^ std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator^"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc,Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::BAnd(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) && std::get(right)); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator&&"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } 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(fn)) { auto obj = dynamic_cast(std::get(fn).obj); if(obj != nullptr) { auto closure = dynamic_cast(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::Add(GC* gc) { std::vector& cse=this->call_stack_entries; GCList ls(gc); auto right = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls); if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) + std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) + std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) + std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) + std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) + std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) + std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { cse.back()->Push(gc,std::get(left) + std::get(right)); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { std::string str={}; str.append(std::get(left)); str.append(std::get(right)); cse.back()->Push(gc,str); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { std::string str={}; str.push_back(std::get(left)); str.append(std::get(right)); cse.back()->Push(gc,str); } else if(std::holds_alternative(left) && std::holds_alternative(right)) { std::string str={}; str.append(std::get(left)); str.push_back(std::get(right)); cse.back()->Push(gc,str); } else if(std::holds_alternative(left)) { auto obj = std::get(left).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("operator+"); gc->BarrierEnd(); return InvokeTwo(ls,fn,left,right); } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc, Undefined()); } return false; } bool InterperterThread::ExecuteFunction(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); std::vector& code = stk->callable->closure->code; GCList ls(gc); auto res = stk->Pop(ls); if(std::holds_alternative(res)) { uint32_t n=(uint32_t)std::get(res); std::vector args; for(size_t i = 0;iPop(ls)}); } TObject fn = stk->Pop(ls); if(std::holds_alternative(fn)) { if(args.size() == 3) { if(std::holds_alternative(args[1]) && std::holds_alternative(args[2])) { std::string key = std::get(args[1]); TList* ls = dynamic_cast(std::get(args[2]).obj); if(ls != nullptr) return ExecuteMethod2(gc,args[0],key,ls->items); } } stk->Push(gc, Undefined()); return false; } if(std::holds_alternative(fn)) { auto obj = dynamic_cast(std::get(fn).obj); if(obj != nullptr) { auto closure = dynamic_cast(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::ExecuteMethod2(GC* gc, TObject instance, std::string key, std::vector args) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { GCList ls(gc); if(std::holds_alternative(instance)) { bool flag = std::get(instance); if(key == "ToString") { cse.back()->Push(gc, flag ? "true" : "false"); return false; } else if(key == "ToLong") { cse.back()->Push(gc, flag ? (int64_t)1 : (int64_t)0); return false; } cse.back()->Push(gc, Undefined()); return false; } else if(std::holds_alternative(instance)) { char c = std::get(instance); if(key == "ToString") { cse.back()->Push(gc, std::string{c}); return false; } else if(key == "ToLong") { uint8_t uc = (uint8_t)c; cse.back()->Push(gc, (int64_t)uc); return false; } else if(key == "IsAscii") { bool isAscii = c >= 0; cse.back()->Push(gc, isAscii); return false; } if(key == "IsLetter") { bool isLetter = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); cse.back()->Push(gc, isLetter); return false; } if(key == "IsDigit") { bool isDigit = (c >= '0' && c <= '9'); cse.back()->Push(gc, isDigit); return false; } if(key == "IsLetterOrDigit") { bool isDigit = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); cse.back()->Push(gc, isDigit); return false; } if(key == "ToLower") { if(c >= 'A' && c <= 'Z') cse.back()->Push(gc, (char)tolower(c)); else cse.back()->Push(gc, c); return false; } if(key == "ToUpper") { if(c >= 'a' && c <= 'z') cse.back()->Push(gc, (char)toupper(c)); else cse.back()->Push(gc, c); return false; } cse.back()->Push(gc, Undefined()); return false; } else if(std::holds_alternative(instance)) { double number = std::get(instance); if(key == "ToString") { cse.back()->Push(gc, std::to_string(number)); return false; } if(key == "ToLong") { cse.back()->Push(gc, (int64_t)number); return false; } if(key == "ToLongBits") { cse.back()->Push(gc, std::bit_cast(number)); return false; } if(key == "Floor") { cse.back()->Push(gc,floor(number)); return false; } if(key == "Ceiling") { cse.back()->Push(gc,ceil(number)); return false; } if(key == "Abs") { cse.back()->Push(gc,fabs(number)); return false; } if(key == "Pow") { if(args.size() != 1) { throw VMException("Double.Pow must only accept one argument"); } if(!std::holds_alternative(args[0])) { throw VMException("Double.Pow must only accept a double"); } cse.back()->Push(gc,pow(number, std::get(args[0]))); return false; } if(key == "Atan2") { if(args.size() != 1) { throw VMException("Double.Atan2 must only accept one argument"); } if(!std::holds_alternative(args[0])) { throw VMException("Double.Atan2 must only accept a double"); } cse.back()->Push(gc,atan2(number, std::get(args[0]))); return false; } if(key == "Atan") { cse.back()->Push(gc,tan(number)); return false; } if(key == "Tan") { cse.back()->Push(gc,tan(number)); return false; } if(key == "Tanh") { cse.back()->Push(gc,tanh(number)); return false; } if(key == "Asin") { cse.back()->Push(gc,asin(number)); return false; } if(key == "Sin") { cse.back()->Push(gc,sin(number)); return false; } if(key == "Sinh") { cse.back()->Push(gc,sinh(number)); return false; } if(key == "Acos") { cse.back()->Push(gc,acos(number)); return false; } if(key == "Cos") { cse.back()->Push(gc,cos(number)); return false; } if(key == "Cosh") { cse.back()->Push(gc,cosh(number)); return false; } if(key == "Log") { cse.back()->Push(gc,log(number)); return false; } if(key == "Log10") { cse.back()->Push(gc,log10(number)); return false; } if(key == "Sqrt") { cse.back()->Push(gc,sqrt(number)); return false; } cse.back()->Push(gc, Undefined()); return false; } else if(std::holds_alternative(instance)) { int64_t number = std::get(instance); if(key == "ToHexString") { int64_t width = 1; if(!GetArgument(args,0,width)) width=1; size_t _width = (size_t)width; std::stringstream strm; if(_width > 1) strm << std::setfill('0') << std::setw((int)_width) << std::hex << number; else strm << std::hex << number; cse.back()->Push(gc,strm.str()); return false; } if(key == "ToString") { cse.back()->Push(gc, std::to_string(number)); return false; } if(key == "ToChar") { uint8_t c = (uint8_t)number; cse.back()->Push(gc, (char)c); return false; } if(key == "Abs") { if(number < 0) cse.back()->Push(gc, -number); else cse.back()->Push(gc, number); } if(key == "ToDouble") { cse.back()->Push(gc,(double)number); return false; } if(key == "ToDoubleBits") { cse.back()->Push(gc,std::bit_cast(number)); return false; } cse.back()->Push(gc, Undefined()); return false; } else if(std::holds_alternative(instance)) { auto path = std::get(instance); if(key == "GetEnumerator") { TList* _ls = TList::Create(ls); for(auto item : path.path) { _ls->Add(item); } cse.back()->Push(gc, TListEnumerator::Create(ls,_ls)); return false; } if(key == "ToString") { cse.back()->Push(gc, path.ToString()); return false; } if(key == "GetAt") { int64_t index; if(GetArgument(args,0,index)) { size_t idx = (size_t)idx; if(idx < path.path.size()) cse.back()->Push(gc, path.path[idx]); else cse.back()->Push(gc, nullptr); return false; } } if(key == "Count" || key == "Length") { cse.back()->Push(gc, (int64_t)path.path.size()); return false; } if(key == "GetParent") { cse.back()->Push(gc, path.GetParent()); return false; } if(key == "GetFileName") { cse.back()->Push(gc, path.GetFileName()); return false; } if(key == "CollapseRelativeParents") { cse.back()->Push(gc, path.CollapseRelativeParents()); return false; } if(key == "RelativeCurrentDirectory") { cse.back()->Push(gc, path.RelativeCurrentDirectory()); return false; } if(key == "IsRelative") { cse.back()->Push(gc, path.relative); return false; //Path.FromString(); } } else if(std::holds_alternative(instance)) { std::string str = std::get(instance); if(key == "GetEnumerator") { cse.back()->Push(gc, TStringEnumerator::Create(ls,str)); return false; } if(key == "Substring") { if(args.size() >=1 && std::holds_alternative(args[0])) { size_t offset = (size_t)std::get(args[0]); size_t count = std::string::npos; if(args.size() == 2 && std::holds_alternative(args[1])) { count = (size_t)std::get(args[1]); } cse.back()->Push(gc, str.substr(offset,count)); return false; } } if(key == "Remove") { if(args.size() >=1 && std::holds_alternative(args[0])) { size_t offset = (size_t)std::get(args[0]); size_t count = std::string::npos; if(args.size() == 2 && std::holds_alternative(args[1])) { count = (size_t)std::get(args[1]); } cse.back()->Push(gc, str.erase(offset,count)); return false; } } if(key == "TrimStart") { if(args.size() >= 0) { char c = (args.size() == 1 && std::holds_alternative(args[0])) ? std::get(args[0]) : ' '; size_t i = 0; for(; i < str.size();i++) { if(str[i] != c) break; } cse.back()->Push(gc,str.substr(i)); return false; } } if(key == "TrimEnd") { if(args.size() >= 0) { char c = (args.size() == 1 && std::holds_alternative(args[0])) ? std::get(args[0]) : ' '; size_t i = str.size()-1; for(; i >= 0;i--) { if(str[i] != c) break; } cse.back()->Push(gc,str.substr(0,i+1)); return false; } } if(key == "Escape") { bool quote; if(!GetArgument(args,0,quote)) quote=false; cse.back()->Push(gc, EscapeString(str, quote)); return false; } if(key == "Replace") { std::string oldStr; std::string newStr; std::string str={}; if(GetArgument(args,0,oldStr) && GetArgument(args,1,newStr)) { bool first=true; for(auto txt : Tesses::Framework::Http::HttpUtils::SplitString(str,oldStr)) { if(!first) str.append(newStr); first=false; str.append(txt); } } cse.back()->Push(gc,str); return false; } if(key == "Split") { std::string delimiter; bool removeEmpty=false; size_t count=std::string::npos; if(args.size() < 1 || args.size() > 3) throw VMException("String.Split must only accept 1-3 arguments"); if(!std::holds_alternative(args[0])) throw VMException("String.Split first arg must be a string"); else delimiter = std::get(args[0]); if(args.size() > 1 && !std::holds_alternative(args[1])) throw VMException("String.Split second arg must be a bool"); else if(args.size() > 1) removeEmpty = std::get(args[1]); if(args.size() > 2 && !std::holds_alternative(args[2])) throw VMException("String.Split third arg must be a int64_t"); else if(args.size() > 2) count = (size_t)std::get(args[2]); auto res = Tesses::Framework::Http::HttpUtils::SplitString(str, delimiter,count); TList* mls = TList::Create(ls); for(auto item : res) { if(!removeEmpty || !item.empty()) mls->Add(item); } cse.back()->Push(gc,mls); return false; // SplitString() } if(key == "GetAt") { if(args.size() != 1) { throw VMException("String.GetAt must only accept one argument"); } if(!std::holds_alternative(args[0])) { throw VMException("String.GetAt must only accept a long"); } size_t index = (size_t)std::get(args[0]); size_t sz = str.size(); if(index >= 0 && index < sz) { cse.back()->Push(gc, str[index]); return false; } } if(key == "Count" || key == "Length") { int64_t len = (int64_t)str.size(); if(len < 0) len = 0; cse.back()->Push(gc, len); return false; } if(key == "ToString") { cse.back()->Push(gc, str); return false; } cse.back()->Push(gc, Undefined()); return false; } else if(std::holds_alternative(instance)) { auto obj = std::get(instance).obj; auto list = dynamic_cast(obj); auto bArray = dynamic_cast(obj); auto dict = dynamic_cast(obj); auto ittr = dynamic_cast(obj); auto strm = dynamic_cast(obj); auto vfs = dynamic_cast(obj); auto env = dynamic_cast(obj); auto rootEnv = dynamic_cast(obj); if(rootEnv != nullptr) { //TStd::RegisterCrypto //TStd::RegisterDictionary //TStd::RegisterEnv //TStd::RegisterIO //TStd::RegisterJson //TStd::RegisterNet //TStd::RegisterOGC //TStd::RegisterPath //TStd::RegisterRoot //TStd::RegisterSDL2 //TStd::RegisterSqlite //TStd::RegisterVM auto myEnv = cse.back()->env->GetRootEnvironment(); if(key == "RegisterConsole") { if(myEnv->permissions.canRegisterConsole && !rootEnv->permissions.locked) TStd::RegisterConsole(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterCrypto") { if(myEnv->permissions.canRegisterCrypto && !rootEnv->permissions.locked) TStd::RegisterCrypto(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterDictionary") { if(myEnv->permissions.canRegisterDictionary && !rootEnv->permissions.locked) TStd::RegisterDictionary(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterEnv") { if(myEnv->permissions.canRegisterEnv && !rootEnv->permissions.locked) TStd::RegisterDictionary(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterIO") { bool r; if(GetArgument(args,0,r)) { if(myEnv->permissions.canRegisterIO && !rootEnv->permissions.locked) TStd::RegisterIO(gc, rootEnv, myEnv->permissions.canRegisterLocalFS ? r : false); } cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterJson") { if(myEnv->permissions.canRegisterJSON && !rootEnv->permissions.locked) TStd::RegisterJson(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterNet") { if(myEnv->permissions.canRegisterNet && !rootEnv->permissions.locked) TStd::RegisterNet(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterOGC") { if(myEnv->permissions.canRegisterOGC && !rootEnv->permissions.locked) TStd::RegisterNet(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterPath") { if(myEnv->permissions.canRegisterPath && !rootEnv->permissions.locked) TStd::RegisterPath(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterRoot") { if(myEnv->permissions.canRegisterRoot && !rootEnv->permissions.locked) TStd::RegisterRoot(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterSDL2") { if(myEnv->permissions.canRegisterSDL2 && !rootEnv->permissions.locked) TStd::RegisterSDL2(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterSqlite") { if(myEnv->permissions.canRegisterSqlite && !rootEnv->permissions.locked) TStd::RegisterSqlite(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "SetSqliteRoot") { Tesses::Framework::Filesystem::VFSPath p; if(!rootEnv->permissions.locked) { if(GetArgumentAsPath(args,0,p)) { if(myEnv->permissions.sqlite3Scoped) { rootEnv->permissions.sqliteOffsetPath = myEnv->permissions.sqliteOffsetPath / p.CollapseRelativeParents(); rootEnv->permissions.sqlite3Scoped = true; } else { rootEnv->permissions.sqliteOffsetPath = p; rootEnv->permissions.sqlite3Scoped = true; } } else { if(myEnv->permissions.sqlite3Scoped) { rootEnv->permissions.sqliteOffsetPath = myEnv->permissions.sqliteOffsetPath; rootEnv->permissions.sqlite3Scoped = true; } else { rootEnv->permissions.sqlite3Scoped = false; } } } cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterVM") { if(myEnv->permissions.canRegisterVM && !rootEnv->permissions.locked) TStd::RegisterVM(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "LockRegister") { if(!rootEnv->permissions.locked) { rootEnv->permissions.locked=true; } cse.back()->Push(gc,nullptr); return false; } if(key == "GetDictionary") { cse.back()->Push(gc,rootEnv->GetDictionary()); return false; } if(key == "LoadFileWithDependencies") { TVFSHeapObject* vfs0; TFile* f; Tesses::Framework::Filesystem::VFSPath p; if(GetArgumentHeap(args,0,vfs0) ) { if(GetArgumentHeap(args,1,f)) { rootEnv->LoadFileWithDependencies(gc,vfs0->vfs,f); } else if(GetArgumentAsPath(args,1,p)) { rootEnv->LoadFileWithDependencies(gc,vfs0->vfs,p); } } cse.back()->Push(gc,nullptr); return false; } } if(env != nullptr) { if(key == "Eval") { std::string str; if(GetArgument(args,0,str)) { cse.back()->Push(gc,env->Eval(ls,str)); return false; } cse.back()->Push(gc,nullptr); return false; } if(key == "GetRootEnvironment") { cse.back()->Push(gc,env->GetRootEnvironment()); return false; } if(key == "GetSubEnvironment") { cse.back()->Push(gc,env->GetSubEnvironment(ls)); return false; } if(key == "GetParentEnvironment") { cse.back()->Push(gc,env->GetParentEnvironment()); return false; } if(key == "GetVariable") { std::string key; gc->BarrierBegin(); if(GetArgument(args,0,key)) cse.back()->Push(gc,env->GetVariable(key)); gc->BarrierEnd(); return false; } if(key == "SetVariable") { std::string key; gc->BarrierBegin(); if(args.size() > 1 && GetArgument(args,0,key)) env->SetVariable(key,args[1]); gc->BarrierEnd(); cse.back()->Push(gc,nullptr); return false; } if(key == "DeclareVariable") { std::string key; gc->BarrierBegin(); if(args.size() > 1 && GetArgument(args,0,key)) env->DeclareVariable(key,args[1]); gc->BarrierEnd(); cse.back()->Push(gc,nullptr); return false; } if(key == "LoadFile") { TFile* f; if(GetArgumentHeap(args,0,f)) { env->LoadFile(gc,f); } cse.back()->Push(gc,nullptr); return false; } cse.back()->Push(gc,nullptr); return false; } if(vfs != nullptr) { auto myvfs = dynamic_cast(vfs->vfs); auto mountable = dynamic_cast(vfs->vfs); if(myvfs != nullptr) { TDictionary* dict2; if(GetObjectHeap(myvfs->obj, dict2)) { gc->BarrierBegin(); auto o = dict2->GetValue(key); gc->BarrierEnd(); return InvokeMethod(ls,o,dict2,args); } } if(mountable != nullptr) { if(key == "Unmount") { Tesses::Framework::Filesystem::VFSPath path; if(GetArgumentAsPath(args,0,path)) { mountable->Unmount(path); } cse.back()->Push(gc, nullptr); return false; } if(key == "Mount") { Tesses::Framework::Filesystem::VFSPath path; TVFSHeapObject* vfs2; if(GetArgumentAsPath(args,0,path) && GetArgumentHeap(args,1,vfs2)) { TObjectVFS* vfs3 = new TObjectVFS(gc, vfs2); //mountable->Mount(path, , true); mountable->Mount(path, vfs3, true); } cse.back()->Push(gc, nullptr); return false; } } if(key == "EnumeratePaths") { Tesses::Framework::Filesystem::VFSPath dir; if(GetArgumentAsPath(args,0,dir)) { auto tem = TExternalMethod::Create(ls,"Get the enumerator",{},[vfs,dir](GCList& ls, std::vector args)->TObject{ return TVFSPathEnumerator::Create(ls,vfs->vfs->EnumeratePaths(dir)); }); auto d1=TDictionary::Create(ls); gc->BarrierBegin(); tem->watch.push_back(vfs); d1->SetValue("GetEnumerator", tem); gc->BarrierEnd(); cse.back()->Push(gc,d1); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "MoveDirectory") { Tesses::Framework::Filesystem::VFSPath existingFile; Tesses::Framework::Filesystem::VFSPath symlinkFile; if(GetArgumentAsPath(args,0,existingFile) && GetArgumentAsPath(args,1,symlinkFile)) { vfs->vfs->MoveDirectory(existingFile,symlinkFile); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "SetDate") { Tesses::Framework::Filesystem::VFSPath path; int64_t lastWrite; int64_t lastAccess; if(GetArgumentAsPath(args,0,path) && GetArgument(args,1,lastWrite) && GetArgument(args,2,lastAccess)) { vfs->vfs->SetDate(path,(time_t)lastWrite,(time_t)lastAccess); } cse.back()->Push(gc, nullptr); return false; } if(key == "GetDate") { Tesses::Framework::Filesystem::VFSPath path; if(GetArgumentAsPath(args,0,path)) { time_t lastWrite; time_t lastAccess; vfs->vfs->GetDate(path,lastWrite,lastAccess); auto dict = TDictionary::Create(ls); ls.GetGC()->BarrierBegin(); dict->SetValue("LastWrite", (int64_t)lastWrite); dict->SetValue("LastAccess", (int64_t)lastAccess); ls.GetGC()->BarrierEnd(); cse.back()->Push(gc, dict); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "MoveFile") { Tesses::Framework::Filesystem::VFSPath existingFile; Tesses::Framework::Filesystem::VFSPath symlinkFile; if(GetArgumentAsPath(args,0,existingFile) && GetArgumentAsPath(args,1,symlinkFile)) { vfs->vfs->MoveFile(existingFile,symlinkFile); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "CreateHardlink") { Tesses::Framework::Filesystem::VFSPath existingFile; Tesses::Framework::Filesystem::VFSPath symlinkFile; if(GetArgumentAsPath(args,0,existingFile) && GetArgumentAsPath(args,1,symlinkFile)) { vfs->vfs->CreateHardlink(existingFile,symlinkFile); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "CreateSymlink") { Tesses::Framework::Filesystem::VFSPath existingFile; Tesses::Framework::Filesystem::VFSPath symlinkFile; if(GetArgumentAsPath(args,0,existingFile) && GetArgumentAsPath(args,1,symlinkFile)) { vfs->vfs->CreateSymlink(existingFile,symlinkFile); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "RegularFileExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->RegularFileExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "SpecialFileExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->SpecialFileExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "FIFOFileExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->FIFOFileExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "SocketFileExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->SocketFileExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "BlockDeviceExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->BlockDeviceExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "CharacterDeviceExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->CharacterDeviceExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "SymlinkExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->SymlinkExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "DirectoryExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->DirectoryExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "FileExists") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->FileExists(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "ReadLink") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->ReadLink(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "VFSPathToSystem") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->VFSPathToSystem(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "SystemToVFSPath") { std::string filename; if(GetArgument(args,0,filename)) { cse.back()->Push(gc,vfs->vfs->SystemToVFSPath(filename)); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "DeleteFile") { Tesses::Framework::Filesystem::VFSPath filename; if(GetArgumentAsPath(args,0,filename)) { vfs->vfs->DeleteFile(filename); } cse.back()->Push(gc, nullptr); return false; } if(key == "DeleteDirectoryRecurse") { Tesses::Framework::Filesystem::VFSPath dirname; if(GetArgumentAsPath(args,0,dirname)) { vfs->vfs->DeleteDirectoryRecurse(dirname); } cse.back()->Push(gc, nullptr); return false; } if(key == "DeleteDirectory") { Tesses::Framework::Filesystem::VFSPath dirname; if(GetArgumentAsPath(args,0,dirname)) { vfs->vfs->DeleteDirectory(dirname); } cse.back()->Push(gc, nullptr); return false; } if(key == "CreateDirectory") { Tesses::Framework::Filesystem::VFSPath dirname; if(GetArgumentAsPath(args,0,dirname)) { vfs->vfs->CreateDirectory(dirname); } cse.back()->Push(gc, nullptr); return false; } if(key == "OpenFile") { Tesses::Framework::Filesystem::VFSPath path; std::string mode; if(GetArgumentAsPath(args,0,path) && GetArgument(args,1,mode)) { auto res = vfs->vfs->OpenFile(path,mode); TStreamHeapObject* strm = TStreamHeapObject::Create(ls,res); cse.back()->Push(gc, strm); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "Close") { vfs->Close(); cse.back()->Push(gc, nullptr); return false; } cse.back()->Push(gc, nullptr); return false; } if(strm != nullptr) { auto memStrm = dynamic_cast(strm->stream); auto netStrm = dynamic_cast(strm->stream); auto mystrm = dynamic_cast(strm->stream); if(mystrm != nullptr) { TDictionary* dict2; if(GetObjectHeap(mystrm->obj, dict2)) { gc->BarrierBegin(); auto o = dict2->GetValue(key); gc->BarrierEnd(); return InvokeMethod(ls,o,dict2,args); } } if(memStrm != nullptr) { if(key == "GetBytes") { auto res = TByteArray::Create(ls); res->data = memStrm->GetBuffer(); cse.back()->Push(gc, res); return false; } } if(netStrm != nullptr) { if(key == "Bind") { std::string ip; int64_t port; if(GetArgument(args,0,ip) && GetArgument(args,1,port)) netStrm->Bind(ip,(uint16_t)port); cse.back()->Push(gc, nullptr); return false; } if(key == "Accept") { std::string ip; uint16_t port; auto strm = netStrm->Accept(ip,port); TDictionary* dict = TDictionary::Create(ls); gc->BarrierBegin(); dict->SetValue("IP",ip); dict->SetValue("Port",(int64_t)port); dict->SetValue("Stream", TStreamHeapObject::Create(ls,strm)); gc->BarrierEnd(); cse.back()->Push(gc, dict); return false; } if(key == "Listen") { int64_t backlog; if(GetArgument(args,0,backlog)) { netStrm->Listen((int32_t)backlog); } else { netStrm->Listen(10); } cse.back()->Push(gc, nullptr); return false; } if(key == "ReadFrom") { TByteArray* data; int64_t offset; int64_t length; if(GetArgumentHeap(args, 0, data) && GetArgument(args, 1, offset) && GetArgument(args,2,length)) { size_t off = (size_t)offset; size_t len = (size_t)length; std::string ip={}; uint16_t port=0; if(off < len) len = netStrm->ReadFrom(data->data.data()+off,std::min(len,std::min(data->data.size() - off, data->data.size())),ip,port); else len = 0; TDictionary* dict = TDictionary::Create(ls); gc->BarrierBegin(); dict->SetValue("IP",ip); dict->SetValue("Port",(int64_t)port); dict->SetValue("Read", (int64_t)len); gc->BarrierEnd(); cse.back()->Push(gc, dict); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "WriteTo") { TByteArray* data; int64_t offset; int64_t length; std::string ip; int64_t port; if(GetArgumentHeap(args, 0, data) && GetArgument(args, 1, offset) && GetArgument(args,2,length) && GetArgument(args,3,ip) && GetArgument(args,4,port)) { size_t off = (size_t)offset; size_t len = (size_t)length; if(off < len) len = netStrm->WriteTo(data->data.data()+off,std::min(len, std::min(data->data.size() - off, data->data.size())), ip, (int64_t)port); else len = 0; cse.back()->Push(gc, (int64_t)len); return false; } cse.back()->Push(gc, nullptr); return false; } } if(key == "Read") { TByteArray* data; int64_t offset; int64_t length; if(GetArgumentHeap(args, 0, data) && GetArgument(args, 1, offset) && GetArgument(args,2,length)) { size_t off = (size_t)offset; size_t len = (size_t)length; if(off < len) len = strm->stream->Read(data->data.data()+off,std::min(len,std::min(data->data.size() - off, data->data.size()))); else len = 0; cse.back()->Push(gc, (int64_t)len); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "Write") { TByteArray* data; int64_t offset; int64_t length; if(GetArgumentHeap(args, 0, data) && GetArgument(args, 1, offset) && GetArgument(args,2,length)) { size_t off = (size_t)offset; size_t len = (size_t)length; if(off < len) len = strm->stream->Write(data->data.data()+off,std::min(len, std::min(data->data.size() - off, data->data.size()))); else len = 0; cse.back()->Push(gc, (int64_t)len); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "ReadBlock") { TByteArray* data; int64_t offset; int64_t length; if(GetArgumentHeap(args, 0, data) && GetArgument(args, 1, offset) && GetArgument(args,2,length)) { size_t off = (size_t)offset; size_t len = (size_t)length; if(off < len) len = strm->stream->ReadBlock(data->data.data()+off,std::min(len, std::min(data->data.size() - off, data->data.size()))); else len = 0; cse.back()->Push(gc, (int64_t)len); return false; } cse.back()->Push(gc, nullptr); return false; } if(key == "WriteText") { std::string text; if(GetArgument(args,0,text)) { strm->stream->WriteBlock((const uint8_t*)text.data(), text.size()); } cse.back()->Push(gc, nullptr); return false; } if(key == "WriteBlock") { TByteArray* data; int64_t offset; int64_t length; if(GetArgumentHeap(args, 0, data) && GetArgument(args, 1, offset) && GetArgument(args,2,length)) { size_t off = (size_t)offset; size_t len = (size_t)length; if(off < len) strm->stream->WriteBlock(data->data.data()+off,std::min(len,std::min(data->data.size() - off, data->data.size()))); } cse.back()->Push(gc, nullptr); return false; } if(key == "CopyTo") { TStreamHeapObject* data; int64_t buffSize; if(GetArgumentHeap(args,0,data)) { if(!GetArgument(args,1,buffSize)) buffSize=1024; strm->stream->CopyTo(*data->stream,(size_t)buffSize); } cse.back()->Push(gc, nullptr); return false; } if(key == "Flush") { strm->stream->Flush(); cse.back()->Push(gc, nullptr); return false; } if(key == "Seek") { int64_t pos,whence; if(!GetArgument(args,0,pos)) pos=0; if(!GetArgument(args,1,whence)) whence=0; strm->stream->Seek(pos, whence == 0 ? Tesses::Framework::Streams::SeekOrigin::Begin : whence == 1 ? Tesses::Framework::Streams::SeekOrigin::Current : Tesses::Framework::Streams::SeekOrigin::End); cse.back()->Push(gc, nullptr); return false; } if(key == "Close") { strm->Close(); cse.back()->Push(gc, nullptr); return false; } cse.back()->Push(gc, nullptr); return false; } if(ittr != nullptr) { if(key == "MoveNext") { cse.back()->Push(gc, ittr->MoveNext(gc)); return false; } cse.back()->Push(gc, nullptr); return false; } else if(bArray != nullptr) { if(key == "Count" || key == "Length") { int64_t len = (int64_t)bArray->data.size(); if(len < 0) len = 0; cse.back()->Push(gc, len); return false; } if(key == "ToString") { cse.back()->Push(gc,std::string(bArray->data.begin(),bArray->data.end())); return false; } if(key == "GetAt") { if(args.size() != 1) { throw VMException("ByteArray.GetAt must only accept one argument"); } if(!std::holds_alternative(args[0])) { throw VMException("ByteArray.GetAt must only accept a long"); } size_t index = (size_t)std::get(args[0]); size_t sz = bArray->data.size(); if(index >= 0 && index < sz) { cse.back()->Push(gc, (int64_t)bArray->data[index]); return false; } } if(key == "GetAt") { if(args.size() != 2) { throw VMException("ByteArray.SetAt must only accept two arguments"); } if(!std::holds_alternative(args[0])) { throw VMException("ByteArray.SetAt first argument must only accept a long"); } uint8_t v = 0; if(std::holds_alternative(args[1])) { v = (uint8_t)(std::get(args[1]) & 0xFF); } size_t index = (size_t)std::get(args[0]); size_t sz = bArray->data.size(); if(index >= 0 && index < sz) { bArray->data[index]=v; return false; } } if(key == "CopyTo") { //CopyTo(destBuff, offsetSrc, offsetDest, length) if(args.size() != 4) { throw VMException("ByteArray.CopyTo must only accept 4 arguments"); } TByteArray* bArray2; int64_t offsetSrc; int64_t offsetDest; int64_t count; if(!GetArgumentHeap(args,0,bArray2)) { throw VMException("ByteArray.CopyTo first argument must be a ByteArray"); } if(!GetArgument(args,1, offsetSrc)) { throw VMException("ByteArray.CopyTo second argument must be a Long (offsetSrc)"); } if(!GetArgument(args,2, offsetDest)) { throw VMException("ByteArray.CopyTo third argument must be a Long (offsetDest)"); } if(!GetArgument(args,3,count)) { throw VMException("ByteArray.CopyTo fourth argument must be a Long (length)"); } size_t offsrc = (size_t)offsetSrc; size_t offdest = (size_t)offsetDest; size_t len = (size_t)count; if(offsrc > bArray->data.size()) { offsrc = bArray->data.size(); } if(offdest > bArray2->data.size()) { offdest = bArray2->data.size(); } len = std::min(std::min(bArray->data.size()-offsrc,bArray2->data.size()-offdest),len); if(len > 0) memcpy(bArray2->data.data()+offdest,bArray->data.data()+offsrc,len); cse.back()->Push(gc,bArray2); return false; } if(key == "Insert") { if(args.size() != 4) { throw VMException("ByteArray.Insert must only accept 4 arguments"); } //Insert(offsetDest, buffer, offsetSrc, length) TByteArray* bArray2; int64_t offsetSrc; int64_t offsetDest; int64_t count; if(!GetArgumentHeap(args,1,bArray2)) { throw VMException("ByteArray.Insert second argument must be a ByteArray"); } if(!GetArgument(args,0, offsetSrc)) { throw VMException("ByteArray.Insert first argument must be a Long (offsetSrc)"); } if(!GetArgument(args,2, offsetDest)) { throw VMException("ByteArray.Insert third argument must be a Long (offsetDest)"); } if(!GetArgument(args,3,count)) { throw VMException("ByteArray.Insert fourth argument must be a Long (length)"); } size_t offsrc = (size_t)offsetSrc; size_t offdest = (size_t)offsetDest; size_t len = (size_t)count; if(offsrc > bArray->data.size()) { offsrc = bArray->data.size(); } if(offdest > bArray->data.size()) { offdest = bArray->data.size(); } len = std::min(len,bArray2->data.size()-offsrc); bArray->data.insert(bArray->data.begin()+offdest,bArray2->data.begin()+offsrc,bArray2->data.begin()+offsrc+len); cse.back()->Push(gc, bArray); return false; } if(key == "Append") { if(args.size() != 3) { throw VMException("ByteArray.Append must only accept 3 arguments"); } TByteArray* bArray2; int64_t offset; int64_t count; if(!GetArgumentHeap(args,0,bArray2)) { throw VMException("ByteArray.Append first argument must be a ByteArray"); } if(!GetArgument(args,1, offset)) { throw VMException("ByteArray.Append second argument must be a Long (offset)"); } if(!GetArgument(args,2,count)) { throw VMException("ByteArray.Append third argument must be a Long (length)"); } size_t off = (size_t)offset; size_t len = (size_t)count; if(off > bArray->data.size()) { off = bArray->data.size(); } len = std::min(bArray->data.size() - off,len); bArray->data.insert(bArray->data.end(),bArray2->data.begin()+off,bArray2->data.begin()+off+len); cse.back()->Push(gc,bArray); return false; } if(key == "Resize") { if(args.size() != 1) { throw VMException("ByteArray.Resize must only accept one argument"); } if(!std::holds_alternative(args[0])) { throw VMException("ByteArray.Resize must only accept a long"); } size_t len = (size_t)std::get(args[0]); if(len >= 0) { bArray->data.resize(len); } cse.back()->Push(gc, bArray); return false; } cse.back()->Push(gc, Undefined()); return false; } else if(list != nullptr) { if(key == "GetEnumerator") { cse.back()->Push(gc, TListEnumerator::Create(ls,list)); return false; } if(key == "Insert") { if(args.size() != 2) { throw VMException("List.Insert must only accept two arguments"); } int64_t index; if(!GetArgument(args,0,index)) { throw VMException("List.Insert first argument must be Long"); } gc->BarrierBegin(); list->Insert(index,args[1]); gc->BarrierEnd(); cse.back()->Push(gc, Undefined()); return false; } if(key == "Add") { if(args.size() != 1) { throw VMException("List.Add must only accept one argument"); } gc->BarrierBegin(); list->Add(args[0]); gc->BarrierEnd(); cse.back()->Push(gc, Undefined()); return false; } if(key == "RemoveAt") { if(args.size() != 1) { throw VMException("List.RemoveAt must only accept one argument"); } if(!std::holds_alternative(args[0])) { throw VMException("List.RemoveAt must only accept a long"); } gc->BarrierBegin(); list->RemoveAt(std::get(args[0])); gc->BarrierEnd(); cse.back()->Push(gc, Undefined()); return false; } if(key == "Clear") { gc->BarrierBegin(); list->Clear(); gc->BarrierEnd(); cse.back()->Push(gc, Undefined()); return false; } if(key == "GetAt") { if(args.size() != 1) { throw VMException("List.GetAt must only accept one argument"); } if(!std::holds_alternative(args[0])) { throw VMException("List.GetAt must only accept a long"); } int64_t index = std::get(args[0]); if(index >= 0 && index < list->Count()) { cse.back()->Push(gc, list->Get(index)); return false; } } if(key == "SetAt") { if(args.size() != 2) { throw VMException("List.SetAt must only accept two arguments"); } if(!std::holds_alternative(args[0])) { throw VMException("List.SetAt first argument must only accept a long"); } int64_t index = std::get(args[0]); if(index >= 0 && index < list->Count()) { list->Set(index,args[1]); return false; } } if(key == "Count" || key == "Length") { gc->BarrierBegin(); cse.back()->Push(gc, list->Count()); gc->BarrierEnd(); return false; } cse.back()->Push(gc, Undefined()); return false; } else if(dict != nullptr) { gc->BarrierBegin(); auto o = dict->GetValue(key); gc->BarrierEnd(); return InvokeMethod(ls,o,dict,args); } else { cse.back()->Push(gc, Undefined()); } } else { cse.back()->Push(gc,Undefined()); } } return false; } bool InterperterThread::ExecuteMethod(GC* gc) { GCList ls(gc); std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); std::vector& code = stk->callable->closure->code; auto cnt = stk->Pop(ls); if(std::holds_alternative(cnt)) { uint32_t n=(uint32_t)std::get(cnt); std::vector args; for(size_t i = 0;iPop(ls)}); } TObject key = stk->Pop(ls); TObject instance = stk->Pop(ls); if(std::holds_alternative(key)) { return ExecuteMethod2(gc,instance,std::get(key),args); } stk->Push(gc, Undefined()); return false; } } return false; } bool InterperterThread::GetField(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); GCList ls(gc); TObject _key = stk->Pop(ls); TObject instance = stk->Pop(ls); if(!std::holds_alternative(_key)) { stk->Push(gc,Undefined()); return false; } std::string key = std::get(_key); if(std::holds_alternative(instance)) { std::string str = std::get(instance); if(key == "Count" || key == "Length") { int64_t len = (int64_t)str.size(); if(len < 0) len = 0; cse.back()->Push(gc, len); return false; } cse.back()->Push(gc, Undefined()); return false; } if(std::holds_alternative(instance)) { auto obj = std::get(instance).obj; auto bA = dynamic_cast(obj); auto list = dynamic_cast(obj); auto dict = dynamic_cast(obj); auto tcallable = dynamic_cast(obj); auto closure = dynamic_cast(obj); auto externalMethod = dynamic_cast(obj); auto ittr = dynamic_cast(obj); auto strm = dynamic_cast(obj); auto vfs = dynamic_cast(obj); if(strm != nullptr) { auto netStrm = dynamic_cast(strm->stream); auto objStrm = dynamic_cast(strm->stream); if(objStrm != nullptr) { GetObjectHeap(objStrm->obj,dict); }else{ if(key == "CanRead") { bool r = strm->stream != nullptr ? strm->stream->CanRead() : false; cse.back()->Push(gc, r); return false; } if(key == "CanWrite") { bool r = strm->stream != nullptr ? strm->stream->CanWrite() : false; cse.back()->Push(gc, r); return false; } if(key == "CanSeek") { bool r = strm->stream != nullptr ? strm->stream->CanSeek() : false; cse.back()->Push(gc, r); return false; } if(key == "EndOfStream") { bool r = strm->stream != nullptr ? strm->stream->EndOfStream() : false; cse.back()->Push(gc, r); return false; } cse.back()->Push(gc, nullptr); return false; } } if(vfs != nullptr) { auto d = dynamic_cast(vfs->vfs); if(d != nullptr) { GetObjectHeap(d->obj,dict); } } if(ittr != nullptr) { if(key == "Current") { cse.back()->Push(gc, ittr->GetCurrent(ls)); return false; } cse.back()->Push(gc, nullptr); return false; } if(closure != nullptr) { if(key == "args") { GCList ls2(gc); TList* ls = TList::Create(ls2); for(auto arg : closure->closure->args) { ls->Add(arg); } cse.back()->Push(gc,ls); return false; } } if(externalMethod != nullptr) { if(key == "args") { GCList ls2(gc); TList* ls = TList::Create(ls2); for(auto arg : externalMethod->args) { ls->Add(arg); } cse.back()->Push(gc,ls); return false; } } if(tcallable != nullptr) { if(key == "documentation") { cse.back()->Push(gc, tcallable->documentation); return false; } cse.back()->Push(gc,Undefined()); return false; } if(bA != nullptr) { if(key == "Count" || key == "Length") { int64_t len = (int64_t)bA->data.size(); if(len < 0) len = 0; stk->Push(gc, len); return false; } } if(list != nullptr) { if(key == "Count" || key == "Length") { int64_t len = list->Count(); if(len < 0) len = 0; stk->Push(gc, len); return false; } } if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("get" + key); gc->BarrierEnd(); if(std::holds_alternative(fn) && dynamic_cast(std::get(fn).obj) != nullptr) { return InvokeOne(ls,fn, dict); } else { gc->BarrierBegin(); fn = dict->GetValue(key); stk->Push(gc, fn); gc->BarrierEnd(); return false; } } } stk->Push(gc, Undefined()); } return false; } bool InterperterThread::SetField(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); GCList ls(gc); TObject value = stk->Pop(ls); TObject _key = stk->Pop(ls); TObject instance = stk->Pop(ls); if(!std::holds_alternative(_key)) { stk->Push(gc,Undefined()); return false; } std::string key = std::get(_key); if(std::holds_alternative(instance)) { auto obj = std::get(instance).obj; auto vfs = dynamic_cast(obj); auto strm = dynamic_cast(obj); auto dict = dynamic_cast(obj); if(strm != nullptr) { auto netStrm = dynamic_cast(strm->stream); auto objStrm = dynamic_cast(strm->stream); if(objStrm != nullptr) { GetObjectHeap(objStrm->obj,dict); } if(netStrm != nullptr && key == "Broadcast") { bool r; if(GetObject(value,r)) netStrm->SetBroadcast(r); cse.back()->Push(gc,nullptr); return false; } } if(vfs != nullptr) { auto d = dynamic_cast(vfs->vfs); if(d != nullptr) { GetObjectHeap(d->obj,dict); } } if(dict != nullptr) { gc->BarrierBegin(); TObject fn = dict->GetValue("set" + key); gc->BarrierEnd(); if(std::holds_alternative(fn) && dynamic_cast(std::get(fn).obj) != nullptr) { return InvokeTwo(ls,fn, dict, value); } else { gc->BarrierBegin(); dict->SetValue(key, value); stk->Push(gc, value); gc->BarrierEnd(); return false; } } } stk->Push(gc, Undefined()); } return false; } void InterperterThread::GetVariable(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); GCList ls(gc); auto key = stk->Pop(ls); if(std::holds_alternative(key)) { gc->BarrierBegin(); stk->Push(gc, stk->env->GetVariable(std::get(key))); gc->BarrierEnd(); } else { throw VMException("[GETVARIABLE] Can't pop string."); } } } void InterperterThread::SetVariable(GC* gc) { std::vector& 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); if(std::holds_alternative(key)) { gc->BarrierBegin(); stk->env->SetVariable(std::get(key),value); stk->Push(gc, value); gc->BarrierEnd(); } else { throw VMException("[SETVARIABLE] Can't pop string."); } } } void InterperterThread::DeclareVariable(GC* gc) { std::vector& 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); if(std::holds_alternative(key)) { gc->BarrierBegin(); stk->env->DeclareVariable(std::get(key),value); stk->Push(gc, value); gc->BarrierEnd(); } else { throw VMException("[DECLAREVARIABLE] Can't pop string."); } } } void InterperterThread::PushResource(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); std::vector& code = stk->callable->closure->code; if(stk->ip + 4 <= code.size()) { uint32_t n=BitConverter::ToUint32BE(code[stk->ip]); if(n >= stk->callable->file->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."); } } } void InterperterThread::PushClosure(GC* gc,bool ownScope) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); std::vector& code = stk->callable->closure->code; if(stk->ip + 4 <= code.size()) { uint32_t n=BitConverter::ToUint32BE(code[stk->ip]); if(n >= stk->callable->file->chunks.size()) throw VMException("Can't read chunk."); stk->ip = stk->ip + 4; gc->BarrierBegin(); GCList ls(gc); TClosure* closure = TClosure::Create(ls,stk->env,stk->callable->file,n,ownScope); stk->Push(gc,closure); gc->BarrierEnd(); } else { throw VMException("Can't read chunk."); } } } void InterperterThread::PushString(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); std::vector& code = stk->callable->closure->code; if(stk->ip + 4 <= code.size()) { uint32_t n=BitConverter::ToUint32BE(code[stk->ip]); if(n < stk->callable->file->strings.size()) stk->Push(gc,stk->callable->file->strings[n]); else throw VMException("Can't read string."); stk->ip = stk->ip + 4; } } } void InterperterThread::PushLong(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); std::vector& code = stk->callable->closure->code; if(stk->ip + 8 <= code.size()) { uint64_t n=BitConverter::ToUint64BE(code[stk->ip]); stk->Push(gc,(int64_t)n); stk->ip = stk->ip + 8; } } } void InterperterThread::PushChar(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); std::vector& code = stk->callable->closure->code; if(stk->ip + 1 <= code.size()) { char c = (char)code[stk->ip]; stk->Push(gc,c); stk->ip = stk->ip + 1; } } } void InterperterThread::PushDouble(GC* gc) { std::vector& cse=this->call_stack_entries; if(!cse.empty()) { auto stk = cse.back(); std::vector& code = stk->callable->closure->code; if(stk->ip + 8 <= code.size()) { double dbl = BitConverter::ToDoubleBE(code[stk->ip]); stk->Push(gc,dbl); stk->ip = stk->ip + 8; } } } void InterperterThread::Execute(GC* gc) { std::vector& cse=this->call_stack_entries; execute: if(!cse.empty()) { auto stk = cse.back(); try{ while(stk->ip < 0xFFFFFFFF && stk->ip < stk->callable->closure->code.size()) { uint32_t ip = stk->ip; stk->ip = ip + 1; switch(stk->callable->closure->code[ip]) { case JMP: { if(stk->ip + 4 <= stk->callable->closure->code.size()) { uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); stk->ip = n; } else throw VMException("Can't read jmp pc."); } break; case JMPC: { 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."); } break; case TRYCATCH: { 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(VMException& ex) { TDictionary* dict = TDictionary::Create(ls); auto gc = ls.GetGC(); gc->BarrierBegin(); dict->SetValue("Type","NativeException"); dict->SetValue("Text",ex.what()); gc->BarrierEnd(); stk->Push(gc, catchC->Call(ls,{dict})); } catch(VMByteCodeException& ex) { stk->Push(gc, catchC->Call(ls,{ex.exception})); } catch(std::exception& ex) { TDictionary* dict = TDictionary::Create(ls); auto gc = ls.GetGC(); gc->BarrierBegin(); dict->SetValue("Type","NativeException"); dict->SetValue("Text",ex.what()); gc->BarrierEnd(); stk->Push(gc, catchC->Call(ls,{dict})); } } } break; case THROW: { GCList ls2(gc); auto _res2 = stk->Pop(ls2); if(!std::holds_alternative(_res2)) { throw VMByteCodeException(gc,_res2); } } break; case JMPUNDEFINED: { if(stk->ip + 4 <= stk->callable->closure->code.size()) { uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); GCList ls2(gc); auto _res2 = stk->Pop(ls2); stk->ip = stk->ip + 4; if(std::holds_alternative(_res2)) stk->ip = n; else stk->Push(gc,_res2); } else throw VMException("Can't read jmpundefined pc."); } break; case ADD: TVM_HANDLER(Add); break; case SUB: TVM_HANDLER(Sub); break; case TIMES: TVM_HANDLER(Times); break; case DIVIDE: TVM_HANDLER(Divide); break; case MODULO: TVM_HANDLER(Mod); break; case LEFTSHIFT: TVM_HANDLER(LShift); break; case RIGHTSHIFT: TVM_HANDLER(RShift); case LESSTHAN: TVM_HANDLER(Lt); break; case LESSTHANEQ: TVM_HANDLER(Lte); break; case GREATERTHAN: TVM_HANDLER(Gt); break; case GREATERTHANEQ: TVM_HANDLER(Gte); break; case NEQ: TVM_HANDLER(NEq); break; case EQ: TVM_HANDLER(Eq); break; case NEGATIVE: TVM_HANDLER(Neg); break; case BITWISEOR: TVM_HANDLER(BOr); break; case BITWISEAND: TVM_HANDLER(BAnd); break; case BITWISENOT: TVM_HANDLER(BNot); break; case NOT: TVM_HANDLER(LNot); break; case XOR: TVM_HANDLER(XOr); break; case CALLFUNCTION: TVM_HANDLER(ExecuteFunction); break; case CALLMETHOD: TVM_HANDLER(ExecuteMethod); break; case GETVARIABLE: GetVariable(gc); break; case SETVARIABLE: SetVariable(gc); break; case GETFIELD: TVM_HANDLER(GetField); break; case SETFIELD: TVM_HANDLER(SetField); break; case DECLAREVARIABLE: DeclareVariable(gc); break; case PUSHRESOURCE: PushResource(gc); break; case PUSHCLOSURE: PushClosure(gc); break; case PUSHSCOPELESSCLOSURE: PushClosure(gc,false); break; case PUSHLONG: PushLong(gc); break; case PUSHDOUBLE: PushDouble(gc); break; case PUSHSTRING: PushString(gc); break; case PUSHCHAR: PushChar(gc); break; case SCOPEBEGIN: { gc->BarrierBegin(); GCList ls(gc); stk->env = stk->env->GetSubEnvironment(ls); stk->scopes++; gc->BarrierEnd(); } break; case SCOPEEND: { gc->BarrierBegin(); GCList ls(gc); std::vector callable; if(!stk->env->defers.empty()) { ls.Add(stk->env); callable.insert(callable.end(), stk->env->defers.begin(),stk->env->defers.end()); } stk->scopes--; stk->env = stk->env->GetParentEnvironment(); gc->BarrierEnd(); for(auto item : callable) { GCList ls2(gc); item->Call(ls2,{}); } } break; case SCOPEENDTIMES: { gc->BarrierBegin(); GCList ls(gc); std::vector callable; std::vector& 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,{}); } } break; case PUSHFALSE: { GCList ls(gc); stk->Push(gc,false); } break; case PUSHTRUE: { GCList ls(gc); stk->Push(gc,true); } break; case PUSHNULL: { GCList ls(gc); stk->Push(gc,nullptr); } break; case PUSHUNDEFINED: { GCList ls(gc); stk->Push(gc,Undefined()); } break; case CREATEDICTIONARY: { GCList ls(gc); TDictionary* dict = TDictionary::Create(ls); stk->Push(gc,dict); } break; case POP: { GCList ls(gc); stk->Pop(ls); } break; case CREATEARRAY: { GCList ls(gc); TList* myList = TList::Create(ls); stk->Push(gc,myList); } break; case APPENDLIST: { GCList ls(gc); gc->BarrierBegin(); auto obj = stk->Pop(ls); auto objhold= stk->Pop(ls); if(std::holds_alternative(objhold)) { auto list= dynamic_cast(std::get(objhold).obj); if(list != nullptr) { list->Add(obj); } /* if(dict != nullptr) { auto potential_str = stk->Pop(ls); if(std::holds_alternative(potential_str)) { dict->SetValue(std::get(potential_str), stk->Pop(ls)); } }*/ } stk->Push(gc, objhold); gc->BarrierEnd(); } break; case APPENDDICT: { GCList ls(gc); gc->BarrierBegin(); auto value = stk->Pop(ls); auto k = stk->Pop(ls); auto objhold= stk->Pop(ls); if(std::holds_alternative(objhold) && std::holds_alternative(k)) { auto dict= dynamic_cast(std::get(objhold).obj); if(dict != nullptr) { dict->SetValue(std::get(k), value); } } stk->Push(gc, objhold); gc->BarrierEnd(); } break; case NOP: //this does nothing break; case RET: stk->ip = (uint32_t)stk->callable->closure->code.size(); break; case DEFER: { gc->BarrierBegin(); GCList ls(gc); auto item = stk->Pop(ls); TCallable* call; if(GetObjectHeap(item,call)) cse.back()->env->defers.insert(cse.back()->env->defers.begin(), {call}); gc->BarrierEnd(); } break; default: { char chr[3]; snprintf(chr,3,"%02X",stk->callable->closure->code[ip]); throw VMException("Illegal instruction: 0x" + std::string(chr) + "."); } } if(gc->UsingNullThreads()) gc->Collect(); } } catch(VMByteCodeException& ex) { { gc->BarrierBegin(); GCList ls(gc); std::vector 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,{}); } } throw ex; } catch(VMException& ex) { { gc->BarrierBegin(); GCList ls(gc); std::vector 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,{}); } } throw ex; } catch(std::exception& ex) { { gc->BarrierBegin(); GCList ls(gc); std::vector 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,{}); } } throw ex; } if(cse.size()==1) { current_function=nullptr; { gc->BarrierBegin(); GCList ls(gc); std::vector 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 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); current_function = 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(GC* gc,TObject o) { gc->BarrierBegin(); this->stack.push_back(o); gc->BarrierEnd(); } 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) { InterperterThread* it = new InterperterThread(); GC* _gc = ls.GetGC(); ls.Add(it); _gc->Watch(it); return it; } InterperterThread* InterperterThread::Create(GCList* ls) { InterperterThread* it = new InterperterThread(); GC* _gc = ls->GetGC(); ls->Add(it); _gc->Watch(it); return it; } CallStackEntry* CallStackEntry::Create(GCList& ls) { CallStackEntry* cse = new CallStackEntry(); GC* _gc = ls.GetGC(); ls.Add(cse); _gc->Watch(cse); return cse; } CallStackEntry* CallStackEntry::Create(GCList* ls) { CallStackEntry* cse = new CallStackEntry(); GC* _gc = ls->GetGC(); ls->Add(cse); _gc->Watch(cse); return cse; } void InterperterThread::AddCallStackEntry(GCList& ls, TClosure* closure, std::vector args) { ls.GetGC()->BarrierBegin(); CallStackEntry* cse = CallStackEntry::Create(ls); cse->callable = closure; cse->env = closure->chunkId == 0 ? closure->env : closure->env->GetSubEnvironment(ls); 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 { for(size_t i = 0; i < std::min(args.size(),closure->closure->args.size()); i++) { cse->env->DeclareVariable(closure->closure->args[i], args[i]); } } current_function = cse; this->call_stack_entries.push_back(cse); ls.GetGC()->BarrierEnd(); } std::string ToString(GC* gc, TObject o) { if(std::holds_alternative(o)) { return std::get(o).ToString(); } if(std::holds_alternative(o)) { return std::get(o); } if(std::holds_alternative(o)) { return std::to_string(std::get(o)); } if(std::holds_alternative(o)) { return std::to_string(std::get(o)); } if(std::holds_alternative(o)) { return std::string{std::get(o)}; } if(std::holds_alternative(o)) { return "null"; } if(std::holds_alternative(o)) { return "undefined"; } if(std::holds_alternative(o)) { return std::get(o) ? "true" : "false"; } if(std::holds_alternative(o)) { auto obj = std::get(o).obj; auto dict = dynamic_cast(obj); if(dict != nullptr) { gc->BarrierBegin(); auto v = dict->GetValue("ToString"); gc->BarrierEnd(); if(std::holds_alternative(v)) { auto callable=dynamic_cast(std::get(v).obj); if(callable != nullptr) { GCList ls(gc); auto res = callable->Call(ls,{}); return ToString(gc,res); } } } } return ""; } }