crosslang/include/CrossLang.hpp

1376 lines
47 KiB
C++

#pragma once
#include <cstddef>
#include <vector>
#include <cstdint>
#include <string>
#include <cstdint>
#include <string>
#include <functional>
#include <variant>
#include <cstdio>
#include <atomic>
#include <filesystem>
#include <memory>
#include <cstring>
#include <TessesFramework/TessesFramework.hpp>
#define TVM_MAJOR 1
#define TVM_MINOR 0
#define TVM_PATCH 0
#define TVM_BUILD 0
#define TVM_VERSIONSTAGE DevVersion
namespace Tesses::CrossLang {
std::string EscapeString(std::string text,bool quote);
enum TVMVersionStage : uint8_t
{
DevVersion=0,
AlphaVersion=1,
BetaVersion=2,
ProductionVersion=3
};
class TVMVersion
{
uint8_t major;
uint8_t minor;
uint8_t patch;
uint16_t build;
public:
uint8_t Major()
{
return major;
}
uint8_t Minor()
{
return minor;
}
uint8_t Patch()
{
return patch;
}
uint16_t Build()
{
return build >> 2;
}
TVMVersionStage VersionStage()
{
return (TVMVersionStage)(build & 3);
}
void SetMajor(uint8_t major)
{
this->major=major;
}
void SetMinor(uint8_t minor)
{
this->minor=minor;
}
void SetPatch(uint8_t patch)
{
this->patch=patch;
}
void SetBuild(uint16_t build)
{
this->build = build;
}
void SetBuild(uint16_t build,TVMVersionStage version)
{
this->build = (build << 2) | version;
}
void SetVersion(uint8_t major, uint8_t minor, uint8_t patch, uint16_t build, TVMVersionStage ver)
{
this->SetMajor(major);
this->SetMinor(minor);
this->SetPatch(patch);
this->SetBuild(build,ver);
}
void SetVersion(uint8_t major, uint8_t minor, uint8_t patch, uint16_t build)
{
this->SetMajor(major);
this->SetMinor(minor);
this->SetPatch(patch);
this->SetBuild(build);
}
void SetVersion(uint8_t major, uint8_t minor, uint8_t patch, uint8_t buildHigh, uint8_t buildLow)
{
this->SetVersion(major, minor, patch, buildHigh << 8 | buildLow);
}
void SetVersion(uint8_t* versionData)
{
this->SetVersion(versionData[0],versionData[1],versionData[2],versionData[3],versionData[4]);
}
void ToArray(uint8_t* versionData)
{
versionData[0] = major;
versionData[1] = minor;
versionData[2] = patch;
versionData[3] = build >> 8;
versionData[4] = build & 0xFF;
}
TVMVersion(uint8_t major, uint8_t minor, uint8_t patch, uint16_t build, TVMVersionStage version)
{
this->SetVersion(major,minor,patch,build,version);
}
TVMVersion(uint8_t* versionData)
{
this->SetVersion(versionData);
}
TVMVersion()
{
this->major=1;
this->minor=0;
this->patch=0;
this->SetBuild(0, TVMVersionStage::DevVersion);
}
int CompareTo(TVMVersion& version)
{
if(this->major > version.major) return 1;
if(this->major < version.major) return -1;
if(this->minor > version.minor) return 1;
if(this->minor < version.minor) return -1;
if(this->patch > version.patch) return 1;
if(this->patch < version.patch) return -1;
if(this->build > version.build) return 1;
if(this->build < version.build) return -1;
return 0;
}
int CompareToRuntime()
{
TVMVersion version(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE);
return CompareTo(version);
}
static bool TryParse(std::string versionStr, TVMVersion& version)
{
if(versionStr.empty()) return false;
size_t sep=versionStr.find_last_of('-');
std::string left = versionStr;
std::string right = "prod";
if(sep != std::string::npos)
{
left = versionStr.substr(0, sep);
right = versionStr.substr(sep+1);
}
if(left.empty()) return false;
TVMVersionStage stage;
if(right == "dev")
stage = TVMVersionStage::DevVersion;
else if(right == "alpha")
stage = TVMVersionStage::AlphaVersion;
else if(right == "beta")
stage = TVMVersionStage::BetaVersion;
else if(right == "prod")
stage = TVMVersionStage::ProductionVersion;
else
return false;
//1 0.0.0
sep=left.find_first_of('.');
if(sep != std::string::npos)
{
auto lStr = left.substr(0, sep);
right = left.substr(sep+1);
left = lStr;
}
else
{
version.SetMajor((uint8_t)std::stoul(left));
version.SetBuild(0,stage);
return true;
}
version.SetMajor((uint8_t)std::stoul(left));
left = right;
sep=left.find_first_of('.');
if(sep != std::string::npos)
{
auto lStr = left.substr(0, sep);
right = left.substr(sep+1);
left = lStr;
}
else
{
version.SetMinor((uint8_t)std::stoul(left));
version.SetBuild(0,stage);
return true;
}
version.SetMinor((uint8_t)std::stoul(left));
left = right;
sep=left.find_first_of('.');
if(sep != std::string::npos)
{
auto lStr = left.substr(0, sep);
right = left.substr(sep+1);
left = lStr;
}
else
{
version.SetPatch((uint8_t)std::stoul(left));
version.SetBuild(0,stage);
return true;
}
version.SetPatch((uint8_t)std::stoul(left));
version.SetBuild((uint16_t)std::stoul(right),stage);
return true;
}
std::string ToString()
{
std::string str={};
str.append(std::to_string((int)this->Major()));
str.push_back('.');
str.append(std::to_string((int)this->Minor()));
str.push_back('.');
str.append(std::to_string((int)this->Patch()));
str.push_back('.');
str.append(std::to_string((int)this->Build()));
if(this->VersionStage() == TVMVersionStage::DevVersion)
{
str.append("-dev");
}
else if(this->VersionStage() == TVMVersionStage::AlphaVersion)
{
str.append("-alpha");
}
else if(this->VersionStage() == TVMVersionStage::BetaVersion)
{
str.append("-beta");
}
else if(this->VersionStage() == TVMVersionStage::ProductionVersion)
{
str.append("-prod");
}
return str;
}
};
void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name,TVMVersion version,std::string info);
std::pair<std::pair<std::string,TVMVersion>,std::string> CrossArchiveExtract(Tesses::Framework::Streams::Stream* strm,Tesses::Framework::Filesystem::VFS* vfs);
typedef enum {
Identifier,
Symbol,
String,
Char,
Documentation
} LexTokenType;
class LexTokenLineInfo
{
public:
int line;
int column;
int offset;
std::string filename;
void Add(int c);
void Subtract(size_t c);
};
class LexToken {
public:
LexTokenLineInfo lineInfo;
LexTokenType type;
std::string text;
};
int Lex(std::string filename, std::istream& strm, std::vector<LexToken>& tokens);
class Undefined
{
};
class AdvancedSyntaxNode;
typedef enum {
ADD,
SUB,
TIMES,
DIVIDE,
MODULO,
LEFTSHIFT,
RIGHTSHIFT,
BITWISEOR,
BITWISEAND,
BITWISENOT,
LESSTHAN,
GREATERTHAN,
LESSTHANEQ,
GREATERTHANEQ,
EQ,
NEQ,
NOT,
NEGATIVE,
XOR,
POP,
DUP,
NOP,
PUSHCLOSURE,
CREATEDICTIONARY,
CREATEARRAY,
APPENDLIST,
APPENDDICT,
PUSHRESOURCE,
PUSHLONG,
PUSHCHAR,
PUSHDOUBLE,
PUSHSTRING,
PUSHNULL,
PUSHUNDEFINED,
SCOPEBEGIN,
SCOPEEND,
SCOPEENDTIMES,
PUSHFALSE,
PUSHTRUE,
SETVARIABLE,
GETVARIABLE,
DECLAREVARIABLE,
SETFIELD,
GETFIELD,
CALLFUNCTION,
CALLMETHOD,
RET,
JMPC,
JMP,
JMPUNDEFINED,
DEFER,
TRYCATCH,
THROW,
PUSHSCOPELESSCLOSURE
} Instruction;
class ByteCodeInstruction {
public:
virtual size_t Size()=0;
virtual void Write(std::vector<uint8_t>& data)=0;
virtual ~ByteCodeInstruction()
{}
};
class SimpleInstruction : public ByteCodeInstruction {
public:
Instruction instruction;
SimpleInstruction(Instruction instr);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class BitConverter {
public:
static double ToDoubleBits(uint64_t v);
static uint64_t ToUintBits(double v);
static double ToDoubleBE(uint8_t& b);
static uint64_t ToUint64BE(uint8_t& b);
static uint32_t ToUint32BE(uint8_t& b);
static uint16_t ToUint16BE(uint8_t& b);
static void FromDoubleBE(uint8_t& b, double v);
static void FromUint64BE(uint8_t& b, uint64_t v);
static void FromUint32BE(uint8_t& b, uint32_t v);
static void FromUint16BE(uint8_t& b, uint16_t v);
};
class StringInstruction : public ByteCodeInstruction {
public:
uint32_t n;
StringInstruction(uint32_t n);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class ScopeEndTimesInstruction : public ByteCodeInstruction {
public:
uint32_t n;
ScopeEndTimesInstruction(uint32_t n);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class LabelInstruction : public ByteCodeInstruction {
public:
std::string label;
LabelInstruction(std::string lbl);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class LabelableInstruction : public ByteCodeInstruction {
public:
uint32_t n;
std::string label;
virtual size_t Size();
virtual void Write(std::vector<uint8_t>& data);
};
class JumpStyleInstruction : public LabelableInstruction {
public:
Instruction type;
JumpStyleInstruction(Instruction conditional,std::string label);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class EmbedInstruction : public ByteCodeInstruction {
public:
uint32_t n;
EmbedInstruction(uint32_t n);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class ClosureInstruction : public ByteCodeInstruction {
public:
bool hasScope;
uint32_t n;
ClosureInstruction(uint32_t n,bool hasScope=true);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class DoubleInstruction : public ByteCodeInstruction {
public:
double n;
DoubleInstruction(double n);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class LongInstruction : public ByteCodeInstruction {
public:
int64_t n;
LongInstruction(int64_t n);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
class CharInstruction : public ByteCodeInstruction {
public:
char n;
CharInstruction(char n);
size_t Size();
void Write(std::vector<uint8_t>& data);
};
using SyntaxNode = std::variant<int64_t, double, std::string, char, bool, std::nullptr_t, Undefined, AdvancedSyntaxNode>;
class CodeGen {
uint32_t id;
uint32_t NewId();
void GetFunctionArgs(std::vector<uint32_t>& args,SyntaxNode n);
void GetFunctionName(std::vector<uint32_t>& name,SyntaxNode n);
void GetFunctionArgs(std::vector<SyntaxNode>& args,SyntaxNode n);
uint32_t GetString(std::string str);
uint32_t GetResource(std::string res);
std::vector<std::string> strs;
std::vector<std::string> res;
std::vector<std::pair<std::vector<uint32_t>, std::vector<ByteCodeInstruction*>>> chunks;
std::vector<std::pair<std::vector<uint32_t>,uint32_t>> funcs;
void GenNode(std::vector<ByteCodeInstruction*>& instructions, SyntaxNode n,int32_t scope, int32_t contscope, int32_t brkscope, int32_t contI, int32_t brkI);
void GenPop(std::vector<ByteCodeInstruction*>& instrs,SyntaxNode n);
public:
std::vector<std::pair<std::string, TVMVersion>> dependencies;
TVMVersion version;
std::string name;
std::string info;
void GenRoot(SyntaxNode n);
void Save(Tesses::Framework::Filesystem::VFS* embedFS,Tesses::Framework::Streams::Stream* output);
~CodeGen();
};
constexpr std::string_view EmbedExpression = "embedExpression";
constexpr std::string_view NegativeExpression = "negativeExpression";
constexpr std::string_view NotExpression = "notExpression";
constexpr std::string_view BitwiseNotExpression = "bitwiseNotExpression";
constexpr std::string_view PrefixIncrementExpression = "prefixIncrementExpression";
constexpr std::string_view PrefixDecrementExpression = "prefixDecrementExpression";
constexpr std::string_view PostfixIncrementExpression = "postfixIncrementExpression";
constexpr std::string_view PostfixDecrementExpression = "postfixDecrementExpression";
constexpr std::string_view GetVariableExpression = "getVariableExpression";
constexpr std::string_view GetFieldExpression = "getFieldExpression";
constexpr std::string_view GetArrayExpression = "getArrayExpression";
constexpr std::string_view FunctionCallExpression = "functionCallExpression";
constexpr std::string_view CompoundAssignExpression = "compoundAssignExpression";
constexpr std::string_view AssignExpression = "assignExpression";
constexpr std::string_view CharExpression = "charExpression";
constexpr std::string_view UndefinedExpression = "undefinedExpression";
constexpr std::string_view ScopeNode = "scopeNode";
constexpr std::string_view NodeList = "nodeList";
constexpr std::string_view ArrayExpression = "arrayExpression";
constexpr std::string_view DictionaryExpression = "dictionaryExpression";
constexpr std::string_view DeclareExpression = "declareExpression";
constexpr std::string_view ClosureExpression = "closureExpression";
constexpr std::string_view ScopelessClosureExpression = "scopelessClosureExpression";
constexpr std::string_view TernaryExpression = "ternaryExpression";
constexpr std::string_view IfStatement = "ifStatement";
constexpr std::string_view ForStatement = "forStatement";
constexpr std::string_view WhileStatement = "whileStatement";
constexpr std::string_view DoStatement = "doStatement";
constexpr std::string_view EachStatement = "eachStatement";
constexpr std::string_view ReturnStatement = "returnStatement";
constexpr std::string_view BreakStatement = "breakStatement";
constexpr std::string_view ContinueStatement = "continueStatement";
constexpr std::string_view FunctionStatement = "functionStatement";
constexpr std::string_view DocumentationStatement = "documentationStatement";
constexpr std::string_view CommaExpression = "commaExpression";
constexpr std::string_view AddExpression = "addExpression";
constexpr std::string_view SubExpression = "subtractExpression";
constexpr std::string_view TimesExpression = "timesExpression";
constexpr std::string_view DivideExpression = "divideExpression";
constexpr std::string_view ModExpression = "modExpression";
constexpr std::string_view LeftShiftExpression = "leftShiftExpression";
constexpr std::string_view RightShiftExpression = "rightShiftExpression";
constexpr std::string_view BitwiseOrExpression = "bitwiseOrExpression";
constexpr std::string_view BitwiseAndExpression = "bitwiseAndExpression";
constexpr std::string_view XOrExpression = "xOrExpression";
constexpr std::string_view LogicalOrExpression = "logicalOrExpression";
constexpr std::string_view LogicalAndExpression = "logicalAndExpression";
constexpr std::string_view EqualsExpression = "equalsExpression";
constexpr std::string_view NotEqualsExpression = "notEqualsExpression";
constexpr std::string_view LessThanExpression = "lessThanExpression";
constexpr std::string_view GreaterThanExpression = "greaterThanExpression";
constexpr std::string_view LessThanEqualsExpression = "lessThanEqualsExpression";
constexpr std::string_view GreaterThanEqualsExpression = "greaterThanEqualsExpression";
constexpr std::string_view ParenthesesExpression = "parenthesesExpression";
constexpr std::string_view ThrowStatement = "throwStatement";
constexpr std::string_view TryStatement = "tryStatement";
constexpr std::string_view DeferStatement = "deferStatement";
class AdvancedSyntaxNode {
public:
std::string nodeName;
bool isExpression;
std::vector<SyntaxNode> nodes;
static AdvancedSyntaxNode Create(std::string_view nodeName,bool isExpression, std::vector<SyntaxNode> n);
};
SyntaxNode Deserialize(std::string astData);
std::string Serialize(SyntaxNode node);
class Parser {
uint64_t i;
std::vector<LexToken> tokens;
LexToken tkn;
void EnsureSymbol(std::string txt);
bool IsIdentifier(std::string txt,bool pop=true);
bool IsAnyIdentifier(std::initializer_list<std::string> idents, bool pop=true);
bool IsSymbol(std::string txt,bool pop=true);
bool IsAnySymbol(std::initializer_list<std::string> idents, bool pop=true);
SyntaxNode ParseExpression();
SyntaxNode ParseTernary();
SyntaxNode ParseNode(bool isRoot=false);
SyntaxNode ParseAssignment();
SyntaxNode ParseXOr();
SyntaxNode ParseBOr();
SyntaxNode ParseLOr();
SyntaxNode ParseLAnd();
SyntaxNode ParseBAnd();
SyntaxNode ParseEq();
SyntaxNode ParseRel();
SyntaxNode ParseShift();
SyntaxNode ParseSum();
SyntaxNode ParseFactor();
SyntaxNode ParseValue();
SyntaxNode ParseUnary();
public:
Parser(std::vector<LexToken> tokens);
SyntaxNode ParseRoot()
{
return ParseNode(true);
}
};
class THeapObject;
class CallStackEntry;
class InterperterThread;
class THeapObject {
public:
bool marked;
virtual void Mark()
{
marked = true;
}
virtual ~THeapObject()
{
}
};
class THeapObjectHolder
{
public:
THeapObject* obj;
THeapObjectHolder(THeapObject* obj)
{
this->obj = obj;
}
THeapObjectHolder()
{
this->obj = obj;
}
};
class MethodInvoker {
};
using TObject = std::variant<int64_t,double,char,bool,std::string,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder>;
class GC {
Tesses::Framework::Threading::Thread* thrd;
Tesses::Framework::Threading::Mutex* mtx;
volatile std::atomic<bool> running;
std::vector<THeapObject*> roots;
std::vector<THeapObject*> objects;
public:
bool UsingNullThreads();
GC();
void Start();
bool IsRunning();
void BarrierBegin();
void BarrierEnd();
void Collect();
void Watch(TObject obj);
void Unwatch(TObject obj);
void SetRoot(TObject obj);
void UnsetRoot(TObject obj);
static void Mark(TObject obj);
~GC();
};
std::string ToString(GC* gc, TObject obj);
class GCList : public THeapObject
{
std::vector<THeapObject*> items;
GC* gc;
public:
GCList(GC* gc);
GCList(GC& gc);
GC* GetGC();
void Add(TObject v);
void Remove(TObject v);
void Mark();
~GCList();
};
class TFile;
class TFileChunk : public THeapObject
{
public:
static TFileChunk* Create(GCList* gc);
static TFileChunk* Create(GCList& gc);
TFile* file;
std::vector<uint8_t> code;
std::vector<std::string> args;
std::string name;
void Mark();
};
class TByteArray : public THeapObject
{
public:
std::vector<uint8_t> data;
static TByteArray* Create(GCList* gc);
static TByteArray* Create(GCList& gc);
};
class TFile : public THeapObject
{
public:
static TFile* Create(GCList* gc);
static TFile* Create(GCList& gc);
std::vector<TFileChunk*> chunks;
std::vector<std::string> strings;
std::vector<std::pair<std::vector<std::string>, uint32_t>> functions;
std::vector<std::pair<std::string,TVMVersion>> dependencies;
std::vector<std::vector<uint8_t>> resources;
std::string name;
TVMVersion version;
std::string info;
void Load(GC* gc, Tesses::Framework::Streams::Stream* strm);
void Skip(Tesses::Framework::Streams::Stream* strm,size_t len);
void Ensure(Tesses::Framework::Streams::Stream* strm,uint8_t* buffer, size_t len);
uint32_t EnsureInt(Tesses::Framework::Streams::Stream* strm);
std::string EnsureString(Tesses::Framework::Streams::Stream* strm);
std::string GetString(Tesses::Framework::Streams::Stream* strm);
void Mark();
};
class TList : public THeapObject
{
public:
std::vector<TObject> items;
static TList* Create(GCList* gc);
static TList* Create(GCList& gc);
virtual int64_t Count();
virtual TObject Get(int64_t index);
virtual void Set(int64_t index, TObject value);
virtual void Insert(int64_t index,TObject value);
virtual void Add(TObject value);
virtual void RemoveAt(int64_t index);
virtual void Clear();
virtual void Mark();
};
class TDictionary : public THeapObject
{
public:
std::unordered_map<std::string,TObject> items;
static TDictionary* Create(GCList* gc);
static TDictionary* Create(GCList& gc);
virtual bool HasValue(std::string key);
virtual TObject GetValue(std::string key);
virtual void SetValue(std::string key, TObject value);
virtual void Mark();
void DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb);
void DeclareFunction(GC& gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb);
void DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
void DeclareFunction(GC& gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
TObject CallMethod(GCList& ls, std::string key, std::vector<TObject> args);
};
class TRootEnvironment;
class TSubEnvironment;
class TCallable : public THeapObject
{
public:
std::string documentation;
virtual TObject Call(GCList& ls,std::vector<TObject> args)=0;
};
class TEnvironment : public THeapObject {
public:
std::vector<TCallable*> defers;
TObject LoadFile(GC* gc, TFile* f);
TObject Eval(GCList& ls,std::string code);
virtual bool HasVariable(std::string key)=0;
virtual bool HasVariableRecurse(std::string key)=0;
virtual TObject GetVariable(std::string key)=0;
virtual void SetVariable(std::string key, TObject value)=0;
virtual void DeclareVariable(std::string key, TObject value)=0;
virtual TRootEnvironment* GetRootEnvironment()=0;
virtual TEnvironment* GetParentEnvironment()=0;
virtual TSubEnvironment* GetSubEnvironment(TDictionary* dict);
TSubEnvironment* GetSubEnvironment(GCList* gc);
TSubEnvironment* GetSubEnvironment(GCList& gc);
void DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb);
void DeclareFunction(GC& gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb);
void DeclareFunction(GC* gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
void DeclareFunction(GC& gc,std::string key,std::string documentation, std::vector<std::string> argNames, std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
TObject CallFunction(GCList& ls, std::string key, std::vector<TObject> args);
};
class EnvironmentPermissions {
public:
EnvironmentPermissions();
Tesses::Framework::Filesystem::VFSPath sqliteOffsetPath;
bool canRegisterConsole;
bool canRegisterIO;
bool canRegisterLocalFS;
bool canRegisterNet;
bool canRegisterSqlite;
bool canRegisterVM;
bool canRegisterDictionary;
bool canRegisterJSON;
bool canRegisterCrypto;
bool canRegisterSDL2;
bool canRegisterRoot;
bool canRegisterPath;
bool canRegisterOGC;
bool canRegisterEnv;
bool sqlite3Scoped;
bool locked;
};
class TRootEnvironment : public TEnvironment
{
TDictionary* dict;
void LoadDependency(GC* gc,Tesses::Framework::Filesystem::VFS* vfs, std::pair<std::string,TVMVersion> dep);
public:
EnvironmentPermissions permissions;
std::vector<std::pair<std::string, TVMVersion>> dependencies;
void LoadFileWithDependencies(GC* gc,Tesses::Framework::Filesystem::VFS* vfs, TFile* f);
void LoadFileWithDependencies(GC* gc,Tesses::Framework::Filesystem::VFS* vfs, Tesses::Framework::Filesystem::VFSPath path);
TDictionary* GetDictionary();
static TRootEnvironment* Create(GCList* gc,TDictionary* dict);
static TRootEnvironment* Create(GCList& gc,TDictionary* dict);
TRootEnvironment(TDictionary* dict);
bool HasVariable(std::string key);
bool HasVariableRecurse(std::string key);
TObject GetVariable(std::string key);
void SetVariable(std::string key, TObject value);
void DeclareVariable(std::string key, TObject value);
TRootEnvironment* GetRootEnvironment();
TEnvironment* GetParentEnvironment();
void Mark();
};
class TStd {
public:
static void RegisterStd(GC* gc, TRootEnvironment* env);
static void RegisterConsole(GC* gc,TRootEnvironment* env);
static void RegisterIO(GC* gc,TRootEnvironment* env, bool enableLocalFilesystem=true);
static void RegisterNet(GC* gc, TRootEnvironment* env);
static void RegisterSqlite(GC* gc,TRootEnvironment* env);
static void RegisterVM(GC* gc,TRootEnvironment* env);
static void RegisterDictionary(GC* gc, TRootEnvironment* env);
static void RegisterJson(GC* gc, TRootEnvironment* env);
static void RegisterCrypto(GC* gc,TRootEnvironment* env);
static void RegisterSDL2(GC* gc, TRootEnvironment* env);
static void RegisterRoot(GC* gc, TRootEnvironment* env);
static void RegisterPath(GC* gc, TRootEnvironment* env);
static void RegisterOGC(GC* gc, TRootEnvironment* env);
static void RegisterEnv(GC* gc, TRootEnvironment* env);
};
class TSubEnvironment : public TEnvironment
{
TEnvironment* env;
TDictionary* dict;
public:
static TSubEnvironment* Create(GCList* gc,TEnvironment* env,TDictionary* dict);
static TSubEnvironment* Create(GCList& gc,TEnvironment* env,TDictionary* dict);
TSubEnvironment(TEnvironment* env,TDictionary* dict);
bool HasVariable(std::string key);
bool HasVariableRecurse(std::string key);
TObject GetVariable(std::string key);
void SetVariable(std::string key, TObject value);
void DeclareVariable(std::string key, TObject value);
TRootEnvironment* GetRootEnvironment();
TEnvironment* GetParentEnvironment();
void Mark();
};
TDictionary* CreateThread(GCList& ls, TCallable* callable,bool detached);
class TArgWrapper : public TCallable
{
public:
TCallable* callable;
static TArgWrapper* Create(GCList& ls, TCallable* callable);
static TArgWrapper* Create(GCList* ls, TCallable* callable);
TObject Call(GCList& ls,std::vector<TObject> args);
void Mark();
};
class TExternalMethod : public TCallable
{
std::function<TObject(GCList& ls, std::vector<TObject> args)> cb;
std::function<void()> destroy;
public:
std::vector<std::string> args;
std::vector<TObject> watch;
TExternalMethod(std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::string documentation, std::vector<std::string> argNames,std::function<void()> destroy);
static TExternalMethod* Create(GCList& ls,std::string documentation, std::vector<std::string> argNames,std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
static TExternalMethod* Create(GCList* ls,std::string documentation, std::vector<std::string> argNames,std::function<TObject(GCList& ls, std::vector<TObject> args)> cb,std::function<void()> destroy);
static TExternalMethod* Create(GCList& ls,std::string documentation, std::vector<std::string> argNames,std::function<TObject(GCList& ls, std::vector<TObject> args)> cb);
static TExternalMethod* Create(GCList* ls,std::string documentation, std::vector<std::string> argNames,std::function<TObject(GCList& ls, std::vector<TObject> args)> cb);
TObject Call(GCList& ls, std::vector<TObject> args);
~TExternalMethod();
void Mark()
{
if(this->marked) return;
this->marked=true;
for(auto item : watch)
GC::Mark(item);
}
};
class TEnumerator : public THeapObject
{
public:
virtual bool MoveNext(GC* ls)=0;
virtual TObject GetCurrent(GCList& ls)=0;
static TEnumerator* CreateFromObject(GCList& ls, TObject obj);
};
class TCustomEnumerator : public TEnumerator {
public:
TDictionary* dict;
bool MoveNext(GC* ls);
TObject GetCurrent(GCList& ls);
void Mark();
static TCustomEnumerator* Create(GCList& ls,TDictionary* dict);
static TCustomEnumerator* Create(GCList* ls,TDictionary* dict);
};
class TStringEnumerator : public TEnumerator
{
bool hasStarted;
size_t index;
std::string str;
public:
static TStringEnumerator* Create(GCList& ls,std::string str);
static TStringEnumerator* Create(GCList* ls,std::string str);
bool MoveNext(GC* ls);
TObject GetCurrent(GCList& ls);
};
class TListEnumerator : public TEnumerator
{
int64_t index;
TList* ls;
public:
static TListEnumerator* Create(GCList& ls, TList* list);
static TListEnumerator* Create(GCList* ls, TList* list);
bool MoveNext(GC* ls);
TObject GetCurrent(GCList& ls);
void Mark();
};
class TVFSPathEnumerator : public TEnumerator
{
Tesses::Framework::Filesystem::VFSPathEnumerator enumerator;
public:
static TVFSPathEnumerator* Create(GCList& ls, Tesses::Framework::Filesystem::VFSPathEnumerator list);
static TVFSPathEnumerator* Create(GCList* ls, Tesses::Framework::Filesystem::VFSPathEnumerator list);
bool MoveNext(GC* ls);
TObject GetCurrent(GCList& ls);
};
class TStreamHeapObject : public THeapObject
{
public:
Tesses::Framework::Streams::Stream* stream;
static TStreamHeapObject* Create(GCList& ls, Tesses::Framework::Streams::Stream* strm);
static TStreamHeapObject* Create(GCList* ls, Tesses::Framework::Streams::Stream* strm);
~TStreamHeapObject();
void Close();
};
class TVFSHeapObject : public THeapObject
{
public:
Tesses::Framework::Filesystem::VFS* vfs;
static TVFSHeapObject* Create(GCList& ls, Tesses::Framework::Filesystem::VFS* vfs);
static TVFSHeapObject* Create(GCList* ls, Tesses::Framework::Filesystem::VFS* vfs);
~TVFSHeapObject();
void Close();
};
class TServerHeapObject : public THeapObject
{
public:
Tesses::Framework::Http::IHttpServer* server;
static TServerHeapObject* Create(GCList& ls, Tesses::Framework::Http::IHttpServer* vfs);
static TServerHeapObject* Create(GCList* ls, Tesses::Framework::Http::IHttpServer* vfs);
~TServerHeapObject();
void Close();
};
class TObjectVFS : public Tesses::Framework::Filesystem::VFS
{
public:
TObject obj;
GCList* ls;
TObjectVFS(GC* gc, TObject obj);
Tesses::Framework::Streams::Stream* OpenFile(Tesses::Framework::Filesystem::VFSPath path, std::string mode);
void CreateDirectory(Tesses::Framework::Filesystem::VFSPath path);
void DeleteDirectory(Tesses::Framework::Filesystem::VFSPath path);
bool RegularFileExists(Tesses::Framework::Filesystem::VFSPath path);
bool SymlinkExists(Tesses::Framework::Filesystem::VFSPath path);
bool CharacterDeviceExists(Tesses::Framework::Filesystem::VFSPath path);
bool BlockDeviceExists(Tesses::Framework::Filesystem::VFSPath path);
bool SocketFileExists(Tesses::Framework::Filesystem::VFSPath path);
bool FIFOFileExists(Tesses::Framework::Filesystem::VFSPath path);
bool FileExists(Tesses::Framework::Filesystem::VFSPath path);
bool SpecialFileExists(Tesses::Framework::Filesystem::VFSPath path);
void CreateSymlink(Tesses::Framework::Filesystem::VFSPath existingFile, Tesses::Framework::Filesystem::VFSPath symlinkFile);
void CreateHardlink(Tesses::Framework::Filesystem::VFSPath existingFile, Tesses::Framework::Filesystem::VFSPath newName);
bool DirectoryExists(Tesses::Framework::Filesystem::VFSPath path);
void DeleteFile(Tesses::Framework::Filesystem::VFSPath path);
void DeleteDirectoryRecurse(Tesses::Framework::Filesystem::VFSPath path);
Tesses::Framework::Filesystem::VFSPathEnumerator EnumeratePaths(Tesses::Framework::Filesystem::VFSPath path);
void MoveFile(Tesses::Framework::Filesystem::VFSPath src, Tesses::Framework::Filesystem::VFSPath dest);
void MoveDirectory(Tesses::Framework::Filesystem::VFSPath src, Tesses::Framework::Filesystem::VFSPath dest);
Tesses::Framework::Filesystem::VFSPath ReadLink(Tesses::Framework::Filesystem::VFSPath path);
std::string VFSPathToSystem(Tesses::Framework::Filesystem::VFSPath path);
Tesses::Framework::Filesystem::VFSPath SystemToVFSPath(std::string path);
void GetDate(Tesses::Framework::Filesystem::VFSPath path, time_t& lastWrite, time_t& lastAccess);
void SetDate(Tesses::Framework::Filesystem::VFSPath path, time_t lastWrite, time_t lastAccess);
~TObjectVFS();
};
class TObjectStream : public Tesses::Framework::Streams::Stream
{
int64_t _GetPosInternal();
public:
TObject obj;
GCList* ls;
TObjectStream(GC* gc, TObject obj);
bool EndOfStream();
size_t Read(uint8_t* buff, size_t sz);
size_t Write(const uint8_t* buff, size_t sz);
bool CanRead();
bool CanWrite();
bool CanSeek();
int64_t GetPosition();
int64_t GetLength();
void Flush();
void Seek(int64_t pos, Tesses::Framework::Streams::SeekOrigin whence);
~TObjectStream();
};
class TObjectHttpServer : public Tesses::Framework::Http::IHttpServer
{
public:
TObject obj;
GCList* ls;
TObjectHttpServer(GC* gc,TObject obj);
bool Handle(Tesses::Framework::Http::ServerContext& ctx);
~TObjectHttpServer();
};
class TDictionaryEnumerator : public TEnumerator
{
bool hasStarted;
std::unordered_map<std::string, Tesses::CrossLang::TObject>::iterator ittr;
TDictionary* dict;
public:
static TDictionaryEnumerator* Create(GCList& ls, TDictionary* dict);
static TDictionaryEnumerator* Create(GCList* ls, TDictionary* dict);
bool MoveNext(GC* ls);
TObject GetCurrent(GCList& ls);
void Mark();
};
class TClosure : public TCallable
{
public:
static TClosure* Create(GCList& ls,TEnvironment* env,TFile* file,uint32_t chunkId,bool ownScope=true);
static TClosure* Create(GCList* ls,TEnvironment* env,TFile* file,uint32_t chunkId,bool ownScope=true);
bool ownScope;
TFileChunk* closure;
TFile* file;
uint32_t chunkId;
TEnvironment* env;
TObject Call(GCList& ls,std::vector<TObject> args);
void Mark();
};
class CallStackEntry : public THeapObject
{
public:
static CallStackEntry* Create(GCList* ls);
static CallStackEntry* Create(GCList& ls);
std::vector<TObject> stack;
TEnvironment* env;
TClosure* callable;
uint32_t ip;
uint32_t scopes;
void Mark();
void Push(GC* gc,TObject v);
TObject Pop(GCList& gcl);
};
extern thread_local CallStackEntry* current_function;
class InterperterThread : public THeapObject
{
private:
bool InvokeTwo(GCList& ls,TObject fn, TObject left, TObject right);
bool InvokeOne(GCList& ls,TObject fn, TObject arg);
bool InvokeMethod(GCList& ls, TObject fn, TObject instance, std::vector<TObject> args);
bool ExecuteMethod2(GC* gc, TObject instance, std::string key, std::vector<TObject> args);
protected:
static void* ThreadCallback(void* ptr);
bool Add(GC* gc);
bool Sub(GC* gc);
bool Times(GC* gc);
bool Divide(GC* gc);
bool Mod(GC* gc);
bool Neg(GC* gc);
bool Lt(GC* gc);
bool Gt(GC* gc);
bool Lte(GC* gc);
bool Gte(GC* gc);
bool Eq(GC* gc);
bool NEq(GC* gc);
bool LShift(GC* gc);
bool RShift(GC* gc);
bool BOr(GC* gc);
bool XOr(GC* gc);
bool LNot(GC* gc);
bool BNot(GC* gc);
bool BAnd(GC* gc);
bool ExecuteFunction(GC* gc);
bool ExecuteMethod(GC* gc);
bool GetVariable(GC* gc);
bool SetVariable(GC* gc);
bool GetField(GC* gc);
bool SetField(GC* gc);
bool GetArray(GC* gc);
bool SetArray(GC* gc);
bool DeclareVariable(GC* gc);
bool PushLong(GC* gc);
bool PushDouble(GC* gc);
bool PushChar(GC* gc);
bool PushString(GC* gc);
bool PushClosure(GC* gc);
bool PushScopelessClosure(GC* gc);
bool PushResource(GC* gc);
bool Illegal(GC* gc);
bool Throw(GC* gc);
bool Jump(GC* gc);
bool JumpConditional(GC* gc);
bool JumpUndefined(GC* gc);
bool Defer(GC* gc);
bool TryCatch(GC* gc);
bool Return(GC* gc);
bool ScopeBegin(GC* gc);
bool ScopeEnd(GC* gc);
bool ScopeEndTimes(GC* gc);
bool PushTrue(GC* gc);
bool PushFalse(GC* gc);
bool PushNull(GC* gc);
bool PushUndefined(GC* gc);
bool CreateDictionary(GC* gc);
bool CreateArray(GC* gc);
bool AppendList(GC* gc);
bool AppendDictionary(GC* gc);
bool Pop(GC* gc);
bool Dup(GC* gc);
bool Nop(GC* gc);
public:
static InterperterThread* Create(GCList* ls);
static InterperterThread* Create(GCList& ls);
std::vector<CallStackEntry*> call_stack_entries;
virtual void Execute(GC* gc);
void AddCallStackEntry(GCList& ls,TClosure* closure, std::vector<TObject> args);
void Mark();
};
class VMException : public std::exception {
std::string error_message;
public:
VMException(std::string ex)
{
error_message = "VMException: ";
error_message.append(ex);
}
const char * what() const noexcept override
{
return error_message.c_str();
}
};
class TNative : public THeapObject
{
std::atomic<bool> destroyed;
void* ptr;
std::function<void(void*)> destroy;
public:
TObject other;
TNative(void* ptr,std::function<void(void*)> destroy);
bool GetDestroyed();
void* GetPointer();
void Destroy();
void Mark();
static TNative* Create(GCList& ls, void* ptr,std::function<void(void*)> destroy);
static TNative* Create(GCList* ls, void* ptr,std::function<void(void*)> destroy);
~TNative();
};
class ThreadHandle : public THeapObject {
public:
Tesses::Framework::Threading::Thread* thrd;
std::atomic<bool> hasInit;
std::atomic<bool> hasReturned;
std::atomic<bool> detached;
TCallable* callable;
TObject returnValue;
GC* gc;
void Mark()
{
if(this->marked) return;
this->marked = true;
callable->Mark();
GC::Mark(returnValue);
}
~ThreadHandle()
{
if(this->detached)
{
this->thrd->Join();
delete this->thrd;
}
}
};
TObject ExecuteFunction(GCList& ls,TCallable* callable,std::vector<TObject> args);
class VMByteCodeException : public std::exception
{
std::string lastErrorText;
std::shared_ptr<GCList> gcList;
public:
TObject exception;
VMByteCodeException()
{
}
VMByteCodeException(GC* gc,TObject obj)
{
gcList = std::make_shared<GCList>(gc);
gcList.get()->Add(obj);
this->exception = obj;
UpdateError();
}
void UpdateError()
{
lastErrorText = ToString(gcList.get()->GetGC(),exception);
}
const char * what() const noexcept override
{
return lastErrorText.c_str();
}
};
class SyntaxException : public std::exception
{
std::string msg={};
public:
SyntaxException(LexTokenLineInfo lineInfo, std::string message)
{
msg.append("in file: ");
msg.append(lineInfo.filename);
msg.append(":");
msg.append(std::to_string(lineInfo.line));
msg.append(":");
msg.append(std::to_string(lineInfo.column));
msg.append(":");
msg.append(std::to_string(lineInfo.offset));
msg.append(": ");
msg.append(message);
}
const char * what() const noexcept override
{
return msg.c_str();
}
};
template<typename T>
bool GetObject(TObject& obj, T& res)
{
if(!std::holds_alternative<T>(obj)) return false;
res = std::get<T>(obj);
return true;
}
template<typename T>
bool GetArgument(std::vector<TObject>& args, size_t index, T& obj)
{
if( index >= args.size()) return false;
return GetObject(args[index], obj);
}
template<typename T>
bool GetObjectHeap(TObject& obj, T& res)
{
THeapObjectHolder h;
if(!GetObject<THeapObjectHolder>(obj,h)) return false;
auto v = dynamic_cast<T>(h.obj);
if(v == nullptr) return false;
res = v;
return true;
}
template<typename T>
bool GetArgumentHeap(std::vector<TObject>& args, size_t index, T& obj)
{
if( index >= args.size()) return false;
return GetObjectHeap(args[index], obj);
}
bool GetObjectAsPath(TObject& obj, Tesses::Framework::Filesystem::VFSPath& path, bool allowString=true);
bool GetArgumentAsPath(std::vector<TObject>& args, size_t index, Tesses::Framework::Filesystem::VFSPath& path,bool allowString=true);
};