From 4b18c4e448c93fbb44c80b89e744cfacea8d8bc4 Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 29 May 2018 23:16:56 -0300 Subject: Add typed instructions to GDScript - Typed assignment (built-in, native, and script). - Cast (built-in conversion; native and script checks). - Check type of functions arguments on call. - Check type of members on set. --- modules/gdscript/gdscript_function.cpp | 223 ++++++++++++++++++++++++++++++++- 1 file changed, 220 insertions(+), 3 deletions(-) (limited to 'modules/gdscript/gdscript_function.cpp') diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 319400bbbe..6a08d86904 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -200,6 +200,12 @@ static String _get_var_type(const Variant *p_type) { &&OPCODE_ASSIGN, \ &&OPCODE_ASSIGN_TRUE, \ &&OPCODE_ASSIGN_FALSE, \ + &&OPCODE_ASSIGN_TYPED_BUILTIN, \ + &&OPCODE_ASSIGN_TYPED_NATIVE, \ + &&OPCODE_ASSIGN_TYPED_SCRIPT, \ + &&OPCODE_CAST_TO_BUILTIN, \ + &&OPCODE_CAST_TO_NATIVE, \ + &&OPCODE_CAST_TO_SCRIPT, \ &&OPCODE_CONSTRUCT, \ &&OPCODE_CONSTRUCT_ARRAY, \ &&OPCODE_CONSTRUCT_DICTIONARY, \ @@ -318,10 +324,28 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (_stack_size) { stack = (Variant *)aptr; - for (int i = 0; i < p_argcount; i++) - memnew_placement(&stack[i], Variant(*p_args[i])); - for (int i = p_argcount; i < _stack_size; i++) + for (int i = 0; i < p_argcount; i++) { + if (!argument_types[i].has_type) { + memnew_placement(&stack[i], Variant(*p_args[i])); + continue; + } + + if (!argument_types[i].is_type(*p_args[i], true)) { + r_err.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_err.argument = i; + r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT; + return Variant(); + } + if (argument_types[i].kind == GDScriptDataType::BUILTIN) { + Variant arg = Variant::construct(argument_types[i].builtin_type, &p_args[i], 1, r_err); + memnew_placement(&stack[i], Variant(arg)); + } else { + memnew_placement(&stack[i], Variant(*p_args[i])); + } + } + for (int i = p_argcount; i < _stack_size; i++) { memnew_placement(&stack[i], Variant); + } } else { stack = NULL; } @@ -709,6 +733,199 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_ASSIGN_TYPED_BUILTIN) { + + CHECK_SPACE(4); + Variant::Type var_type = (Variant::Type)_code_ptr[ip + 1]; + GET_VARIANT_PTR(dst, 2); + GET_VARIANT_PTR(src, 3); + + GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX); + + if (src->get_type() != var_type) { + err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) + + "' to a variable of type '" + Variant::get_type_name(var_type) + "'."; + OPCODE_BREAK; + } + + *dst = *src; + + ip += 4; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) { + + CHECK_SPACE(4); + GET_VARIANT_PTR(type, 1); + GET_VARIANT_PTR(dst, 2); + GET_VARIANT_PTR(src, 3); + + GDScriptNativeClass *nc = Object::cast_to(type->operator Object *()); + GD_ERR_BREAK(!nc); + Object *src_obj = src->operator Object *(); + GD_ERR_BREAK(!src_obj); + + if (!ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) { + err_text = "Trying to assign value of type '" + src_obj->get_class_name() + + "' to a variable of type '" + nc->get_name() + "'."; + OPCODE_BREAK; + } + + *dst = *src; + + ip += 4; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_ASSIGN_TYPED_SCRIPT) { + + CHECK_SPACE(4); + GET_VARIANT_PTR(type, 1); + GET_VARIANT_PTR(dst, 2); + GET_VARIANT_PTR(src, 3); + + Script *base_type = Object::cast_to