Add single file runtime binaries

This commit is contained in:
2026-02-25 23:36:42 -06:00
parent 5be9d96b54
commit 572c0ab468
29 changed files with 898 additions and 235 deletions

View File

@@ -0,0 +1,95 @@
#include "CrossLang.hpp"
#include <iostream>
namespace Tesses::CrossLang::Programs {
using namespace Tesses::Framework::Filesystem;
using namespace Tesses::Framework::Streams;
static void Help(std::string& filename)
{
std::cout << "USAGE: " << filename << " [OPTIONS] <dirasroot> <archive.crvm>" << std::endl;
printf("OPTIONS:\n");
printf(" -i: Set info (ex {\"maintainer\": \"Mike Nolan\", \"repo\": \"https://example.com/\", \"homepage\": \"https://example.com/\",\"license\":\"MIT\"})\n");
printf(" -I: Set icon name (relative to dirasroot), should be a 128x128 png\n");
printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n");
printf(" -n: Set name (MyAppOrLibName defaults to out)\n");
printf(" -h, --help: Prints help\n");
printf("Options except for help have flag with arg like this: -F ARG\n");
exit(1);
}
int64_t CrossArchiveCreate(std::vector<std::string>& argv)
{
Tesses::Framework::TF_Init();
std::string name="out";
std::string info="{}";
TVMVersion version;
std::string icon="";
std::vector<std::string> args;
for(int i = 1; i < argv.size(); i++)
{
if(argv[i] == "--help" || argv[i] == "-h")
{
Help(argv[0]);
}
else if(argv[i] == "-i")
{
i++;
if(i < argv.size())
{
info = argv[i];
}
}
else if(argv[i] == "-I")
{
i++;
if(i < argv.size())
{
icon = argv[i];
}
}
else if(argv[i] == "-n")
{
i++;
if(i < argv.size())
{
name = argv[i];
}
}
else if(argv[i] == "-v")
{
i++;
if(i < argv.size())
{
if(!TVMVersion::TryParse(argv[i],version))
{
printf("ERROR: Invalid syntax for version\n");
printf("Expected MAJOR[.MINOR[.PATCH[.BUILD[-dev,-alpha,-beta,-prod]]]]\n");
exit(1);
}
}
}
else {
args.push_back(argv[i]);
}
}
if(args.size() < 2) Help(argv[0]);
auto path = Tesses::Framework::Filesystem::LocalFS->SystemToVFSPath(args[0]);
Tesses::Framework::Filesystem::LocalFS->CreateDirectory(path);
auto sdfs = std::make_shared<SubdirFilesystem>(Tesses::Framework::Filesystem::LocalFS,path);
FILE* f = fopen(args[1].c_str(),"wb");
if(f == NULL)
{
printf("ERROR: could not open %s\n", args[1].c_str());
return 1;
}
auto strm = std::make_shared<FileStream>(f,true,"wb",true);
CrossArchiveCreate(sdfs,strm,name,version,info,icon);
return 0;
}
}

View File

@@ -0,0 +1,34 @@
#include "CrossLang.hpp"
#include <iostream>
namespace Tesses::CrossLang::Programs {
using namespace Tesses::Framework::Filesystem;
using namespace Tesses::Framework::Streams;
int64_t CrossArchiveExtract(std::vector<std::string>& argv)
{
Tesses::Framework::TF_Init();
if(argv.size() < 3)
{
std::cout << "USAGE: " << argv[0] << " <archive.crvm> <dirasroot>" << std::endl;
return 1;
}
auto sdfs= std::make_shared<SubdirFilesystem>(Tesses::Framework::Filesystem::LocalFS,std::string(argv[2]));
auto strm= LocalFS->OpenFile(argv[1], "rb");
if(strm->CanRead())
{
std::cout << "ERROR: could not open " << argv[1] << std::endl;
return 1;
}
auto res = Tesses::CrossLang::CrossArchiveExtract(strm,sdfs);
std::cout << "Crvm Name: " << res.first.first << std::endl;
std::cout << "Crvm Version: " << res.first.second.ToString() << std::endl;
std::cout << "Crvm Info: " << std::endl << res.second << std::endl;
return 0;
}
}

