Fix for tessesframework migration

This commit is contained in:
2025-07-03 16:18:29 -05:00
parent 7797b0b387
commit f5e17217dd
23 changed files with 789 additions and 273625 deletions

View File

@@ -1,138 +1,43 @@
#include "CrossLang.hpp"
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
#include "../sago/platform_folders.h"
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
namespace Tesses::CrossLang
{
using namespace Tesses::Framework::Platform::Environment;
#if defined(_WIN32)
static char EnvPathSeperator=';';
#else
static char EnvPathSeperator=':';
#endif
static std::string GetHomeFolder()
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getHomeDir();
#elif defined(__EMSCRIPTEN__)
return "/home/web_user";
#else
return "/CrossLangProfile";
#endif
}
Tesses::Framework::Filesystem::VFSPath GetCrossLangConfigDir()
{
#if defined(CROSSLANG_ENABLE_CONFIG_ENVVAR)
char* conf = std::getenv("CROSSLANG_CONFIG");
if(conf != NULL)
{
return std::string(conf);
}
#endif
Tesses::Framework::Filesystem::VFSPath p;
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
p=sago::getConfigHome();
#else
p = GetHomeFolder() + "/Config";
#endif
return p / "Tesses" / "CrossLang";
}
Tesses::Framework::Filesystem::VFSPath GetRealExecutablePath(Tesses::Framework::Filesystem::VFSPath realPath)
{
using namespace Tesses::Framework::Filesystem;
using namespace Tesses::Framework::Http;
LocalFilesystem lfs;
if(!realPath.relative) return realPath.MakeAbsolute();
if(lfs.FileExists(realPath)) return realPath.MakeAbsolute();
const char* path = std::getenv("PATH");
#if defined(_WIN32)
const char* pathext = std::getenv("PATHEXT");
auto pext = HttpUtils::SplitString(pathext,";");
pext.push_back({});
auto pathParts = HttpUtils::SplitString(path,";");
for(auto item : pathParts)
{
for(auto item2 : pext)
{
auto newPath = (lfs.SystemToVFSPath(item) / realPath) + item2;
if(lfs.FileExists(newPath)) return newPath;
}
}
return realPath;
#else
auto pathParts = HttpUtils::SplitString(path,":");
for(auto item : pathParts)
{
auto newPath = lfs.SystemToVFSPath(item) / realPath;
if(lfs.FileExists(newPath)) return newPath;
}
return realPath.MakeAbsolute();
#endif
return SpecialFolders::GetConfig() / "Tesses" / "CrossLang";
}
static TObject Env_getCrossLangConfig(GCList& ls, std::vector<TObject> args)
{
return GetCrossLangConfigDir();
}
static TObject Env_getPlatform(GCList& ls, std::vector<TObject> args)
{
#if defined(__SWITCH__)
return "Nintendo Switch";
#endif
#if defined(GEKKO)
#if defined(HW_RVL)
return "Nintendo Wii";
#endif
return "Nintendo Gamecube";
#endif
#if defined(WIN32) || defined(_WIN32)
return "Windows";
#endif
#if defined(linux)
return "Linux";
#endif
#ifdef __APPLE__
#include "TargetConditionals.h"
#if TARGET_OS_MAC
return "MacOS";
#endif
#if TARGET_OS_IOS
return "iOS";
#endif
#if TARGET_OS_TV
return "Apple TV";
#endif
#if TARGET_OS_WATCH
return "Apple Watch";
#endif
#if __EMSCRIPTEN__
return "WebAssembly";
#endif
return "Unknown Apple Device";
#endif
return "Unknown";
return Tesses::Framework::Platform::Environment::GetPlatform();
}
static TObject Env_GetAt(GCList& ls, std::vector<TObject> args)
{
std::string key;
if(GetArgument(args,0,key))
{
auto res = std::getenv(key.c_str());
if(res == nullptr) return nullptr;
std::string value = res;
return value;
auto v = GetVariable(key);
if(v) return v.value();
}
return nullptr;
}
@@ -143,108 +48,62 @@ namespace Tesses::CrossLang
if(GetArgument(args,0,key))
{
if(GetArgument(args,1,value))
#if defined(_WIN32)
SetEnvironmentVariable(key.c_str(),value.c_str());
#else
setenv(key.c_str(), value.c_str(),1);
#endif
else
#if defined(_WIN32)
{
SetVariable(key,value);
return value;
}
else
{
SetVariable(key,std::nullopt);
}
#else
unsetenv(key.c_str());
#endif
return value;
}
return nullptr;
}
static TObject Env_getDownloads(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getDownloadFolder();
#else
return GetHomeFolder() + "/Downloads";
#endif
return SpecialFolders::GetDownloads();
}
static TObject Env_getMusic(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getMusicFolder();
#else
return GetHomeFolder() + "/Music";
#endif
return SpecialFolders::GetMusic();
}
static TObject Env_getPictures(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getPicturesFolder();
#else
return GetHomeFolder() + "/Pictures";
#endif
return SpecialFolders::GetPictures();
}
static TObject Env_getVideos(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getVideoFolder();
#else
return GetHomeFolder() + "/Videos";
#endif
return SpecialFolders::GetVideos();
}
static TObject Env_getDocuments(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getDocumentsFolder();
#else
return GetHomeFolder() + "/Documents";
#endif
return SpecialFolders::GetDocuments();
}
static TObject Env_getConfig(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getConfigHome();
#else
return GetHomeFolder() + "/Config";
#endif
return SpecialFolders::GetConfig();
}
static TObject Env_getDesktop(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getDesktopFolder();
#else
return GetHomeFolder() + "/Desktop";
#endif
return SpecialFolders::GetDesktop();
}
static TObject Env_getState(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getStateDir();
#else
return GetHomeFolder() + "/State";
#endif
return SpecialFolders::GetState();
}
static TObject Env_getCache(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getCacheDir();
#else
return GetHomeFolder() + "/Cache";
#endif
return SpecialFolders::GetCache();
}
static TObject Env_getData(GCList& ls, std::vector<TObject> args)
{
#if defined(CROSSLANG_ENABLE_PLATFORM_FOLDERS)
return sago::getDataHome();
#else
return GetHomeFolder() + "/Data";
#endif
return SpecialFolders::GetData();
}
static TObject Env_getUser(GCList& ls, std::vector<TObject> args)
{
return GetHomeFolder();
return SpecialFolders::GetHomeFolder();
}
static TObject Env_GetRealExecutablePath(GCList& ls, std::vector<TObject> args)
{

View File

@@ -230,10 +230,17 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc,"getNeedToParseFormData","Check if Need to parse form data",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
return ctx->NeedToParseFormData();
});
dict->DeclareFunction(gc,"ReadString","Read string from request",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
return ctx->ReadString();
});
dict->DeclareFunction(gc,"ReadStream","Read request to stream",{},[ctx](Tesses::CrossLang::GCList& ls2, std::vector<TObject> args)->TObject {
Tesses::CrossLang::TStreamHeapObject* strm;
if(GetArgumentHeap(args,0,strm))
{
ctx->ReadStream(strm->stream);
}
return nullptr;
});
dict->DeclareFunction(gc, "ReadJson","Read json from request",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
return Json_Decode(ls2,ctx->ReadString());
});
@@ -615,6 +622,7 @@ namespace Tesses::CrossLang
_obj = dict->GetValue("Key");
GetObject(_obj,key);
_obj = dict->GetValue("Value");
GetObject(_obj,value);
req.requestHeaders.AddValue(key,value);
}
@@ -863,7 +871,7 @@ namespace Tesses::CrossLang
_obj = dict->GetValue("Key");
GetObject(_obj,key);
_obj = dict->GetValue("Value");
GetObject(_obj,value);
hdict.AddValue(key,value);
}
}

