GDScript: Allow `is` operator to test built-in types
This commit is contained in:
parent
653b4829f1
commit
4b974a36b7
|
@ -1253,6 +1253,25 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
||||||
codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter)
|
codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter)
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
case GDScriptParser::OperatorNode::OP_IS_BUILTIN: {
|
||||||
|
ERR_FAIL_COND_V(on->arguments.size() != 2, false);
|
||||||
|
ERR_FAIL_COND_V(on->arguments[1]->type != GDScriptParser::Node::TYPE_TYPE, false);
|
||||||
|
|
||||||
|
int slevel = p_stack_level;
|
||||||
|
|
||||||
|
int src_address_a = _parse_expression(codegen, on->arguments[0], slevel);
|
||||||
|
if (src_address_a < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS)
|
||||||
|
slevel++; //uses stack for return, increase stack
|
||||||
|
|
||||||
|
const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(on->arguments[1]);
|
||||||
|
|
||||||
|
codegen.opcodes.push_back(GDScriptFunction::OPCODE_IS_BUILTIN); // perform operator
|
||||||
|
codegen.opcodes.push_back(src_address_a); // argument 1
|
||||||
|
codegen.opcodes.push_back((int)tn->vtype); // argument 2 (unary only takes one parameter)
|
||||||
|
} break;
|
||||||
default: {
|
default: {
|
||||||
|
|
||||||
ERR_EXPLAIN("Bug in bytecode compiler, unexpected operator #" + itos(on->op) + " in parse tree while parsing expression.");
|
ERR_EXPLAIN("Bug in bytecode compiler, unexpected operator #" + itos(on->op) + " in parse tree while parsing expression.");
|
||||||
|
|
|
@ -191,6 +191,7 @@ static String _get_var_type(const Variant *p_type) {
|
||||||
static const void *switch_table_ops[] = { \
|
static const void *switch_table_ops[] = { \
|
||||||
&&OPCODE_OPERATOR, \
|
&&OPCODE_OPERATOR, \
|
||||||
&&OPCODE_EXTENDS_TEST, \
|
&&OPCODE_EXTENDS_TEST, \
|
||||||
|
&&OPCODE_IS_BUILTIN, \
|
||||||
&&OPCODE_SET, \
|
&&OPCODE_SET, \
|
||||||
&&OPCODE_GET, \
|
&&OPCODE_GET, \
|
||||||
&&OPCODE_SET_NAMED, \
|
&&OPCODE_SET_NAMED, \
|
||||||
|
@ -536,6 +537,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||||
}
|
}
|
||||||
DISPATCH_OPCODE;
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
|
OPCODE(OPCODE_IS_BUILTIN) {
|
||||||
|
|
||||||
|
CHECK_SPACE(4);
|
||||||
|
|
||||||
|
GET_VARIANT_PTR(value, 1);
|
||||||
|
Variant::Type var_type = (Variant::Type)_code_ptr[ip + 2];
|
||||||
|
GET_VARIANT_PTR(dst, 3);
|
||||||
|
|
||||||
|
GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
|
||||||
|
|
||||||
|
*dst = value->get_type() == var_type;
|
||||||
|
ip += 4;
|
||||||
|
}
|
||||||
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
OPCODE(OPCODE_SET) {
|
OPCODE(OPCODE_SET) {
|
||||||
|
|
||||||
CHECK_SPACE(3);
|
CHECK_SPACE(3);
|
||||||
|
|
|
@ -136,6 +136,7 @@ public:
|
||||||
enum Opcode {
|
enum Opcode {
|
||||||
OPCODE_OPERATOR,
|
OPCODE_OPERATOR,
|
||||||
OPCODE_EXTENDS_TEST,
|
OPCODE_EXTENDS_TEST,
|
||||||
|
OPCODE_IS_BUILTIN,
|
||||||
OPCODE_SET,
|
OPCODE_SET,
|
||||||
OPCODE_GET,
|
OPCODE_GET,
|
||||||
OPCODE_SET_NAMED,
|
OPCODE_SET_NAMED,
|
||||||
|
|
|
@ -861,6 +861,20 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
||||||
op->arguments.push_back(subexpr);
|
op->arguments.push_back(subexpr);
|
||||||
expr=op;*/
|
expr=op;*/
|
||||||
|
|
||||||
|
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_IS && tokenizer->get_token(1) == GDScriptTokenizer::TK_BUILT_IN_TYPE) {
|
||||||
|
// 'is' operator with built-in type
|
||||||
|
OperatorNode *op = alloc_node<OperatorNode>();
|
||||||
|
op->op = OperatorNode::OP_IS_BUILTIN;
|
||||||
|
op->arguments.push_back(expr);
|
||||||
|
|
||||||
|
tokenizer->advance();
|
||||||
|
|
||||||
|
TypeNode *tn = alloc_node<TypeNode>();
|
||||||
|
tn->vtype = tokenizer->get_token_type();
|
||||||
|
op->arguments.push_back(tn);
|
||||||
|
tokenizer->advance();
|
||||||
|
|
||||||
|
expr = op;
|
||||||
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_BRACKET_OPEN) {
|
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_BRACKET_OPEN) {
|
||||||
// array
|
// array
|
||||||
tokenizer->advance();
|
tokenizer->advance();
|
||||||
|
@ -1071,6 +1085,15 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
||||||
|
|
||||||
expr = op;
|
expr = op;
|
||||||
|
|
||||||
|
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_TYPE && expression.size() > 0 && expression[expression.size() - 1].is_op && expression[expression.size() - 1].op == OperatorNode::OP_IS) {
|
||||||
|
Expression e = expression[expression.size() - 1];
|
||||||
|
e.op = OperatorNode::OP_IS_BUILTIN;
|
||||||
|
expression.write[expression.size() - 1] = e;
|
||||||
|
|
||||||
|
TypeNode *tn = alloc_node<TypeNode>();
|
||||||
|
tn->vtype = tokenizer->get_token_type();
|
||||||
|
expr = tn;
|
||||||
|
tokenizer->advance();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//find list [ or find dictionary {
|
//find list [ or find dictionary {
|
||||||
|
@ -1329,6 +1352,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
||||||
switch (expression[i].op) {
|
switch (expression[i].op) {
|
||||||
|
|
||||||
case OperatorNode::OP_IS:
|
case OperatorNode::OP_IS:
|
||||||
|
case OperatorNode::OP_IS_BUILTIN:
|
||||||
priority = -1;
|
priority = -1;
|
||||||
break; //before anything
|
break; //before anything
|
||||||
|
|
||||||
|
@ -5793,6 +5817,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
|
||||||
case Node::TYPE_CONSTANT: {
|
case Node::TYPE_CONSTANT: {
|
||||||
node_type = _type_from_variant(static_cast<ConstantNode *>(p_node)->value);
|
node_type = _type_from_variant(static_cast<ConstantNode *>(p_node)->value);
|
||||||
} break;
|
} break;
|
||||||
|
case Node::TYPE_TYPE: {
|
||||||
|
TypeNode *tn = static_cast<TypeNode *>(p_node);
|
||||||
|
node_type.has_type = true;
|
||||||
|
node_type.is_meta_type = true;
|
||||||
|
node_type.kind = DataType::BUILTIN;
|
||||||
|
node_type.builtin_type = tn->vtype;
|
||||||
|
} break;
|
||||||
case Node::TYPE_ARRAY: {
|
case Node::TYPE_ARRAY: {
|
||||||
node_type.has_type = true;
|
node_type.has_type = true;
|
||||||
node_type.kind = DataType::BUILTIN;
|
node_type.kind = DataType::BUILTIN;
|
||||||
|
@ -5896,7 +5927,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
|
||||||
// yield can return anything
|
// yield can return anything
|
||||||
node_type.has_type = false;
|
node_type.has_type = false;
|
||||||
} break;
|
} break;
|
||||||
case OperatorNode::OP_IS: {
|
case OperatorNode::OP_IS:
|
||||||
|
case OperatorNode::OP_IS_BUILTIN: {
|
||||||
|
|
||||||
if (op->arguments.size() != 2) {
|
if (op->arguments.size() != 2) {
|
||||||
_set_error("Parser bug: binary operation without 2 arguments.", op->line);
|
_set_error("Parser bug: binary operation without 2 arguments.", op->line);
|
||||||
|
@ -5913,8 +5945,11 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
|
||||||
}
|
}
|
||||||
type_type.is_meta_type = false; // Test the actual type
|
type_type.is_meta_type = false; // Test the actual type
|
||||||
if (!_is_type_compatible(type_type, value_type) && !_is_type_compatible(value_type, type_type)) {
|
if (!_is_type_compatible(type_type, value_type) && !_is_type_compatible(value_type, type_type)) {
|
||||||
// TODO: Make this a warning?
|
if (op->op == OperatorNode::OP_IS) {
|
||||||
_set_error("A value of type '" + value_type.to_string() + "' will never be an instance of '" + type_type.to_string() + "'.", op->line);
|
_set_error("A value of type '" + value_type.to_string() + "' will never be an instance of '" + type_type.to_string() + "'.", op->line);
|
||||||
|
} else {
|
||||||
|
_set_error("A value of type '" + value_type.to_string() + "' will never be of type '" + type_type.to_string() + "'.", op->line);
|
||||||
|
}
|
||||||
return DataType();
|
return DataType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,6 +345,7 @@ public:
|
||||||
OP_PARENT_CALL,
|
OP_PARENT_CALL,
|
||||||
OP_YIELD,
|
OP_YIELD,
|
||||||
OP_IS,
|
OP_IS,
|
||||||
|
OP_IS_BUILTIN,
|
||||||
//indexing operator
|
//indexing operator
|
||||||
OP_INDEX,
|
OP_INDEX,
|
||||||
OP_INDEX_NAMED,
|
OP_INDEX_NAMED,
|
||||||
|
|
Loading…
Reference in New Issue