@@ -811,13 +811,22 @@ def generate_pyi_class(otype: ObjectType, model: Model) -> List[str]:
811811
812812 body = []
813813
814- ctor = next ( iter ( otype . constructors ), None )
815- if ctor is not None and not ctor .throws :
816- params = pyi_parameters (ctor .input_parameters , model )
814+ primary = primary_constructor ( otype )
815+ if primary is not None and not primary .throws :
816+ params = pyi_parameters (primary .input_parameters , model )
817817 if params is not None :
818818 signature = ", " .join (["self" ] + params )
819819 body .append (f" def __init__({ signature } ) -> None: ..." )
820820
821+ for ctor in otype .constructors :
822+ if ctor is primary :
823+ continue
824+ params = pyi_parameters (ctor .input_parameters , model )
825+ if params is None :
826+ continue
827+ body .append (" @staticmethod" )
828+ body .append (f" def { ctor .name } ({ ', ' .join (params )} ) -> { otype .py_name } : ..." )
829+
821830 if otype .name == "Object" :
822831 body .append (" def on(self, signal: str, callback: Callable[..., Any]) -> None: ..." )
823832 body .append (" def off(self, signal: str, callback: Callable[..., Any]) -> None: ..." )
@@ -966,6 +975,8 @@ def generate_extension_c(model: Model) -> str:
966975 code += generate_interface_implementation (otype )
967976
968977 code += generate_object_type_constructor (otype )
978+ for ctor in factory_constructors (otype ):
979+ code += generate_factory_function (otype , ctor , build_constructor_marshals (ctor ))
969980
970981 return code
971982
@@ -1241,6 +1252,10 @@ def generate_prototypes(model: Model) -> str:
12411252 "" ,
12421253 f"static int { otype_cprefix } _init ({ otype_cprefix } * self, PyObject * args, PyObject * kw);" ,
12431254 ]
1255+ for ctor in factory_constructors (otype ):
1256+ prototypes .append (
1257+ f"static PyObject * { otype_cprefix } _{ ctor .name } (PyObject * self, PyObject * args, PyObject * kw);"
1258+ )
12441259 if implementable_interface (otype ):
12451260 prototypes += [
12461261 f"static int { otype_cprefix } _traverse (PyObject * self, visitproc visit, void * arg);" ,
@@ -1357,6 +1372,9 @@ def generate_object_type_methods(otype: ObjectType) -> str:
13571372 functions .append (function )
13581373 entries .append (entry )
13591374
1375+ for ctor in factory_constructors (otype ):
1376+ entries .append (factory_method_entry (otype , ctor ))
1377+
13601378 return f"""{ "" .join (functions )}
13611379static PyMethodDef { otype .c_symbol_prefix } _methods[] =
13621380{{
@@ -2308,28 +2326,47 @@ def generate_object_type_constructor(otype: ObjectType) -> str:
23082326 if implementable_interface (otype ):
23092327 return generate_interface_init (otype )
23102328
2311- ctor = next ( iter ( otype . constructors ), None )
2329+ ctor = primary_constructor ( otype )
23122330
23132331 if ctor is None :
23142332 return generate_bare_init (otype )
23152333
2316- marshals : Optional [List [ParamMarshal ]] = None
2317- if not ctor .throws :
2318- marshals = []
2319- for param in ctor .input_parameters :
2320- marshal = build_param_marshal (param )
2321- if marshal is None :
2322- marshals = None
2323- break
2324- marshal .optional = param .optional
2325- marshals .append (marshal )
2334+ if ctor .throws :
2335+ return generate_unconstructable_init (otype )
23262336
2337+ marshals = build_constructor_marshals (ctor )
23272338 if marshals is None :
23282339 return generate_unconstructable_init (otype )
23292340
23302341 return generate_constructor_init (otype , ctor , marshals )
23312342
23322343
2344+ def primary_constructor (otype : ObjectType ) -> Optional [Procedure ]:
2345+ if not otype .constructors :
2346+ return None
2347+ return next ((c for c in otype .constructors if c .name == "new" ), otype .constructors [0 ])
2348+
2349+
2350+ def factory_constructors (otype : ObjectType ) -> List [Procedure ]:
2351+ primary = primary_constructor (otype )
2352+ return [
2353+ ctor
2354+ for ctor in otype .constructors
2355+ if ctor is not primary and not ctor .is_async and build_constructor_marshals (ctor ) is not None
2356+ ]
2357+
2358+
2359+ def build_constructor_marshals (ctor : Procedure ) -> Optional [List ["ParamMarshal" ]]:
2360+ marshals = []
2361+ for param in ctor .input_parameters :
2362+ marshal = build_param_marshal (param )
2363+ if marshal is None :
2364+ return None
2365+ marshal .optional = param .optional
2366+ marshals .append (marshal )
2367+ return marshals
2368+
2369+
23332370def generate_interface_init (otype : ObjectType ) -> str :
23342371 n = interface_impl_names (otype )
23352372 indent = constructor_indent (otype )
@@ -2430,7 +2467,88 @@ def generate_constructor_init(otype: ObjectType, ctor: Procedure, marshals: List
24302467{ generate_constructor_tail (marshals )} """
24312468
24322469
2433- def generate_argument_parse (marshals : List ["ParamMarshal" ]) -> str :
2470+ def factory_method_entry (otype : ObjectType , ctor : Procedure ) -> str :
2471+ return (
2472+ f' {{ "{ ctor .name } ", (PyCFunction) { otype .c_symbol_prefix } _{ ctor .name } , '
2473+ "METH_VARARGS | METH_KEYWORDS | METH_STATIC, NULL },"
2474+ )
2475+
2476+
2477+ def generate_factory_function (otype : ObjectType , ctor : Procedure , marshals : List ["ParamMarshal" ]) -> str :
2478+ indent = " " * (len (otype .c_symbol_prefix ) + len (ctor .name ) + 3 )
2479+
2480+ decls = [line for m in marshals for line in m .decls ]
2481+ decls .append (f"{ otype .c_type } * handle;" )
2482+ if ctor .throws :
2483+ decls .append ("GError * error = NULL;" )
2484+ decls .append ("PyObject * result = NULL;" )
2485+ decls_block = indent_c_code ("\n " .join (decls ), 1 , prologue = "\n " )
2486+
2487+ keyword_decl = ""
2488+ parse_block = ""
2489+ if marshals :
2490+ keywords = ", " .join ([f'"{ m .keyword } "' for m in marshals ] + ["NULL" ])
2491+ keyword_decl = f"\n static char * keywords[] = {{ { keywords } }};"
2492+ parse_block = "\n " + generate_argument_parse (marshals , on_failure = "return NULL;" )
2493+
2494+ post_block = ""
2495+ for m in marshals :
2496+ if m .post is not None :
2497+ post_block += indent_c_code (m .post , 1 , prologue = "\n " ) + "\n "
2498+
2499+ call_args = [m .call_arg for m in marshals ]
2500+ if ctor .throws :
2501+ call_args .append ("&error" )
2502+ call = f"handle = ({ otype .c_type } *) { ctor .c_identifier } ({ ', ' .join (call_args )} );"
2503+
2504+ error_block = ""
2505+ if ctor .throws :
2506+ error_block = """
2507+ if (error != NULL)
2508+ {
2509+ result = PyFrida_raise (error);
2510+ goto beach;
2511+ }
2512+ """
2513+
2514+ take_handle = f"result = PyGObject_new_take_handle (g_steal_pointer (&handle), PYFRIDA_TYPE ({ otype .py_name } ));"
2515+
2516+ return f"""
2517+ static PyObject *
2518+ { otype .c_symbol_prefix } _{ ctor .name } (PyObject * self,
2519+ { indent } PyObject * args,
2520+ { indent } PyObject * kw)
2521+ {{{ keyword_decl } { decls_block }
2522+ { parse_block } { post_block }
2523+ { call }
2524+ { error_block }
2525+ { take_handle }
2526+
2527+ { generate_factory_tail (marshals , ctor .throws )} """
2528+
2529+
2530+ def generate_factory_tail (marshals : List ["ParamMarshal" ], throws : bool ) -> str :
2531+ cleanups = [m .cleanup for m in marshals if m .cleanup is not None ]
2532+ cleanup_block = indent_c_code ("\n " .join (reversed (cleanups )), 1 ) if cleanups else ""
2533+
2534+ if throws or constructor_needs_beach (marshals ):
2535+ prologue = f"{ cleanup_block } \n \n " if cleanup_block else ""
2536+ return f"""beach:
2537+ { prologue } return result;
2538+ }}
2539+ """
2540+ if cleanup_block :
2541+ return f"""{ cleanup_block }
2542+
2543+ return result;
2544+ }}
2545+ """
2546+ return """ return result;
2547+ }
2548+ """
2549+
2550+
2551+ def generate_argument_parse (marshals : List ["ParamMarshal" ], on_failure : str = "return -1;" ) -> str :
24342552 fmt = ""
24352553 optional_started = False
24362554 for m in marshals :
@@ -2444,7 +2562,7 @@ def generate_argument_parse(marshals: List["ParamMarshal"]) -> str:
24442562 indent = " " * len (" if (!PyArg_ParseTupleAndKeywords (" )
24452563 parse_args_str = (",\n " + indent ).join (parse_args )
24462564 return f""" if (!PyArg_ParseTupleAndKeywords ({ parse_args_str } ))
2447- return -1;
2565+ { on_failure }
24482566"""
24492567
24502568
0 commit comments