View File

@@ -17,7 +17,8 @@ namespace Tesses::CrossLang
//Process.Start({
// FileName = "git",
// Arguments = ["clone","https://gitea.site.tesses.net/tesses50/crosslang.git"],
// Environment = []
// Environment = [],
// InheritParentEnvironment=true
//})
TDictionary* dict;

View File

@@ -12,6 +12,9 @@
#include <TessesFramework/SDL2/Views/LabelView.hpp>
#include <TessesFramework/SDL2/Views/ProgressView.hpp>
#include <TessesFramework/SDL2/Views/TextListView.hpp>
#include <TessesFramework/SDL2/Views/ScrollableTextListView.hpp>
#include <TessesFramework/SDL2/Views/DropDownView.hpp>
#include <TessesFramework/SDL2/Views/EditTextView.hpp>
using namespace Tesses::Framework::SDL2;
#endif
@@ -756,6 +759,7 @@ namespace Tesses::CrossLang
{
this->view = view;
}
static TObject FindViewById(GCList& ls,View* v, std::string id);
TObject FindViewById(GCList& ls,std::string id);
@@ -816,19 +820,52 @@ namespace Tesses::CrossLang
}
};
class GUI_EditTextView : public GUI_View {
public:
GUI_EditTextView(Views::EditTextView* view) : GUI_View(view)
{
}
GUI_EditTextView(std::string hint) : GUI_View(new Views::EditTextView(hint))
{
class GUI_Window : public GUI_ContainerView {
}
std::string TypeName()
{
return "GUI.EditTextView";
}
virtual TObject CallMethod(GCList& ls, std::string key, std::vector<TObject> args)
{
auto edit = dynamic_cast<Views::EditTextView*>(this->view);
if(edit == nullptr) return GUI_View::CallMethod(ls,key,args);
if(key == "getHint")
{
return edit->GetHint();
}
if(key == "setHint")
{
std::string str;
if(GetArgument(args,0,str))
{
edit->SetHint(str);
return str;
}
}
return GUI_View::CallMethod(ls,key,args);
}
};
class GUI_Window : public TNativeObject {
Tesses::Framework::SDL2::GUIPalette Default()
{
return Tesses::Framework::SDL2::GUIPalette(true,{.r=192,.g=255,.b=0,.a=255});
}
public:
GUIWindow* window;
//"title","width","height","flags","$pallete"
GUI_Window(std::string title, int width, int height, Uint32 flags, Tesses::Framework::SDL2::GUIPalette* palette)
{
this->view = new Tesses::Framework::SDL2::GUIWindow(title,width,height,flags,palette != nullptr ? *palette : Default());
this->window = new Tesses::Framework::SDL2::GUIWindow(title,width,height,flags,palette != nullptr ? *palette : Default());
}
std::string TypeName()
@@ -838,19 +875,46 @@ namespace Tesses::CrossLang
TObject CallMethod(GCList& ls, std::string key, std::vector<TObject> args)
{
auto win = dynamic_cast<GUIWindow*>(this->view);
if(win != nullptr)
if(window)
{
if(key == "setView")
{
GUI_View* v;
if(GetArgumentHeap(args,0,v))
{
win->SetView(v->view,true);
window->SetView(v->view,true);
}
}
if(key == "FindViewById")
{
std::string id;
if(GetArgument(args,0,id))
{
if(id == window->GetId()) return this;
else {
auto v=window->GetViewAt(0);
if(v != nullptr)
return GUI_View::FindViewById(ls,v,id);
}
}
return nullptr;
}
if(key == "getText")
{
return this->window->GetText();
}
if(key == "setText")
{
std::string str;
if(GetArgument(args,0,str))
{
this->window->SetText(str);
return str;
}
}
}
return GUI_ContainerView::CallMethod(ls,key,args);
return Undefined();
}
};
@@ -1012,12 +1076,21 @@ namespace Tesses::CrossLang
};
TObject GUI_View::FindViewById(GCList& ls,std::string id)
{
auto view = this->view->FindViewById(id);
return FindViewById(ls,view,id);
}
TObject GUI_View::FindViewById(GCList& ls,View* curView,std::string id)
{
auto view = curView->FindViewById(id);
auto buttonView = dynamic_cast<Views::ButtonView*>(view);
auto editTextView = dynamic_cast<Views::EditTextView*>(view);
if(buttonView != nullptr)
{
return TNativeObject::Create<GUI_ButtonView>(ls,buttonView);
}
if(editTextView != nullptr)
{
return TNativeObject::Create<GUI_EditTextView>(ls,editTextView);
}
return nullptr;
}
static TObject SDL2_getEvents(GCList& ls, std::vector<TObject> args)
@@ -1039,7 +1112,7 @@ namespace Tesses::CrossLang
std::string jsonText = ToString(ls.GetGC(),args[0]);
GUI_Window* window = TNativeObject::Create<GUI_Window>(ls,std::string("Unnamed Window"),320,240,flags,nullptr);
dynamic_cast<GUIWindow*>(window->view)->SetView(Tesses::Framework::Serialization::Json::Json::Decode(jsonText));
window->window->SetView(Tesses::Framework::Serialization::Json::Json::Decode(jsonText));
return window;
}
return nullptr;

