/*
CrossLang is a dynamically-typed scripting language built on
TessesFramework, named in honor of Jesus's sacrifice.
Copyright (C) 2026 Mike Nolan
SPDX-License-Identifier: GPL-3.0-or-later WITH TessesFramework-Exception-1.0
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "CrossLang.hpp"
namespace Tesses::CrossLang {
static TList *VectorOfStringToList(GCList &ls, std::vector &strs) {
TList *list = TList::Create(ls);
ls.GetGC()->BarrierBegin();
for (auto &item : strs)
list->Add(item);
ls.GetGC()->BarrierEnd();
return list;
}
static TList *EntriesToList(GCList &ls, std::vector &ents) {
TList *list = TList::Create(ls);
ls.GetGC()->BarrierBegin();
for (auto &item : ents) {
std::string modifier = "public";
switch (item.modifier) {
case TClassModifier::Public:
modifier = "public";
break;
case TClassModifier::Private:
modifier = "private";
break;
case TClassModifier::Protected:
modifier = "protected";
break;
case TClassModifier::Static:
modifier = "static";
break;
}
list->Add(TDictionary::Create(
ls,
{TDItem("Name", item.name), TDItem("IsAbstract", item.isAbstract),
TDItem("IsFunction", item.isFunction),
TDItem("Documentation", item.documentation),
TDItem("ChunkId", (int64_t)item.chunkId),
TDItem("Arguments", VectorOfStringToList(ls, item.args)),
TDItem("Modifier", modifier)}));
}
ls.GetGC()->BarrierEnd();
return list;
}
static TList *ClassInstanceToList(GCList &ls, TClassObject *co) {
TList *list = TList::Create(ls);
ls.GetGC()->BarrierBegin();
for (auto &item : co->entries) {
if (item.modifier == TClassModifier::Public) {
list->Add(TDictionary::Create(
ls,
{TDItem("Name", item.name), TDItem("IsFunction", !item.canSet),
TDItem("Owner", item.owner), TDItem("Value", item.value)}));
}
}
ls.GetGC()->BarrierEnd();
return list;
}
TObject GetClassInfo(GCList &ls, TFile *f, uint32_t index) {
return TDictionary::Create(
ls, {TDItem("Name", JoinPeriod(f->classes.at(index).name)),
TDItem("NameParts",
VectorOfStringToList(ls, f->classes.at(index).name)),
TDItem("Inherits", JoinPeriod(f->classes.at(index).inherits)),
TDItem("InheritsParts",
VectorOfStringToList(ls, f->classes.at(index).inherits)),
TDItem("Documentation", f->classes.at(index).documentation),
TDItem("Entries", EntriesToList(ls, f->classes.at(index).entry))});
}
static TObject Class_CreateInstance(TRootEnvironment *env, GCList &ls,
std::vector args) {
TList *args_ls;
if (!GetArgumentHeap(args, 1, args_ls))
return nullptr;
TList *list;
TClassObject *obj;
std::string str;
if (GetArgumentHeap(args, 0, list)) {
std::vector clsName;
for (int64_t i = 0; i < list->Count(); i++) {
auto o = list->Get(i);
if (GetObject(o, str))
clsName.push_back(str);
}
for (auto &item : env->classes) {
auto &f = item.first->classes.at(item.second);
if (f.name.size() != clsName.size())
continue;
bool found = true;
for (size_t i = 0; i < f.name.size(); i++)
if (f.name[i] != clsName[i]) {
found = false;
break;
}
if (found) {
return TClassObject::Create(ls, item.first, item.second, env,
args_ls->items);
} else
continue;
}
} else if (GetArgument(args, 0, str)) {
std::vector clsName =
Tesses::Framework::Http::HttpUtils::SplitString(str, ".");
for (auto &item : env->classes) {
auto &f = item.first->classes.at(item.second);
if (f.name.size() != clsName.size())
continue;
bool found = true;
for (size_t i = 0; i < f.name.size(); i++)
if (f.name[i] != clsName[i]) {
found = false;
break;
}
if (found) {
return TClassObject::Create(ls, item.first, item.second, env,
args_ls->items);
} else
continue;
}
}
return nullptr;
}
static TObject Class_GetClassNames(TRootEnvironment *env, GCList &ls,
std::vector args) {
TList *list = TList::Create(ls);
ls.GetGC()->BarrierBegin();
for (auto &item : env->classes) {
list->Add(JoinPeriod(item.first->classes.at(item.second).name));
}
ls.GetGC()->BarrierEnd();
return list;
}
static TObject Class_GetInfo(TRootEnvironment *env, GCList &ls,
std::vector args) {
TList *list;
TClassObject *obj;
std::string str;
if (GetArgumentHeap(args, 0, list)) {
std::vector clsName;
for (int64_t i = 0; i < list->Count(); i++) {
auto o = list->Get(i);
if (GetObject(o, str))
clsName.push_back(str);
}
for (auto &item : env->classes) {
auto &f = item.first->classes.at(item.second);
if (f.name.size() != clsName.size())
continue;
bool found = true;
for (size_t i = 0; i < f.name.size(); i++)
if (f.name[i] != clsName[i]) {
found = false;
break;
}
if (found) {
return GetClassInfo(ls, item.first, item.second);
} else
continue;
}
} else if (GetArgument(args, 0, str)) {
std::vector clsName =
Tesses::Framework::Http::HttpUtils::SplitString(str, ".");
for (auto &item : env->classes) {
auto &f = item.first->classes.at(item.second);
if (f.name.size() != clsName.size())
continue;
bool found = true;
for (size_t i = 0; i < f.name.size(); i++)
if (f.name[i] != clsName[i]) {
found = false;
break;
}
if (found) {
return GetClassInfo(ls, item.first, item.second);
} else
continue;
}
} else if (GetArgumentHeap(args, 0, obj)) {
return GetClassInfo(ls, obj->file, obj->classIndex);
}
return nullptr;
}
void TStd::RegisterZeClass(std::shared_ptr gc, TRootEnvironment *env) {
GCList ls(gc);
env->permissions.canRegisterZeClass = true;
TDictionary *cls = env->EnsureDictionary(gc, "Class");
gc->BarrierBegin();
TExternalMethod *ext = TExternalMethod::Create(
ls, "Get the class info", {"classInstanceOrClassName"},
[env](GCList &ls, std::vector args) -> TObject {
return Class_GetInfo(env, ls, args);
});
ext->watch.push_back(env);
cls->SetValue("GetInfo", ext);
ext = TExternalMethod::Create(
ls, "Get the class names", {},
[env](GCList &ls, std::vector args) -> TObject {
return Class_GetClassNames(env, ls, args);
});
ext->watch.push_back(env);
cls->SetValue("GetClassNames", ext);
ext = TExternalMethod::Create(
ls, "Create an instance of class", {"name", "args"},
[env](GCList &ls, std::vector args) -> TObject {
return Class_CreateInstance(env, ls, args);
});
ext->watch.push_back(env);
cls->SetValue("CreateInstance", ext);
cls->DeclareFunction(gc, "Name", "Get class name via instance",
{"instance"},
[](GCList &ls, std::vector args) -> TObject {
TClassObject *cls;
if (GetArgumentHeap(args, 0, cls)) {
return cls->name;
}
return "";
});
cls->DeclareFunction(
gc, "GetInstanceInfo",
"Get the instance specific info, including current values", {},
[](GCList &ls, std::vector args) -> TObject {
TClassObject *co;
if (GetArgumentHeap(args, 0, co)) {
ls.GetGC()->BarrierBegin();
auto res = TDictionary::Create(
ls, {TDItem("Name", co->name), TDItem("File", co->file),
TDItem("ClassIndex", (int64_t)co->classIndex),
TDItem("InheritList",
VectorOfStringToList(ls, co->inherit_tree)),
TDItem("Entries", ClassInstanceToList(ls, co))});
ls.GetGC()->BarrierEnd();
return res;
}
return nullptr;
});
gc->BarrierEnd();
}
} // namespace Tesses::CrossLang