View File

@@ -0,0 +1,255 @@
#include "CrossLang.hpp"
#include <iostream>
namespace Tesses::CrossLang::Programs {
static void Ensure(std::shared_ptr<Tesses::Framework::Streams::Stream> strm,uint8_t* buffer, size_t len)
{
if(strm->ReadBlock(buffer,len) != len)
{
throw VMException("Could not read " + std::to_string(len) + " byte(s).");
}
}
static uint32_t EnsureInt(std::shared_ptr<Tesses::Framework::Streams::Stream> strm)
{
uint8_t buff[4];
Ensure(strm,buff,sizeof(buff));
return BitConverter::ToUint32BE(buff[0]);
}
static std::string EnsureString(std::shared_ptr<Tesses::Framework::Streams::Stream> strm)
{
size_t len = (size_t)EnsureInt(strm);
std::string myStr={};
myStr.resize(len);
Ensure(strm,(uint8_t*)myStr.data(), len);
return myStr;
}
void CrossLangDump(std::shared_ptr<Tesses::Framework::Streams::Stream> strm)
{
uint8_t main_header[18];
Ensure(strm,main_header,sizeof(main_header));
if(strncmp((const char*)main_header,"TCROSSVM",8) != 0) throw VMException("Invalid TCrossVM image.");
TVMVersion version(main_header+8);
if(version.CompareToRuntime() == 1)
{
throw VMException("Runtime is too old.");
}
TVMVersion v2(main_header+13);
std::cout << "Version: " << v2.ToString() << std::endl;
size_t _len = (size_t)EnsureInt(strm);
std::cout << "SectionCount: " << _len << std::endl;
std::vector<std::string> strs;
std::unordered_map<uint32_t, std::vector<std::string>> funs;
std::vector<std::vector<std::string>> closures;
char table_name[4];
bool hasIcon=false;
for(size_t i = 0; i < _len; i++)
{
Ensure(strm,(uint8_t*)table_name,sizeof(table_name));
size_t tableLen = (size_t)EnsureInt(strm);
std::string tableName(table_name,4);
if(tableName == "ICON")
{
hasIcon=true;
}
else if(tableName == "STRS")
{
size_t strsLen = (size_t)EnsureInt(strm);
for(size_t j = 0;j < strsLen;j++)
{
strs.push_back(EnsureString(strm));
}
}
else if(tableName == "DEPS")
{
std::string name = strs.at((size_t)EnsureInt(strm));
uint8_t version_bytes[5];
Ensure(strm,version_bytes,sizeof(version_bytes));
TVMVersion depVersion(version_bytes);
std::cout << "Dependency: " << name << "-" << depVersion.ToString() << std::endl;
}
else if(tableName == "NAME")
{
std::cout << "Name: " << strs.at((size_t)EnsureInt(strm)) << std::endl;
}
else if(tableName == "CLSS")
{
std::cout << "Classes:\n";
uint32_t clss_cnt= EnsureInt(strm);
for(uint32_t j = 0; j < clss_cnt; j++)
{
std::cout << "\t/^" << strs.at(EnsureInt(strm)) << "^/" << std::endl;
uint32_t fnPartsC = EnsureInt(strm);
std::cout << "\tName: ";
for(uint32_t k = 0; k < fnPartsC; k++)
{
if(k > 0) std::cout << ".";
std::cout << strs.at(EnsureInt(strm));
}
std::cout << std::endl;
fnPartsC = EnsureInt(strm);
std::cout << "\tInherits: ";
for(uint32_t k = 0; k < fnPartsC; k++)
{
if(k > 0) std::cout << ".";
std::cout << strs.at(EnsureInt(strm));
}
std::cout << std::endl;
uint32_t ents = EnsureInt(strm);
for(uint8_t k = 0; k < ents; k++)
{
Ensure(strm,main_header,1);
uint8_t flags = main_header[0];
std::cout << "\t\t/^" << strs.at(EnsureInt(strm)) << "^/" << std::endl;
std::string fnname = strs.at(EnsureInt(strm));
std::string fnargs;
uint32_t argParts = EnsureInt(strm);
for(uint32_t l = 0; l < argParts; l++)
{
if(l > 0) fnargs += ", ";
fnargs += strs.at(EnsureInt(strm));
}
uint32_t fnchunk = EnsureInt(strm);
switch(flags & 3)
{
case 0:
std::cout << "\t\tprivate ";
break;
case 1:
std::cout << "\t\tprotected ";
break;
case 2:
std::cout << "\t\tpublic ";
break;
case 3:
std::cout << "\t\tstatic ";
break;
}
switch((flags >> 2) & 3)
{
case 0:
std::cout << "func " << fnname << "(" << fnargs << "), chunk = " << fnchunk << std::endl;
break;
case 1:
std::cout << "field " << fnname << ", chunk = " << fnchunk << std::endl;
break;
case 2:
std::cout << "abstract " << fnname << "(" << fnargs << ")" << std::endl;
break;
case 3:
std::cout << "unset_field " << fnname << std::endl;
break;
}
std::cout << std::endl;
}
}
}
else if(tableName == "CHKS")
{
size_t chunkCount = (size_t)EnsureInt(strm);
for(size_t j = 0; j < chunkCount; j++)
{
std::vector<std::string> args;
size_t argCount = (size_t)EnsureInt(strm);
for(size_t k = 0; k < argCount; k++)
{
args.push_back(strs.at(EnsureInt(strm)));
}
auto len = EnsureInt(strm);
strm->Seek(len,Tesses::Framework::Streams::SeekOrigin::Current);
closures.push_back(args);
}
}
else if(tableName == "FUNS")
{
size_t funLength = (size_t)EnsureInt(strm);
for(size_t j = 0; j < funLength;j++)
{
std::vector<std::string> fnParts;
uint32_t fnPartsC = EnsureInt(strm);
for(uint32_t k = 0; k < fnPartsC; k++)
{
fnParts.push_back(strs.at(EnsureInt(strm)));
}
uint32_t fnNumber = EnsureInt(strm);
funs[fnNumber] = fnParts;
}
}
else if(tableName == "INFO")
{
std::cout << "Info: " << strs.at((size_t)EnsureInt(strm)) << std::endl;
}
else
{
strm->Seek((int64_t)tableLen,Tesses::Framework::Streams::SeekOrigin::Current);
}
}
if(hasIcon)
std::cout << "Has Icon: yes" << std::endl;
else
std::cout << "Has Icon: no" << std::endl;
for(size_t i = 1; i < closures.size(); i++)
{
if(funs.count((uint32_t)i) > 0)
{
std::cout << "Func: ";
auto res = funs[(uint32_t)i];
if(!res.empty()) {
std::cout << "/^" << res[0] << "^/ ";
}
for(size_t i = 1; i < res.size(); i++)
{
if(i > 1) std::cout << ".";
std::cout << res[i];
}
}
else
{
std::cout << "Closure: ";
}
std::cout << "(";
bool first=true;
for(auto arg : closures[i])
{
if(!first) std::cout << ", ";
std::cout << arg;
if(first) first=false;
}
std::cout << ")" << std::endl;
}
std::cout << std::endl;
std::cout << "String Table:" << std::endl;
for(auto str : strs) {
std::cout << EscapeString(str, true) << std::endl;
}
}
}

