#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CrossLangVersion.h" #include "TessesFramework/Streams/ByteReader.hpp" #define CROSSLANG_BYTECODE_MAJOR 1 #define CROSSLANG_BYTECODE_MINOR 0 #define CROSSLANG_BYTECODE_PATCH 0 #define CROSSLANG_BYTECODE_BUILD 0 // SHOULD ALWAYS BE 0 #define CROSSLANG_BYTECODE_VERSIONSTAGE DevVersion #if defined(_WIN32) #undef Yield #endif /** * @namespace Tesses::CrossLang * @brief The CrossLang namespace * */ namespace Tesses::CrossLang { using BitConverter = Tesses::Framework::Serialization::BitConverter; constexpr std::string_view VMName = "CrossLangVM"; constexpr std::string_view VMHowToGet = "https://crosslang.tesseslanguage.com/"; /** * @brief Escape a crosslang string (for generating source code) * * @param text text to escape * @param quote whether to surround with double quotes * @return std::string the escaped string */ std::string EscapeString(std::string text, bool quote); /** * @brief Get the config folder used by crosslang * * @return Tesses::Framework::Filesystem::VFSPath the config folder for * crosslang */ Tesses::Framework::Filesystem::VFSPath GetCrossLangConfigDir(); /** * @brief Version stage * */ enum TVMVersionStage : uint8_t { DevVersion = 0, AlphaVersion = 1, BetaVersion = 2, ProductionVersion = 3 }; /** * @brief CrossLang version * */ class TVMVersion { uint8_t major; uint8_t minor; uint8_t patch; uint16_t build; public: /** * @brief Major * * @return uint8_t The major */ uint8_t Major() { return major; } /** * @brief Minor * * @return uint8_t The minor */ uint8_t Minor() { return minor; } /** * @brief Patch * * @return uint8_t The patch */ uint8_t Patch() { return patch; } /** * @brief Build * * @return uint16_t The build */ uint16_t Build() { return build >> 2; } /** * @brief Stage (dev, alpha, beta or prod) * * @return TVMVersionStage The stage */ TVMVersionStage VersionStage() { return (TVMVersionStage)(build & 3); } /** * @brief Set the Major * * @param major The major */ void SetMajor(uint8_t major) { this->major = major; } /** * @brief Set the Minor * * @param minor The minor */ void SetMinor(uint8_t minor) { this->minor = minor; } /** * @brief Set the Patch * * @param patch The patch */ void SetPatch(uint8_t patch) { this->patch = patch; } /** * @brief Set the Build * * @param build The build << 2 | (stage & 3) */ void SetBuild(uint16_t build) { this->build = build; } /** * @brief Set the Build (and stage) * * @param build * @param version */ void SetBuild(uint16_t build, TVMVersionStage version) { this->build = (build << 2) | version; } /** * @brief Set the Version * * @param major The major * @param minor The minor * @param patch The patch * @param build The build * @param ver The stage */ 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); } /** * @brief Set the Version * * @param major The major * @param minor The minor * @param patch The patch * @param build The build << 2 | (stage & 3) */ 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); } /** * @brief Set the Version * * @param major The major * @param minor The minor * @param patch The patch * @param buildHigh The build (high 8 bits) * @param buildLow The build (low 6 bits) << 2 | (stage & 3) */ 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); } /** * @brief Set the Version * * @param versionData same order as SetVersion(uint8_t major, uint8_t minor, * uint8_t patch, uint8_t buildHigh, uint8_t buildLow) but is a pointer to * uint8_t version[5] */ void SetVersion(uint8_t *versionData) { this->SetVersion(versionData[0], versionData[1], versionData[2], versionData[3], versionData[4]); } /** * @brief Set the version from long * * @param v version serialized as long */ void SetFromLong(uint64_t v) { this->major = (uint8_t)((v >> 32) & 0xFF); this->minor = (uint8_t)(v >> 24) & 0xFF; this->patch = (uint8_t)(v >> 16) & 0xFF; this->build = (uint16_t)(v & 0xFFFF); } /** * @brief Encodes the version to bytes to be decoded by SetVersion(uint8_t*) * or the constructor * * @param versionData an array that is 5 bytes long */ void ToArray(uint8_t *versionData) { versionData[0] = major; versionData[1] = minor; versionData[2] = patch; versionData[3] = build >> 8; versionData[4] = build & 0xFF; } /** * @brief Construct a new Version object * * @param major Major * @param minor Minor * @param patch Patch * @param build Build * @param version Stage (dev, alpha, beta, prod) see TVMVersionStage for * actual names */ TVMVersion(uint8_t major, uint8_t minor, uint8_t patch, uint16_t build, TVMVersionStage version) { this->SetVersion(major, minor, patch, build, version); } /** * @brief Construct a new Version object * * @param versionData same order as SetVersion(uint8_t major, uint8_t minor, * uint8_t patch, uint8_t buildHigh, uint8_t buildLow) but is a pointer to * uint8_t version[5] */ TVMVersion(uint8_t *versionData) { this->SetVersion(versionData); } /** * @brief Construct a new 1.0.0.0-dev Version object * */ TVMVersion() { this->major = 1; this->minor = 0; this->patch = 0; this->SetBuild(0, TVMVersionStage::DevVersion); } /** * @brief Construct a new Version object from a long * * @param v version serialized as long */ TVMVersion(uint64_t v) { this->SetFromLong(v); } /** * @brief Compares to another version * * @param version another version object * @return int returns 1 if this is newer than other version, 0 if same, -1 * if this is older than other version */ 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; } /** * @brief Serializes to a long * * @return uint64_t serialized as a long */ uint64_t AsLong() { uint64_t v = (uint64_t)major << 32; v |= (uint64_t)minor << 24; v |= (uint64_t)patch << 16; v |= (uint64_t)build; return v; } /** * @brief Compares this to the runtime version (for Bytecode) * * @return int CompareTo(RuntimeVersion) where RuntimeVersion is the runtime * version */ int CompareToRuntime() { TVMVersion version(CROSSLANG_BYTECODE_MAJOR, CROSSLANG_BYTECODE_MINOR, CROSSLANG_BYTECODE_PATCH, CROSSLANG_BYTECODE_BUILD, CROSSLANG_BYTECODE_VERSIONSTAGE); return CompareTo(version); } /** * @brief Try to parse the version from a string * * @param versionStr the version string like 1.0.0.0-prod (or dev, alpha, * beta) * @param version a reference to a version * @return true the parsing succeeded * @return false the parsing failed */ 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; } /** * @brief Converts version to string * * @return std::string the version string like 1.0.0.0-prod (or dev, alpha, * beta) */ 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; } }; /** * @brief Create a crvm archive file * * @param vfs the filesystem used as root of the archive * @param strm the output stream * @param name the crvm name * @param version the crvm version * @param info the crvm info * @param icon the crvm icon */ void CrossArchiveCreate( std::shared_ptr vfs, std::shared_ptr strm, std::string name, TVMVersion version, std::string info, std::string icon = ""); /** * @brief * * @param strm the input stream * @param vfs vfs to extract to (as root) * @return std::pair,std::string> ((name, * version),info) */ std::pair, std::string> CrossArchiveExtract(std::shared_ptr strm, std::shared_ptr vfs); /** * @brief The token type for lexer * */ typedef enum { Identifier, Symbol, String, Char, Documentation } LexTokenType; /** * @brief The line info for lextoken * */ class LexTokenLineInfo { public: /** * @brief line number * */ int line; /** * @brief column number * */ int column; /** * @brief byte offset in file * */ int offset; /** * @brief filename * */ std::string filename; /** * @brief Add a char * * @param c a char to add to line, column, offset */ void Add(int c); /** * @brief Subtract from column and offset * * @param c the number of chars */ void Subtract(size_t c); }; /** * @brief The lextoken for lexer * */ class LexToken { public: /** * @brief line information * */ LexTokenLineInfo lineInfo; /** * @brief the token type * */ LexTokenType type; /** * @brief the token text * */ std::string text; /** * @brief any white space characters before this token * */ std::string whiteSpaceCharsBefore; }; /** * @brief Start lexing the file * * @param filename the filename used for exception purposes * @param strm the character stream * @param tokens the tokens * @return int 0 on success, line number on failure */ int Lex(std::string filename, std::istream &strm, std::vector &tokens); using Undefined = std::monostate; class AdvancedSyntaxNode; /** * @brief Bytecode instruction enumeration * */ 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, YIELD, PUSHROOTPATH, PUSHRELATIVEPATH, BREAKPOINT, PUSHBREAK, PUSHCONTINUE, JMPIFBREAK, JMPIFCONTINUE, JMPIFDEFINED, DECLARECONSTVARIABLE, LINEINFO, PUSHRESOURCESTREAM, PUSHRESOUURCEDIR, PUSHPRIVATEXPRESSION } Instruction; /** * @brief Base type for bytecode instruction * */ class ByteCodeInstruction { public: /** * @brief Size of instruction * * @return size_t the length of the instruction */ virtual size_t Size() = 0; /** * @brief Write the instruction to vector * * @param data the vector of uint8_t */ virtual void Write(std::vector &data) = 0; virtual ~ByteCodeInstruction() {} }; /** * @brief Basic bytecode instruction * */ class SimpleInstruction : public ByteCodeInstruction { public: /** * @brief The instruction * */ Instruction instruction; /** * @brief Construct a new Simple Instruction object * * @param instr the instruction */ SimpleInstruction(Instruction instr); /** * @brief Size of instruction * * @return size_t 1, because simple instructions are just an instruction */ size_t Size(); /** * @brief Write the opcode to the vector * * @param data the vector of uint8_t */ void Write(std::vector &data); }; class StringInstruction : public ByteCodeInstruction { public: uint32_t n; StringInstruction(uint32_t n); size_t Size(); void Write(std::vector &data); }; class ScopeEndTimesInstruction : public ByteCodeInstruction { public: uint32_t n; ScopeEndTimesInstruction(uint32_t n); size_t Size(); void Write(std::vector &data); }; class LabelInstruction : public ByteCodeInstruction { public: std::string label; LabelInstruction(std::string lbl); size_t Size(); void Write(std::vector &data); }; class LabelableInstruction : public ByteCodeInstruction { public: uint32_t n; std::string label; virtual size_t Size(); virtual void Write(std::vector &data); }; class JumpStyleInstruction : public LabelableInstruction { public: Instruction type; JumpStyleInstruction(Instruction conditional, std::string label); size_t Size(); void Write(std::vector &data); }; class EmbedInstruction : public ByteCodeInstruction { public: uint32_t n; EmbedInstruction(uint32_t n); size_t Size(); void Write(std::vector &data); }; class EmbedStreamInstruction : public ByteCodeInstruction { public: uint32_t n; EmbedStreamInstruction(uint32_t n); size_t Size(); void Write(std::vector &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 &data); }; class DoubleInstruction : public ByteCodeInstruction { public: double n; DoubleInstruction(double n); size_t Size(); void Write(std::vector &data); }; class LongInstruction : public ByteCodeInstruction { public: int64_t n; LongInstruction(int64_t n); size_t Size(); void Write(std::vector &data); }; class CharInstruction : public ByteCodeInstruction { public: char n; CharInstruction(char n); size_t Size(); void Write(std::vector &data); }; using SyntaxNode = std::variant, AdvancedSyntaxNode, std::shared_ptr, std::shared_ptr>; struct CodeGenClassEntry { uint8_t type; uint32_t documentation; uint32_t name; std::vector arguments; uint32_t closure; }; struct CodeGenClass { uint32_t documentation; std::vector name; std::vector inherits; std::vector entries; }; class ResourceBase { public: virtual uint32_t GetLength(std::shared_ptr embedFS) = 0; virtual void Write(std::shared_ptr output) = 0; virtual ~ResourceBase(); virtual bool IsEqual(ResourceBase *base); }; class ResourceFile : public ResourceBase { std::shared_ptr strm = nullptr; public: ResourceFile(); ResourceFile(std::string file); std::string file; uint32_t GetLength(std::shared_ptr embedFS); void Write(std::shared_ptr output); bool IsEqual(ResourceBase *base); ~ResourceFile(); }; class ResourceByteArray : public ResourceBase { public: std::vector data; uint32_t GetLength(std::shared_ptr embedFS); void Write(std::shared_ptr output); }; class CodeGen { uint32_t id; uint32_t NewId(); void GetFunctionArgs(std::vector &args, SyntaxNode n); void GetFunctionName(std::vector &name, SyntaxNode n); void GetFunctionArgs(std::vector &args, SyntaxNode n); SyntaxNode StringifyListOfVars(SyntaxNode n); uint32_t GetString(std::string str); uint32_t GetResource(std::shared_ptr resource); std::vector strs; std::vector> res; std::vector< std::pair, std::vector>> chunks; std::vector, uint32_t>> funcs; std::vector classes; std::vector> meta; SyntaxNode OptimizeNode(SyntaxNode n); void WriteMetadataObject(std::vector &bytes, SyntaxNode n); void GenNode(std::vector &instructions, SyntaxNode n, int32_t scope, int32_t contscope, int32_t brkscope, int32_t contI, int32_t brkI); void GenPop(std::vector &instrs, SyntaxNode n); public: std::shared_ptr embedFS; std::vector> dependencies; std::vector> tools; TVMVersion version; std::string name; std::string info; std::string icon; void GenRoot(SyntaxNode n); void Save(std::shared_ptr output); ~CodeGen(); }; /** * @brief A html expression * */ constexpr std::string_view HtmlRootExpression = "htmlRootExpression"; /** * @brief an intrinsic function that embeds a resource from the filename based * on the constant string argument * */ constexpr std::string_view EmbedExpression = "embedExpression"; /** * @brief an intrinsic function that embeds a resource as a stream from the * filename based on the constant string argument * */ constexpr std::string_view EmbedStreamExpression = "embedStreamExpression"; /** * @brief an intrinsic function that embeds a resource directory from the * directory name based on the constant string argument * */ constexpr std::string_view EmbedDirectoryExpression = "embedDirectoryExpression"; /** * @brief Negative operator -EXPR * */ constexpr std::string_view NegativeExpression = "negativeExpression"; /** * @brief Not operator !EXPR * */ constexpr std::string_view NotExpression = "notExpression"; /** * @brief Bitwise not operator ~EXPR * */ constexpr std::string_view BitwiseNotExpression = "bitwiseNotExpression"; /** * @brief ++i * */ constexpr std::string_view PrefixIncrementExpression = "prefixIncrementExpression"; /** * @brief --i * */ constexpr std::string_view PrefixDecrementExpression = "prefixDecrementExpression"; /** * @brief i++ * */ constexpr std::string_view PostfixIncrementExpression = "postfixIncrementExpression"; /** * @brief i-- * */ constexpr std::string_view PostfixDecrementExpression = "postfixDecrementExpression"; /** * @brief Gets variable value * */ constexpr std::string_view GetVariableExpression = "getVariableExpression"; /** * @brief Get field or get property (EXPR.getNAME()) (unless it is wrapped in * AssignExpression) which then it sets the field or calls EXPR.setNAME(VALUE) * */ constexpr std::string_view GetFieldExpression = "getFieldExpression"; /** * @brief Syntax sugar for EXPR.GetAt(index) (unless it is wrapped in * AssignExpresion) which then it is EXPR.SetAt(index, VALUE) * */ constexpr std::string_view GetArrayExpression = "getArrayExpression"; /** * @brief Function Call myFn() or MyDict.Fn() * */ constexpr std::string_view FunctionCallExpression = "functionCallExpression"; /** * @brief Used for compound assignment like VAR += EXPR * */ constexpr std::string_view CompoundAssignExpression = "compoundAssignExpression"; /** * @brief Assign something using = * */ constexpr std::string_view AssignExpression = "assignExpression"; /** * @brief A char litteral * */ constexpr std::string_view CharExpression = "charExpression"; /** * @brief The undefined literal * */ constexpr std::string_view UndefinedExpression = "undefinedExpression"; /** * @brief A list of nodes that does create a new scope * */ constexpr std::string_view ScopeNode = "scopeNode"; /** * @brief A list of nodes that doesn't create a new scope * */ constexpr std::string_view NodeList = "nodeList"; /** * @brief Array expresion [1,2,10] * */ constexpr std::string_view ArrayExpression = "arrayExpression"; /** * @brief Dictionary expression { a = 42, b = false} * */ constexpr std::string_view DictionaryExpression = "dictionaryExpression"; /** * @brief var v = 59; * */ constexpr std::string_view DeclareExpression = "declareExpression"; /** * @brief const v = 59; * */ constexpr std::string_view ConstExpression = "constExpression"; /** * @brief Closure expression (a,b)=> a * b * */ constexpr std::string_view ClosureExpression = "closureExpression"; /** * @brief Just like normal closures but doesn't create its own scope * */ constexpr std::string_view ScopelessClosureExpression = "scopelessClosureExpression"; /** * @brief Ternary operator COND ? EXPR : EXPR * */ constexpr std::string_view TernaryExpression = "ternaryExpression"; /** * @brief If statement if(COND) {} else if(COND) {} else {} * */ constexpr std::string_view IfStatement = "ifStatement"; /** * @brief For statement for(var i = 0; i < 42; i++) * */ constexpr std::string_view ForStatement = "forStatement"; /** * @brief While statement while(COND) * */ constexpr std::string_view WhileStatement = "whileStatement"; /** * @brief using statement using(EXPR) * */ constexpr std::string_view UsingStatement = "usingStatement"; /** * @brief Do statement do(COND) * */ constexpr std::string_view DoStatement = "doStatement"; /** * @brief Each statement each(var item : EXPR) * */ constexpr std::string_view EachStatement = "eachStatement"; /** * @brief Return statement return EXPR; * */ constexpr std::string_view ReturnStatement = "returnStatement"; /** * @brief Break statement break; * */ constexpr std::string_view BreakStatement = "breakStatement"; /** * @brief Continue statement continue; * */ constexpr std::string_view ContinueStatement = "continueStatement"; /** * @brief Function statement func main(args) * */ constexpr std::string_view FunctionStatement = "functionStatement"; /** * @brief The documentation statement /^ Documentation ^/ func main(args) {} * */ constexpr std::string_view DocumentationStatement = "documentationStatement"; /** * @brief The comma expression EXPR, EXPR * */ constexpr std::string_view CommaExpression = "commaExpression"; /** * @brief The addition operator EXPR + EXPR * */ constexpr std::string_view AddExpression = "addExpression"; /** * @brief The subtraction operator EXPR - EXPR * */ constexpr std::string_view SubExpression = "subtractExpression"; /** * @brief The times operator EXPR * EXPR * */ constexpr std::string_view TimesExpression = "timesExpression"; /** * @brief The divsion operator EXPR / EXPR * */ constexpr std::string_view DivideExpression = "divideExpression"; /** * @brief The modulo operator (get remainder) EXPR % EXPR * */ constexpr std::string_view ModExpression = "modExpression"; /** * @brief The left shift operator EXPR << EXPR * */ constexpr std::string_view LeftShiftExpression = "leftShiftExpression"; /** * @brief The right shift operator EXPR >> EXPR * */ constexpr std::string_view RightShiftExpression = "rightShiftExpression"; /** * @brief The bitwise or expression EXPR | EXPR * */ constexpr std::string_view BitwiseOrExpression = "bitwiseOrExpression"; /** * @brief The bitwise and expression EXPR & EXPR * */ constexpr std::string_view BitwiseAndExpression = "bitwiseAndExpression"; /** * @brief The xor expression EXPR ^ EXPR * */ constexpr std::string_view XOrExpression = "xOrExpression"; /** * @brief The logical or expression EXPR || EXPR * */ constexpr std::string_view LogicalOrExpression = "logicalOrExpression"; /** * @brief The logical and expression EXPR && EXPR * */ constexpr std::string_view LogicalAndExpression = "logicalAndExpression"; /** * @brief The equals expression EXPR == EXPR * */ constexpr std::string_view EqualsExpression = "equalsExpression"; /** * @brief The not equals expression EXPR != EXPR * */ constexpr std::string_view NotEqualsExpression = "notEqualsExpression"; /** * @brief The less than expression EXPR < EXPR * */ constexpr std::string_view LessThanExpression = "lessThanExpression"; /** * @brief The greater than expression EXPR > EXPR * */ constexpr std::string_view GreaterThanExpression = "greaterThanExpression"; /** * @brief The less than equals expression EXPR <= EXPR * */ constexpr std::string_view LessThanEqualsExpression = "lessThanEqualsExpression"; /** * @brief The greater than equals expression EXPR >= EXPR * */ constexpr std::string_view GreaterThanEqualsExpression = "greaterThanEqualsExpression"; /** * @brief The parentheses expression (expression) * */ constexpr std::string_view ParenthesesExpression = "parenthesesExpression"; /** * @brief The throw statement * */ constexpr std::string_view ThrowStatement = "throwStatement"; /** * @brief The breakpoint statement */ constexpr std::string_view BreakpointStatement = "breakpointStatement"; /** * @brief The try statement * */ constexpr std::string_view TryStatement = "tryStatement"; /** * @brief The defer statement * */ constexpr std::string_view DeferStatement = "deferStatement"; /** * @brief The defer statement * */ constexpr std::string_view YieldStatement = "yieldStatement"; /** * @brief The enumerable statement * */ constexpr std::string_view EnumerableStatement = "enumerableStatement"; /** * @brief The switch statement * */ constexpr std::string_view SwitchStatement = "switchStatement"; /** * @brief Case clause of switch statement * */ constexpr std::string_view CaseStatement = "caseStatement"; /** * @brief Default clause of switch statement * */ constexpr std::string_view DefaultStatement = "defaultStatement"; /** * @brief Class statement (not implemented) * */ constexpr std::string_view ClassStatement = "classStatement"; /** * @brief Method statement (in class statement) * */ constexpr std::string_view MethodStatement = "methodStatement"; /** * @brief Abstract method statement (in class statement) * */ constexpr std::string_view AbstractMethodStatement = "abstractMethodStatement"; /** * @brief Field statement (in class statement) * */ constexpr std::string_view FieldStatement = "fieldStatement"; /** * @brief Root path expression / "path" / "to" / "file" (fullfils the first /) * */ constexpr std::string_view RootPathExpression = "rootPathExpression"; /** * @brief The relative path expression ./ "path" / "to" / "subdir" (fullfills * the ./) * */ constexpr std::string_view RelativePathExpression = "relativePathExpression"; /** * @brief await expression for async/await */ constexpr std::string_view AwaitExpression = "awaitExpression"; /** * @brief ?? operator */ constexpr std::string_view NullCoalescingExpression = "nullCoalescingExpression"; /** * @brief For debugging (store line info and filename) */ constexpr std::string_view LineNode = "lineNode"; /** * @brief For storing generic metadata */ constexpr std::string_view MetadataStatement = "MetadataStatement"; /** * @brief For storing private data (isolated to specific crvm file) */ constexpr std::string_view GetPrivateExpression = "getPrivateExpression"; /** * @brief Advanced AST node * */ class AdvancedSyntaxNode { public: /** * @brief The name of the advanced AST node * */ std::string nodeName; /** * @brief The advanced syntax node is an expression * */ bool isExpression; /** * @brief The subnodes of the abstract syntax node * */ std::vector nodes; /** * @brief Create abstract syntax node * * @param nodeName The name of the advanced AST node * @param isExpression The advanced syntax node is an expression * @param n The subnodes of the abstract syntax node * @return AdvancedSyntaxNode The AST node */ static AdvancedSyntaxNode Create(std::string_view nodeName, bool isExpression, std::vector n); }; SyntaxNode Deserialize(std::string astData); std::string Serialize(SyntaxNode node); class GC; class TRootEnvironment; /** * @brief Token Parser * */ class Parser { uint32_t id; uint32_t NewId(); uint64_t i; std::vector tokens; LexToken tkn; void EnsureSymbol(std::string txt); bool IsIdentifier(std::string txt, bool pop = true); bool IsAnyIdentifier(std::initializer_list idents, bool pop = true); bool IsSymbol(std::string txt, bool pop = true); bool IsAnySymbol(std::initializer_list 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(); SyntaxNode ParseNullCoalescing(); void ParseHtml(std::vector &nodes, std::string var); std::shared_ptr gc; TRootEnvironment *env; int lastLine = -1; std::string lastFile = ""; bool CanEmit(LexTokenLineInfo &token); public: bool debug = true; /** * @brief Construct a new Parser object * * @param tokens the tokens from lexer */ Parser(std::vector tokens); Parser(std::vector tokens, std::shared_ptr gc, TRootEnvironment *env); /** * @brief Turn tokens into abstract syntax tree * * @return SyntaxNode the abstract syntax tree */ 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 is a dummy type with class MethodInvoker {}; class TBreak {}; class TContinue {}; /** * @brief A script object * */ using TObject = std::variant, std::shared_ptr, TBreak, TContinue, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr, Tesses::Framework::Uuid>; class TRootEnvironment; class GC : public std::enable_shared_from_this { Tesses::Framework::Threading::Thread *thrd; Tesses::Framework::Threading::Mutex *mtx; volatile std::atomic running; std::vector roots; std::vector objects; Tesses::Framework::Lazy *tpool; std::vector< std::function gc, TRootEnvironment *env)>> register_everything; public: Tesses::Framework::Threading::ThreadPool *GetPool(); 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); void RegisterEverythingCallback( std::function gc, TRootEnvironment *env)> cb); void RegisterEverything(TRootEnvironment *env); ~GC(); }; std::string GetObjectTypeString(TObject obj); std::string ToString(std::shared_ptr gc, TObject obj); class GCList : public THeapObject { std::vector items; std::shared_ptr gc; public: GCList(std::shared_ptr gc); std::shared_ptr GetGC(); void Add(TObject v); void Remove(TObject v); void Mark(); ~GCList(); friend class GC; }; class TFile; class TFileChunk : public THeapObject { public: static TFileChunk *Create(GCList *gc); static TFileChunk *Create(GCList &gc); TFile *file; std::vector code; std::vector args; std::optional name; void Mark(); }; class TByteArray : public THeapObject { public: std::vector data; static TByteArray *Create(GCList *gc); static TByteArray *Create(GCList &gc); }; enum class TClassModifier { Private, Protected, Public, Static }; class TClassEntry { public: TClassModifier modifier; bool isFunction; bool isAbstract; std::vector args; std::string documentation; std::string name; uint32_t chunkId; }; class TClass { public: std::string documentation; std::vector name; std::vector inherits; std::vector entry; }; class TClassObjectEntry { public: TClassModifier modifier; bool canSet; std::string name; std::string owner; TObject value; }; class TDictionary; class TFile : public THeapObject { public: static TFile *Create(GCList *gc); static TFile *Create(GCList &gc); std::vector chunks; std::vector strings; std::vector> vms; std::vector, uint32_t>> functions; std::vector> dependencies; std::vector> tools; std::vector>> sections; std::vector>> metadata; std::vector> resources; std::vector classes; std::string name; TVMVersion version; std::string info; int32_t icon; void Load(std::shared_ptr gc, std::shared_ptr strm); void Skip(std::shared_ptr strm, size_t len); void Ensure(std::shared_ptr strm, uint8_t *buffer, size_t len); uint32_t EnsureInt(std::shared_ptr strm); std::string EnsureString(std::shared_ptr strm); std::string GetString(std::shared_ptr strm); void Mark(); void EnsureCanRunInCrossLang(); TDictionary *MetadataDecode(GCList &ls, size_t index); }; class TAssociativeArray : public THeapObject { public: std::vector> items; static TAssociativeArray *Create(GCList &ls); static TAssociativeArray *Create(GCList *ls); void Set(std::shared_ptr gc, TObject key, TObject value); TObject Get(std::shared_ptr gc, TObject key); TObject GetKey(int64_t index); TObject GetValue(int64_t index); void SetKey(int64_t index, TObject key); void SetValue(int64_t index, TObject value); int64_t Count(); void Mark(); }; class TList : public THeapObject { public: std::vector items; static TList *Create(GCList *gc); static TList *Create(GCList &gc); template static TList *Create(GCList *gc, Itterator begin, Itterator end) { auto list = Create(gc); gc->GetGC()->BarrierBegin(); for (Itterator i = begin; i != end; ++i) { TObject item = *i; list->Add(item); } gc->GetGC()->BarrierEnd(); return list; } template static TList *Create(GCList &gc, Itterator begin, Itterator end) { return Create(&gc, begin, end); } static TList *Create(GCList *gc, std::initializer_list il) { return Create(gc, il.begin(), il.end()); } static TList *Create(GCList &gc, std::initializer_list il) { return Create(gc, il.begin(), il.end()); } 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(); }; using TDItem = std::pair; class TDictionary : public THeapObject { public: std::map items; static TDictionary *Create(GCList *gc); static TDictionary *Create(GCList &gc); template static TDictionary *Create(GCList *gc, Itterator begin, Itterator end) { auto dict = Create(gc); gc->GetGC()->BarrierBegin(); for (Itterator i = begin; i != end; ++i) { TDItem item = *i; dict->SetValue(item.first, item.second); } gc->GetGC()->BarrierEnd(); return dict; } template static TDictionary *Create(GCList &gc, Itterator begin, Itterator end) { return Create(&gc, begin, end); } static TDictionary *Create(GCList *gc, std::initializer_list il) { return Create(gc, il.begin(), il.end()); } static TDictionary *Create(GCList &gc, std::initializer_list il) { return Create(gc, il.begin(), il.end()); } virtual bool HasValue(std::string key); virtual bool MethodExists(GCList &ls, std::string key); virtual TObject GetValue(std::string key); virtual void SetValue(std::string key, TObject value); virtual void Mark(); void DeclareFunction( std::shared_ptr gc, std::string key, std::string documentation, std::vector argNames, std::function args)> cb); void DeclareFunction( std::shared_ptr gc, std::string key, std::string documentation, std::vector argNames, std::function args)> cb, std::function destroy); TObject CallMethod(GCList &ls, std::string key, std::vector args); TObject CallMethodWithFatalError(GCList &ls, std::string key, std::vector args); }; class TRootEnvironment; class TSubEnvironment; class TCallable : public THeapObject { public: TObject tag; std::string documentation; virtual TObject Call(GCList &ls, std::vector args) = 0; TObject CallWithFatalError(GCList &ls, std::vector args); virtual void Mark(); Tesses::Framework::Http::ServerRequestHandler ToRouteServerRequestHandler(std::shared_ptr gc); }; void ThrowFatalError(std::exception &ex); void ThrowConstError(std::string key); class TEnvironment : public THeapObject { std::vector consts; public: std::vector defers; TObject LoadFile(std::shared_ptr 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 bool HasVariableOrFieldRecurse(std::string key, bool setting = false) = 0; virtual TObject GetVariable(std::string key) = 0; virtual TObject GetVariable(GCList &ls, std::string key) = 0; virtual TObject SetVariable(GCList &ls, std::string key, TObject v) = 0; virtual void SetVariable(std::string key, TObject value) = 0; TDictionary *EnsureDictionary(std::shared_ptr gc, std::string key); virtual void DeclareVariable(std::string key, TObject value) = 0; void DeclareConstVariable(std::string key, TObject value); bool HasConstForDeclare(std::string key); virtual bool HasConstForSet(std::string key); void DeclareVariable(std::shared_ptr gc, std::vector key, TObject value); virtual TRootEnvironment *GetRootEnvironment() = 0; virtual TEnvironment *GetParentEnvironment() = 0; virtual TSubEnvironment *GetSubEnvironment(TDictionary *dict); TSubEnvironment *GetSubEnvironment(GCList *gc); TSubEnvironment *GetSubEnvironment(GCList &gc); void DeclareFunction( std::shared_ptr gc, std::string key, std::string documentation, std::vector argNames, std::function args)> cb); void DeclareFunction( std::shared_ptr gc, std::string key, std::string documentation, std::vector argNames, std::function args)> cb, std::function destroy); TObject CallFunction(GCList &ls, std::string key, std::vector args); TObject CallFunctionWithFatalError(GCList &ls, std::string key, std::vector args); }; class TClassEnvironment; class TClassObject : public THeapObject { TClassObjectEntry *GetEntry(std::string classN, std::string key); public: TFile *file; uint32_t classIndex; TEnvironment *ogEnv; TClassEnvironment *env; std::string name; std::vector inherit_tree; std::vector entries; static TClassObject *Create(GCList &ls, TFile *f, uint32_t classIndex, TEnvironment *env, std::vector args); static TClassObject *Create(GCList *ls, TFile *f, uint32_t classIndex, TEnvironment *env, std::vector args); TObject GetValue(std::string className, std::string name); void SetValue(std::string className, std::string name, TObject value); bool HasValue(std::string className, std::string name); bool HasField(std::string className, std::string name); bool HasMethod(std::string className, std::string name); TObject CallMethod(GCList &ls, std::string className, std::string name, std::vector args); std::string TypeName(); void Mark(); }; class TClassEnvironment : public TEnvironment { TEnvironment *env; TClassObject *clsObj; public: static TClassEnvironment *Create(GCList *gc, TEnvironment *env, TClassObject *obj); static TClassEnvironment *Create(GCList &gc, TEnvironment *env, TClassObject *obj); TClassEnvironment(TEnvironment *env, TClassObject *obj); bool HasVariable(std::string key); bool HasVariableRecurse(std::string key); bool HasVariableOrFieldRecurse(std::string key, bool setting = false); TObject GetVariable(std::string key); void SetVariable(std::string key, TObject value); TObject GetVariable(GCList &ls, std::string key); TObject SetVariable(GCList &ls, std::string key, TObject v); void DeclareVariable(std::string key, TObject value); bool HasConstForSet(std::string key); TRootEnvironment *GetRootEnvironment(); TEnvironment *GetParentEnvironment(); void Mark(); }; class EnvironmentPermissions { public: EnvironmentPermissions(); Tesses::Framework::Filesystem::VFSPath sqliteOffsetPath; std::shared_ptr localfs; bool canRegisterEverything; bool canRegisterConsole; bool canRegisterIO; bool canRegisterNet; bool canRegisterSqlite; bool canRegisterVM; bool canRegisterDictionary; bool canRegisterJSON; bool canRegisterCrypto; bool canRegisterRoot; bool canRegisterProcess; bool canRegisterPath; bool canRegisterOGC; bool canRegisterEnv; bool canRegisterClass; bool sqlite3Scoped; bool locked; TDictionary *customConsole = nullptr; }; class TRootEnvironment : public TEnvironment { TDictionary *dict; TCallable *error = nullptr; std::map private_file_data; void LoadDependency(std::shared_ptr gc, std::shared_ptr vfs, std::pair dep); public: EnvironmentPermissions permissions; std::vector> dependencies; std::vector> classes; TDictionary *GetPrivateFromFile(std::shared_ptr gc, TFile *file); bool TryFindClass(std::vector &name, size_t &index); void LoadFileWithDependencies( std::shared_ptr gc, std::shared_ptr vfs, TFile *f); void LoadFileWithDependencies( std::shared_ptr gc, std::shared_ptr 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); bool HasVariableOrFieldRecurse(std::string key, bool setting = false); TObject GetVariable(std::string key); void SetVariable(std::string key, TObject value); TObject GetVariable(GCList &ls, std::string key); TObject SetVariable(GCList &ls, std::string key, TObject v); void DeclareVariable(std::string key, TObject value); TRootEnvironment *GetRootEnvironment(); TEnvironment *GetParentEnvironment(); void RegisterOnError(TCallable *callable); bool HandleException(std::shared_ptr gc, TEnvironment *env, TObject err); bool HandleBreakpoint(std::shared_ptr gc, TEnvironment *env, TObject err); void Mark(); }; class TStd { private: static void RegisterHelpers(std::shared_ptr gc, TRootEnvironment *env); static void RegisterUuid(std::shared_ptr gc, TRootEnvironment *env); public: static void RegisterStd( std::shared_ptr gc, TRootEnvironment *env, std::shared_ptr localfs); static void RegisterStd(std::shared_ptr gc, TRootEnvironment *env); static void RegisterConsole(std::shared_ptr gc, TRootEnvironment *env); static void RegisterIO( std::shared_ptr gc, TRootEnvironment *env, std::shared_ptr local); static void RegisterIO(std::shared_ptr gc, TRootEnvironment *env, bool enableLocalFS = true); static void RegisterNet(std::shared_ptr gc, TRootEnvironment *env); static void RegisterSqlite(std::shared_ptr gc, TRootEnvironment *env); static void RegisterVM(std::shared_ptr gc, TRootEnvironment *env); static void RegisterDictionary(std::shared_ptr gc, TRootEnvironment *env); static void RegisterJson(std::shared_ptr gc, TRootEnvironment *env); static void RegisterCrypto(std::shared_ptr gc, TRootEnvironment *env); static void RegisterRoot(std::shared_ptr gc, TRootEnvironment *env); static void RegisterPath(std::shared_ptr gc, TRootEnvironment *env); static void RegisterOGC(std::shared_ptr gc, TRootEnvironment *env); static void RegisterEnv(std::shared_ptr gc, TRootEnvironment *env); static void RegisterProcess(std::shared_ptr gc, TRootEnvironment *env); static void RegisterClass(std::shared_ptr 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); bool HasVariableOrFieldRecurse(std::string key, bool setting = false); bool HasConstForSet(std::string key); TObject GetVariable(std::string key); void SetVariable(std::string key, TObject value); TObject GetVariable(GCList &ls, std::string key); TObject SetVariable(GCList &ls, std::string key, TObject v); void DeclareVariable(std::string key, TObject value); TRootEnvironment *GetRootEnvironment(); TEnvironment *GetParentEnvironment(); TDictionary *GetDictionary(); 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 args); void Mark(); }; class TExternalMethod : public TCallable { std::function args)> cb; std::function destroy; public: std::vector args; std::vector watch; TExternalMethod( std::function args)> cb, std::string documentation, std::vector argNames, std::function destroy); static TExternalMethod * Create(GCList &ls, std::string documentation, std::vector argNames, std::function args)> cb, std::function destroy); static TExternalMethod * Create(GCList *ls, std::string documentation, std::vector argNames, std::function args)> cb, std::function destroy); static TExternalMethod * Create(GCList &ls, std::string documentation, std::vector argNames, std::function args)> cb); static TExternalMethod * Create(GCList *ls, std::string documentation, std::vector argNames, std::function args)> cb); TObject Call(GCList &ls, std::vector args); ~TExternalMethod(); void Mark() { if (this->marked) return; this->marked = true; for (auto item : watch) GC::Mark(item); GC::Mark(this->tag); } }; class TEnumerator : public THeapObject { public: virtual bool MoveNext(std::shared_ptr ls) = 0; virtual TObject GetCurrent(GCList &ls) = 0; static TEnumerator *CreateFromObject(GCList &ls, TObject obj); }; class TAssociativeArrayEnumerator : public TEnumerator { int64_t index; TAssociativeArray *ls; public: static TAssociativeArrayEnumerator *Create(GCList &ls, TAssociativeArray *list); static TAssociativeArrayEnumerator *Create(GCList *ls, TAssociativeArray *list); bool MoveNext(std::shared_ptr ls); TObject GetCurrent(GCList &ls); void Mark(); }; class TCustomEnumerator : public TEnumerator { public: TDictionary *dict; bool MoveNext(std::shared_ptr ls); TObject GetCurrent(GCList &ls); void Mark(); static TCustomEnumerator *Create(GCList &ls, TDictionary *dict); static TCustomEnumerator *Create(GCList *ls, TDictionary *dict); }; class TYieldEnumerator : public TEnumerator { bool hasStarted; TObject enumerator; TObject current; public: bool MoveNext(std::shared_ptr ls); TObject GetCurrent(GCList &ls); void Mark(); static TYieldEnumerator *Create(GCList &ls, TObject v); static TYieldEnumerator *Create(GCList *ls, TObject v); }; 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(std::shared_ptr 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(std::shared_ptr ls); TObject GetCurrent(GCList &ls); void Mark(); }; class TDynamicList; class TDynamicDictionary; class TDynamicListEnumerator : public TEnumerator { int64_t index; TDynamicList *ls; public: static TDynamicListEnumerator *Create(GCList &ls, TDynamicList *list); static TDynamicListEnumerator *Create(GCList *ls, TDynamicList *list); bool MoveNext(std::shared_ptr 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(std::shared_ptr ls); TObject GetCurrent(GCList &ls); }; class TObjectVFS : public Tesses::Framework::Filesystem::VFS { public: TObject obj; GCList *ls; TObjectVFS(std::shared_ptr gc, TObject obj); std::shared_ptr OpenFile(Tesses::Framework::Filesystem::VFSPath path, std::string mode); Tesses::Framework::Filesystem::FIFOCreationResult CreateFIFO(Tesses::Framework::Filesystem::VFSPath path); void CreateDirectory(Tesses::Framework::Filesystem::VFSPath path); void DeleteDirectory(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); void DeleteFile(Tesses::Framework::Filesystem::VFSPath path); void Lock(Tesses::Framework::Filesystem::VFSPath path); void Unlock(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 SetDate(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Date::DateTime lastWrite, Tesses::Framework::Date::DateTime lastAccess); void Chmod(Tesses::Framework::Filesystem::VFSPath path, uint32_t mode); void Chown(Tesses::Framework::Filesystem::VFSPath path, uint32_t uid, uint32_t gid); bool StatVFS(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Filesystem::StatVFSData &data); bool Stat(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Filesystem::StatData &data); void Close(); ~TObjectVFS(); }; class TObjectStream : public Tesses::Framework::Streams::Stream { int64_t _GetPosInternal(); public: TObject obj; GCList *ls; TObjectStream(std::shared_ptr 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); void Close(); ~TObjectStream(); }; class TObjectHttpServer : public Tesses::Framework::Http::IHttpServer { public: TObject obj; GCList *ls; TObjectHttpServer(std::shared_ptr gc, TObject obj); bool Handle(Tesses::Framework::Http::ServerContext &ctx); ~TObjectHttpServer(); }; class TDictionaryEnumerator : public TEnumerator { bool hasStarted; std::map::iterator ittr; TDictionary *dict; public: static TDictionaryEnumerator *Create(GCList &ls, TDictionary *dict); static TDictionaryEnumerator *Create(GCList *ls, TDictionary *dict); bool MoveNext(std::shared_ptr 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; std::string className; TObject Call(GCList &ls, std::vector args); void Mark(); }; class TDynamicList : public THeapObject { public: TCallable *cb; static TDynamicList *Create(GCList &ls, TCallable *callable); static TDynamicList *Create(GCList *ls, TCallable *callable); void Mark(); int64_t Count(GCList &ls); TObject GetAt(GCList &ls, int64_t index); TObject SetAt(GCList &ls, int64_t index, TObject val); TObject Add(GCList &ls, TObject v); TObject Insert(GCList &ls, int64_t index, TObject v); TObject RemoveAllEqual(GCList &ls, TObject v); TObject Remove(GCList &ls, TObject v); TObject RemoveAt(GCList &ls, int64_t v); TObject Clear(GCList &ls); TObject ToString(GCList &ls); ~TDynamicList(); }; class TDynamicDictionary : public THeapObject { public: TCallable *cb; static TDynamicDictionary *Create(GCList &ls, TCallable *callable); static TDynamicDictionary *Create(GCList *ls, TCallable *callable); void Mark(); TObject GetField(GCList &ls, std::string key); TObject SetField(GCList &ls, std::string key, TObject value); TObject CallMethod(GCList &ls, std::string name, std::vector args); bool MethodExists(GCList &ls, std::string name); TEnumerator *GetEnumerator(GCList &ls); ~TDynamicDictionary(); }; class InterperterThread; class CallStackEntry : public THeapObject { public: static CallStackEntry *Create(GCList *ls); static CallStackEntry *Create(GCList &ls); InterperterThread *thread; std::vector stack; TEnvironment *env; TClosure *callable; uint32_t ip; uint32_t scopes; int64_t srcline; std::string srcfile; bool mustReturn; void Mark(); void Push(std::shared_ptr gc, TObject v); TObject Pop(GCList &gcl); TObject Resume(GCList &ls); }; class TTask : public THeapObject { TCallable *cont = nullptr; std::exception_ptr ex = nullptr; std::shared_ptr gc; TObject obj = Undefined(); bool isCompleted = false; TTask(std::shared_ptr gc); public: static TTask *Create(GCList &ls); bool IsCompleted(); void ContinueWith(TCallable *callable); TTask *ContinueWith(GCList &ls, TCallable *callable); void SetFailed(std::exception_ptr ex); void SetSucceeded(TObject v); TObject Wait(); void Mark(); static TTask *FromClosure(GCList &ls, TClosure *closure); static TTask *FromCallStackEntry(GCList &ls, CallStackEntry *ent); static TTask *Run(GCList &ls, TCallable *callable); static TTask *FromResult(GCList &ls, TObject v); }; 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 args); bool ExecuteMethod2(std::shared_ptr gc, TObject instance, std::string key, std::vector args); protected: static void *ThreadCallback(void *ptr); bool JumpIfDefined(std::shared_ptr gc); bool Add(std::shared_ptr gc); bool Sub(std::shared_ptr gc); bool Times(std::shared_ptr gc); bool Divide(std::shared_ptr gc); bool Mod(std::shared_ptr gc); bool Neg(std::shared_ptr gc); bool Lt(std::shared_ptr gc); bool Gt(std::shared_ptr gc); bool Lte(std::shared_ptr gc); bool Gte(std::shared_ptr gc); bool Eq(std::shared_ptr gc); bool NEq(std::shared_ptr gc); bool LShift(std::shared_ptr gc); bool RShift(std::shared_ptr gc); bool BOr(std::shared_ptr gc); bool XOr(std::shared_ptr gc); bool LNot(std::shared_ptr gc); bool BNot(std::shared_ptr gc); bool BAnd(std::shared_ptr gc); bool ExecuteFunction(std::shared_ptr gc); bool ExecuteMethod(std::shared_ptr gc); bool GetVariable(std::shared_ptr gc); bool SetVariable(std::shared_ptr gc); bool GetField(std::shared_ptr gc); bool SetField(std::shared_ptr gc); bool GetArray(std::shared_ptr gc); bool SetArray(std::shared_ptr gc); bool DeclareVariable(std::shared_ptr gc); bool DeclareConstVariable(std::shared_ptr gc); bool PushLong(std::shared_ptr gc); bool PushDouble(std::shared_ptr gc); bool PushChar(std::shared_ptr gc); bool PushString(std::shared_ptr gc); bool PushClosure(std::shared_ptr gc); bool PushScopelessClosure(std::shared_ptr gc); bool PushResource(std::shared_ptr gc); bool Illegal(std::shared_ptr gc); bool Throw(std::shared_ptr gc); bool Yield(std::shared_ptr gc); bool Jump(std::shared_ptr gc); bool JumpConditional(std::shared_ptr gc); bool JumpUndefined(std::shared_ptr gc); bool Defer(std::shared_ptr gc); bool TryCatch(std::shared_ptr gc); bool Return(std::shared_ptr gc); bool ScopeBegin(std::shared_ptr gc); bool ScopeEnd(std::shared_ptr gc); bool ScopeEndTimes(std::shared_ptr gc); bool PushTrue(std::shared_ptr gc); bool PushFalse(std::shared_ptr gc); bool PushNull(std::shared_ptr gc); bool PushUndefined(std::shared_ptr gc); bool CreateDictionary(std::shared_ptr gc); bool CreateArray(std::shared_ptr gc); bool AppendList(std::shared_ptr gc); bool AppendDictionary(std::shared_ptr gc); bool PushRootPath(std::shared_ptr gc); bool PushRelativePath(std::shared_ptr gc); bool Pop(std::shared_ptr gc); bool Dup(std::shared_ptr gc); bool Nop(std::shared_ptr gc); bool Breakpoint(std::shared_ptr gc); bool PushBreak(std::shared_ptr gc); bool PushContinue(std::shared_ptr gc); bool JumpIfBreak(std::shared_ptr gc); bool JumpIfContinue(std::shared_ptr gc); bool LineInfo(std::shared_ptr gc); bool PushResourceStream(std::shared_ptr gc); bool PushResourceDirectory(std::shared_ptr gc); bool PushPrivateExpression(std::shared_ptr gc); public: static InterperterThread *Create(GCList *ls); static InterperterThread *Create(GCList &ls); std::vector call_stack_entries; virtual void Execute(std::shared_ptr gc); void AddCallStackEntry(GCList &ls, TClosure *closure, std::vector 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 TAny : public THeapObject { public: std::any any; TObject other; static TAny *Create(GCList &ls); static TAny *Create(GCList *ls); void Mark(); }; class TNativeObject : public THeapObject { public: template static T *Create(GCList &ls, TArgs... args) { T *obj = new T(args...); std::shared_ptr gc = ls.GetGC(); ls.Add(obj); gc->Watch(obj); return obj; } template static T *Create(GCList *ls, TArgs... args) { T *obj = new T(args...); std::shared_ptr gc = ls->GetGC(); ls->Add(obj); gc->Watch(obj); return obj; } virtual TObject CallMethod(GCList &ls, std::string name, std::vector args) = 0; virtual std::string TypeName() = 0; virtual bool ToBool(); virtual bool Equals(std::shared_ptr gc, TObject right); virtual ~TNativeObject(); }; class TRandom : public TNativeObject { public: Tesses::Framework::Random random; TRandom(); TRandom(uint64_t seed); std::string TypeName(); TObject CallMethod(GCList &ls, std::string name, std::vector args); }; class TNative : public THeapObject { std::atomic destroyed; void *ptr; std::function destroy; public: TObject other; TNative(void *ptr, std::function destroy); bool GetDestroyed(); void *GetPointer(); void Destroy(); void Mark(); static TNative *Create(GCList &ls, void *ptr, std::function destroy); static TNative *Create(GCList *ls, void *ptr, std::function destroy); ~TNative(); }; class ThreadHandle : public THeapObject { public: Tesses::Framework::Threading::Thread *thrd; std::atomic hasInit; std::atomic hasReturned; std::atomic detached; TCallable *callable; TObject returnValue; std::shared_ptr 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 args); class VMByteCodeException : public std::exception { std::string lastErrorText; std::shared_ptr gcList; public: TObject exception; std::vector stack_trace; VMByteCodeException() {} VMByteCodeException(std::shared_ptr gc, TObject obj, CallStackEntry *ent) { gcList = std::make_shared(gc); gcList->Add(obj); if (ent != nullptr && ent->thread != nullptr) { this->stack_trace = ent->thread->call_stack_entries; for (auto item : this->stack_trace) gcList->Add(item); } this->exception = obj; UpdateError(); } void UpdateError() { lastErrorText = ToString(gcList->GetGC(), exception); } const char *what() const noexcept override { return lastErrorText.c_str(); } std::shared_ptr GetGCList() { return this->gcList; } }; class SyntaxException : public std::exception { std::string msg = {}; LexTokenLineInfo line; std::string message; public: SyntaxException(LexTokenLineInfo lineInfo, std::string message) : line(lineInfo), message(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(); } std::string Message() { return message; } LexTokenLineInfo LineInfo() { return line; } }; template bool GetObject(TObject &obj, T &res) { if (!std::holds_alternative(obj)) return false; res = std::get(obj); return true; } template bool GetArgument(std::vector &args, size_t index, T &obj) { if (index >= args.size()) return false; return GetObject(args[index], obj); } template bool GetObjectHeap(TObject &obj, T &res) { THeapObjectHolder h; if (!GetObject(obj, h)) return false; auto v = dynamic_cast(h.obj); if (v == nullptr) return false; res = v; return true; } template bool GetArgumentHeap(std::vector &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 &args, size_t index, Tesses::Framework::Filesystem::VFSPath &path, bool allowString = true); bool ToBool(TObject obj); bool Equals(std::shared_ptr gc, TObject left, TObject right); typedef void (*PluginFunction)(std::shared_ptr gc, TRootEnvironment *env); #if !defined(_WIN32) #define DLLEXPORT #else #define DLLEXPORT __declspec(dllexport) #endif #define CROSSLANG_PLUGIN(plugin) \ DLLEXPORT extern "C" void CrossLangPluginInit(std::shared_ptr gc, \ TRootEnvironment *env) { \ plugin(gc, env); \ } void LoadPlugin(std::shared_ptr gc, TRootEnvironment *env, Tesses::Framework::Filesystem::VFSPath sharedObjectPath); std::string Json_Encode(TObject o, bool indent = false); TObject Json_Decode(GCList ls, std::string str); std::string Json_DocEncode(TObject o, bool indent); TObject Json_DocDecode(GCList ls, std::string str); // DO NOT USE DIRECTLY class SharedPtrTObject { GCList *ls; TObject o; public: SharedPtrTObject(std::shared_ptr gc, TObject o); TObject &GetObject(); std::shared_ptr GetGC(); ~SharedPtrTObject(); }; using MarkedTObject = std::shared_ptr; MarkedTObject CreateMarkedTObject(std::shared_ptr gc, TObject o); MarkedTObject CreateMarkedTObject(GCList *gc, TObject o); MarkedTObject CreateMarkedTObject(GCList &gc, TObject o); std::string JoinPeriod(std::vector &p); TObject GetClassInfo(GCList &ls, TFile *f, uint32_t index); extern Tesses::Framework::Filesystem::VFSPath CrossLangConfigPath; std::shared_ptr ToHttpServer(std::shared_ptr gc, TObject obj); class EmbedStream : public Tesses::Framework::Streams::Stream { size_t offset; MarkedTObject file; uint32_t resource; public: EmbedStream(std::shared_ptr gc, TFile *file, uint32_t resource); bool CanRead(); bool CanSeek(); bool EndOfStream(); size_t Read(uint8_t *buff, size_t len); int64_t GetPosition(); int64_t GetLength(); void Seek(int64_t pos, Tesses::Framework::Streams::SeekOrigin whence); }; class EmbedDirectory : public Tesses::Framework::Filesystem::VFS { MarkedTObject dir; TObject getEntry(Tesses::Framework::Filesystem::VFSPath path); public: EmbedDirectory(std::shared_ptr gc, TDictionary *dict); std::shared_ptr OpenFile(Tesses::Framework::Filesystem::VFSPath path, std::string mode); Tesses::Framework::Filesystem::VFSPathEnumerator EnumeratePaths(Tesses::Framework::Filesystem::VFSPath path); std::string VFSPathToSystem(Tesses::Framework::Filesystem::VFSPath path); Tesses::Framework::Filesystem::VFSPath SystemToVFSPath(std::string path); bool Stat(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Filesystem::StatData &data); }; namespace Programs { int64_t CrossArchiveCreate(std::vector &argv); int64_t CrossArchiveExtract(std::vector &argv); TObject CrossLangInterperter(GCList &ls, TRootEnvironment *env, std::vector &argv); TObject CrossLangShell(GCList &ls, std::vector &argv); TObject CrossLangVM(GCList &ls, TRootEnvironment *env, std::vector &argv); void CrossLangDump(std::shared_ptr strm); void CrossLangCompiler(std::vector &argv); } // namespace Programs enum class TQueryableMode { Passthrough, Skip, SkipWhile, Take, TakeWhile, Select, Where }; class TQueryable : public THeapObject { TObject parent; TQueryableMode mode; std::vector args; TQueryable(TObject parent); TQueryable(TObject parent, TQueryableMode mode, std::vector args); public: static TQueryable *Create(GCList &ls, TObject parent); static TQueryable *Create(GCList &ls, TObject parent, TQueryableMode mode, std::vector args); TQueryable *Skip(GCList &ls, int64_t no); TQueryable *SkipWhile(GCList &ls, TCallable *call); TQueryable *Take(GCList &ls, int64_t no); TQueryable *TakeWhile(GCList &ls, TCallable *call); TQueryable *Select(GCList &ls, TCallable *call); TQueryable *Where(GCList &ls, TCallable *call); void ForEach(std::shared_ptr gc, TCallable *call); int64_t Count(std::shared_ptr gc, TCallable *call); int64_t Count(std::shared_ptr gc); bool Contains(std::shared_ptr, TObject value); bool Any(std::shared_ptr gc, TCallable *call); bool All(std::shared_ptr gc, TCallable *call); TList *ToList(GCList &ls); TEnumerator *GetEnumerator(GCList &ls); void Mark(); }; }; // namespace Tesses::CrossLang