View File

@@ -1,32 +1,84 @@
#include "CrossLang.hpp"
#if defined(CROSSLANG_ENABLE_SQLITE)
#include "../sqlite/sqlite3.h"
#endif
#include <TessesFramework/TessesFrameworkFeatures.h>
#include <iostream>
namespace Tesses::CrossLang {
#if defined(CROSSLANG_ENABLE_SQLITE)
static int sqlcollector(void* user, int count,char** vals, char** keys)
{
std::pair<GCList*,TList*>* ls2 = static_cast<std::pair<GCList*,TList*>*>(user);
TDictionary* dict = TDictionary::Create(ls2->first);
for(int i = 0; i < count; i++)
{
std::string key = keys[i] == nullptr ? "" : keys[i];
if(vals[i] == nullptr)
#if defined(TESSESFRAMEWORK_ENABLE_SQLITE)
using namespace Tesses::Framework::Serialization;
class SQLiteObject : public TNativeObject
{
public:
SQLiteDatabase* db;
SQLiteObject(Tesses::Framework::Filesystem::VFSPath path)
{
dict->SetValue(key,nullptr);
db=new SQLiteDatabase(path);
}
else
{
dict->SetValue(key,vals[i]);
}
}
ls2->second->Add(dict);
return 0;
}
std::string TypeName()
{
return "SQLiteDatabase";
}
void Close()
{
if(this->db == nullptr) return;
delete this->db;
this->db = nullptr;
}
bool ToBool()
{
return this->db != nullptr;
}
TObject CallMethod(GCList& ls,std::string name, std::vector<TObject> args)
{
if(name == "Close") this->Close();
if(name == "Escape") {
std::string str;
if(GetArgument(args,0,str))
{
return SQLiteDatabase::Escape(str); //here for completeness
}
}
if(name == "Exec")
{
std::string arg;
if(GetArgument(args,0,arg))
{
if(this->db == nullptr) return nullptr;
std::vector<std::vector<std::pair<std::string, std::optional<std::string>>>> res;
this->db->Exec(arg,res);
TList* list = TList::Create(ls);
for(auto& item : res)
{
TDictionary* dict = TDictionary::Create(ls);
for(auto& item2 : item)
{
if(item2.second)
dict->SetValue(item2.first,item2.second.value());
else
dict->SetValue(item2.first,nullptr);
}
list->Add(dict);
}
return list;
}
}
return Undefined();
}
~SQLiteObject()
{
if(this->db != nullptr)
delete this->db;
}
};
TObject Sqlite_Open(GCList& ls, std::vector<TObject> args,TRootEnvironment* env)
{
Tesses::Framework::Filesystem::VFSPath p;
@@ -36,20 +88,8 @@ namespace Tesses::CrossLang {
{
p = env->permissions.sqliteOffsetPath / p.CollapseRelativeParents();
}
std::string name = p.ToString();
sqlite3* sqlite;
int rc =sqlite3_open(name.c_str(),&sqlite);
if(rc)
{
std::string error = sqlite3_errmsg(sqlite);
sqlite3_close(sqlite);
return error;
}
return TNative::Create(ls,sqlite,[](void* a)->void {
if(a != nullptr)
sqlite3_close((sqlite3*)a);
});
return TNativeObject::Create<SQLiteObject>(ls,p);
}
return Undefined();
@@ -57,26 +97,11 @@ namespace Tesses::CrossLang {
}
TObject Sqlite_Exec(GCList& ls, std::vector<TObject> args)
{
if(args.size() == 2 && std::holds_alternative<THeapObjectHolder>(args[0]) && std::holds_alternative<std::string>(args[1]))
SQLiteObject* sql;
std::string cmd;
if(GetArgumentHeap(args,0,sql) && GetArgument(args,1,cmd))
{
TNative* native = dynamic_cast<TNative*>(std::get<THeapObjectHolder>(args[0]).obj);
std::string sqlStatement = std::get<std::string>(args[1]);
if(native != nullptr && !native->GetDestroyed())
{
sqlite3* sql = (sqlite3*)native->GetPointer();
TList* myLs = TList::Create(ls);
std::pair<GCList*,TList*> result(&ls, myLs);
char* err;
int res = sqlite3_exec(sql,sqlStatement.c_str(),sqlcollector,&result,&err);
if(res != SQLITE_OK)
{
std::string errstr = err == nullptr ? "" : err;
sqlite3_free(err);
return errstr;
}
return myLs;
}
return sql->CallMethod(ls,"Exec",{cmd});
}
return Undefined();
@@ -85,32 +110,21 @@ namespace Tesses::CrossLang {
TObject Sqlite_Escape(GCList& ls, std::vector<TObject> args)
{
if(args.size() == 1 && std::holds_alternative<std::string>(args[0]))
std::string str;
if(GetArgument(args,0,str))
{
std::string srcStr = std::get<std::string>(args[0]);
std::string myStr = "\'";
for(auto c : srcStr)
{
if(c == '\'') myStr += "\'\'";
else
myStr += c;
}
myStr += '\'';
return myStr;
return SQLiteDatabase::Escape(str);
}
return Undefined();
}
TObject Sqlite_Close(GCList& ls, std::vector<TObject> args)
{
if(args.size() == 1 && std::holds_alternative<THeapObjectHolder>(args[0]))
SQLiteObject* sql;
if(GetArgumentHeap(args,0,sql))
{
TNative* native = dynamic_cast<TNative*>(std::get<THeapObjectHolder>(args[0]).obj);
if(native != nullptr && !native->GetDestroyed())
{
native->Destroy();
}
sql->Close();
}
return Undefined();
}
@@ -120,7 +134,7 @@ namespace Tesses::CrossLang {
{
env->permissions.canRegisterSqlite=true;
#if defined(CROSSLANG_ENABLE_SQLITE)
#if defined(TESSESFRAMEWORK_ENABLE_SQLITE)
GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc,"Open","Opens the database (returns database handle or an error message as string or undefined)",{"filename"},[env](GCList& ls, std::vector<TObject> args)->TObject {

View File

@@ -857,11 +857,13 @@ namespace Tesses::CrossLang
}
void TStd::RegisterRoot(GC* gc, TRootEnvironment* env)
{
GCList ls(gc);
GCList ls(gc);
gc->BarrierBegin();
env->permissions.canRegisterRoot=true;
TDictionary* date = TDictionary::Create(ls);
auto date =env->EnsureDictionary(gc,"DateTime");
date->DeclareFunction(gc, "Sleep","Sleep for a specified amount of milliseconds (multiply seconds by 1000 to get milliseconds)", {"ms"},DateTime_Sleep);
date->DeclareFunction(gc, "getNow", "Get the current time",{},DateTime_getNow);
date->DeclareFunction(gc, "getNowUTC","Get the current time in UTC",{},DateTime_getNowUTC);
@@ -869,16 +871,29 @@ namespace Tesses::CrossLang
date->DeclareFunction(gc, "TryParseHttpDate","Parse the http date",{},DateTime_TryParseHttpDate);
gc->BarrierBegin();
date->SetValue("Zone", (int64_t)Tesses::Framework::Date::GetTimeZone());
date->SetValue("SupportsDaylightSavings",Tesses::Framework::Date::TimeZoneSupportDST());
env->DeclareVariable("DateTime", date);
auto task = env->EnsureDictionary(gc,"Task");
task->DeclareFunction(gc,"AsyncClosure","Create async closure (internal for compiler to generate calls to)",{"closure"},[](GCList& ls, std::vector<TObject> args)->TObject {
TClosure* closure;
if(GetArgumentHeap(args,0,closure))
return TTask::FromClosure(ls,closure);
return nullptr;
});
task->DeclareFunction(gc,"Run","Run code async",{"callable"},[](GCList& ls, std::vector<TObject> args)->TObject {
TCallable* closure;
if(GetArgumentHeap(args,0,closure))
return TTask::Run(ls,closure);
return nullptr;
});
gc->BarrierEnd();
TDictionary* newTypes = env->EnsureDictionary(gc, "New");
newTypes->DeclareFunction(gc, "DateTime","Create a DateTime object, if only one arg is provided year is epoch, isLocal defaults to true unless epoch",{"year","$month","$day","$hour","$minute","$second","$isLocal"},New_DateTime);
newTypes->DeclareFunction(gc, "MountableFilesystem","Create a mountable filesystem",{"root"}, New_MountableFilesystem);
@@ -1018,7 +1033,7 @@ namespace Tesses::CrossLang
return TAssociativeArray::Create(ls);
});
newTypes->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray);
gc->BarrierBegin();
env->DeclareVariable("Version", TDictionary::Create(ls,{
TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector<TObject> args)->TObject{
std::string str;
@@ -1056,6 +1071,8 @@ namespace Tesses::CrossLang
}))
}));
env->DeclareVariable("InvokeMethod",MethodInvoker());
gc->BarrierEnd();
}

View File

@@ -242,15 +242,18 @@ namespace Tesses::CrossLang
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");
TList* _toolList;
TList* _depList; TList* srcLst;
TRootEnvironment* comptimeEnv=nullptr;
GetObject<std::string>(_name,name);
GetObject<std::string>(_info,info);
GetObject<std::string>(_icon,icon);
GetObjectHeap(_resourceFileSystem, vfsHO);
GetObjectHeap(_comptime,comptimeEnv);
std::string v2;
if(GetObject<std::string>(_version,v2))
TVMVersion::TryParse(v2, version);
@@ -348,7 +351,7 @@ namespace Tesses::CrossLang
return Failure(ls, "Lex error in file \"" + source.second + "\":" + std::to_string(res));
}
}
Parser parser(tokens);
Parser parser(tokens,ls.GetGC(),comptimeEnv);
SyntaxNode n = parser.ParseRoot();
CodeGen gen;
gen.GenRoot(n);