Skip to content

Commit

Permalink
implement ?? and ?. operators
Browse files Browse the repository at this point in the history
  • Loading branch information
ate47 committed Jul 30, 2024
1 parent 568463c commit f06f45b
Show file tree
Hide file tree
Showing 9 changed files with 1,450 additions and 1,151 deletions.
11 changes: 6 additions & 5 deletions grammar/gsc.g4
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ operator_inst: BUILTIN (IDENTIFIER | expression)?;

expression:
set_expression
| expression1 '?' expression ':' expression
| expression1
;
| expression0 '?' expression ':' expression
| expression0
;

set_expression:
left_value (
Expand All @@ -88,6 +88,7 @@ set_expression:
) expression
;

expression0: expression0 '??' expression1 | expression1;
expression1: expression1 '||' expression2 | expression2;
expression2: expression2 '&&' expression3 | expression3;
expression3: expression3 '|' expression4 | expression4;
Expand Down Expand Up @@ -122,9 +123,9 @@ function_call:

left_value:
idf
| left_value '.' (idf | ('(' expression ')'))
| left_value ('.' | '?.') (idf | ('(' expression ')'))
| left_value '[' expression ']'
| (function_call | const_expr | expression15) '.' (idf | ('(' expression ')'))
| (function_call | const_expr | expression15) ('.' | '?.') (idf | ('(' expression ')'))
| (function_call | const_expr | expression15) '[' expression ']';

const_expr:
Expand Down
4 changes: 4 additions & 0 deletions src/acts/compiler/gscBaseVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ class gscBaseVisitor : public gscVisitor {
return visitChildren(ctx);
}

virtual std::any visitExpression0(gscParser::Expression0Context *ctx) override {
return visitChildren(ctx);
}

virtual std::any visitExpression1(gscParser::Expression1Context *ctx) override {
return visitChildren(ctx);
}
Expand Down
511 changes: 257 additions & 254 deletions src/acts/compiler/gscLexer.cpp

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/acts/compiler/gscLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ class gscLexer : public antlr4::Lexer {
T__68 = 69, T__69 = 70, T__70 = 71, T__71 = 72, T__72 = 73, T__73 = 74,
T__74 = 75, T__75 = 76, T__76 = 77, T__77 = 78, T__78 = 79, T__79 = 80,
T__80 = 81, T__81 = 82, T__82 = 83, T__83 = 84, T__84 = 85, T__85 = 86,
T__86 = 87, T__87 = 88, NEWLINE = 89, WHITESPACE = 90, INTEGER10 = 91,
INTEGER16 = 92, INTEGER8 = 93, INTEGER2 = 94, FLOATVAL = 95, BUILTIN = 96,
BOOL_VALUE = 97, UNDEFINED_VALUE = 98, IDENTIFIER = 99, STRUCT_IDENTIFIER = 100,
PATH = 101, STRING = 102, HASHSTRING = 103
T__86 = 87, T__87 = 88, T__88 = 89, T__89 = 90, NEWLINE = 91, WHITESPACE = 92,
INTEGER10 = 93, INTEGER16 = 94, INTEGER8 = 95, INTEGER2 = 96, FLOATVAL = 97,
BUILTIN = 98, BOOL_VALUE = 99, UNDEFINED_VALUE = 100, IDENTIFIER = 101,
STRUCT_IDENTIFIER = 102, PATH = 103, STRING = 104, HASHSTRING = 105
};

explicit gscLexer(antlr4::CharStream *input);
Expand Down
1,866 changes: 993 additions & 873 deletions src/acts/compiler/gscParser.cpp

Large diffs are not rendered by default.

43 changes: 30 additions & 13 deletions src/acts/compiler/gscParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ class gscParser : public antlr4::Parser {
T__68 = 69, T__69 = 70, T__70 = 71, T__71 = 72, T__72 = 73, T__73 = 74,
T__74 = 75, T__75 = 76, T__76 = 77, T__77 = 78, T__78 = 79, T__79 = 80,
T__80 = 81, T__81 = 82, T__82 = 83, T__83 = 84, T__84 = 85, T__85 = 86,
T__86 = 87, T__87 = 88, NEWLINE = 89, WHITESPACE = 90, INTEGER10 = 91,
INTEGER16 = 92, INTEGER8 = 93, INTEGER2 = 94, FLOATVAL = 95, BUILTIN = 96,
BOOL_VALUE = 97, UNDEFINED_VALUE = 98, IDENTIFIER = 99, STRUCT_IDENTIFIER = 100,
PATH = 101, STRING = 102, HASHSTRING = 103
T__86 = 87, T__87 = 88, T__88 = 89, T__89 = 90, NEWLINE = 91, WHITESPACE = 92,
INTEGER10 = 93, INTEGER16 = 94, INTEGER8 = 95, INTEGER2 = 96, FLOATVAL = 97,
BUILTIN = 98, BOOL_VALUE = 99, UNDEFINED_VALUE = 100, IDENTIFIER = 101,
STRUCT_IDENTIFIER = 102, PATH = 103, STRING = 104, HASHSTRING = 105
};

