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)
|
||||
|
||||
} 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: {
|
||||
|
||||
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[] = { \
|
||||
&&OPCODE_OPERATOR, \
|
||||
&&OPCODE_EXTENDS_TEST, \
|
||||
&&OPCODE_IS_BUILTIN, \
|
||||
&&OPCODE_SET, \
|
||||
&&OPCODE_GET, \
|
||||
&&OPCODE_SET_NAMED, \
|
||||
|
@ -536,6 +537,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
}
|
||||
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) {
|
||||
|
||||
CHECK_SPACE(3);
|
||||
|
|
|
@ -136,6 +136,7 @@ public:
|
|||
enum Opcode {
|
||||
OPCODE_OPERATOR,
|
||||
OPCODE_EXTENDS_TEST,
|
||||
OPCODE_IS_BUILTIN,
|
||||
OPCODE_SET,
|
||||
OPCODE_GET,
|
||||
OPCODE_SET_NAMED,
|
||||
|
|
|
@ -861,6 +861,20 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
|||
op->arguments.push_back(subexpr);
|
||||
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) {
|
||||
// array
|
||||
tokenizer->advance();
|
||||
|
@ -1071,6 +1085,15 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
|||
|
||||
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 {
|
||||
|
||||
//find list [ or find dictionary {
|
||||
|
@ -1329,6 +1352,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
|||
switch (expression[i].op) {
|
||||
|
||||
case OperatorNode::OP_IS:
|
||||
case OperatorNode::OP_IS_BUILTIN:
|
||||
priority = -1;
|
||||
break; //before anything
|
||||
|
||||
|
@ -5793,6 +5817,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
|
|||
case Node::TYPE_CONSTANT: {
|
||||
node_type = _type_from_variant(static_cast<ConstantNode *>(p_node)->value);
|
||||
} 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: {
|
||||
node_type.has_type = true;
|
||||
node_type.kind = DataType::BUILTIN;
|
||||
|
@ -5896,7 +5927,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
|
|||
// yield can return anything
|
||||
node_type.has_type = false;
|
||||
} break;
|
||||
case OperatorNode::OP_IS: {
|
||||
case OperatorNode::OP_IS:
|
||||
case OperatorNode::OP_IS_BUILTIN: {
|
||||
|
||||
if (op->arguments.size() != 2) {
|
||||
_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
|
||||
if (!_is_type_compatible(type_type, value_type) && !_is_type_compatible(value_type, type_type)) {
|
||||
// TODO: Make this a warning?
|
||||
_set_error("A value of type '" + value_type.to_string() + "' will never be an instance of '" + type_type.to_string() + "'.", op->line);
|
||||
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);
|
||||
} else {
|
||||
_set_error("A value of type '" + value_type.to_string() + "' will never be of type '" + type_type.to_string() + "'.", op->line);
|
||||
}
|
||||
return DataType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,6 +345,7 @@ public:
|
|||
OP_PARENT_CALL,
|
||||
OP_YIELD,
|
||||
OP_IS,
|
||||
OP_IS_BUILTIN,
|
||||
//indexing operator
|
||||
OP_INDEX,
|
||||
OP_INDEX_NAMED,
|
||||
|
|
Loading…
Reference in New Issue