View File

@@ -0,0 +1,133 @@
#include "CrossLang.hpp"
#include <iostream>
#include <string>
using namespace Tesses::Framework;
using namespace Tesses::Framework::Http;
namespace Tesses::CrossLang::Programs
{
static bool Download(Tesses::Framework::Filesystem::VFSPath filename,std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs)
{
while(true)
{
std::cout << "File " << filename.ToString() << " not found, do you want to download the installer from: https://downloads.tesses.net/ShellPackage.crvm (this may install other stuff as well) (Y/n)? ";
std::string line;
std::getline(std::cin,line);
if(line == "Y" || line == "y")
{
HttpRequest req;
req.url = "https://downloads.tesses.net/ShellPackage.crvm";
req.method = "GET";
HttpResponse resp(req);
if(resp.statusCode == StatusCode::OK)
{
auto strm = resp.ReadAsStream();
CrossLang::CrossArchiveExtract(strm, vfs);
return true;
}
else
{
std::cout << "Error when fetching the script error: " << std::to_string(resp.statusCode) << " " << HttpUtils::StatusCodeString(resp.statusCode) << std::endl;
return false;
}
}
else if(line == "N" || line == "n")
{
std::cout << "Looks like you will need to install manually" << std::endl;
return false;
}
else
{
std::cout << "Please use Y or N (case insensitive)" << std::endl;
}
}
return false;
}
TObject CrossLangShell(GCList& ls, std::vector<std::string>& argv)
{
Tesses::Framework::Filesystem::VFSPath dir = GetCrossLangConfigDir();
Tesses::Framework::Filesystem::VFSPath filename = dir / "Shell" / "Shell.crvm";
auto p = Tesses::Framework::Platform::Environment::GetRealExecutablePath(Tesses::Framework::Filesystem::LocalFS->SystemToVFSPath(argv[0])).GetParent().GetParent() / "share" / "Tesses" / "CrossLang" / "Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm";
if(argv.size() == 2 && argv[1] == "configdir")
{
std::cout << dir.ToString() << std::endl;
return 0;
}
if(argv.size() > 1 && argv[1] == "update-shell")
{
auto subdir = std::make_shared<Tesses::Framework::Filesystem::SubdirFilesystem>(Tesses::Framework::Filesystem::LocalFS,dir);
HttpRequest req;
req.url = "https://downloads.tesses.net/ShellPackage.crvm";
req.method = "GET";
HttpResponse resp(req);
if(resp.statusCode == StatusCode::OK)
{
auto strm = resp.ReadAsStream();
CrossLang::CrossArchiveExtract(strm, subdir);
return 0;
}
else
{
std::cout << "Error when fetching the script error: " << std::to_string(resp.statusCode) << " " << HttpUtils::StatusCodeString(resp.statusCode) << std::endl;
return 1;
}
return 0;
}
if(!Tesses::Framework::Filesystem::LocalFS->RegularFileExists(filename))
{
auto subdir = std::make_shared<Tesses::Framework::Filesystem::SubdirFilesystem>(Tesses::Framework::Filesystem::LocalFS,dir);
if(Tesses::Framework::Filesystem::LocalFS->RegularFileExists(p))
{
std::cout << "Installing " << p.ToString() << " -> " << dir.ToString() << std::endl;
auto strm = Tesses::Framework::Filesystem::LocalFS->OpenFile(p,"rb");
if(strm != nullptr)
{
CrossLang::CrossArchiveExtract(strm, subdir);
}
else
{
return 1;
}
}
else
{
if(!Download(filename,subdir)) return 1;
return 0;
}
}
TRootEnvironment* env = TRootEnvironment::Create(ls, TDictionary::Create(ls));
TStd::RegisterStd(ls.GetGC(),env);
env->LoadFileWithDependencies(ls.GetGC(), Tesses::Framework::Filesystem::LocalFS, filename);
TList* args = TList::Create(ls);
args->Add(filename.ToString());
for(size_t arg=1;arg<argv.size();arg++)
args->Add(std::string(argv[arg]));
return env->CallFunctionWithFatalError(ls,"main",{args});
}
}

