commit a2205a44f129c52caf8fda2d6fb72f8ebea7970e Author: Mike Nolan Date: Fri Jan 23 05:20:23 2026 -0600 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2661122 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,34 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/bcrossc", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] + } + + + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..43e3d85 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.16) + + +project(BetterCrossLangCompiler) + +find_package(TessesCrossLang REQUIRED) + +add_executable(bcrossc + src/bcrossc.cpp + src/node.cpp + src/parser.cpp +) + +target_link_libraries(bcrossc PUBLIC TessesCrossLang::crosslang_shared) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..874f8d4 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +I AM STILL WORKING ON THIS, +DON'T CLONE \ No newline at end of file diff --git a/result.json b/result.json new file mode 100644 index 0000000..e69de29 diff --git a/sourceCode.btcross b/sourceCode.btcross new file mode 100644 index 0000000..faac5b4 --- /dev/null +++ b/sourceCode.btcross @@ -0,0 +1,120 @@ +/*var mylist : List?; +var str : String = "My Text" + "is" + "Demi Lovato"; +var myLs : List>?; +var nl : Char = '\n'; + +delegate Action(a: T); +delegate Func(a: T): TResult; + +var a = 42; +var p : Path = ""; + + + + +func main(args: List): Long +{ + + return 42; +} + +func times(a: T, b: T, typ: Type): T +{ + return a * b; +} +/^ + my doc +^/ +func a(arg: String) +{ + if(times(6,7) == 42) + { + Console.WriteLine($"It is the meaning of life {arg}"); + + var fs : LocalFilesystem = FS.Local; + var path: Path = "/mypath"; + + + } + + each(var v : Char in "Demi Lovato") + { + + } + + for(var i : Long = 0; i < 42; i++) + { + + } +} + + +func b(a,b) +{ + var c = 52; + c += a; + c += b; + return c; +} + +func c(a: Long, b: Long): Long +{ + var c : Long = 52; + c += a; + c += b; + return c; +} + +func d() +{ + var e : Func = (a: Long, b: Long) => : Long { + Console.WriteLine(a + b); + return 42; + }; + + var file: ByteArray = embed("demi.bin"); +} +namespace FS { + extern var Local: LocalFilesystem; +} + +use FS; + +interface IAddable { + func add(val: T): T; +} + +class Add : IAddable { + private val: Long + public func Add(a: Long) + { + this.val = a; + } + + public func add(a: Long): Long + { + return this.val + a; + } +} + + +*/ +/^ + The filesystem API +^/ +namespace FS { + /^ + The local filesystem + ^/ + extern var Local: LocalFilesystem; +} +/^ + My interface +^/ +interface MyInterface : IOtherInterface, IAN { + /^ + Me + @name "Steve" + ^/ + func doThing(a: T): Long; +} diff --git a/src/bcrossc.cpp b/src/bcrossc.cpp new file mode 100644 index 0000000..816be85 --- /dev/null +++ b/src/bcrossc.cpp @@ -0,0 +1,19 @@ +#include "bcrossc.hpp" +#include +#include +using namespace Tesses::Framework; +using namespace Tesses::CrossLang; + +int main(int argc, char** argv) +{ + TF_Init(); + std::ifstream strm("../sourceCode.btcross",std::ios_base::binary); + std::vector tokens; + + Lex("sourceCode.btcross",strm, tokens); + BCParser parser(tokens); + auto node = parser.ParseRoot(); + auto json = node->ToJsonObject(); + std::cout << Tesses::Framework::Serialization::Json::Json::Encode(json) << std::endl; + +} \ No newline at end of file diff --git a/src/bcrossc.hpp b/src/bcrossc.hpp new file mode 100644 index 0000000..7a79b58 --- /dev/null +++ b/src/bcrossc.hpp @@ -0,0 +1,296 @@ +#include + + +namespace Tesses::CrossLang { + using TF_JToken = Tesses::Framework::Serialization::Json::JToken; + class BNode { + public: + virtual bool IsExpression() = 0; + virtual ~BNode() = default; + virtual TF_JToken ToJsonObject() = 0; + }; + + using BSyntaxNode = std::shared_ptr; + + struct BType { + std::vector nameParts; + std::vector generics; + bool nullable=false; + std::string Stringify(); + }; + class BUndefined : public BNode { + public: + bool IsExpression(); + TF_JToken ToJsonObject(); + }; + class BNull : public BNode { + public: + bool IsExpression(); + TF_JToken ToJsonObject(); + }; + class BString : public BNode { + public: + BString(std::string text); + bool IsExpression(); + TF_JToken ToJsonObject(); + std::string text; + }; + class BChar : public BNode { + public: + BChar(char value); + bool IsExpression(); + TF_JToken ToJsonObject(); + char value; + }; + class BBoolean : public BNode { + public: + BBoolean(bool text); + bool IsExpression(); + TF_JToken ToJsonObject(); + bool value; + }; + class BLong : public BNode { + public: + BLong(int64_t text); + bool IsExpression(); + TF_JToken ToJsonObject(); + int64_t value; + }; + class BDouble : public BNode { + public: + BDouble(double text); + bool IsExpression(); + TF_JToken ToJsonObject(); + double value; + }; + + class BUnaryExpression : public BNode { + public: + BUnaryExpression(std::string_view type, BSyntaxNode val); + bool IsExpression(); + TF_JToken ToJsonObject(); + std::string_view type; + BSyntaxNode value; + }; + class BBinaryExpression : public BNode { + public: + BBinaryExpression(std::string_view type, BSyntaxNode left, BSyntaxNode right); + bool IsExpression(); + TF_JToken ToJsonObject(); + std::string_view type; + BSyntaxNode left; + BSyntaxNode right; + }; + class BTernaryExpression : public BNode { + public: + BTernaryExpression(BSyntaxNode cond, BSyntaxNode yes, BSyntaxNode no); + bool IsExpression(); + TF_JToken ToJsonObject(); + BSyntaxNode cond; + BSyntaxNode yes; + BSyntaxNode no; + }; + class BIfStatement : public BNode { + public: + BIfStatement(BSyntaxNode cond, BSyntaxNode yes, BSyntaxNode no); + bool IsExpression(); + TF_JToken ToJsonObject(); + BSyntaxNode cond; + BSyntaxNode yes; + BSyntaxNode no; + }; + class BEachStatement : public BNode { + public: + BEachStatement(BSyntaxNode var, BSyntaxNode list, BSyntaxNode body); + bool IsExpression(); + TF_JToken ToJsonObject(); + BSyntaxNode var; + BSyntaxNode list; + BSyntaxNode body; + }; + + class BExternVariableNode : public BNode { + public: + BExternVariableNode(std::string documentation,std::string name, BType type); + bool IsExpression(); + TF_JToken ToJsonObject(); + std::string documentation; + std::string name; + BType type; + }; + class BExternFuncNode : public BNode { + public: + BExternFuncNode(std::string documentation,BType returnType, BType name, BSyntaxNode args); + bool IsExpression(); + TF_JToken ToJsonObject(); + std::string documentation; + BType returnType; + BType name; + BSyntaxNode args; + }; + + class BNamespaceNode : public BNode { + public: + BNamespaceNode(BType name, BSyntaxNode body); + bool IsExpression(); + TF_JToken ToJsonObject(); + BType name; + BSyntaxNode body; + }; + class BUsingType : public BNode { + public: + BUsingType(BType name, BType type); + bool IsExpression(); + TF_JToken ToJsonObject(); + BType name; + BType type; + }; + class BUsingNamespace : public BNode { + public: + BUsingNamespace(BType name); + bool IsExpression(); + TF_JToken ToJsonObject(); + BType name; + }; + + class BVariableDeclarationNode : public BNode { + public: + BVariableDeclarationNode(std::string documetnation,std::string name, BType type, BSyntaxNode value); + std::string documentation; + std::string name; + BType type; + BSyntaxNode value; + bool IsExpression(); + TF_JToken ToJsonObject(); + }; + + class BArgumentNode : public BNode { + public: + BArgumentNode(std::string name, BType type); + std::string name; + BType type; + bool IsExpression(); + TF_JToken ToJsonObject(); + }; + class BGetVariableExpression : public BNode { + public: + BGetVariableExpression(std::string name); + std::string name; + bool IsExpression(); + TF_JToken ToJsonObject(); + }; + + class BScopeNode : public BNode { + bool isExpression; + bool isRoot; + public: + BScopeNode(bool isRoot=false,bool isExpression=false); + bool IsRoot(); + bool IsExpression(); + std::vector childern; + TF_JToken ToJsonObject(); + }; + + + class BFunctionNode : public BNode { + public: + BFunctionNode(std::string documentation,BType returnType, BType name, BSyntaxNode args, BSyntaxNode body); + bool IsExpression(); + TF_JToken ToJsonObject(); + std::string documentation; + BType returnType; + BType name; + BSyntaxNode args; + BSyntaxNode body; + }; + + class BClosureExpression : public BNode { + public: + BClosureExpression(BType returnType, BSyntaxNode args, BSyntaxNode body); + bool IsExpression(); + TF_JToken ToJsonObject(); + BType returnType; + BSyntaxNode args; + BSyntaxNode body; + }; + + class BFunctionCallExpression : public BNode { + public: + BFunctionCallExpression(BSyntaxNode fun, BSyntaxNode args, std::vector generics); + bool IsExpression(); + TF_JToken ToJsonObject(); + BSyntaxNode fun; + BSyntaxNode args; + std::vector generics; + }; + + + class BDelegateNode : public BNode { + public: + BDelegateNode(std::string documentation,BType returnType, BType name, BSyntaxNode args); + bool IsExpression(); + TF_JToken ToJsonObject(); + std::string documentation; + BType returnType; + BType name; + BSyntaxNode args; + }; + class BInterfaceNode : public BNode { + public: + BInterfaceNode(std::string documentation, BType name); + bool IsExpression(); + TF_JToken ToJsonObject(); + std::string documentation; + BType name; + std::vector inherits; + std::vector funs; + }; + + class BReturnNode : public BNode { + public: + BReturnNode(BSyntaxNode retVal); + BSyntaxNode retVal; + bool IsExpression(); + TF_JToken ToJsonObject(); + }; + + class BCParser { + size_t i = 0; + std::vector tokens; + BSyntaxNode ParseNode(bool isRoot=false); + 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); + std::string ReadIdentifier(); + BType ReadType(); + bool IsGeneric(); + void ReadGenerics(std::vector& generics); + BSyntaxNode ParseParenElement(); + BSyntaxNode ParseParen(); + BSyntaxNode ParseAssignment(); + BSyntaxNode ParseSum(); + BSyntaxNode ParseNullCoalescing(); + BSyntaxNode ParseTernary(); + BSyntaxNode ParseShift(); + BSyntaxNode ParseRel(); + BSyntaxNode ParseEq(); + BSyntaxNode ParseBAnd(); + BSyntaxNode ParseExpression(); + BSyntaxNode ParseXOr(); + BSyntaxNode ParseBOr(); + BSyntaxNode ParseLAnd(); + BSyntaxNode ParseLOr(); + BSyntaxNode ParseFactor(); + BSyntaxNode ParseUnary(); + BSyntaxNode ParseValue(); + + public: + BCParser(const std::vector& tokens); + BSyntaxNode ParseRoot(); + }; + + +} \ No newline at end of file diff --git a/src/node.cpp b/src/node.cpp new file mode 100644 index 0000000..d021796 --- /dev/null +++ b/src/node.cpp @@ -0,0 +1,513 @@ +#include "bcrossc.hpp" +using namespace Tesses::Framework::Serialization::Json; +namespace Tesses::CrossLang { + BScopeNode::BScopeNode(bool isRoot,bool isExpression) : isRoot(isRoot), isExpression(isExpression) + { + + } + bool BScopeNode::IsRoot() + { + return isRoot; + } + bool BScopeNode::IsExpression() + { + return isExpression; + } + TF_JToken BScopeNode::ToJsonObject() + { + JObject o; + o.SetValue("Type", "ScopeNode"); + o.SetValue("IsRoot", isRoot); + o.SetValue("IsExpression", isExpression); + + JArray a; + for(auto& item : this->childern) + { + a.Add(item->ToJsonObject()); + } + o.SetValue("Childern",a); + return o; + } + + + bool BNull::IsExpression() + { + return true; + } + + TF_JToken BNull::ToJsonObject() + { + return nullptr; + } + BVariableDeclarationNode::BVariableDeclarationNode(std::string documentation,std::string name, BType type, BSyntaxNode value) + : documentation(documentation), name(name), type(type), value(value) + { + + } + bool BVariableDeclarationNode::IsExpression() + { + return false; + } + TF_JToken BVariableDeclarationNode::ToJsonObject() + { + JObject o; + o.SetValue("Type", "VariableDeclarationNode"); + o.SetValue("TypeString", this->type.Stringify()); + o.SetValue("Name", this->name); + o.SetValue("Documentation",this->documentation); + if(this->value) + o.SetValue("Value", this->value->ToJsonObject()); + return o; + } + + BBinaryExpression::BBinaryExpression(std::string_view type, BSyntaxNode left, BSyntaxNode right) : type(type), left(left), right(right) + { + + } + bool BBinaryExpression::IsExpression() + { + return true; + } + TF_JToken BBinaryExpression::ToJsonObject() + { + JObject o; + o.SetValue("Type",(std::string)this->type); + if(this->left) + o.SetValue("Left", this->left->ToJsonObject()); + + if(this->right) + o.SetValue("Right", this->right->ToJsonObject()); + + return o; + } + + BUnaryExpression::BUnaryExpression(std::string_view type, BSyntaxNode value) : type(type), value(value) + { + + } + + bool BUnaryExpression::IsExpression() + { + return true; + } + TF_JToken BUnaryExpression::ToJsonObject() + { + JObject o; + o.SetValue("Type",(std::string)this->type); + if(this->value) + o.SetValue("Value", this->value->ToJsonObject()); + + + return o; + } + + BTernaryExpression::BTernaryExpression(BSyntaxNode cond, BSyntaxNode yes, BSyntaxNode no): cond(cond), yes(yes), no(no) + { + + } + bool BTernaryExpression::IsExpression() + { + return true; + } + TF_JToken BTernaryExpression::ToJsonObject() + { + JObject o; + o.SetValue("Type","TernaryExpression"); + if(this->cond) + o.SetValue("Condition", this->cond->ToJsonObject()); + + if(this->yes) + o.SetValue("True", this->yes->ToJsonObject()); + + + if(this->no) + o.SetValue("False", this->no->ToJsonObject()); + + return o; + } + + BIfStatement::BIfStatement(BSyntaxNode cond, BSyntaxNode yes, BSyntaxNode no): cond(cond), yes(yes), no(no) + { + + } + bool BIfStatement::IsExpression() + { + return false; + } + TF_JToken BIfStatement::ToJsonObject() + { + JObject o; + o.SetValue("Type","IfStatement"); + if(this->cond) + o.SetValue("Condition", this->cond->ToJsonObject()); + + if(this->yes) + o.SetValue("True", this->yes->ToJsonObject()); + + + if(this->no) + o.SetValue("False", this->no->ToJsonObject()); + + return o; + } + + BString::BString(std::string text) : text(text) + {} + bool BString::IsExpression() + { + return true; + } + TF_JToken BString::ToJsonObject() + { + return text; + } + + + + + BChar::BChar(char value) : value(value) + {} + bool BChar::IsExpression() + { + return true; + } + TF_JToken BChar::ToJsonObject() + { + JObject o; + o.SetValue("Type","Char"); + o.SetValue("Value", std::string{value}); + return o; + } + + BLong::BLong(int64_t value) : value(value) + {} + bool BLong::IsExpression() + { + return true; + } + TF_JToken BLong::ToJsonObject() + { + return value; + } + BDouble::BDouble(double value) : value(value) + {} + bool BDouble::IsExpression() + { + return true; + } + TF_JToken BDouble::ToJsonObject() + { + return value; + } + BBoolean::BBoolean(bool value) : value(value) + {} + bool BBoolean::IsExpression() + { + return true; + } + TF_JToken BBoolean::ToJsonObject() + { + return value; + } + + BArgumentNode::BArgumentNode(std::string name, BType type): name(name), type(type) + {} + bool BArgumentNode::IsExpression() + { + return false; + } + TF_JToken BArgumentNode::ToJsonObject() + { + JObject o; + o.SetValue("Type","ArgumentNode"); + o.SetValue("Name",this->name); + o.SetValue("TypeString",this->type.Stringify()); + return o; + } + + BGetVariableExpression::BGetVariableExpression(std::string name) : name(name) + { + + } + bool BGetVariableExpression::IsExpression() + { + return true; + } + TF_JToken BGetVariableExpression::ToJsonObject() + { + JObject o; + o.SetValue("Type","GetVariableExpression"); + o.SetValue("Name",this->name); + return o; + } + + bool BUndefined::IsExpression() + { + return true; + } + TF_JToken BUndefined::ToJsonObject() + { + JObject o; + o.SetValue("Type","Undefined"); + return o; + } + + BFunctionNode::BFunctionNode(std::string documentation,BType returnType, BType name, BSyntaxNode args, BSyntaxNode body): documentation(documentation), returnType(returnType), name(name), args(args), body(body) + { + + } + bool BFunctionNode::IsExpression() + { + return false; + } + TF_JToken BFunctionNode::ToJsonObject() + { + JObject o; + o.SetValue("Type","FunctionNode"); + o.SetValue("ReturnType", this->returnType.Stringify()); + o.SetValue("Name", this->name.Stringify()); + o.SetValue("Documentation",this->documentation); + if(this->args) + o.SetValue("Arguments", this->args->ToJsonObject()); + if(this->body) + o.SetValue("Body",this->body->ToJsonObject()); + return o; + } + + BClosureExpression::BClosureExpression(BType returnType, BSyntaxNode args, BSyntaxNode body): returnType(returnType), args(args), body(body) + { + + } + bool BClosureExpression::IsExpression() + { + return true; + } + TF_JToken BClosureExpression::ToJsonObject() + { + JObject o; + o.SetValue("Type","ClosureExpression"); + o.SetValue("ReturnType", this->returnType.Stringify()); + + if(this->args) + o.SetValue("Arguments", this->args->ToJsonObject()); + if(this->body) + o.SetValue("Body",this->body->ToJsonObject()); + return o; + } + BDelegateNode::BDelegateNode(std::string documentation,BType returnType, BType name, BSyntaxNode args): documentation(documentation),returnType(returnType), name(name), args(args) + { + + } + bool BDelegateNode::IsExpression() + { + return false; + } + TF_JToken BDelegateNode::ToJsonObject() + { + JObject o; + o.SetValue("Type","DelegateNode"); + o.SetValue("ReturnType", this->returnType.Stringify()); + o.SetValue("Name", this->name.Stringify()); + if(this->args) + o.SetValue("Arguments", this->args->ToJsonObject()); + o.SetValue("Documentation",this->documentation); + + return o; + } + + BReturnNode::BReturnNode(BSyntaxNode retVal): retVal(retVal) + { + + } + bool BReturnNode::IsExpression() + { + return false; + } + TF_JToken BReturnNode::ToJsonObject() + { + JObject o; + o.SetValue("Type","ReturnNode"); + if(this->retVal) + o.SetValue("Value",this->retVal->ToJsonObject()); + return o; + } + + BFunctionCallExpression::BFunctionCallExpression(BSyntaxNode fun, BSyntaxNode args, std::vector generics) + :fun(fun), args(args), generics(generics) + { + + } + bool BFunctionCallExpression::IsExpression() + { + return true; + } + TF_JToken BFunctionCallExpression::ToJsonObject() + { + JObject o; + o.SetValue("Type","FunctionCallExpression"); + if(this->args) + o.SetValue("Arguments",this->args->ToJsonObject()); + if(this->fun) + o.SetValue("Function", this->fun->ToJsonObject()); + if(!this->generics.empty()) + { + JArray a; + for(auto& item : this->generics) + { + a.Add(item.Stringify()); + } + o.SetValue("Generics",a); + } + return o; + } + + BEachStatement::BEachStatement(BSyntaxNode var, BSyntaxNode list, BSyntaxNode body) + :var(var), list(list), body(body) + { + + } + bool BEachStatement::IsExpression() + { + return false; + } + TF_JToken BEachStatement::ToJsonObject() + { + JObject o; + o.SetValue("Type","EachStatement"); + if(this->var) + o.SetValue("Variable", this->var->ToJsonObject()); + if(this->list) + o.SetValue("List",this->list->ToJsonObject()); + if(this->body) + o.SetValue("Body", this->body->ToJsonObject()); + return o; + } + + BExternFuncNode::BExternFuncNode(std::string documentation,BType returnType, BType name, BSyntaxNode args): documentation(documentation), + returnType(returnType), name(name), args(args) + { + + } + bool BExternFuncNode::IsExpression() + { + return false; + } + + TF_JToken BExternFuncNode::ToJsonObject() + { + JObject o; + o.SetValue("Type","ExternFuncNode"); + if(this->args) + o.SetValue("Arguments",this->args->ToJsonObject()); + o.SetValue("Name",this->name.Stringify()); + o.SetValue("ReturnType",this->returnType.Stringify()); + o.SetValue("Documentation",this->documentation); + return o; + } + + + BExternVariableNode::BExternVariableNode(std::string documentation,std::string name, BType type) : documentation(documentation), name(name), type(type) + { + + } + bool BExternVariableNode::IsExpression() + { + return false; + } + TF_JToken BExternVariableNode::ToJsonObject() + { + JObject o; + o.SetValue("Type","ExternVariableNode"); + o.SetValue("Name",this->name); + o.SetValue("Documentation",this->documentation); + o.SetValue("TypeString", this->type.Stringify()); + return o; + } + + BNamespaceNode::BNamespaceNode(BType name, BSyntaxNode body): + name(name), body(body) + { + + } + + bool BNamespaceNode::IsExpression() + { + return false; + } + + TF_JToken BNamespaceNode::ToJsonObject() + { + JObject o; + o.SetValue("Type","NamespaceNode"); + o.SetValue("Name",this->name.Stringify()); + if(this->body) + o.SetValue("Body",this->body->ToJsonObject()); + + return o; + } + + BUsingType::BUsingType(BType name, BType type): + name(name), type(type) + { + + } + bool BUsingType::IsExpression() + { + return false; + } + TF_JToken BUsingType::ToJsonObject() + { + JObject o; + o.SetValue("Type","UsingType"); + o.SetValue("Name",this->name.Stringify()); + o.SetValue("TypeString",this->type.Stringify()); + return o; + } + + BUsingNamespace::BUsingNamespace(BType name): name(name) + { + + } + bool BUsingNamespace::IsExpression() + { + return false; + } + + TF_JToken BUsingNamespace::ToJsonObject() + { + JObject o; + o.SetValue("Type", "UsingNamespace"); + o.SetValue("Name",this->name.Stringify()); + return o; + } + + BInterfaceNode::BInterfaceNode(std::string documentation, BType name): + documentation(documentation), name(name) + { + + } + bool BInterfaceNode::IsExpression() + { + return false; + } + TF_JToken BInterfaceNode::ToJsonObject() + { + JObject o; + o.SetValue("Type","InterfaceNode"); + o.SetValue("Documentation",this->documentation); + o.SetValue("Name",this->name.Stringify()); + JArray a; + for(auto& item : this->inherits) + { + a.Add(item.Stringify()); + } + o.SetValue("Inherits", a); + a.Clear(); + for(auto& item : this->funs) + { + a.Add(item.ToJsonObject()); + } + o.SetValue("Functions",a); + return o; + } +} \ No newline at end of file diff --git a/src/parser.cpp b/src/parser.cpp new file mode 100644 index 0000000..2ea98b2 --- /dev/null +++ b/src/parser.cpp @@ -0,0 +1,1087 @@ +#include "bcrossc.hpp" + +namespace Tesses::CrossLang { + static std::string EnsureSafeVariable(LexToken token) + { + if(token.text.find("__compGen") == 0) + { + throw SyntaxException(token.lineInfo,"__compGen* is reserved for compilers (this error is enforced by the compiler)"); + } + return token.text; + } + std::string BType::Stringify() + { + std::string text; + bool first=true; + for(auto& item : this->nameParts) + { + if(!first) + { + text += "."; + } + text += item; + first=false; + } + if(!this->generics.empty()) + { + first=true; + text += "generics) + { + if(!first) + { + text += ", "; + } + text += item.Stringify(); + first=false; + } + text += ">"; + } + if(this->nullable) + text += "?"; + return text; + } + BCParser::BCParser(const std::vector& tokens) : tokens(tokens) + { + + } + extern std::string LexTokenType_ToString(LexTokenType t); + + std::string BCParser::ReadIdentifier() + { + if(i >= tokens.size()) + throw std::out_of_range("End of file"); + + if(tokens[i].type != LexTokenType::Identifier) + throw SyntaxException(tokens[i].lineInfo, "We expect an identifer here, but got type \"" + LexTokenType_ToString(tokens[i].type) + "\" which is not a identifer"); + + return tokens[i++].text; + } + + void BCParser::ReadGenerics(std::vector& generics) + { + + while(i < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i].type == LexTokenType::Symbol) break; + if(IsSymbol(",")) continue; + generics.push_back(ReadType()); + if(!IsSymbol(",",false)) break; + } + if(i >= tokens.size()) throw std::out_of_range("End of file"); + if(tokens[i].text != ">" || tokens[i].type != LexTokenType::Symbol) + throw SyntaxException(tokens[i].lineInfo, "Generics must end with >"); + i++; + } + bool BCParser::IsGeneric() + { + if(i+1 < tokens.size() && tokens[i].text == "<" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].text == "of" && tokens[i+1].type == LexTokenType::Identifier) + { + i+=2; + + return true; + } + return false; + } + BType BCParser::ReadType() + { + BType t; + while(i < tokens.size()) + { + if(IsSymbol(".")) continue; + if(tokens[i].type != LexTokenType::Identifier) break; + //TODO dont allow idents that start with number + t.nameParts.push_back(ReadIdentifier()); + if(!IsSymbol(".",false)) break; + } + if(IsGeneric()) + { + ReadGenerics(t.generics); + } + else if(IsSymbol("<")) + { + throw SyntaxException(tkn.lineInfo,"Generics need to be Type"); + } + if(IsSymbol("?")) + t.nullable=true; + return t; + } + /* Crosslang's utility functions */ + void BCParser::EnsureSymbol(std::string txt) + { + if(i < tokens.size()) + { + + if(tokens[i].type != LexTokenType::Symbol) + { + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the " + LexTokenType_ToString(tokens[i].type) + " \"" + tokens[i].text + "\" which is not a symbol at all."); + } + if(txt == ">") + { + if(i+1" || tokens[i+1].text == ">=") && tokens[i+1].type == LexTokenType::Symbol) + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + tokens[i+1].text + "\"");; + } + if(txt == tokens[i].text) + { + + tkn = tokens[i]; + i++; + return; + } + } + if(txt == ">>=") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">=" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + + tkn = tokens[i]; + i+=2; + return; + } + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + tokens[i+1].text + "\""); + } + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + "\""); + } + else if(txt == ">>") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + + tkn = tokens[i]; + i+=2; + return; + } + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + tokens[i+1].text + "\""); + } + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + "\""); + } + else if(tokens[i].text != txt) + { + + throw SyntaxException(tokens[i].lineInfo, "expected the symbol \"" + txt + "\" but got the symbol \"" + tokens[i].text + "\""); + } + tkn = tokens[i]; + i++; + return; + } + throw std::out_of_range("End of file"); + } + bool BCParser::IsSymbol(std::string txt,bool pop) + { + + if(i < tokens.size()) + { + if(tokens[i].type != LexTokenType::Symbol) return false; + if(txt == ">") + { + if(i+1" || tokens[i+1].text == ">=") && tokens[i+1].type == LexTokenType::Symbol) return false; + } + if(txt == tokens[i].text) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } + } + else if(txt == ">>=") + { + if(i+1 < tokens.size()) + { + + if(tokens[i].text == ">" && tokens[i+1].text == ">=" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + tkn = tokens[i]; + tkn.text = ">>="; + if(pop) i+=2; + return true; + } + } + } + else if(txt == ">>") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + tkn = tokens[i]; + tkn.text = ">>"; + if(pop) i+=2; + return true; + } + } + + } + else if(tokens[i].text == txt) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } + } + return false; + } + bool BCParser::IsIdentifier(std::string txt,bool pop) + { + if(i < tokens.size()) + { + if(tokens[i].type != LexTokenType::Identifier) return false; + if(tokens[i].text == txt) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } + } + return false; + } + bool BCParser::IsAnyIdentifier(std::initializer_list idents, bool pop) + { + if(i < tokens.size()) + { + if(tokens[i].type != LexTokenType::Identifier) return false; + for(auto item : idents) + { + if(item == tokens[i].text) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } + } + } + return false; + } + bool BCParser::IsAnySymbol(std::initializer_list idents, bool pop) + { + + if(i < tokens.size()) + { + if(tokens[i].type != LexTokenType::Symbol) return false; + + if(tokens[i].text == "<") + { + bool hasLT = false; + for(auto& i : idents) + { + if(i == "<") {hasLT=true; break;} + } + if(hasLT && i + 1 < tokens.size() && tokens[i+1].text == "of" && tokens[i+1].type == LexTokenType::Identifier) + { + return false; + } + } + + for(auto item : idents) + { + if(item == ">") + { + if(i+1" || tokens[i+1].text == ">=") && tokens[i+1].type == LexTokenType::Symbol) continue; + } + if(item == tokens[i].text) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } + } + else if(item == ">>=") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">=" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + tkn = tokens[i]; + tkn.text = ">>="; + if(pop) i+=2; + return true; + } + } + } + else if(item == ">>") + { + if(i+1 < tokens.size()) + { + if(tokens[i].text == ">" && tokens[i+1].text == ">" && tokens[i].type == LexTokenType::Symbol && tokens[i+1].type == LexTokenType::Symbol) + { + tkn = tokens[i]; + tkn.text = ">>"; + if(pop) i+=2; + return true; + } + } + + } + else { + if(item == tokens[i].text) + { + tkn = tokens[i]; + if(pop) i++; + return true; + } + } + } + } + return false; + } + BSyntaxNode BCParser::ParseRoot() + { + return ParseNode(true); + } + + + BSyntaxNode BCParser::ParseNode(bool isRoot) + { + std::string documentation=""; + if(i < tokens.size() && !isRoot && tokens[i].type == Documentation) + { + auto txt = tokens[i].text; + i++; + documentation = txt; + } + if(isRoot || IsSymbol("{")) + { + auto aSN = std::make_shared(isRoot); + + while(i < tokens.size() && (isRoot || !IsSymbol("}",false))) + { + auto token = tokens[i]; + //if(CanEmit(token.lineInfo)) {aSN.nodes.push_back(Advancedauto::Create(LineNode,false, {(int64_t)tokens[i].lineInfo.line,tokens[i].lineInfo.filename}));} + aSN->childern.push_back(ParseNode()); + IsSymbol(";"); + } + + if(!isRoot) i++; + return aSN; + } + + if(IsIdentifier("var")) + { + //var i = false; + //var i : Boolean = true; + auto variableName = ReadIdentifier(); + if(IsSymbol(":")) + { + auto type = ReadType(); + if(IsSymbol(";")) { + if(!type.nullable) throw SyntaxException(tkn.lineInfo, "Type is not nullable"); + return std::make_shared(documentation,variableName,type,std::make_shared()); + } + else if(IsSymbol("=")){ + auto res= std::make_shared(documentation,variableName,type,ParseExpression()); + EnsureSymbol(";"); + return res; + } + else { + throw SyntaxException(tkn.lineInfo, "Must be assignment or null"); + } + } + else if(IsSymbol("=")) { + auto res= std::make_shared(documentation,variableName,BType(),ParseExpression()); + EnsureSymbol(";"); + return res; + } + else { + throw SyntaxException(tkn.lineInfo, "Must be assignment"); + } + } + if(IsIdentifier("return")) + { + if(IsSymbol(";")) + { + return std::make_shared(nullptr); + } + else { + auto res = std::make_shared(ParseExpression()); + EnsureSymbol(";"); + return res; + } + } + if(IsIdentifier("func")) + { + auto name = ReadType(); + EnsureSymbol("("); + auto args = ParseParen(); + BType returnType; + BSyntaxNode body; + if(IsSymbol(":")) + { + returnType = ReadType(); + } + + if(IsSymbol("{",false)) + { + body = ParseNode(); + } + else { + body = std::make_shared(ParseExpression()); + EnsureSymbol(";"); + } + return std::make_shared(documentation,returnType,name,args,body); + } + if(IsIdentifier("delegate")) + { + auto name = ReadType(); + EnsureSymbol("("); + auto args = ParseParen(); + BType returnType; + if(IsSymbol(":")) + { + returnType = ReadType(); + } + + EnsureSymbol(";"); + + return std::make_shared(documentation,returnType,name,args); + } + if(IsIdentifier("interface")) + { + auto interface = std::make_shared(documentation,ReadType()); + if(IsSymbol(":")) + { + while(i < tokens.size()) + { + if(IsSymbol("{",false)) break; + if(IsSymbol(",")) continue; + interface->inherits.push_back(ReadType()); + if(!IsSymbol(",",false)) break; + } + } + EnsureSymbol("{"); + documentation = ""; + while(i < tokens.size()) + { + if(IsSymbol("}",false)) break; + documentation = ""; + if(i < tokens.size() && !isRoot && tokens[i].type == Documentation) + { + auto txt = tokens[i].text; + i++; + documentation = txt; + } + if(IsIdentifier("func")) + { + + auto name = ReadType(); + EnsureSymbol("("); + auto args = ParseParen(); + BType returnType; + if(IsSymbol(":")) + { + returnType = ReadType(); + } + + EnsureSymbol(";"); + + interface->funs.emplace_back(documentation,returnType,name,args,nullptr); + continue; + } + + throw SyntaxException(tkn.lineInfo, "Must be a func"); + } + EnsureSymbol("}"); + return interface; + } + if(IsIdentifier("extern")) + { + if(IsIdentifier("var")) + { + auto variableName = ReadIdentifier(); + EnsureSymbol(":"); + BType type = ReadType(); + EnsureSymbol(";"); + return std::make_shared(documentation,variableName, type); + } + else if(IsIdentifier("func")) + { + auto name = ReadType(); + EnsureSymbol("("); + auto args = ParseParen(); + BType returnType; + if(IsSymbol(":")) + { + returnType = ReadType(); + } + + EnsureSymbol(";"); + + return std::make_shared(documentation,returnType,name,args); + } + } + if(IsIdentifier("namespace")) + { + auto nsType = ReadType(); + if(IsSymbol(";")) + { + return std::make_shared(nsType,nullptr); + } + else if(IsSymbol("{",false)) + { + return std::make_shared(nsType,ParseNode()); + } + } + if(IsIdentifier("use")) + { + //use FS; + //use MyType: Variant; + //use MyList: List; + + + auto useName = ReadType(); + if(IsSymbol(":")) + { + auto useType = ReadType(); + EnsureSymbol(";"); + return std::make_shared(useName, useType); + } + else if(IsSymbol(";")) + { + return std::make_shared(useName); + } + } + + if(IsIdentifier("if")) + { + EnsureSymbol("("); + BSyntaxNode cond = ParseExpression(); + EnsureSymbol(")"); + BSyntaxNode truthy = nullptr; + BSyntaxNode falsey = nullptr; + + if(!IsIdentifier("else",false)) + { + truthy = ParseNode(); + } + + if(IsIdentifier("else")) + { + falsey = ParseNode(); + } + + return std::make_shared(cond, truthy,falsey); + } + if(IsIdentifier("each")) + { + BSyntaxNode item = nullptr; + EnsureSymbol("("); + BSyntaxNode list = nullptr; + BSyntaxNode body = nullptr; + if(IsIdentifier("var")) + { + auto variableName = ReadIdentifier(); + BType type; + if(IsSymbol(":")) + { + type = ReadType(); + } + if(ReadIdentifier() != "in") { + throw SyntaxException(tokens[i-1].lineInfo, "Must be keyword in"); + } + item = std::make_shared("",variableName,type,std::make_shared()); + list = ParseExpression(); + } + else { + list = ParseExpression(); + if(IsSymbol(":") || IsIdentifier("in")) + { + item = list; + list = ParseExpression(); + } + } + + EnsureSymbol(")"); + + if(!IsSymbol(";")) + { + body = ParseNode(); + } + if(item == nullptr) + { + item= std::make_shared("","item",BType(),std::make_shared()); + } + return std::make_shared(item,list,body); + } + auto ret = ParseExpression(); + EnsureSymbol(";"); + return ret; + } + + BSyntaxNode BCParser::ParseNullCoalescing() + { + BSyntaxNode expr = ParseLOr(); + while(IsSymbol("?\?")) + { + expr = std::make_shared(NullCoalescingExpression,expr,ParseLOr()); + } + return expr; + } + BSyntaxNode BCParser::ParseTernary() + { + BSyntaxNode node = ParseNullCoalescing(); + if(IsSymbol("?")) + { + auto yes = ParseTernary(); + EnsureSymbol(":"); + auto no = ParseTernary(); + + return std::make_shared(node,yes,no); + } + return node; + } + BSyntaxNode BCParser::ParseValue() + { + if(i >= tokens.size()) throw std::out_of_range("End of file"); + auto tkn2 = tokens[i]; + BSyntaxNode node = nullptr; + if(tokens[i].type == LexTokenType::String) + { + node = std::make_shared(tkn2.text); + i++; + + } + else if(tokens[i].type == LexTokenType::Char) + { + node = std::make_shared(tkn2.text.empty() ? '\0' : tkn2.text.front()); + i++; + + } + else if(IsSymbol("(")) + { + node = ParseParen(); + } + else if(tokens[i].type == LexTokenType::Identifier) + { + auto token=tokens[i]; + + i++; + + bool hasNumber=true; + int64_t lngNum = 0; + + if(token.text.size() == 1 && token.text[0] == '0') + { + lngNum = 0; + } + else + if(token.text.size() > 0 && token.text[0] == '0') + { + if(token.text.size() > 1 && token.text[1] == 'x') + { + lngNum = std::stoll(token.text.substr(2),nullptr,16); + } + else if(token.text.size() > 1 && token.text[1] == 'b') + { + lngNum = std::stoll(token.text.substr(2),nullptr,2); + } + else + { + lngNum = std::stoll(token.text.substr(1),nullptr,8); + } + + } + else if(token.text.size() > 0 && token.text[0] >= '0' && token.text[0] <= '9') + { + lngNum=std::stoll(token.text,nullptr,10); + } + else + { + hasNumber = false; + } + + if(hasNumber && this->IsSymbol(".",false) && i+1 < tokens.size() && tokens[i+1].type == LexTokenType::Identifier) + { + std::string myToken = tokens[i+1].text; + if(myToken.size() > 0 && myToken[0] >= '0' && myToken[0] <= '9') + { + i+=2; + std::string myN = std::to_string(lngNum) + "." + myToken; + + double v = std::stod(myN,nullptr); + + node = std::make_shared(lngNum); + } + else + { + node = std::make_shared(lngNum); + } + } + else if(hasNumber) + { + node = std::make_shared(lngNum); + } + + if(!hasNumber) + { + if(token.text == "true") + node = std::make_shared(true); + else if(token.text == "false") + node = std::make_shared(false); + else if(token.text == "null") + node = std::make_shared(); + else if(token.text == "undefined") + node = std::make_shared(); + else { + node = std::make_shared(EnsureSafeVariable(token)); + } + } + } + + if(IsSymbol("=>")) + { + BType type; + BSyntaxNode body; + if(IsSymbol(":")) + { + type = ReadType(); + } + if(IsSymbol("{",false)) + { + body = ParseNode(); + } + else { + body = std::make_shared(ParseExpression()); + + } + node = std::make_shared(type,node,body); + } + + if(IsGeneric()) + { + std::vector types; + ReadGenerics(types); + EnsureSymbol("("); + auto args = ParseParen(); + node =std::make_shared(node,args,types); + } + + while(IsAnySymbol({".","[","("})) + { + if(tkn.text == ".") + { + if(i>=tokens.size()) throw std::out_of_range("End of file"); + if(IsSymbol("[")) + { + + node = std::make_shared(GetFieldExpression,node, ParseExpression()); + EnsureSymbol("]"); + continue; + } + if(tokens[i].type != LexTokenType::Identifier) throw std::runtime_error("Not an identifier (member)"); + std::string name = tokens[i].text; + if(name == "operator") + { + if(i >= tokens.size()) throw std::out_of_range("End of file"); + auto op = tokens[i]; + if(op.type != LexTokenType::Identifier && op.type != LexTokenType::Symbol) throw SyntaxException(op.lineInfo, "Expected an identifier or a symbol got a " + LexTokenType_ToString(op.type) + " \"" + op.text + "\""); + + name += tokens[i+1].text; + i++; + } + i++; + node = std::make_shared(GetFieldExpression, node, std::make_shared(name)); + if(IsGeneric()) + { + std::vector types; + ReadGenerics(types); + EnsureSymbol("("); + auto args = ParseParen(); + node =std::make_shared(node,args,types); + } + } + else if(tkn.text == "[") + { + node = std::make_shared(GetArrayExpression,node,ParseExpression()); + EnsureSymbol("]"); + if(IsGeneric()) + { + std::vector types; + ReadGenerics(types); + EnsureSymbol("("); + auto args = ParseParen(); + node =std::make_shared(node,args,types); + } + } + else if(tkn.text == "(") + { + if(IsSymbol(")",false)) + { + node = std::make_shared(node,std::make_shared(ParenthesesExpression,nullptr), (std::vector){}); + } + else + { + node = std::make_shared(node,ParseExpression(),(std::vector){}); + + } + EnsureSymbol(")"); + if(IsGeneric()) + { + std::vector types; + ReadGenerics(types); + EnsureSymbol("("); + auto args = ParseParen(); + node =std::make_shared(node,args,types); + } + } + } + return node; + } + BSyntaxNode BCParser::ParseUnary() + { + return ParseValue(); + } + + BSyntaxNode BCParser::ParseFactor() + { + BSyntaxNode expr = ParseUnary(); + while(IsAnySymbol({"*","/","%"},true)) + { + if(tkn.text == "*") + { + expr = std::make_shared(TimesExpression,expr,ParseUnary()); + } + else if(tkn.text == "/") + { + expr = std::make_shared(DivideExpression, expr,ParseUnary()); + } + else if(tkn.text == "%") + { + expr = std::make_shared(ModExpression, expr,ParseUnary()); + } + } + return expr; + } + + BSyntaxNode BCParser::ParseSum() + { + BSyntaxNode expr = ParseFactor(); + while(IsAnySymbol({"+","-"},true)) + { + if(tkn.text == "+") + { + expr = std::make_shared(AddExpression,expr,ParseFactor()); + } + else if(tkn.text == "-") + { + expr = std::make_shared(SubExpression, expr,ParseFactor()); + } + } + return expr; + } + + BSyntaxNode BCParser::ParseShift() + { + BSyntaxNode expr = ParseSum(); + while(IsAnySymbol({"<<",">>"},true)) + { + if(tkn.text == "<<") + { + expr = std::make_shared(LeftShiftExpression,expr,ParseSum()); + } + else if(tkn.text == ">>") + { + expr = std::make_shared(RightShiftExpression, expr,ParseSum()); + } + } + return expr; + } + + BSyntaxNode BCParser::ParseRel() + { + BSyntaxNode expr = ParseShift(); + while(IsAnySymbol({"<",">","<=",">="},true)) + { + if(tkn.text == "<") + { + expr = std::make_shared(LessThanExpression, expr,ParseShift()); + } + else if(tkn.text == ">") + { + expr = std::make_shared(GreaterThanExpression, expr,ParseShift()); + } + else if(tkn.text == "<=") + { + expr = std::make_shared(LessThanEqualsExpression, expr,ParseShift()); + } + else if(tkn.text == ">=") + { + expr = std::make_shared(GreaterThanEqualsExpression, expr,ParseShift()); + } + } + return expr; + } + BSyntaxNode BCParser::ParseEq() + { + BSyntaxNode expr = ParseRel(); + while(IsAnySymbol({"==","!="},true)) + { + if(tkn.text == "==") + { + expr = std::make_shared(EqualsExpression, expr,ParseRel()); + } + else if(tkn.text == "!=") + { + expr = std::make_shared(NotEqualsExpression, expr,ParseRel()); + } + } + return expr; + } + BSyntaxNode BCParser::ParseBAnd() + { + BSyntaxNode expr = ParseEq(); + while(IsSymbol("&")) + { + expr = std::make_shared(BitwiseAndExpression,expr,ParseEq()); + } + return expr; + } + BSyntaxNode BCParser::ParseAssignment() + { + BSyntaxNode node = ParseTernary(); + if(IsSymbol("=")) + { + return std::make_shared(AssignExpression,node,ParseAssignment()); + } + else if(IsSymbol("+=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(AddExpression,node,ParseAssignment())); + } + else if(IsSymbol("-=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(SubExpression,node,ParseAssignment())); + } + else if(IsSymbol("*=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(TimesExpression,node,ParseAssignment())); + } + else if(IsSymbol("/=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(DivideExpression,node,ParseAssignment())); + } + else if(IsSymbol("%=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(ModExpression,node,ParseAssignment())); + } + else if(IsSymbol("<<=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(LeftShiftExpression,node,ParseAssignment())); + } + else if(IsSymbol(">>=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(RightShiftExpression,node,ParseAssignment())); + } + else if(IsSymbol("|=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(BitwiseOrExpression,node,ParseAssignment())); + } + else if(IsSymbol("&=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(BitwiseAndExpression,node,ParseAssignment())); + } + else if(IsSymbol("^=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(XOrExpression,node,ParseAssignment())); + } + else if(IsSymbol("?\?=")) + { + return std::make_shared(CompoundAssignExpression,std::make_shared(NullCoalescingExpression,node,ParseAssignment())); + } + return node; + } + BSyntaxNode BCParser::ParseExpression() + { + BSyntaxNode expr = ParseAssignment(); + while(IsSymbol(",")) + { + expr = std::make_shared(CommaExpression,expr,ParseAssignment()); + } + return expr; + } + BSyntaxNode BCParser::ParseXOr() + { + BSyntaxNode expr = ParseBAnd(); + while(IsSymbol("^")) + { + expr = std::make_shared(XOrExpression,expr,ParseBAnd()); + } + return expr; + } + BSyntaxNode BCParser::ParseBOr() + { + BSyntaxNode expr = ParseXOr(); + while(IsSymbol("|")) + { + expr = std::make_shared(BitwiseOrExpression,expr,ParseXOr()); + } + return expr; + } + BSyntaxNode BCParser::ParseLAnd() + { + BSyntaxNode expr = ParseBOr(); + while(IsSymbol("&&")) + { + expr = std::make_shared(LogicalAndExpression,expr,ParseBOr()); + } + return expr; + } + BSyntaxNode BCParser::ParseLOr() + { + BSyntaxNode expr = ParseLAnd(); + while(IsSymbol("||")) + { + expr = std::make_shared(LogicalOrExpression,expr,ParseLAnd()); + } + return expr; + } + + BSyntaxNode BCParser::ParseParen() + { + if(IsSymbol(")")) return std::make_shared(ParenthesesExpression,nullptr); + BSyntaxNode node = ParseParenElement(); + while(IsSymbol(",")) + { + node = std::make_shared(CommaExpression,node, ParseParenElement()); + } + EnsureSymbol(")"); + return std::make_shared(ParenthesesExpression,node); + } + BSyntaxNode BCParser::ParseParenElement() + { + BSyntaxNode node = ParseAssignment(); + if(IsSymbol(":")) + { + auto type = ReadType(); + auto str = std::dynamic_pointer_cast(node); + if(str == nullptr) throw SyntaxException(tkn.lineInfo, "Not a argument"); + if(str->name.size() > 1 && str->name[0] == '$' && str->name[1] == '$') + { + if(type.nameParts.empty() || type.nameParts.size() != 1 || type.nameParts[0] != "List") + { + throw SyntaxException(tkn.lineInfo, "argument \"" + str->name + "\" is variadic, please make the type List"); + } + + } + else if(!str->name.empty() && str->name[0] == '$') + { + if(!type.nullable) + { + throw SyntaxException(tkn.lineInfo, "argument \"" + str->name + "\" can be undefined, make the type nullable by appending ? to the type"); + } + } + node = std::make_shared(str->name,type); + } + return node; + } +} \ No newline at end of file