diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index b4f8a95..cb803e3 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -664,7 +664,8 @@ typedef enum { PUSHBREAK, PUSHCONTINUE, JMPIFBREAK, - JMPIFCONTINUE + JMPIFCONTINUE, + JMPIFDEFINED } Instruction; /** * @brief Base type for bytecode instruction @@ -1274,6 +1275,10 @@ 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 Advanced AST node * @@ -1346,6 +1351,7 @@ class Parser { SyntaxNode ParseFactor(); SyntaxNode ParseValue(); SyntaxNode ParseUnary(); + SyntaxNode ParseNullCoalescing(); void ParseHtml(std::vector& nodes,std::string var); GC* gc; TRootEnvironment* env; @@ -2254,6 +2260,7 @@ class GC { bool ExecuteMethod2(GC* gc, TObject instance, std::string key, std::vector args); protected: static void* ThreadCallback(void* ptr); + bool JumpIfDefined(GC* gc); bool Add(GC* gc); bool Sub(GC* gc); bool Times(GC* gc); diff --git a/src/compiler/codegen.cpp b/src/compiler/codegen.cpp index 28e4dca..760e5b6 100644 --- a/src/compiler/codegen.cpp +++ b/src/compiler/codegen.cpp @@ -521,7 +521,18 @@ namespace Tesses::CrossLang TWO_EXPR(NotEqualsExpression, NEQ) TWO_EXPR(EqualsExpression, EQ) TWO_EXPR(XOrExpression, XOR) - if(adv.nodeName == ClassStatement && adv.nodes.size() >= 3 && std::holds_alternative(adv.nodes[0])) + if(adv.nodeName == NullCoalescingExpression && adv.nodes.size() == 2) + { + uint32_t ifId = NewId(); + std::string ifIdTrue = "__compGenTrue"; + ifIdTrue.append(std::to_string(ifId)); + GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI); + instructions.push_back(new JumpStyleInstruction(Instruction::JMPIFDEFINED, ifIdTrue)); + GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); + instructions.push_back(new LabelInstruction(ifIdTrue)); + + } + else if(adv.nodeName == ClassStatement && adv.nodes.size() >= 3 && std::holds_alternative(adv.nodes[0])) { CodeGenClass cls; cls.documentation = GetString(std::get(adv.nodes[0])); diff --git a/src/compiler/lexer.cpp b/src/compiler/lexer.cpp index fb63cd9..293de2c 100644 --- a/src/compiler/lexer.cpp +++ b/src/compiler/lexer.cpp @@ -579,6 +579,7 @@ namespace Tesses::CrossLang break; case '<': case '>': + case '?': if(peek == read) { Flush(); @@ -670,7 +671,6 @@ namespace Tesses::CrossLang case ':': case ';': case ',': - case '?': Flush(); Symbol({read}); break; diff --git a/src/compiler/parser.cpp b/src/compiler/parser.cpp index 5113747..95d7500 100644 --- a/src/compiler/parser.cpp +++ b/src/compiler/parser.cpp @@ -1088,6 +1088,10 @@ namespace Tesses::CrossLang { return AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(XOrExpression,true,{ node,ParseAssignment()})}); } + else if(IsSymbol("?\?=")) + { + return AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(NullCoalescingExpression,true,{ node,ParseAssignment()})}); + } return node; } SyntaxNode Parser::ParseNode(bool isRoot) @@ -1547,9 +1551,18 @@ namespace Tesses::CrossLang EnsureSymbol(";"); return v; } + SyntaxNode Parser::ParseNullCoalescing() + { + SyntaxNode expr = ParseLOr(); + while(IsSymbol("?\?")) + { + expr = AdvancedSyntaxNode::Create(NullCoalescingExpression,true,{expr,ParseLOr()}); + } + return expr; + } SyntaxNode Parser::ParseTernary() { - SyntaxNode node = ParseLOr(); + SyntaxNode node = ParseNullCoalescing(); if(IsSymbol("?")) { auto yes = ParseTernary(); diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index 5bd8da3..37a64d2 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -6163,6 +6163,32 @@ namespace Tesses::CrossLang { } return false; } + bool InterperterThread::JumpIfDefined(GC* gc) + { + + std::vector& cse=this->call_stack_entries; + auto stk = cse.back(); + + if(stk->ip + 4 <= stk->callable->closure->code.size()) + { + uint32_t n=BitConverter::ToUint32BE(stk->callable->closure->code[stk->ip]); + + GCList ls(gc); + auto _res2 = stk->Pop(ls); + + stk->ip = stk->ip + 4; + if(!std::holds_alternative(_res2) && !std::holds_alternative(_res2)) + { + stk->ip = n; + stk->Push(gc,_res2); + } + + + } + else + throw VMException("Can't read jmpifdefined pc."); + return false; + } bool InterperterThread::JumpIfBreak(GC* gc) { diff --git a/src/vm/vm_opcode_table.h b/src/vm/vm_opcode_table.h index f1ac19d..5beaa6a 100644 --- a/src/vm/vm_opcode_table.h +++ b/src/vm/vm_opcode_table.h @@ -1,3 +1,260 @@ #if defined(VM_OPCODE_TABLE_INLINE) -static opcode opcodes[256]={&InterperterThread::Add, &InterperterThread::Sub, &InterperterThread::Times, &InterperterThread::Divide, &InterperterThread::Mod, &InterperterThread::LShift, &InterperterThread::RShift, &InterperterThread::BOr, &InterperterThread::BAnd, &InterperterThread::BNot, &InterperterThread::Lt, &InterperterThread::Gt, &InterperterThread::Lte, &InterperterThread::Gte, &InterperterThread::Eq, &InterperterThread::NEq, &InterperterThread::LNot, &InterperterThread::Neg, &InterperterThread::XOr, &InterperterThread::Pop, &InterperterThread::Dup,&InterperterThread::Nop, &InterperterThread::PushClosure, &InterperterThread::CreateDictionary, &InterperterThread::CreateArray, &InterperterThread::AppendList, &InterperterThread::AppendDictionary, &InterperterThread::PushResource, &InterperterThread::PushLong, &InterperterThread::PushChar, &InterperterThread::PushDouble, &InterperterThread::PushString, &InterperterThread::PushNull, &InterperterThread::PushUndefined, &InterperterThread::ScopeBegin, &InterperterThread::ScopeEnd, &InterperterThread::ScopeEndTimes, &InterperterThread::PushFalse, &InterperterThread::PushTrue, &InterperterThread::SetVariable, &InterperterThread::GetVariable, &InterperterThread::DeclareVariable, &InterperterThread::SetField, &InterperterThread::GetField, &InterperterThread::ExecuteFunction, &InterperterThread::ExecuteMethod, &InterperterThread::Return, &InterperterThread::JumpConditional, &InterperterThread::Jump, &InterperterThread::JumpUndefined, &InterperterThread::Defer, &InterperterThread::TryCatch, &InterperterThread::Throw, &InterperterThread::PushScopelessClosure, &InterperterThread::Yield, &InterperterThread::PushRootPath, &InterperterThread::PushRelativePath, &InterperterThread::Breakpoint, &InterperterThread::PushBreak, &InterperterThread::PushContinue, &InterperterThread::JumpIfBreak, &InterperterThread::JumpIfContinue, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal, &InterperterThread::Illegal}; +static opcode opcodes[256]={ + &InterperterThread::Add, + &InterperterThread::Sub, + &InterperterThread::Times, + &InterperterThread::Divide, + &InterperterThread::Mod, + &InterperterThread::LShift, + &InterperterThread::RShift, + &InterperterThread::BOr, + &InterperterThread::BAnd, + &InterperterThread::BNot, + &InterperterThread::Lt, + &InterperterThread::Gt, + &InterperterThread::Lte, + &InterperterThread::Gte, + &InterperterThread::Eq, + &InterperterThread::NEq, + &InterperterThread::LNot, + &InterperterThread::Neg, + &InterperterThread::XOr, + &InterperterThread::Pop, + &InterperterThread::Dup, + &InterperterThread::Nop, + &InterperterThread::PushClosure, + &InterperterThread::CreateDictionary, + &InterperterThread::CreateArray, + &InterperterThread::AppendList, + &InterperterThread::AppendDictionary, + &InterperterThread::PushResource, + &InterperterThread::PushLong, + &InterperterThread::PushChar, + &InterperterThread::PushDouble, + &InterperterThread::PushString, + &InterperterThread::PushNull, + &InterperterThread::PushUndefined, + &InterperterThread::ScopeBegin, + &InterperterThread::ScopeEnd, + &InterperterThread::ScopeEndTimes, + &InterperterThread::PushFalse, + &InterperterThread::PushTrue, + &InterperterThread::SetVariable, + &InterperterThread::GetVariable, + &InterperterThread::DeclareVariable, + &InterperterThread::SetField, + &InterperterThread::GetField, + &InterperterThread::ExecuteFunction, + &InterperterThread::ExecuteMethod, + &InterperterThread::Return, + &InterperterThread::JumpConditional, + &InterperterThread::Jump, + &InterperterThread::JumpUndefined, + &InterperterThread::Defer, + &InterperterThread::TryCatch, + &InterperterThread::Throw, + &InterperterThread::PushScopelessClosure, + &InterperterThread::Yield, + &InterperterThread::PushRootPath, + &InterperterThread::PushRelativePath, + &InterperterThread::Breakpoint, + &InterperterThread::PushBreak, + &InterperterThread::PushContinue, + &InterperterThread::JumpIfBreak, + &InterperterThread::JumpIfContinue, + &InterperterThread::JumpIfDefined, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal, + &InterperterThread::Illegal +}; #endif