View File

@@ -0,0 +1,290 @@
#include "CrossLang.hpp"
#include <iostream>
#include <fstream>
using namespace Tesses::Framework;
using namespace Tesses::Framework::Filesystem;
namespace Tesses::CrossLang::Programs {
static void Help(std::string filename)
{
std::cout << "USAGE: " << filename << " [OPTIONS] source_file1 source_file2 source_file_n" << std::endl;
printf("OPTIONS:\n");
printf(" -o: Output directory (OUTDIR, defaults to ./bin)\n");
printf(" -i: Set info (ex {\"maintainer\": \"Mike Nolan\", \"repo\": \"https://example.com/\", \"homepage\": \"https://example.com/\",\"license\":\"MIT\"})\n");
printf(" -I: Set icon resource name (in the resource folder), should be a 128x128 png\n");
printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n");
printf(" -d: Add dependency (DependencyName-1.0.0.0-prod)\n");
printf(" -D: enable debug)\n");
printf(" -t: Declare a tool (ToolName-1.0.0.0-prod)\n");
printf(" -n: Set name (MyAppOrLibName defaults to out)\n");
printf(" -r: Set resource directory (RESDIR defaults to res)\n");
printf(" -h, --help: Prints help\n");
printf(" -e: Set comptime permissions defaults to none, none for no support, \"secure\" for sane without file access, \"secure_file\" for sane with file access to current directory and sub directories, \"full\" has full runtime.\n");
printf("Options except for help have flag with arg like this: -F ARG\n");
exit(1);
}
void CrossLangCompiler(std::vector<std::string>& argv)
{
/*std::ifstream strm(argv[1],std::ios_base::in|std::ios_base::binary);
std::vector<LexToken> tokens;
Lex(argv[1],strm,tokens);
Parser parser(tokens);
CodeGen gen;
gen.GenRoot(parser.ParseRoot());
std::vector<uint8_t> data;
ByteCodeVectorWriter w(data);
gen.Save(std::filesystem::current_path(),w);
*/
TF_InitWithConsole();
std::filesystem::path outputDir = std::filesystem::current_path() / "bin";
std::vector<std::filesystem::path> source;
std::filesystem::path resourceDir = std::filesystem::current_path() / "res";
std::vector<std::pair<std::string, TVMVersion>> dependencies;
std::vector<std::pair<std::string, TVMVersion>> tools;
std::string name="out";
std::string info="{}";
std::string icon="";
std::string comptime="none";
TVMVersion version;
bool debug=false;
for(size_t i = 1; i < argv.size(); i++)
{
if(argv[i] == "--help" || argv[i] == "-h")
{
Help(argv[0]);
}
else if(argv[i] == "-o")
{
i++;
if(i < argv.size())
{
outputDir = argv[i];
}
}
else if(argv[i] == "-r")
{
i++;
if(i < argv.size())
{
resourceDir = argv[i];
}
}
else if(argv[i] == "-e")
{
i++;
if(i < argv.size())
{
comptime = argv[i];
}
}
else if(argv[i] == "-i")
{
i++;
if(i < argv.size())
{
info = argv[i];
}
}
else if(argv[i] == "-I")
{
i++;
if(i < argv.size())
{
icon = argv[i];
}
}
else if(argv[i] == "-d")
{
i++;
if(i < argv.size())
{
std::string str = argv[i];
auto lastDash = str.find_last_of('-');
if(lastDash < str.size())
{
std::string str2 = str.substr(lastDash+1);
if(str2 == "dev" || str2 == "alpha" || str2 == "beta" || str2 == "prod")
{
lastDash = str.find_last_of('-',lastDash-1);
}
std::string str1 = str.substr(0,lastDash);
str2 = str.substr(lastDash+1);
TVMVersion v2;
if(!TVMVersion::TryParse(str2,v2))
{
printf("ERROR: Invalid syntax for version\n");
printf("Expected MAJOR[.MINOR[.PATCH[.BUILD[-dev,-alpha,-beta,-prod]]]]\n");
exit(1);
}
dependencies.push_back(std::pair<std::string,TVMVersion>(str1,v2));
}
else
{
printf("ERROR: Dependency must have version\n");
exit(1);
}
}
}
else if(argv[i] == "-t")
{
i++;
if(i < argv.size())
{
std::string str = argv[i];
auto lastDash = str.find_last_of('-');
if(lastDash < str.size())
{
std::string str2 = str.substr(lastDash+1);
if(str2 == "dev" || str2 == "alpha" || str2 == "beta" || str2 == "prod")
{
lastDash = str.find_last_of('-',lastDash-1);
}
std::string str1 = str.substr(0,lastDash);
str2 = str.substr(lastDash+1);
TVMVersion v2;
if(!TVMVersion::TryParse(str2,v2))
{
printf("ERROR: Invalid syntax for version\n");
printf("Expected MAJOR[.MINOR[.PATCH[.BUILD[-dev,-alpha,-beta,-prod]]]]\n");
exit(1);
}
tools.push_back(std::pair<std::string,TVMVersion>(str1,v2));
}
else
{
printf("ERROR: Tool must have version\n");
exit(1);
}
}
}
else if(argv[i] == "-n")
{
i++;
if(i < argv.size())
{
name = argv[i];
}
}
else if(argv[i] == "-v")
{
i++;
if(i < argv.size())
{
if(!TVMVersion::TryParse(argv[i],version))
{
printf("ERROR: Invalid syntax for version\n");
printf("Expected MAJOR[.MINOR[.PATCH[.BUILD[-dev,-alpha,-beta,-prod]]]]\n");
exit(1);
}
}
}
else if(argv[i] == "-D" || argv[i] == "--debug")
{
debug = true;
}
else {
source.push_back(argv[i]);
}
}
if(source.empty())
{
Help(argv[0]);
}
std::vector<LexToken> tokens;
for(auto src : source)
{
std::ifstream strm(src,std::ios_base::in|std::ios_base::binary);
int res = Lex(std::filesystem::absolute(src).string(),strm,tokens);
}
GC* gc=nullptr;
GCList* ls=nullptr;
TRootEnvironment* env=nullptr;
if(comptime != "none")
{
gc = new GC();
gc->Start();
ls = new GCList(gc);
env = TRootEnvironment::Create(ls,TDictionary::Create(ls));
if(comptime == "secure")
{
TStd::RegisterConsole(gc,env);
TStd::RegisterClass(gc,env);
TStd::RegisterCrypto(gc,env);
TStd::RegisterDictionary(gc,env);
TStd::RegisterJson(gc,env);
TStd::RegisterRoot(gc,env);
TStd::RegisterIO(gc,env,false);
env->permissions.locked=true;
}
else if(comptime == "secure_file")
{
TStd::RegisterConsole(gc,env);
TStd::RegisterClass(gc,env);
TStd::RegisterCrypto(gc,env);
TStd::RegisterDictionary(gc,env);
TStd::RegisterJson(gc,env);
TStd::RegisterRoot(gc,env);
TStd::RegisterIO(gc,env,false);
env->permissions.locked=true;
auto fs = env->EnsureDictionary(gc,"FS");
fs->SetValue("Local", std::make_shared<SubdirFilesystem>(LocalFS,Tesses::Framework::Filesystem::VFSPath::GetAbsoluteCurrentDirectory()));
}
else if(comptime == "full")
{
TStd::RegisterStd(gc,env);
env->permissions.locked=true;
}
}
Parser parser(tokens,gc,env);
parser.debug = debug;
CodeGen gen;
auto sfs = std::make_shared<SubdirFilesystem>(LocalFS,LocalFS->SystemToVFSPath(resourceDir.string()));
gen.embedFS = sfs;
gen.GenRoot(parser.ParseRoot());
gen.name = name;
gen.version = version;
gen.info = info;
gen.icon = icon;
for(auto deps : dependencies)
{
gen.dependencies.push_back(deps);
}
for(auto tool : tools)
{
gen.tools.push_back(tool);
}
std::filesystem::create_directory(outputDir);
{
auto strm = std::make_shared<Tesses::Framework::Streams::FileStream>(outputDir / (name + "-" + version.ToString() + ".crvm"),"wb");
gen.Save(strm);
}
if(gc != nullptr)
{
delete ls;
delete gc;
}
}
}

