1- from typing import TYPE_CHECKING , Dict , Iterable , Union , Optional
1+ from typing import TYPE_CHECKING , Dict , Iterable
22from dataclasses import dataclass , replace
33
44
88 from .builtins import BuiltinSpec
99
1010
11+ # Type alias
12+ TypeDBEntry = str
13+
14+
1115# We devide types into three categories:
1216# - scalars (native types already existing in C/Cython, e.g. float, int32 etc.)
1317# - builtins
@@ -30,11 +34,13 @@ class TypeSpec:
3034 is_object : bool = False
3135 # Type is a Godot builtin (e.g. Vector2)
3236 is_builtin : bool = False
37+ # Nil type (aka None, or NULL) is very special ;-)
38+ is_nil : bool = False
3339 # Type is a scalar (e.g. int, float) or void
3440 is_scalar : bool = False
3541 # Type doesn't use the heap (hence no need for freeing it)
3642 is_stack_only : bool = False
37- # # Type is an enum (e.g. godot_error, Camera::KeepAspect)
43+ # Type is an enum (e.g. godot_error, Camera::KeepAspect)
3844 is_enum : bool = False
3945 # e.g. `GDNATIVE_VARIANT_TYPE_BOOL`
4046 # Default to an invalid value so that we detect incorrect use during Cython compilation
@@ -54,11 +60,58 @@ def __post_init__(self):
5460 assert not self .is_scalar
5561
5662
57- # TODO: put variant_type_name into TypeSpec
63+ # `Nil` is a special case, it is only needed for `BuiltinOperatorSpec.right_type`
64+ # and in `ValueInUse`. But it meaning can differ:
65+ # - `BuiltinOperatorSpec.right_type`: `Nil` represents the absence of value
66+ # - `ValueInUse`: `Nil` represents a singleton value (like `None` in Python)
67+ # So the template code is expected to use the `is_nil` attribute and do ad-hoc
68+ # code according to it need instead of relying on py/c/cy_type
69+
70+
71+ class NilTypeSpec (TypeSpec ):
72+ def __init__ (self ):
73+ # Cannot use super().__init__() given py/cy/c_type are read-only !
74+ self .__dict__ = {
75+ # Default values from parent
76+ ** {f .name : f .default for f in super ().__dataclass_fields__ .values ()},
77+ # Our config values
78+ ** {
79+ "size" : 0 ,
80+ "gdapi_type" : "Nil" ,
81+ "is_scalar" : True ,
82+ "is_stack_only" : True ,
83+ "is_nil" : True ,
84+ "variant_type_name" : "GDNATIVE_VARIANT_TYPE_NIL" ,
85+ },
86+ }
87+
88+ def __repr__ (self ):
89+ return f"<NilTypeSpec { id (self )} >"
90+
91+ @property
92+ def py_type (self ):
93+ raise RuntimeError (
94+ "Nil type ! Should handle this by hand with a if condition on `<my_type>.is_nil`"
95+ )
96+
97+ @property
98+ def cy_type (self ):
99+ raise RuntimeError (
100+ "Nil type ! Should handle this by hand with a if condition on `<my_type>.is_nil`"
101+ )
102+
103+ @property
104+ def c_type (self ):
105+ raise RuntimeError (
106+ "Nil type ! Should handle this by hand with a if condition on `<my_type>.is_nil`"
107+ )
108+
109+
58110# TODO: Object type should match GDNATIVE_VARIANT_TYPE_OBJECT
59111
60112
61- TYPES_DB : Dict [str , TypeSpec ] = {
113+ TYPES_DB : Dict [TypeDBEntry , TypeSpec ] = {
114+ "Nil" : NilTypeSpec (),
62115 # Types marked as `meta` are used in the classes method args/return types
63116 "meta:int8" : TypeSpec (
64117 size = 1 ,
@@ -179,7 +232,7 @@ def register_variant_in_types_db(variant_size: int) -> None:
179232 TYPES_DB ["Variant" ] = TypeSpec (
180233 size = variant_size ,
181234 gdapi_type = "Variant" ,
182- c_type = "CVariant " ,
235+ c_type = "Variant " ,
183236 cy_type = "object" ,
184237 py_type = "GDAny" ,
185238 is_builtin = True ,
@@ -189,9 +242,10 @@ def register_variant_in_types_db(variant_size: int) -> None:
189242def register_builtins_in_types_db (builtins : Iterable ["BuiltinSpec" ]) -> None :
190243 for spec in builtins :
191244 if spec .name == "Nil" :
192- # `Nil` is a special case, it is only needed for
193- # `BuiltinOperatorSpec.right_type` and in `ValueInUse`.
194- # So better skip it and use ad-hoc workaround instead.
245+ # `Nil` is already part of `TYPES_DB`
246+ nil_spec = TYPES_DB ["Nil" ]
247+ assert nil_spec .gdapi_type == spec .original_name # Sanity check
248+ assert nil_spec .variant_type_name == spec .variant_type_name # Sanity check
195249 continue
196250 assert spec .size is not None
197251 if spec .name == "bool" :
@@ -224,7 +278,7 @@ def register_builtins_in_types_db(builtins: Iterable["BuiltinSpec"]) -> None:
224278 size = spec .size ,
225279 gdapi_type = spec .original_name ,
226280 py_type = spec .name ,
227- c_type = f"C { spec .name } " ,
281+ c_type = spec .c_struct_name ,
228282 cy_type = spec .name ,
229283 is_stack_only = not spec .has_destructor ,
230284 is_builtin = True ,
@@ -279,7 +333,7 @@ def register_global_enums_in_types_db(enums: Iterable["GlobalEnumSpec"]) -> None
279333
280334@dataclass (repr = False )
281335class TypeInUse :
282- type_name : str
336+ type_name : TypeDBEntry
283337
284338 def __repr__ (self ) -> str :
285339 try :
0 commit comments