/*
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 {
TDictionary *TSubEnvironment::GetDictionary() { return this->dict; }
bool TSubEnvironment::HasVariableOrFieldRecurse(std::string key, bool setting) {
std::string property = (setting ? "set" : "get") + key;
if (this->HasVariable(property)) {
auto res = this->GetVariable(property);
TCallable *callable;
if (GetObjectHeap(res, callable))
return true;
}
if (this->HasVariable(key))
return true;
return this->env->HasVariableOrFieldRecurse(key, setting);
}
TObject TSubEnvironment::GetVariable(GCList &ls, std::string key) {
ls.GetGC()->BarrierBegin();
if (this->HasVariable("get" + key)) {
auto item = this->GetVariable("get" + key);
TCallable *callable;
if (GetObjectHeap(item, callable)) {
ls.GetGC()->BarrierEnd();
return callable->Call(ls, {});
}
}
if (this->HasVariable(key)) {
auto item = this->GetVariable(key);
ls.GetGC()->BarrierEnd();
return item;
}
if (this->env->HasVariableOrFieldRecurse(key)) {
ls.GetGC()->BarrierEnd();
return this->env->GetVariable(ls, key);
}
ls.GetGC()->BarrierEnd();
return Undefined();
}
bool TSubEnvironment::HasConstForSet(std::string key) {
if (this->dict->HasValue(key)) {
return this->HasConstForDeclare(key);
}
if (this->env->HasVariableRecurse(key)) {
return this->env->HasConstForSet(key);
}
return false;
}
TObject TSubEnvironment::SetVariable(GCList &ls, std::string key,
TObject value) {
ls.GetGC()->BarrierBegin();
if (this->HasVariable("set" + key)) {
auto item = this->GetVariable("set" + key);
TCallable *callable;
if (GetObjectHeap(item, callable)) {
ls.GetGC()->BarrierEnd();
return callable->Call(ls, {value});
}
}
if (this->HasVariable(key)) {
this->SetVariable(key, value);
ls.GetGC()->BarrierEnd();
return value;
}
if (this->env->HasVariableOrFieldRecurse(key, true)) {
ls.GetGC()->BarrierEnd();
return this->env->SetVariable(ls, key, value);
} else {
this->env->SetVariable(key, value);
ls.GetGC()->BarrierEnd();
return value;
}
ls.GetGC()->BarrierEnd();
}
TObject TSubEnvironment::GetVariable(std::string key) {
if (this->dict->HasValue(key)) {
return this->dict->GetValue(key);
}
if (this->decls.count(key) > 0 &&
this->decls[key] == TEnvironmentDeclType::TEDT_VAR) {
return Undefined();
}
if (this->env->HasVariableRecurse(key)) {
return this->env->GetVariable(key);
}
return Undefined();
}
void TSubEnvironment::DeclareVariable(std::string key, TObject value) {
if (this->decls.count(key) == 0)
this->decls[key] = TEnvironmentDeclType::TEDT_VAR;
this->dict->SetValue(key, value);
}
void TSubEnvironment::SetVariable(std::string key, TObject value) {
if (this->dict->HasValue(key) || this->decls.count(key) > 0) {
this->dict->SetValue(key, value);
return;
}
if (this->env->HasVariableRecurse(key)) {
this->env->SetVariable(key, value);
} else {
this->dict->SetValue(key, value);
}
}
bool TSubEnvironment::HasVariable(std::string key) {
return this->dict->HasValue(key) || this->decls.count(key) > 0;
}
bool TSubEnvironment::HasVariableRecurse(std::string key) {
if (this->dict->HasValue(key) || this->decls.count(key) > 0)
return true;
return this->env->HasVariableRecurse(key);
}
TSubEnvironment::TSubEnvironment(TEnvironment *env, TDictionary *dict) {
this->env = env;
this->dict = dict;
}
TSubEnvironment *TEnvironment::GetSubEnvironment(TDictionary *dict) {
TSubEnvironment *subEnv = new TSubEnvironment(this, dict);
return subEnv;
}
TObject TEnvironment::CallFunction(GCList &ls, std::string key,
std::vector args) {
ls.GetGC()->BarrierBegin();
auto res = this->GetVariable(key);
ls.GetGC()->BarrierEnd();
TCallable *callable;
if (GetObjectHeap(res, callable)) {
return callable->Call(ls, args);
}
return Undefined();
}
TObject TEnvironment::CallFunctionWithFatalError(GCList &ls, std::string key,
std::vector args) {
ls.GetGC()->BarrierBegin();
auto res = this->GetVariable(key);
ls.GetGC()->BarrierEnd();
TCallable *callable;
if (GetObjectHeap(res, callable)) {
return callable->CallWithFatalError(ls, args);
}
return Undefined();
}
TSubEnvironment *TEnvironment::GetSubEnvironment(GCList *gc) {
auto dict = TDictionary::Create(gc);
TSubEnvironment *sEnv = this->GetSubEnvironment(dict);
std::shared_ptr _gc = gc->GetGC();
gc->Add(sEnv);
_gc->Watch(sEnv);
return sEnv;
}
TSubEnvironment *TEnvironment::GetSubEnvironment(GCList &gc) {
auto dict = TDictionary::Create(gc);
TSubEnvironment *sEnv = this->GetSubEnvironment(dict);
std::shared_ptr _gc = gc.GetGC();
gc.Add(sEnv);
_gc->Watch(sEnv);
return sEnv;
}
TSubEnvironment *TSubEnvironment::Create(GCList *gc, TEnvironment *env,
TDictionary *dict) {
return gc->Create(env, dict);
}
TSubEnvironment *TSubEnvironment::Create(GCList &gc, TEnvironment *env,
TDictionary *dict) {
return gc.Create(env, dict);
}
TEnvironment *TSubEnvironment::GetParentEnvironment() { return this->env; }
TRootEnvironment *TSubEnvironment::GetRootEnvironment() {
return this->env->GetRootEnvironment();
}
void TSubEnvironment::Mark() {
if (this->marked)
return;
this->marked = true;
this->dict->Mark();
this->env->Mark();
for (auto defer : defers)
defer->Mark();
}
void TEnvironment::DeclareFunction(
std::shared_ptr gc, std::string key, std::string documentation,
std::vector argNames,
std::function args)> cb) {
gc->BarrierBegin();
GCList ls(gc);
this->DeclareVariable(
key, TExternalMethod::Create(ls, documentation, argNames, cb));
gc->BarrierEnd();
}
void TEnvironment::DeclareFunction(
std::shared_ptr gc, std::string key, std::string documentation,
std::vector argNames,
std::function args)> cb,
std::function destroy) {
gc->BarrierBegin();
GCList ls(gc);
this->DeclareVariable(
key, TExternalMethod::Create(ls, documentation, argNames, cb, destroy));
gc->BarrierEnd();
}
}; // namespace Tesses::CrossLang