View File

@@ -0,0 +1,124 @@
#include "CrossLang.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
using namespace Tesses::Framework;
using namespace Tesses::Framework::Filesystem;
namespace Tesses::CrossLang::Programs {
TObject CrossLangInterperter(GCList& ls,TRootEnvironment* env,std::vector<std::string>& argv)
{
GC* gc = ls.GetGC();
if(argv.size() > 1)
{
std::ifstream strm(argv[1],std::ios_base::in|std::ios_base::binary);
std::vector<LexToken> tokens;
Lex(argv[1],strm,tokens);
Parser parser(tokens);
CodeGen gen;
auto sfs = std::make_shared<SubdirFilesystem>(LocalFS,VFSPath("."));
gen.embedFS = sfs;
gen.GenRoot(parser.ParseRoot());
std::vector<uint8_t> data;
{
auto strm2 = std::make_shared<Tesses::Framework::Streams::MemoryStream>(true);
gen.Save(strm2);
{
TFile* file = TFile::Create(ls);
strm2->Seek(0,Tesses::Framework::Streams::SeekOrigin::Begin);
file->Load(gc,strm2);
env->LoadFile(gc, file);
}
}
TList* args = TList::Create(ls);
for(int arg=1;arg<argv.size();arg++)
args->Add(std::string(argv[arg]));
return env->CallFunctionWithFatalError(ls,"main",{args});
}
else
{
while(true)
{
std::cout << "> ";
std::string source;
std::getline(std::cin,source);
auto strm2 = std::make_shared<Tesses::Framework::Streams::MemoryStream>(true);
if(source.find("loadfile ") == 0)
{
std::string filename = source.substr(9);
std::ifstream strm(filename,std::ios_base::in|std::ios_base::binary);
std::vector<LexToken> tokens;
Lex(filename,strm,tokens);
Parser parser(tokens);
CodeGen gen;
auto sfs = std::make_shared<SubdirFilesystem>(LocalFS,VFSPath("."));
gen.embedFS = sfs;
gen.GenRoot(parser.ParseRoot());
gen.Save(strm2);
}
else if(source == "exit")
{
return (int64_t)0;
}
else
{
std::vector<LexToken> tokens;
std::stringstream strm(source,std::ios_base::in | std::ios_base::binary);
Lex("lexed.tcross",strm,tokens);
Parser parser(tokens);
CodeGen gen;
auto sfs = std::make_shared<SubdirFilesystem>(LocalFS,VFSPath("."));
gen.embedFS = sfs;
gen.GenRoot(parser.ParseRoot());
gen.Save(strm2);
}
{
TFile* file = TFile::Create(ls);
strm2->Seek(0,Tesses::Framework::Streams::SeekOrigin::Begin);
file->Load(gc,strm2);
env->LoadFile(gc, file);
}
}
}
return (int64_t)0;
}
}

