1 /*************************************************************************/ 2 /* bindings_generator.h */ 3 /*************************************************************************/ 4 /* This file is part of: */ 5 /* GODOT ENGINE */ 6 /* https://godotengine.org */ 7 /*************************************************************************/ 8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ 9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ 10 /* */ 11 /* Permission is hereby granted, free of charge, to any person obtaining */ 12 /* a copy of this software and associated documentation files (the */ 13 /* "Software"), to deal in the Software without restriction, including */ 14 /* without limitation the rights to use, copy, modify, merge, publish, */ 15 /* distribute, sublicense, and/or sell copies of the Software, and to */ 16 /* permit persons to whom the Software is furnished to do so, subject to */ 17 /* the following conditions: */ 18 /* */ 19 /* The above copyright notice and this permission notice shall be */ 20 /* included in all copies or substantial portions of the Software. */ 21 /* */ 22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ 25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ 26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ 27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ 28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 29 /*************************************************************************/ 30 31 #ifndef BINDINGS_GENERATOR_H 32 #define BINDINGS_GENERATOR_H 33 34 #include "core/class_db.h" 35 #include "core/string_builder.h" 36 #include "editor/doc/doc_data.h" 37 #include "editor/editor_help.h" 38 39 #if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) 40 41 #include "core/ustring.h" 42 43 class BindingsGenerator { 44 45 struct ConstantInterface { 46 String name; 47 String proxy_name; 48 int value; 49 const DocData::ConstantDoc *const_doc; 50 ConstantInterfaceConstantInterface51 ConstantInterface() {} 52 ConstantInterfaceConstantInterface53 ConstantInterface(const String &p_name, const String &p_proxy_name, int p_value) { 54 name = p_name; 55 proxy_name = p_proxy_name; 56 value = p_value; 57 } 58 }; 59 60 struct EnumInterface { 61 StringName cname; 62 List<ConstantInterface> constants; 63 64 _FORCE_INLINE_ bool operator==(const EnumInterface &p_ienum) const { 65 return p_ienum.cname == cname; 66 } 67 EnumInterfaceEnumInterface68 EnumInterface() {} 69 EnumInterfaceEnumInterface70 EnumInterface(const StringName &p_cname) { 71 cname = p_cname; 72 } 73 }; 74 75 struct PropertyInterface { 76 StringName cname; 77 String proxy_name; 78 int index; 79 80 StringName setter; 81 StringName getter; 82 83 const DocData::PropertyDoc *prop_doc; 84 }; 85 86 struct TypeReference { 87 StringName cname; 88 bool is_enum; 89 TypeReferenceTypeReference90 TypeReference() : 91 is_enum(false) { 92 } 93 TypeReferenceTypeReference94 TypeReference(const StringName &p_cname) : 95 cname(p_cname), 96 is_enum(false) { 97 } 98 }; 99 100 struct ArgumentInterface { 101 enum DefaultParamMode { 102 CONSTANT, 103 NULLABLE_VAL, 104 NULLABLE_REF 105 }; 106 107 TypeReference type; 108 109 String name; 110 String default_argument; 111 DefaultParamMode def_param_mode; 112 ArgumentInterfaceArgumentInterface113 ArgumentInterface() { 114 def_param_mode = CONSTANT; 115 } 116 }; 117 118 struct MethodInterface { 119 String name; 120 StringName cname; 121 122 /** 123 * Name of the C# method 124 */ 125 String proxy_name; 126 127 /** 128 * [TypeInterface::name] of the return type 129 */ 130 TypeReference return_type; 131 132 /** 133 * Determines if the method has a variable number of arguments (VarArg) 134 */ 135 bool is_vararg; 136 137 /** 138 * Virtual methods ("virtual" as defined by the Godot API) are methods that by default do nothing, 139 * but can be overridden by the user to add custom functionality. 140 * e.g.: _ready, _process, etc. 141 */ 142 bool is_virtual; 143 144 /** 145 * Determines if the call should fallback to Godot's object.Call(string, params) in C#. 146 */ 147 bool requires_object_call; 148 149 /** 150 * Determines if the method visibility is 'internal' (visible only to files in the same assembly). 151 * Currently, we only use this for methods that are not meant to be exposed, 152 * but are required by properties as getters or setters. 153 * Methods that are not meant to be exposed are those that begin with underscore and are not virtual. 154 */ 155 bool is_internal; 156 157 List<ArgumentInterface> arguments; 158 159 const DocData::MethodDoc *method_doc; 160 161 bool is_deprecated; 162 String deprecation_message; 163 add_argumentMethodInterface164 void add_argument(const ArgumentInterface &argument) { 165 arguments.push_back(argument); 166 } 167 MethodInterfaceMethodInterface168 MethodInterface() { 169 is_vararg = false; 170 is_virtual = false; 171 requires_object_call = false; 172 is_internal = false; 173 method_doc = NULL; 174 is_deprecated = false; 175 } 176 }; 177 178 struct TypeInterface { 179 /** 180 * Identifier name for this type. 181 * Also used to format [c_out]. 182 */ 183 String name; 184 StringName cname; 185 186 /** 187 * Identifier name of the base class. 188 */ 189 StringName base_name; 190 191 /** 192 * Name of the C# class 193 */ 194 String proxy_name; 195 196 ClassDB::APIType api_type; 197 198 bool is_enum; 199 bool is_object_type; 200 bool is_singleton; 201 bool is_reference; 202 203 /** 204 * Used only by Object-derived types. 205 * Determines if this type is not abstract (incomplete). 206 * e.g.: CanvasItem cannot be instantiated. 207 */ 208 bool is_instantiable; 209 210 /** 211 * Used only by Object-derived types. 212 * Determines if the C# class owns the native handle and must free it somehow when disposed. 213 * e.g.: Reference types must notify when the C# instance is disposed, for proper refcounting. 214 */ 215 bool memory_own; 216 217 /** 218 * This must be set to true for any struct bigger than 32-bits. Those cannot be passed/returned by value 219 * with internal calls, so we must use pointers instead. Returns must be replace with out parameters. 220 * In this case, [c_out] and [cs_out] must have a different format, explained below. 221 * The Mono IL interpreter icall trampolines don't support passing structs bigger than 32-bits by value (at least not on WASM). 222 */ 223 bool ret_as_byref_arg; 224 225 // !! The comments of the following fields make reference to other fields via square brackets, e.g.: [field_name] 226 // !! When renaming those fields, make sure to rename their references in the comments 227 228 // --- C INTERFACE --- 229 230 static const char *DEFAULT_VARARG_C_IN; 231 232 /** 233 * One or more statements that manipulate the parameter before being passed as argument of a ptrcall. 234 * If the statement adds a local that must be passed as the argument instead of the parameter, 235 * the name of that local must be specified with [c_arg_in]. 236 * For variadic methods, this field is required and, if empty, [DEFAULT_VARARG_C_IN] is used instead. 237 * Formatting elements: 238 * %0: [c_type] of the parameter 239 * %1: name of the parameter 240 */ 241 String c_in; 242 243 /** 244 * Determines the expression that will be passed as argument to ptrcall. 245 * By default the value equals the name of the parameter, 246 * this varies for types that require special manipulation via [c_in]. 247 * Formatting elements: 248 * %0 or %s: name of the parameter 249 */ 250 String c_arg_in; 251 252 /** 253 * One or more statements that determine how a variable of this type is returned from a function. 254 * It must contain the return statement(s). 255 * Formatting elements: 256 * %0: [c_type_out] of the return type 257 * %1: name of the variable to be returned 258 * %2: [name] of the return type 259 * --------------------------------------- 260 * If [ret_as_byref_arg] is true, the format is different. Instead of using a return statement, 261 * the value must be assigned to a parameter. This type of this parameter is a pointer to [c_type_out]. 262 * Formatting elements: 263 * %0: [c_type_out] of the return type 264 * %1: name of the variable to be returned 265 * %2: [name] of the return type 266 * %3: name of the parameter that must be assigned the return value 267 */ 268 String c_out; 269 270 /** 271 * The actual expected type, as seen (in most cases) in Variant copy constructors 272 * Used for the type of the return variable and to format [c_in]. 273 * The value must be the following depending of the type: 274 * Object-derived types: Object* 275 * Other types: [name] 276 * -- Exceptions -- 277 * VarArg (fictitious type to represent variable arguments): Array 278 * float: double (because ptrcall only supports double) 279 * int: int64_t (because ptrcall only supports int64_t and uint64_t) 280 * Reference types override this for the type of the return variable: Ref<Reference> 281 */ 282 String c_type; 283 284 /** 285 * Determines the type used for parameters in function signatures. 286 */ 287 String c_type_in; 288 289 /** 290 * Determines the return type used for function signatures. 291 * Also used to construct a default value to return in case of errors, 292 * and to format [c_out]. 293 */ 294 String c_type_out; 295 296 // --- C# INTERFACE --- 297 298 /** 299 * An expression that overrides the way the parameter is passed to the internal call. 300 * If empty, the parameter is passed as is. 301 * Formatting elements: 302 * %0 or %s: name of the parameter 303 */ 304 String cs_in; 305 306 /** 307 * One or more statements that determine how a variable of this type is returned from a method. 308 * It must contain the return statement(s). 309 * Formatting elements: 310 * %0: internal method name 311 * %1: internal method call arguments without surrounding parenthesis 312 * %2: [cs_type] of the return type 313 * %3: [im_type_out] of the return type 314 */ 315 String cs_out; 316 317 /** 318 * Type used for method signatures, both for parameters and the return type. 319 * Same as [proxy_name] except for variable arguments (VarArg) and collections (which include the namespace). 320 */ 321 String cs_type; 322 323 /** 324 * Type used for parameters of internal call methods. 325 */ 326 String im_type_in; 327 328 /** 329 * Type used for the return type of internal call methods. 330 */ 331 String im_type_out; 332 333 const DocData::ClassDoc *class_doc; 334 335 List<ConstantInterface> constants; 336 List<EnumInterface> enums; 337 List<PropertyInterface> properties; 338 List<MethodInterface> methods; 339 find_method_by_nameTypeInterface340 const MethodInterface *find_method_by_name(const StringName &p_cname) const { 341 for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) { 342 if (E->get().cname == p_cname) 343 return &E->get(); 344 } 345 346 return NULL; 347 } 348 find_property_by_nameTypeInterface349 const PropertyInterface *find_property_by_name(const StringName &p_cname) const { 350 for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { 351 if (E->get().cname == p_cname) 352 return &E->get(); 353 } 354 355 return NULL; 356 } 357 find_property_by_proxy_nameTypeInterface358 const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const { 359 for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { 360 if (E->get().proxy_name == p_proxy_name) 361 return &E->get(); 362 } 363 364 return NULL; 365 } 366 367 private: _init_value_typeTypeInterface368 static void _init_value_type(TypeInterface &itype) { 369 itype.proxy_name = itype.name; 370 371 itype.c_type = itype.name; 372 itype.cs_type = itype.proxy_name; 373 itype.im_type_in = "ref " + itype.proxy_name; 374 itype.im_type_out = itype.proxy_name; 375 itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name]; 376 } 377 378 public: create_value_typeTypeInterface379 static TypeInterface create_value_type(const String &p_name) { 380 TypeInterface itype; 381 itype.name = p_name; 382 itype.cname = StringName(p_name); 383 _init_value_type(itype); 384 return itype; 385 } 386 create_value_typeTypeInterface387 static TypeInterface create_value_type(const StringName &p_name) { 388 TypeInterface itype; 389 itype.name = p_name.operator String(); 390 itype.cname = p_name; 391 _init_value_type(itype); 392 return itype; 393 } 394 create_object_typeTypeInterface395 static TypeInterface create_object_type(const StringName &p_cname, ClassDB::APIType p_api_type) { 396 TypeInterface itype; 397 398 itype.name = p_cname; 399 itype.cname = p_cname; 400 itype.proxy_name = itype.name.begins_with("_") ? itype.name.substr(1, itype.name.length()) : itype.name; 401 itype.api_type = p_api_type; 402 itype.is_object_type = true; 403 itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name]; 404 405 return itype; 406 } 407 create_placeholder_typeTypeInterface408 static void create_placeholder_type(TypeInterface &r_itype, const StringName &p_cname) { 409 r_itype.name = p_cname; 410 r_itype.cname = p_cname; 411 r_itype.proxy_name = r_itype.name; 412 413 r_itype.c_type = r_itype.name; 414 r_itype.c_type_in = "MonoObject*"; 415 r_itype.c_type_out = "MonoObject*"; 416 r_itype.cs_type = r_itype.proxy_name; 417 r_itype.im_type_in = r_itype.proxy_name; 418 r_itype.im_type_out = r_itype.proxy_name; 419 } 420 postsetup_enum_typeTypeInterface421 static void postsetup_enum_type(TypeInterface &r_enum_itype) { 422 // C interface for enums is the same as that of 'uint32_t'. Remember to apply 423 // any of the changes done here to the 'uint32_t' type interface as well. 424 425 r_enum_itype.c_arg_in = "&%s_in"; 426 { 427 // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'. 428 r_enum_itype.c_in = "\t%0 %1_in = (%0)%1;\n"; 429 r_enum_itype.c_out = "\treturn (%0)%1;\n"; 430 r_enum_itype.c_type = "int64_t"; 431 } 432 r_enum_itype.c_type_in = "int32_t"; 433 r_enum_itype.c_type_out = r_enum_itype.c_type_in; 434 435 r_enum_itype.cs_type = r_enum_itype.proxy_name; 436 r_enum_itype.cs_in = "(int)%s"; 437 r_enum_itype.cs_out = "return (%2)%0(%1);"; 438 r_enum_itype.im_type_in = "int"; 439 r_enum_itype.im_type_out = "int"; 440 r_enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[r_enum_itype.proxy_name]; 441 } 442 TypeInterfaceTypeInterface443 TypeInterface() { 444 445 api_type = ClassDB::API_NONE; 446 447 is_enum = false; 448 is_object_type = false; 449 is_singleton = false; 450 is_reference = false; 451 is_instantiable = false; 452 453 memory_own = false; 454 455 ret_as_byref_arg = false; 456 457 c_arg_in = "%s"; 458 459 class_doc = NULL; 460 } 461 }; 462 463 struct InternalCall { 464 String name; 465 String im_type_out; // Return type for the C# method declaration. Also used as companion of [unique_siq] 466 String im_sig; // Signature for the C# method declaration 467 String unique_sig; // Unique signature to avoid duplicates in containers 468 bool editor_only; 469 InternalCallInternalCall470 InternalCall() {} 471 472 InternalCall(const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) { 473 name = p_name; 474 im_type_out = p_im_type_out; 475 im_sig = p_im_sig; 476 unique_sig = p_unique_sig; 477 editor_only = false; 478 } 479 480 InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) { 481 name = p_name; 482 im_type_out = p_im_type_out; 483 im_sig = p_im_sig; 484 unique_sig = p_unique_sig; 485 editor_only = api_type == ClassDB::API_EDITOR; 486 } 487 488 inline bool operator==(const InternalCall &p_a) const { 489 return p_a.unique_sig == unique_sig; 490 } 491 }; 492 493 bool log_print_enabled; 494 bool initialized; 495 496 OrderedHashMap<StringName, TypeInterface> obj_types; 497 498 Map<StringName, TypeInterface> placeholder_types; 499 Map<StringName, TypeInterface> builtin_types; 500 Map<StringName, TypeInterface> enum_types; 501 502 List<EnumInterface> global_enums; 503 List<ConstantInterface> global_constants; 504 505 List<InternalCall> method_icalls; 506 Map<const MethodInterface *, const InternalCall *> method_icalls_map; 507 508 List<const InternalCall *> generated_icall_funcs; 509 510 List<InternalCall> core_custom_icalls; 511 List<InternalCall> editor_custom_icalls; 512 513 Map<StringName, List<StringName> > blacklisted_methods; 514 515 void _initialize_blacklisted_methods(); 516 517 struct NameCache { 518 StringName type_void; 519 StringName type_Array; 520 StringName type_Dictionary; 521 StringName type_Variant; 522 StringName type_VarArg; 523 StringName type_Object; 524 StringName type_Reference; 525 StringName type_RID; 526 StringName type_String; 527 StringName type_at_GlobalScope; 528 StringName enum_Error; 529 530 StringName type_sbyte; 531 StringName type_short; 532 StringName type_int; 533 StringName type_long; 534 StringName type_byte; 535 StringName type_ushort; 536 StringName type_uint; 537 StringName type_ulong; 538 StringName type_float; 539 StringName type_double; 540 NameCacheNameCache541 NameCache() { 542 type_void = StaticCString::create("void"); 543 type_Array = StaticCString::create("Array"); 544 type_Dictionary = StaticCString::create("Dictionary"); 545 type_Variant = StaticCString::create("Variant"); 546 type_VarArg = StaticCString::create("VarArg"); 547 type_Object = StaticCString::create("Object"); 548 type_Reference = StaticCString::create("Reference"); 549 type_RID = StaticCString::create("RID"); 550 type_String = StaticCString::create("String"); 551 type_at_GlobalScope = StaticCString::create("@GlobalScope"); 552 enum_Error = StaticCString::create("Error"); 553 554 type_sbyte = StaticCString::create("sbyte"); 555 type_short = StaticCString::create("short"); 556 type_int = StaticCString::create("int"); 557 type_long = StaticCString::create("long"); 558 type_byte = StaticCString::create("byte"); 559 type_ushort = StaticCString::create("ushort"); 560 type_uint = StaticCString::create("uint"); 561 type_ulong = StaticCString::create("ulong"); 562 type_float = StaticCString::create("float"); 563 type_double = StaticCString::create("double"); 564 } 565 566 private: 567 NameCache(const NameCache &); 568 NameCache &operator=(const NameCache &); 569 }; 570 571 NameCache name_cache; 572 find_icall_by_name(const String & p_name,const List<InternalCall> & p_list)573 const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) { 574 const List<InternalCall>::Element *it = p_list.front(); 575 while (it) { 576 if (it->get().name == p_name) return it; 577 it = it->next(); 578 } 579 return NULL; 580 } 581 find_constant_by_name(const String & p_name,const List<ConstantInterface> & p_constants)582 const ConstantInterface *find_constant_by_name(const String &p_name, const List<ConstantInterface> &p_constants) const { 583 for (const List<ConstantInterface>::Element *E = p_constants.front(); E; E = E->next()) { 584 if (E->get().name == p_name) 585 return &E->get(); 586 } 587 588 return NULL; 589 } 590 get_unique_sig(const TypeInterface & p_type)591 inline String get_unique_sig(const TypeInterface &p_type) { 592 if (p_type.is_reference) 593 return "Ref"; 594 else if (p_type.is_object_type) 595 return "Obj"; 596 else if (p_type.is_enum) 597 return "int"; 598 599 return p_type.name; 600 } 601 602 String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype); 603 604 int _determine_enum_prefix(const EnumInterface &p_ienum); 605 void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length); 606 607 void _generate_method_icalls(const TypeInterface &p_itype); 608 609 const TypeInterface *_get_type_or_null(const TypeReference &p_typeref); 610 const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref); 611 612 StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta); 613 StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta); 614 615 bool _arg_default_value_from_variant(const Variant &p_val, ArgumentInterface &r_iarg); 616 617 bool _populate_object_type_interfaces(); 618 void _populate_builtin_type_interfaces(); 619 620 void _populate_global_constants(); 621 622 Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file); 623 624 Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, StringBuilder &p_output); 625 Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output); 626 627 void _generate_global_constants(StringBuilder &p_output); 628 629 Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, StringBuilder &p_output); 630 631 Error _save_file(const String &p_path, const StringBuilder &p_content); 632 633 void _log(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; 634 635 void _initialize(); 636 637 public: 638 Error generate_cs_core_project(const String &p_proj_dir); 639 Error generate_cs_editor_project(const String &p_proj_dir); 640 Error generate_cs_api(const String &p_output_dir); 641 Error generate_glue(const String &p_output_dir); 642 is_log_print_enabled()643 _FORCE_INLINE_ bool is_log_print_enabled() { return log_print_enabled; } set_log_print_enabled(bool p_enabled)644 _FORCE_INLINE_ void set_log_print_enabled(bool p_enabled) { log_print_enabled = p_enabled; } 645 is_initialized()646 _FORCE_INLINE_ bool is_initialized() { return initialized; } 647 648 static uint32_t get_version(); 649 650 static void handle_cmdline_args(const List<String> &p_cmdline_args); 651 BindingsGenerator()652 BindingsGenerator() : 653 log_print_enabled(true), 654 initialized(false) { 655 _initialize(); 656 } 657 }; 658 659 #endif 660 661 #endif // BINDINGS_GENERATOR_H 662