Skip to content

Commit

Permalink
Add logical XOR to gdscript
Browse files Browse the repository at this point in the history
applied requested changes
Co-authored-by: Danil Alexeev <[email protected]>
  • Loading branch information
JeffVenancius committed May 5, 2023
1 parent 7a13cf9 commit 74f4e19
Show file tree
Hide file tree
Showing 10 changed files with 51 additions and 54 deletions.
64 changes: 17 additions & 47 deletions core/math/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,12 @@ Error Expression::_get_token(Token &r_token) {
return OK;
}
case '^': {
r_token.type = TK_OP_BIT_XOR;

if (expression[str_ofs] == '^') {
r_token.type = TK_OP_XOR;
str_ofs++;
} else {
r_token.type = TK_OP_BIT_XOR;
}
return OK;
}
case '~': {
Expand Down Expand Up @@ -470,10 +474,12 @@ Error Expression::_get_token(Token &r_token) {
r_token.value = NAN;
} else if (id == "not") {
r_token.type = TK_OP_NOT;
} else if (id == "or") {
r_token.type = TK_OP_OR;
} else if (id == "and") {
r_token.type = TK_OP_AND;
} else if (id == "or") {
r_token.type = TK_OP_OR;
} else if (id == "xor") {
r_token.type = TK_OP_XOR;
} else if (id == "self") {
r_token.type = TK_SELF;
} else {
Expand Down Expand Up @@ -516,48 +522,6 @@ Error Expression::_get_token(Token &r_token) {
return ERR_PARSE_ERROR;
}

const char *Expression::token_name[TK_MAX] = {
"CURLY BRACKET OPEN",
"CURLY BRACKET CLOSE",
"BRACKET OPEN",
"BRACKET CLOSE",
"PARENTHESIS OPEN",
"PARENTHESIS CLOSE",
"IDENTIFIER",
"BUILTIN FUNC",
"SELF",
"CONSTANT",
"BASIC TYPE",
"COLON",
"COMMA",
"PERIOD",
"OP IN",
"OP EQUAL",
"OP NOT EQUAL",
"OP LESS",
"OP LESS EQUAL",
"OP GREATER",
"OP GREATER EQUAL",
"OP AND",
"OP OR",
"OP NOT",
"OP ADD",
"OP SUB",
"OP MUL",
"OP DIV",
"OP MOD",
"OP POW",
"OP SHIFT LEFT",
"OP SHIFT RIGHT",
"OP BIT AND",
"OP BIT OR",
"OP BIT XOR",
"OP BIT INVERT",
"OP INPUT",
"EOF",
"ERROR"
};

Expression::ENode *Expression::_parse_expression() {
Vector<ExpressionNode> expression_nodes;

Expand Down Expand Up @@ -1000,6 +964,9 @@ Expression::ENode *Expression::_parse_expression() {
case TK_OP_OR:
op = Variant::OP_OR;
break;
case TK_OP_XOR:
op = Variant::OP_XOR;
break;
case TK_OP_NOT:
op = Variant::OP_NOT;
break;
Expand Down Expand Up @@ -1125,9 +1092,12 @@ Expression::ENode *Expression::_parse_expression() {
case Variant::OP_AND:
priority = 13;
break;
case Variant::OP_OR:
case Variant::OP_XOR:
priority = 14;
break;
case Variant::OP_OR:
priority = 15;
break;
default: {
_set_error("Parser bug, invalid operator in expression: " + itos(expression_nodes[i].op));
return nullptr;
Expand Down
2 changes: 1 addition & 1 deletion core/math/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class Expression : public RefCounted {
TK_OP_GREATER_EQUAL,
TK_OP_AND,
TK_OP_OR,
TK_OP_XOR,
TK_OP_NOT,
TK_OP_ADD,
TK_OP_SUB,
Expand All @@ -98,7 +99,6 @@ class Expression : public RefCounted {
TK_MAX
};

static const char *token_name[TK_MAX];
struct Token {
TokenType type;
Variant value;
Expand Down
2 changes: 1 addition & 1 deletion doc/classes/@GlobalScope.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3056,7 +3056,7 @@
Logical OR operator ([code]or[/code] or [code]||[/code]).
</constant>
<constant name="OP_XOR" value="22" enum="Variant.Operator">
Logical XOR operator (not implemented in GDScript).
Logical XOR operator ([code]xor[/code] or [code]^^[/code]).
</constant>
<constant name="OP_NOT" value="23" enum="Variant.Operator">
Logical NOT operator ([code]not[/code] or [code]![/code]).
Expand Down
10 changes: 7 additions & 3 deletions modules/gdscript/editor/gdscript_highlighter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,9 +466,13 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_string_name = false;
}

// '^^' has no special meaning, so unlike StringName, when binary, use NodePath color for the last caret.
if (!in_node_path && in_region == -1 && str[j] == '^' && !is_binary_op && (j == 0 || (j > 0 && str[j - 1] != '^') || prev_is_binary_op)) {
in_node_path = true;
// Keep symbol color for binary '^^'. In the case of '^^^' use NodePath color for the last caret.
if (!in_node_path && in_region == -1 && str[j] == '^' && !is_binary_op) {
if (j >= 2 && str[j - 1] == '^' && str[j - 2] != '^' && prev_is_binary_op) {
is_binary_op = true;
} else if (j == 0 || (j > 0 && str[j - 1] != '^') || prev_is_binary_op) {
in_node_path = true;
}
} else if (in_region != -1 || is_a_symbol) {
in_node_path = false;
}
Expand Down
1 change: 1 addition & 0 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2310,6 +2310,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"in",
"not",
"or",
"xor",
// types and values
"false",
"float",
Expand Down
2 changes: 1 addition & 1 deletion modules/gdscript/gdscript_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
}

static const char *_keywords_with_space[] = {
"and", "not", "or", "in", "as", "class", "class_name", "extends", "is", "func", "signal", "await",
"and", "not", "or", "xor", "in", "as", "class", "class_name", "extends", "is", "func", "signal", "await",
"const", "enum", "static", "var", "if", "elif", "else", "for", "match", "while",
nullptr
};
Expand Down
10 changes: 10 additions & 0 deletions modules/gdscript/gdscript_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2491,6 +2491,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(Expression
operation->operation = BinaryOpNode::OP_LOGIC_OR;
operation->variant_op = Variant::OP_OR;
break;
case GDScriptTokenizer::Token::XOR:
case GDScriptTokenizer::Token::CARET_CARET:
operation->operation = BinaryOpNode::OP_LOGIC_XOR;
operation->variant_op = Variant::OP_XOR;
break;
case GDScriptTokenizer::Token::IN:
operation->operation = BinaryOpNode::OP_CONTENT_TEST;
operation->variant_op = Variant::OP_IN;
Expand Down Expand Up @@ -3539,9 +3544,11 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
// Logical
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_AND }, // AND,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_OR }, // OR,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_XOR }, // XOR,
{ &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_not_in_operator, PREC_CONTENT_TEST }, // NOT,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_AND }, // AMPERSAND_AMPERSAND,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_OR }, // PIPE_PIPE,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_XOR }, // CARET_CARET,
{ &GDScriptParser::parse_unary_operator, nullptr, PREC_NONE }, // BANG,
// Bitwise
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_BIT_AND }, // AMPERSAND,
Expand Down Expand Up @@ -4466,6 +4473,9 @@ void GDScriptParser::TreePrinter::print_binary_op(BinaryOpNode *p_binary_op) {
case BinaryOpNode::OP_LOGIC_OR:
push_text(" OR ");
break;
case BinaryOpNode::OP_LOGIC_XOR:
push_text(" XOR ");
break;
case BinaryOpNode::OP_CONTENT_TEST:
push_text(" IN ");
break;
Expand Down
2 changes: 2 additions & 0 deletions modules/gdscript/gdscript_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ class GDScriptParser {
OP_BIT_XOR,
OP_LOGIC_AND,
OP_LOGIC_OR,
OP_LOGIC_XOR,
OP_CONTENT_TEST,
OP_COMP_EQUAL,
OP_COMP_NOT_EQUAL,
Expand Down Expand Up @@ -1334,6 +1335,7 @@ class GDScriptParser {
PREC_CAST,
PREC_TERNARY,
PREC_LOGIC_OR,
PREC_LOGIC_XOR,
PREC_LOGIC_AND,
PREC_LOGIC_NOT,
PREC_CONTENT_TEST,
Expand Down
10 changes: 9 additions & 1 deletion modules/gdscript/gdscript_tokenizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,11 @@ static const char *token_names[] = {
// Logical
"and", // AND,
"or", // OR,
"xor", // XOR,
"not", // NOT,
"&&", // AMPERSAND_AMPERSAND,
"||", // PIPE_PIPE,
"^^", // CARET_CARET,
"!", // BANG,
// Bitwise
"&", // AMPERSAND,
Expand Down Expand Up @@ -222,6 +224,7 @@ bool GDScriptTokenizer::Token::is_node_name() const {
case VAR:
case VOID:
case WHILE:
case XOR:
case YIELD:
return true;
default:
Expand Down Expand Up @@ -511,6 +514,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::annotation() {
KEYWORD("void", Token::VOID) \
KEYWORD_GROUP('w') \
KEYWORD("while", Token::WHILE) \
KEYWORD_GROUP('x') \
KEYWORD("xor", Token::XOR) \
KEYWORD_GROUP('y') \
KEYWORD("yield", Token::YIELD) \
KEYWORD_GROUP('I') \
Expand Down Expand Up @@ -1474,7 +1479,10 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
return make_token(Token::PERCENT);
}
case '^':
if (_peek() == '=') {
if (_peek() == '^') {
_advance();
return make_token(Token::CARET_CARET);
} else if (_peek() == '=') {
_advance();
return make_token(Token::CARET_EQUAL);
} else if (_peek() == '"' || _peek() == '\'') {
Expand Down
2 changes: 2 additions & 0 deletions modules/gdscript/gdscript_tokenizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ class GDScriptTokenizer {
// Logical
AND,
OR,
XOR,
NOT,
AMPERSAND_AMPERSAND,
PIPE_PIPE,
CARET_CARET,
BANG,
// Bitwise
AMPERSAND,
Expand Down

0 comments on commit 74f4e19

Please sign in to comment.