View File

@@ -0,0 +1,61 @@
#include "CrossLang.hpp"
using namespace Tesses::Framework;
namespace Tesses::CrossLang::Programs {
TObject CrossLangVM(GCList& ls,TRootEnvironment* env, std::vector<std::string>& argv)
{
if(argv.size() < 2)
{
std::cout << "USAGE: " << (argv.empty() ? (std::string)"crossvm" : argv[0]) << " <filename.crvm> <args...>" << std::endl;
return 1;
}
env->LoadFileWithDependencies(ls.GetGC(), Tesses::Framework::Filesystem::LocalFS, Tesses::Framework::Filesystem::LocalFS->SystemToVFSPath(argv[1]));
if(env->HasVariable("WebAppMain"))
{
Args args(argv);
int port = 4206;
for(auto& item : args.options)
{
if(item.first == "port")
{
port = std::stoi(item.second);
}
}
env->EnsureDictionary(ls.GetGC(),"Net")->SetValue("WebServerPort", (int64_t)port);
TList* args2 = TList::Create(ls);
for(auto& item : args.positional)
{
args2->Add(item);
}
auto res = env->CallFunctionWithFatalError(ls, "WebAppMain", {args2});
auto svr2 = Tesses::CrossLang::ToHttpServer(ls.GetGC(),res);
if(svr2 == nullptr) return 1;
Tesses::Framework::Http::HttpServer svr(port,svr2);
svr.StartAccepting();
TF_RunEventLoop();
TDictionary* _dict;
TClassObject* _co;
if(GetObjectHeap(res,_dict))
{
_dict->CallMethod(ls,"Close",{});
}
if(GetObjectHeap(res,_co))
{
_co->CallMethod(ls,"","Close",{});
}
TF_Quit();
return 0;
}
else {
TList* args = TList::Create(ls);
for(size_t arg=1;arg<argv.size();arg++)
args->Add(std::string(argv[arg]));
return env->CallFunctionWithFatalError(ls,"main",{args});
}
}
}