#include "CrossLang.hpp" #include #include #include namespace Tesses::CrossLang { static TObject AstToTObject(GCList &ls, SyntaxNode node) { if (std::holds_alternative(node)) return nullptr; if (std::holds_alternative(node)) { return std::get(node); } if (std::holds_alternative(node)) { return std::get(node); } if (std::holds_alternative(node)) { return std::get(node); } if (std::holds_alternative(node)) { std::string str = std::get(node); return str; } if (std::holds_alternative(node)) { char c = std::get(node); return c; } if (std::holds_alternative(node)) { auto r = TDictionary::Create(ls); ls.GetGC()->BarrierBegin(); r->SetValue("Type", std::string(UndefinedExpression)); ls.GetGC()->BarrierEnd(); return r; } if (std::holds_alternative(node)) { auto asn = std::get(node); auto r = TDictionary::Create(ls); ls.GetGC()->BarrierBegin(); r->SetValue("Type", asn.nodeName); r->SetValue("IsExpression", asn.isExpression); TList *ls2 = TList::Create(ls); for (auto item : asn.nodes) { ls2->Add(AstToTObject(ls, item)); } r->SetValue("Arguments", ls2); ls.GetGC()->BarrierEnd(); return r; } return nullptr; } static TObject VM_SourceToAst(GCList &ls, std::vector args) { std::string str; if (GetArgument(args, 0, str)) { std::stringstream strm(str); std::vector tokens; int res = Lex("memory.tcross", strm, tokens); if (res != 0) { throw VMException("Lex error at line: " + std::to_string(res)); } Parser p(tokens); auto res2 = p.ParseRoot(); return AstToTObject(ls, res2); } return nullptr; } static TObject VM_Eval(GCList &ls, std::vector args) { std::string str; if (GetArgument(args, 0, str)) { if (current_function != nullptr) { return current_function->env->Eval(ls, str); } } return nullptr; } static TObject Failure(GCList &ls, std::string reason) { TDictionary *dict = TDictionary::Create(ls); ls.GetGC()->BarrierBegin(); dict->SetValue("Success", false); dict->SetValue("Reason", reason); ls.GetGC()->BarrierEnd(); return dict; } static TObject Success(GCList &ls) { TDictionary *dict = TDictionary::Create(ls); ls.GetGC()->BarrierBegin(); dict->SetValue("Success", true); ls.GetGC()->BarrierEnd(); return dict; } static TObject VM_getCurrentEnvironment(GCList &ls2, std::vector args) { if (current_function != nullptr) return current_function->env; return Undefined(); } static TObject VM_Compile(GCList &ls, std::vector args) { try { TDictionary *dict; if (!GetArgumentHeap(args, 0, dict)) return Undefined(); /* VM.Compile { Name = "My name", Info = "", Sources = [], Version = "", Dependencies = [{Name="Name", Version}], ResourceDirectory = "", } */ std::string name = "Out"; std::vector> sources; TVMVersion version(CROSSLANG_BYTECODE_MAJOR, CROSSLANG_BYTECODE_MINOR, CROSSLANG_BYTECODE_PATCH, CROSSLANG_BYTECODE_BUILD, CROSSLANG_BYTECODE_VERSIONSTAGE); std::vector> dependencies; std::vector> tools; std::string info; std::string icon; bool debug = false; std::shared_ptr vfs; ls.GetGC()->BarrierBegin(); TObject _name = dict->GetValue("Name"); TObject _version = dict->GetValue("Version"); TObject _sources = dict->GetValue("Sources"); TObject _dependencies = dict->GetValue("Dependencies"); TObject _tools = dict->GetValue("Tools"); TObject _info = dict->GetValue("Info"); TObject _icon = dict->GetValue("Icon"); TObject _comptime = dict->GetValue("CompTime"); TObject _resourceFileSystem = dict->GetValue("ResourceFileSystem"); TObject _out = dict->GetValue("Output"); TObject _dbg = dict->GetValue("Debug"); TList *_toolList; TList *_depList; TList *srcLst; TRootEnvironment *comptimeEnv = nullptr; GetObject(_name, name); GetObject(_info, info); GetObject(_icon, icon); GetObject(_resourceFileSystem, vfs); GetObjectHeap(_comptime, comptimeEnv); GetObject(_dbg, debug); std::string v2; if (GetObject(_version, v2)) TVMVersion::TryParse(v2, version); else GetObject(_version, version); if (GetObjectHeap(_dependencies, _depList)) { for (int64_t i = 0; i < _depList->Count(); i++) { TObject _dep = _depList->Get(i); TDictionary *_depD; if (GetObjectHeap(_dep, _depD)) { TObject _name2 = _depD->GetValue("Name"); TObject _version2 = _depD->GetValue("Version"); std::string name2; std::string version2; TVMVersion version02; if (GetObject(_name2, name2) && GetObject(_version2, version2) && TVMVersion::TryParse(version2, version02)) { dependencies.push_back( std::pair(name2, version02)); } else if (GetObject(_name2, name2) && GetObject(_version2, version02)) { dependencies.push_back( std::pair(name2, version02)); } } } } if (GetObjectHeap(_tools, _toolList)) { for (int64_t i = 0; i < _toolList->Count(); i++) { TObject _dep = _toolList->Get(i); TDictionary *_depD; if (GetObjectHeap(_dep, _depD)) { TObject _name2 = _depD->GetValue("Name"); TObject _version2 = _depD->GetValue("Version"); std::string name2; std::string version2; TVMVersion version02; if (GetObject(_name2, name2) && GetObject(_version2, version2) && TVMVersion::TryParse(version2, version02)) { tools.push_back(std::pair( name2, version02)); } else if (GetObject(_name2, name2) && GetObject(_version2, version02)) { tools.push_back(std::pair( name2, version02)); } } } } if (GetObjectHeap(_sources, srcLst)) { for (int64_t i = 0; i < srcLst->Count(); i++) { TObject _src = srcLst->Get(i); TDictionary *_srcD; if (GetObjectHeap(_src, _srcD)) { TObject _sourceTxt = _srcD->GetValue("Source"); TObject _filename = _srcD->GetValue("FileName"); std::string srctxt = ""; std::string filename = "memory_" + std::to_string(i) + ".tcross"; bool fromFile = false; GetObject(_sourceTxt, srctxt); GetObject(_filename, filename); sources.push_back( std::pair(srctxt, filename)); } } } ls.GetGC()->BarrierEnd(); std::vector tokens; for (auto source : sources) { std::stringstream strm(source.first); int res = Lex(source.second, strm, tokens); if (res != 0) { return Failure(ls, "Lex error in file \"" + source.second + "\":" + std::to_string(res)); } } Parser parser(tokens, ls.GetGC(), comptimeEnv); parser.debug = debug; SyntaxNode n = parser.ParseRoot(); CodeGen gen; gen.embedFS = vfs; gen.GenRoot(n); gen.dependencies = dependencies; gen.tools = tools; gen.info = info; gen.name = name; gen.version = version; gen.icon = icon; std::string outpath; std::shared_ptr stream; if (GetObject(_out, stream)) { gen.Save(stream); } return Success(ls); } catch (std::exception &ex) { return Failure(ls, ex.what()); } } static TObject VM_GetStacktrace(GCList &ls, std::vector args) { if (current_function != nullptr) { if (current_function->thread != nullptr) { TList *list = TList::Create(ls); ls.GetGC()->BarrierBegin(); for (auto item : current_function->thread->call_stack_entries) { auto dict = TDictionary::Create(ls); if (item->callable->closure->name) dict->SetValue("Name", *item->callable->closure->name); dict->SetValue("Closure", item->callable->closure); dict->SetValue("FileName", item->callable->file->name + "-" + item->callable->file->version.ToString() + ".crvm"); dict->SetValue("IP", (int64_t)item->ip); if (item->srcline >= 1) { dict->SetValue("SourceFile", item->srcfile); dict->SetValue("SourceLine", item->srcline); } list->Add(dict); } ls.GetGC()->BarrierEnd(); return list; } } return nullptr; } void TStd::RegisterVM(std::shared_ptr gc, TRootEnvironment *env) { env->permissions.canRegisterVM = true; GCList ls(gc); TDictionary *dict = TDictionary::Create(ls); dict->DeclareFunction(gc, "GetStacktrace", "Get the current stack trace", {}, VM_GetStacktrace); dict->DeclareFunction( gc, "getRootEnvironmentAsDictionary", "Get root environment as a dictionary", {}, [env](GCList &ls, std::vector args) -> TObject { return env->GetDictionary(); }); dict->DeclareFunction( gc, "getRootEnvironment", "Get root environment, for reflection purposes", {}, [env](GCList &ls2, std::vector args) -> TObject { return env; }); dict->DeclareFunction(gc, "getCurrentEnvironment", "Get current environment, for reflection purposes", {}, VM_getCurrentEnvironment); dict->DeclareFunction( gc, "CreateEnvironment", "Create root environment", {"$dict"}, [env](GCList &ls, std::vector args) -> TObject { TDictionary *dict; if (GetArgumentHeap(args, 0, dict)) { auto renv = TRootEnvironment::Create(ls, dict); renv->permissions.customConsole = env->permissions.customConsole; return renv; } else { auto renv = TRootEnvironment::Create(ls, TDictionary::Create(ls)); renv->permissions.customConsole = env->permissions.customConsole; return renv; } }); dict->DeclareFunction( gc, "LoadExecutable", "Load a crossvm executable", {"stream"}, [](GCList &ls, std::vector args) -> TObject { std::shared_ptr strm; if (GetArgument(args, 0, strm)) { TFile *f = TFile::Create(ls); f->Load(ls.GetGC(), strm); return f; } return nullptr; }); dict->DeclareFunction(gc, "Eval", "Eval source code", {"source"}, VM_Eval); dict->DeclareFunction(gc, "Compile", "Compile Source", {"dict"}, VM_Compile); dict->DeclareFunction(gc, "SourceToAst", "Convert source to ast", {"source"}, VM_SourceToAst); dict->DeclareFunction( gc, "getRuntimeVersion", "Get the runtime version", {}, [](GCList &ls, std::vector args) -> TObject { return TVMVersion(CROSSLANG_MAJOR, CROSSLANG_MINOR, CROSSLANG_PATCH, 0, TVMVersionStage::DevVersion); }); dict->DeclareFunction( gc, "getBytecodeVersion", "Get the bytecode version", {}, [](GCList &ls, std::vector args) -> TObject { return TVMVersion( CROSSLANG_BYTECODE_MAJOR, CROSSLANG_BYTECODE_MINOR, CROSSLANG_BYTECODE_PATCH, CROSSLANG_BYTECODE_BUILD, CROSSLANG_BYTECODE_VERSIONSTAGE); }); dict->DeclareFunction(gc, "getIsRunning", "Is the program still running", {}, [](GCList &ls, std::vector args) -> TObject { return Tesses::Framework::TF_IsRunning(); }); dict->DeclareFunction(gc, "RunEventLoopItteration", "Run Event Loop Itteration", {}, [](GCList &ls, std::vector args) -> TObject { Tesses::Framework::TF_RunEventLoopItteration(); return Undefined(); }); dict->DeclareFunction(gc, "RunEventLoop", "Run Event Loop", {}, [](GCList &ls, std::vector args) -> TObject { Tesses::Framework::TF_RunEventLoop(); return Undefined(); }); gc->BarrierBegin(); env->DeclareVariable("VM", dict); gc->BarrierEnd(); } } // namespace Tesses::CrossLang