Add Null Coalescing operator

This commit is contained in:
2025-07-26 20:17:19 -05:00
parent a233adf37f
commit 92d65771c1
6 changed files with 319 additions and 5 deletions

View File

@@ -664,7 +664,8 @@ typedef enum {
PUSHBREAK, PUSHBREAK,
PUSHCONTINUE, PUSHCONTINUE,
JMPIFBREAK, JMPIFBREAK,
JMPIFCONTINUE JMPIFCONTINUE,
JMPIFDEFINED
} Instruction; } Instruction;
/** /**
* @brief Base type for bytecode instruction * @brief Base type for bytecode instruction
@@ -1274,6 +1275,10 @@ constexpr std::string_view RelativePathExpression = "relativePathExpression";
* @brief await expression for async/await * @brief await expression for async/await
*/ */
constexpr std::string_view AwaitExpression = "awaitExpression"; constexpr std::string_view AwaitExpression = "awaitExpression";
/**
* @brief ?? operator
*/
constexpr std::string_view NullCoalescingExpression = "nullCoalescingExpression";
/** /**
* @brief Advanced AST node * @brief Advanced AST node
* *
@@ -1346,6 +1351,7 @@ class Parser {
SyntaxNode ParseFactor(); SyntaxNode ParseFactor();
SyntaxNode ParseValue(); SyntaxNode ParseValue();
SyntaxNode ParseUnary(); SyntaxNode ParseUnary();
SyntaxNode ParseNullCoalescing();
void ParseHtml(std::vector<SyntaxNode>& nodes,std::string var); void ParseHtml(std::vector<SyntaxNode>& nodes,std::string var);
GC* gc; GC* gc;
TRootEnvironment* env; TRootEnvironment* env;
@@ -2254,6 +2260,7 @@ class GC {
bool ExecuteMethod2(GC* gc, TObject instance, std::string key, std::vector<TObject> args); bool ExecuteMethod2(GC* gc, TObject instance, std::string key, std::vector<TObject> args);
protected: protected:
static void* ThreadCallback(void* ptr); static void* ThreadCallback(void* ptr);
bool JumpIfDefined(GC* gc);
bool Add(GC* gc); bool Add(GC* gc);
bool Sub(GC* gc); bool Sub(GC* gc);
bool Times(GC* gc); bool Times(GC* gc);

View File

@@ -521,7 +521,18 @@ namespace Tesses::CrossLang
TWO_EXPR(NotEqualsExpression, NEQ) TWO_EXPR(NotEqualsExpression, NEQ)
TWO_EXPR(EqualsExpression, EQ) TWO_EXPR(EqualsExpression, EQ)
TWO_EXPR(XOrExpression, XOR) TWO_EXPR(XOrExpression, XOR)
if(adv.nodeName == ClassStatement && adv.nodes.size() >= 3 && std::holds_alternative<std::string>(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<std::string>(adv.nodes[0]))
{ {
CodeGenClass cls; CodeGenClass cls;
cls.documentation = GetString(std::get<std::string>(adv.nodes[0])); cls.documentation = GetString(std::get<std::string>(adv.nodes[0]));

View File

@@ -579,6 +579,7 @@ namespace Tesses::CrossLang
break; break;
case '<': case '<':
case '>': case '>':
case '?':
if(peek == read) if(peek == read)
{ {
Flush(); Flush();
@@ -670,7 +671,6 @@ namespace Tesses::CrossLang
case ':': case ':':
case ';': case ';':
case ',': case ',':
case '?':
Flush(); Flush();
Symbol({read}); Symbol({read});
break; break;

View File

@@ -1088,6 +1088,10 @@ namespace Tesses::CrossLang
{ {
return AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(XOrExpression,true,{ node,ParseAssignment()})}); 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; return node;
} }
SyntaxNode Parser::ParseNode(bool isRoot) SyntaxNode Parser::ParseNode(bool isRoot)
@@ -1547,9 +1551,18 @@ namespace Tesses::CrossLang
EnsureSymbol(";"); EnsureSymbol(";");
return v; return v;
} }
SyntaxNode Parser::ParseNullCoalescing()
{
SyntaxNode expr = ParseLOr();
while(IsSymbol("?\?"))
{
expr = AdvancedSyntaxNode::Create(NullCoalescingExpression,true,{expr,ParseLOr()});
}
return expr;
}
SyntaxNode Parser::ParseTernary() SyntaxNode Parser::ParseTernary()
{ {
SyntaxNode node = ParseLOr(); SyntaxNode node = ParseNullCoalescing();
if(IsSymbol("?")) if(IsSymbol("?"))
{ {
auto yes = ParseTernary(); auto yes = ParseTernary();

View File

@@ -6163,6 +6163,32 @@ namespace Tesses::CrossLang {
} }
return false; return false;
} }
bool InterperterThread::JumpIfDefined(GC* gc)
{
std::vector<CallStackEntry*>& 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<Undefined>(_res2) && !std::holds_alternative<std::nullptr_t>(_res2))
{
stk->ip = n;
stk->Push(gc,_res2);
}
}
else
throw VMException("Can't read jmpifdefined pc.");
return false;
}
bool InterperterThread::JumpIfBreak(GC* gc) bool InterperterThread::JumpIfBreak(GC* gc)
{ {

File diff suppressed because one or more lines are too long