enum {
Expand All @@ -40,14 +40,15 @@ class gscParser : public antlr4::Parser {
RuleStatement_while = 14, RuleStatement_dowhile = 15, RuleStatement_foreach = 16,
RuleStatement_if = 17, RuleStatement_switch = 18, RuleStatement_inst = 19,
RuleNop_def = 20, RuleDevop_def = 21, RuleFunction_component = 22, RuleOperator_inst = 23,
RuleExpression = 24, RuleSet_expression = 25, RuleExpression1 = 26,
RuleExpression2 = 27, RuleExpression3 = 28, RuleExpression4 = 29, RuleExpression5 = 30,
RuleExpression6 = 31, RuleExpression7 = 32, RuleExpression8 = 33, RuleExpression9 = 34,
RuleExpression10 = 35, RuleExpression11 = 36, RuleExpression12 = 37,
RuleExpression13 = 38, RuleExpression14 = 39, RuleExpression15 = 40,
RuleIs_expression = 41, RuleFunction_call_exp = 42, RuleFunction_call = 43,
RuleLeft_value = 44, RuleConst_expr = 45, RuleFunction_ref = 46, RuleNumber = 47,
RuleVector_value = 48, RuleArray_def = 49, RuleStruct_def = 50, RuleIdf = 51
RuleExpression = 24, RuleSet_expression = 25, RuleExpression0 = 26,
RuleExpression1 = 27, RuleExpression2 = 28, RuleExpression3 = 29, RuleExpression4 = 30,
RuleExpression5 = 31, RuleExpression6 = 32, RuleExpression7 = 33, RuleExpression8 = 34,
RuleExpression9 = 35, RuleExpression10 = 36, RuleExpression11 = 37,
RuleExpression12 = 38, RuleExpression13 = 39, RuleExpression14 = 40,
RuleExpression15 = 41, RuleIs_expression = 42, RuleFunction_call_exp = 43,
RuleFunction_call = 44, RuleLeft_value = 45, RuleConst_expr = 46, RuleFunction_ref = 47,
RuleNumber = 48, RuleVector_value = 49, RuleArray_def = 50, RuleStruct_def = 51,
RuleIdf = 52
};

explicit gscParser(antlr4::TokenStream *input);
Expand Down Expand Up @@ -93,6 +94,7 @@ class gscParser : public antlr4::Parser {
class Operator_instContext;
class ExpressionContext;
class Set_expressionContext;
class Expression0Context;
class Expression1Context;
class Expression2Context;
class Expression3Context;
Expand Down Expand Up @@ -492,7 +494,7 @@ class gscParser : public antlr4::Parser {
ExpressionContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
Set_expressionContext *set_expression();
Expression1Context *expression1();
Expression0Context *expression0();
std::vector<ExpressionContext *> expression();
ExpressionContext* expression(size_t i);

Expand All @@ -517,6 +519,20 @@ class gscParser : public antlr4::Parser {

Set_expressionContext* set_expression();

class Expression0Context : public antlr4::ParserRuleContext {
public:
Expression0Context(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
Expression1Context *expression1();
Expression0Context *expression0();


virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;

};

Expression0Context* expression0();
Expression0Context* expression0(int precedence);
class Expression1Context : public antlr4::ParserRuleContext {
public:
Expression1Context(antlr4::ParserRuleContext *parent, size_t invokingState);
Expand Down Expand Up @@ -910,6 +926,7 @@ class gscParser : public antlr4::Parser {

bool sempred(antlr4::RuleContext *_localctx, size_t ruleIndex, size_t predicateIndex) override;

bool expression0Sempred(Expression0Context *_localctx, size_t predicateIndex);
bool expression1Sempred(Expression1Context *_localctx, size_t predicateIndex);
bool expression2Sempred(Expression2Context *_localctx, size_t predicateIndex);
bool expression3Sempred(Expression3Context *_localctx, size_t predicateIndex);
Expand Down
2 changes: 2 additions & 0 deletions src/acts/compiler/gscVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class gscVisitor : public antlr4::tree::AbstractParseTreeVisitor {

virtual std::any visitSet_expression(gscParser::Set_expressionContext *context) = 0;

virtual std::any visitExpression0(gscParser::Expression0Context *context) = 0;

virtual std::any visitExpression1(gscParser::Expression1Context *context) = 0;

virtual std::any visitExpression2(gscParser::Expression2Context *context) = 0;
Expand Down
148 changes: 146 additions & 2 deletions src/acts/compiler/gsc_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,7 @@ namespace acts::compiler {
size_t size{};
size_t rndVarStart{};
FunctionVar m_vars[256]{};
FunctionVar* specialTempVar{};
size_t m_allocatedVar{};
std::vector<AscmNode*> m_nodes{};
std::stack<AscmNode*> m_jumpBreak{};
Expand Down Expand Up @@ -1183,6 +1184,23 @@ namespace acts::compiler {
return RegisterVar(std::format("$$v{:x}", rndVarStart++), false);
}

/*
* Get or create the tmp variable for this function
*/
std::pair<const char*, FunctionVar*> GetSpecialTmpVar() {
if (!specialTempVar) {
auto [err, var] = RegisterVar("$$tmp", false);

if (err) {
return std::make_pair<>(err, var);
}

specialTempVar = var;
}

return std::make_pair<>(nullptr, specialTempVar);
}

/*
* Compute the nodes relative locations
* @return -1 in case of error, the size otherwise
Expand Down Expand Up @@ -1299,6 +1317,7 @@ namespace acts::compiler {
case gscParser::RuleExpression15:
return NumberNodeValue(rule->children[1]);
case gscParser::RuleExpression:
case gscParser::RuleExpression0:
case gscParser::RuleExpression1:
case gscParser::RuleExpression2:
case gscParser::RuleExpression3:
Expand Down Expand Up @@ -2195,6 +2214,7 @@ namespace acts::compiler {

switch (rule->getRuleIndex()) {
case gscParser::RuleExpression:
case gscParser::RuleExpression0:
case gscParser::RuleExpression1:
case gscParser::RuleExpression2:
case gscParser::RuleExpression3:
Expand Down Expand Up @@ -2228,7 +2248,11 @@ namespace acts::compiler {

std::string second = rule->children[1]->getText();

if (second == ".") {
if (second == "." || second == "?.") {
if (second == "?.") {
// assume that it'll fail by itself if it is undefined so we don't need to do anything
obj.info.PrintLineMessage(alogs::LVL_WARNING, exp, std::format("Usage of ?. in a left value: {}", rule->getText()));
}
// object access
if (IS_IDF(rule->children[2])) {
if (!ParseExpressionNode(first, parser, obj, fobj, true)) {
Expand Down Expand Up @@ -3531,6 +3555,7 @@ namespace acts::compiler {
return true;
}
case gscParser::RuleExpression:
case gscParser::RuleExpression0:
case gscParser::RuleExpression1:
case gscParser::RuleExpression2:
case gscParser::RuleExpression3:
Expand Down Expand Up @@ -3698,6 +3723,40 @@ namespace acts::compiler {
}
return ok;
}
else if (op == "??") {
bool ok{ true };
auto [verr, tmp] = fobj.GetSpecialTmpVar();

if (verr) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, rule->children[1], std::format("Can't create temp variable for ?? operation: {}", verr));
return false;
}

if (!ParseExpressionNode(rule->children[0], parser, obj, fobj, true)) {
ok = false;
}

fobj.AddNode(rule, new AscmNodeVariable(tmp->id, OPCODE_EvalLocalVariableRefCached));
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_SetVariableField));

AscmNode* onDefined = new AscmNode();
fobj.AddNode(rule, new AscmNodeVariable(tmp->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_IsDefined));
fobj.AddNode(rule, new AscmNodeJump(onDefined, OPCODE_JumpOnTrue));


if (!ParseExpressionNode(rule->children[2], parser, obj, fobj, true)) {
ok = false;
}
AscmNode* end = new AscmNode();
fobj.AddNode(rule, new AscmNodeJump(end, OPCODE_Jump));

fobj.AddNode(rule, onDefined);
fobj.AddNode(rule, new AscmNodeVariable(tmp->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(rule, end);

return ok;
}
else {
// push operands
bool ok{ true };
Expand Down Expand Up @@ -3821,7 +3880,32 @@ namespace acts::compiler {
}

if (typeNameHash == hash::Hash64("false")) {
// todo: find implementation for mwiii
if (!obj.HasOpCode(OPCODE_SuperEqual)) {
auto [err, tmp] = fobj.GetSpecialTmpVar();

if (err) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, rule->children[1], std::format("Can't create temp variable for is operation: {}", err));
return false;
}
// tmp = ...
// isdefined(tmp) && tmp == false
fobj.AddNode(rule, new AscmNodeVariable(tmp->id, OPCODE_EvalLocalVariableRefCached));
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_SetVariableField));

fobj.AddNode(rule, new AscmNodeVariable(tmp->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_IsDefined));

AscmNode* after = new AscmNode();
fobj.AddNode(rule, new AscmNodeJump(after, OPCODE_JumpOnFalseExpr));

// tmp == false
fobj.AddNode(rule, new AscmNodeVariable(tmp->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(rule, obj.BuildAscmNodeData(0));
fobj.AddNode(rule, new AscmNodeOpCode(hasNot ? OPCODE_NotEqual : OPCODE_Equal));

fobj.AddNode(rule, after);
return true;
}

fobj.AddNode(rule, obj.BuildAscmNodeData(0));
fobj.AddNode(rule, new AscmNodeOpCode(hasNot ? OPCODE_SuperNotEqual : OPCODE_SuperEqual));
Expand Down Expand Up @@ -4190,6 +4274,66 @@ namespace acts::compiler {
}
return true;
}
else if (second == "?.") {
auto [verr, var] = fobj.GetSpecialTmpVar();
if (verr) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, exp, std::format("Can't allocate temp variable for ?. operator: {}", verr));
return false;
}

// tmp = left
if (!ParseExpressionNode(first, parser, obj, fobj, true)) {
return false;
}
fobj.AddNode(rule, new AscmNodeVariable(var->id, OPCODE_EvalLocalVariableRefCached));
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_SetVariableField));

AscmNode* valUndefined = new AscmNode();
fobj.AddNode(rule, new AscmNodeVariable(var->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_IsDefined));
fobj.AddNode(rule, new AscmNodeJump(valUndefined, OPCODE_JumpOnFalse));

// object access
bool ok{ true };
AscmNode* end = new AscmNode();
fobj.AddNode(rule, new AscmNodeVariable(var->id, OPCODE_EvalLocalVariableCached));
if (IS_IDF(rule->children[2])) {
std::string fieldText = rule->children[2]->getText();

if (fieldText == "size") {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_SizeOf));
}
else {
// use identifier
if (obj.HasOpCode(OPCODE_CastAndEvalFieldVariable)) {
fobj.AddNode(rule, fobj.CreateFieldHash(fieldText, OPCODE_CastAndEvalFieldVariable));
}
else {
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_CastFieldObject));
fobj.AddNode(rule, fobj.CreateFieldHash(fieldText, OPCODE_EvalFieldVariable));
}
}
}
else {
if (!ParseExpressionNode(rule->children[3], parser, obj, fobj, true)) {
ok = false;
}
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_CastCanon));

if (!ParseExpressionNode(first, parser, obj, fobj, true)) {
ok = false;
}
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_CastFieldObject));
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_EvalFieldVariableOnStack));
}
fobj.AddNode(rule, new AscmNodeJump(end, OPCODE_Jump));

fobj.AddNode(rule, valUndefined);
fobj.AddNode(rule, new AscmNodeOpCode(OPCODE_GetUndefined));
fobj.AddNode(rule, end);

return ok;
}
else if (second == "[") {
// array access

Expand Down
8 changes: 8 additions & 0 deletions test/gsc-compiler/acts_t7.gsc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ function __pre_init__() {
self iprintln("int");
}
};
b = 42;
c = 52;

a = b ?? c;

if (a?.b?.c is defined) {
self iprintln("a.b.c " + a.b.c);
}
}

function on_player_connect() {
Expand Down

0 comments on commit f06f45b

Please sign in to comment.