From 75d2ce73ce267036cbade664c23595715e50d88a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 15 Dec 2025 22:46:55 +0000 Subject: [PATCH 01/12] Remove unused wrapped type --- src/generators/cpp/cppAst.ml | 1 - src/generators/cpp/cppAstTools.ml | 5 +---- src/generators/cpp/gen/cppCppia.ml | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/generators/cpp/cppAst.ml b/src/generators/cpp/cppAst.ml index 0d1e97dfaa9..20ed1a6d29a 100644 --- a/src/generators/cpp/cppAst.ml +++ b/src/generators/cpp/cppAst.ml @@ -76,7 +76,6 @@ and tcpp = | TCppAutoCast | TCppDynamicArray | TCppObjectArray of tcpp - | TCppWrapped of tcpp | TCppScalarArray of tcpp | TCppObjC of tclass | TCppNativePointer of tclass diff --git a/src/generators/cpp/cppAstTools.ml b/src/generators/cpp/cppAstTools.ml index 33dfb17630d..d0747227d84 100644 --- a/src/generators/cpp/cppAstTools.ml +++ b/src/generators/cpp/cppAstTools.ml @@ -409,7 +409,6 @@ and tcpp_to_string_suffix suffix tcpp = tcpp_objc_block_struct argTypes retType ^ "::t" | TCppDynamicArray -> "::cpp::VirtualArray" ^ suffix | TCppObjectArray _ -> "::Array" ^ suffix ^ "< ::Dynamic>" - | TCppWrapped _ -> " ::Dynamic" | TCppScalarArray value -> "::Array" ^ suffix ^ "< " ^ tcpp_to_string value ^ " >" | TCppObjC klass -> @@ -792,7 +791,7 @@ let rec cpp_is_native_array_access t = | _ -> false let cpp_is_dynamic_type = function - | TCppDynamic | TCppObject | TCppVariant | TCppWrapped _ | TCppGlobal | TCppNull + | TCppDynamic | TCppObject | TCppVariant | TCppGlobal | TCppNull | TCppInterface _ -> true | _ -> false @@ -813,7 +812,6 @@ let is_object_element member_type = | TCppFunction _ | TCppDynamicArray | TCppObjectArray _ - | TCppWrapped _ | TCppScalarArray _ | TCppClass -> true @@ -834,7 +832,6 @@ let cpp_variant_type_of t = match t with | TCppDynamicArray | TCppObjectArray _ | TCppScalarArray _ - | TCppWrapped _ | TCppObjC _ | TCppObjCBlock _ | TCppRest _ diff --git a/src/generators/cpp/gen/cppCppia.ml b/src/generators/cpp/gen/cppCppia.ml index da7dbc856eb..97792aceac4 100644 --- a/src/generators/cpp/gen/cppCppia.ml +++ b/src/generators/cpp/gen/cppCppia.ml @@ -96,7 +96,7 @@ let rec script_type_string haxe_type = let rec script_cpptype_string cppType = match cppType with - | TCppDynamic | TCppUnchanged | TCppWrapped _ | TCppObject | TCppMarshalManagedType _ -> "Dynamic" + | TCppDynamic | TCppUnchanged | TCppObject | TCppMarshalManagedType _ -> "Dynamic" | TCppObjectPtr -> ".*.hx.Object*" | TCppReference t -> ".ref." ^ script_cpptype_string t | TCppStruct t -> ".struct." ^ script_cpptype_string t From 2303c5349b9c21fbcf529e4a5de8016979a30eac Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 15 Dec 2025 22:59:17 +0000 Subject: [PATCH 02/12] optional type for TCppVariant --- src/generators/cpp/cppAst.ml | 2 +- src/generators/cpp/cppAstTools.ml | 7 ++++--- src/generators/cpp/cppRetyper.ml | 12 ++++++------ src/generators/cpp/filters/cppFilterAutoCast.ml | 14 ++++++++++---- src/generators/cpp/gen/cppCppia.ml | 2 +- src/generators/cpp/gen/cppGen.ml | 2 +- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/generators/cpp/cppAst.ml b/src/generators/cpp/cppAst.ml index 20ed1a6d29a..f4c08744877 100644 --- a/src/generators/cpp/cppAst.ml +++ b/src/generators/cpp/cppAst.ml @@ -79,7 +79,7 @@ and tcpp = | TCppScalarArray of tcpp | TCppObjC of tclass | TCppNativePointer of tclass - | TCppVariant + | TCppVariant of tcpp option | TCppCode of tcpp | TCppInst of tclass * tcpp list | TCppInterface of tclass diff --git a/src/generators/cpp/cppAstTools.ml b/src/generators/cpp/cppAstTools.ml index d0747227d84..e91c26e41be 100644 --- a/src/generators/cpp/cppAstTools.ml +++ b/src/generators/cpp/cppAstTools.ml @@ -385,7 +385,8 @@ and tcpp_to_string_suffix suffix tcpp = | TCppRest _ -> "vaarg_list" | TCppVarArg -> "vararg" | TCppAutoCast -> "::cpp::AutoCast" - | TCppVariant -> "::cpp::Variant" + | TCppVariant None -> "::cpp::Variant" + | TCppVariant Some t -> Printf.sprintf "::cpp::Variant( %s )" (tcpp_to_string t) | TCppEnum enum -> " ::" ^ join_class_path_remap enum.e_path "::" ^ suffix | TCppScalar scalar -> scalar | TCppString -> "::String" @@ -791,7 +792,7 @@ let rec cpp_is_native_array_access t = | _ -> false let cpp_is_dynamic_type = function - | TCppDynamic | TCppObject | TCppVariant | TCppGlobal | TCppNull + | TCppDynamic | TCppObject | TCppVariant _ | TCppGlobal | TCppNull | TCppInterface _ -> true | _ -> false @@ -858,7 +859,7 @@ let cpp_variant_type_of t = match t with | TCppScalar "double" | TCppScalar "float" -> TCppScalar("Float") | TCppScalar _ -> TCppScalar("int") - | TCppVariant -> TCppVariant + | TCppVariant v -> TCppVariant v let cpp_cast_variant_type_of t = match t with | TCppObjectArray _ diff --git a/src/generators/cpp/cppRetyper.ml b/src/generators/cpp/cppRetyper.ml index 088f8d17063..1ebfe7e8b94 100644 --- a/src/generators/cpp/cppRetyper.ml +++ b/src/generators/cpp/cppRetyper.ml @@ -667,7 +667,7 @@ let expression ctx request_type function_args function_type expression_tree forI CppFunction (FuncInstance (retypedObj, InstPtr, member, []), funcReturn), exprType ) else - (retyper_ctx, CppDynamicField (retypedObj, member.cf_name), TCppVariant) + (retyper_ctx, CppDynamicField (retypedObj, member.cf_name), TCppVariant (Some exprType)) else if cpp_is_struct_access retypedObj.cpptype then match retypedObj.cppexpr with | CppThis ThisReal -> @@ -709,7 +709,7 @@ let expression ctx request_type function_args function_type expression_tree forI | TCppInterface _, _ | TCppDynamic, _ -> ( retyper_ctx, CppDynamicField (retypedObj, member.cf_name), - TCppVariant ) + TCppVariant (Some exprType)) | TCppObjC _, _ -> ( retyper_ctx, CppVar (VarInstance ( retypedObj, member, tcpp_to_string clazzType, "." )), @@ -808,7 +808,7 @@ let expression ctx request_type function_args function_type expression_tree forI CppFunction (FuncInternal (obj, fieldName, "->"), cppType), cppType ) else - (retyper_ctx, CppDynamicField (obj, field.cf_name), TCppVariant) + (retyper_ctx, CppDynamicField (obj, field.cf_name), TCppVariant None) | FDynamic fieldName -> let retyper_ctx, obj = retype retyper_ctx TCppDynamic obj in if obj.cpptype = TCppNull then (retyper_ctx, CppNullAccess, TCppDynamic) @@ -844,7 +844,7 @@ let expression ctx request_type function_args function_type expression_tree forI ( retyper_ctx, CppVar (VarInternal (obj, "->", fieldName)), cpp_type_of expr.etype ) - else (retyper_ctx, CppDynamicField (obj, fieldName), TCppVariant) + else (retyper_ctx, CppDynamicField (obj, fieldName), TCppVariant None) | FEnum (enum, enum_field) -> (retyper_ctx, CppEnumField (enum, enum_field), TCppEnum enum)) | TCall ({ eexpr = TIdent "__cpp__" }, arg_list) -> @@ -1287,8 +1287,8 @@ let expression ctx request_type function_args function_type expression_tree forI in match (op, e1.cpptype, e2.cpptype) with (* Variant + Variant = Variant *) - | OpAdd, _, TCppVariant | OpAdd, TCppVariant, _ -> - (retyper_ctx, reference, TCppVariant) + | OpAdd, _, TCppVariant o | OpAdd, TCppVariant o, _ -> + (retyper_ctx, reference, TCppVariant o) | _, _, _ -> (retyper_ctx, reference, cpp_type_of expr.etype)) | TUnop (op, pre, e1) -> diff --git a/src/generators/cpp/filters/cppFilterAutoCast.ml b/src/generators/cpp/filters/cppFilterAutoCast.ml index e6f62f5c181..d7e59441fde 100644 --- a/src/generators/cpp/filters/cppFilterAutoCast.ml +++ b/src/generators/cpp/filters/cppFilterAutoCast.ml @@ -7,7 +7,7 @@ open CppError let autocast_filter for_cppia return_type cppexpr = let object_expression = match cppexpr.cpptype with - | TCppVariant + | TCppVariant _ | TCppDynamic | TCppObject -> true | _ -> false @@ -34,6 +34,12 @@ let autocast_filter for_cppia return_type cppexpr = in let cast_from_object () = + let is_variant t = + match t with + | TCppVariant _ -> true + | _ -> false + in + match return_type with | TCppUnchanged -> cppexpr @@ -60,9 +66,9 @@ let autocast_filter for_cppia return_type cppexpr = mk_cppexpr (CppCastScalar (cppexpr, scalar)) return_type | TCppString -> mk_cppexpr (CppCastScalar (cppexpr, "::String")) return_type - | TCppInterface _ when cppexpr.cpptype = TCppVariant -> + | TCppInterface _ when is_variant cppexpr.cpptype -> mk_cppexpr (CppCastVariant cppexpr) return_type - | TCppDynamic when cppexpr.cpptype = TCppVariant -> + | TCppDynamic when is_variant cppexpr.cpptype -> mk_cppexpr (CppCastVariant cppexpr) return_type | TCppStar (t, const) as ptr -> let ptr_type = TCppPointer ((if const then "ConstPointer" else "Pointer"), t) in @@ -182,7 +188,7 @@ let autocast_filter for_cppia return_type cppexpr = | TCppMarshalNativeType (_, Promoted), TCppMarshalNativeType (value_type, (Stack)) -> let reference = TCppMarshalNativeType(value_type, Reference) in mk_cppexpr (CppCast (cppexpr, reference)) reference - | TCppMarshalNativeType (value_type, (Stack | Promoted)), (TCppMarshalNativeType (_, Reference) | TCppDynamic | TCppVariant) -> + | TCppMarshalNativeType (value_type, (Stack | Promoted)), (TCppMarshalNativeType (_, Reference) | TCppDynamic | TCppVariant _) -> let reference = TCppMarshalNativeType(value_type, Reference) in mk_cppexpr (CppCast (cppexpr, reference)) reference | _ -> cppexpr diff --git a/src/generators/cpp/gen/cppCppia.ml b/src/generators/cpp/gen/cppCppia.ml index 97792aceac4..0519316d4da 100644 --- a/src/generators/cpp/gen/cppCppia.ml +++ b/src/generators/cpp/gen/cppCppia.ml @@ -106,7 +106,7 @@ let rec script_cpptype_string cppType = | TCppRest _ -> "vaarg_list" | TCppVarArg -> "vararg" | TCppAutoCast -> ".cpp.AutoCast" - | TCppVariant -> ".cpp.Variant" + | TCppVariant _ -> ".cpp.Variant" | TCppEnum enum -> join_class_path enum.e_path "." | TCppScalar scalar -> scalar | TCppString -> "String" diff --git a/src/generators/cpp/gen/cppGen.ml b/src/generators/cpp/gen/cppGen.ml index 71bd523720c..7d96860b628 100644 --- a/src/generators/cpp/gen/cppGen.ml +++ b/src/generators/cpp/gen/cppGen.ml @@ -1453,7 +1453,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ out name | CppDynamicRef (expr, name) -> let objPtr = - match expr.cpptype with TCppVariant -> "getObject()" | _ -> ".mPtr" + match expr.cpptype with TCppVariant _ -> "getObject()" | _ -> ".mPtr" in out "::hx::FieldRef(("; gen expr; From 7babdc4a143cf499079f0083267d6b66504a5060 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 16 Dec 2025 13:57:22 +0000 Subject: [PATCH 03/12] InstPtr store tcpp --- src/generators/cpp/cppAst.ml | 5 ++++- src/generators/cpp/cppAstTools.ml | 2 +- src/generators/cpp/cppRetyper.ml | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/generators/cpp/cppAst.ml b/src/generators/cpp/cppAst.ml index f4c08744877..8584d793c46 100644 --- a/src/generators/cpp/cppAst.ml +++ b/src/generators/cpp/cppAst.ml @@ -118,7 +118,10 @@ and tcppvarloc = | VarStatic of tclass * bool * tclass_field | VarInternal of tcppexpr * string * string -and tcppinst = InstPtr | InstObjC | InstStruct +and tcppinst = + | InstPtr of tcpp + | InstObjC + | InstStruct and tcppfuncloc = | FuncThis of tclass_field * tcpp diff --git a/src/generators/cpp/cppAstTools.ml b/src/generators/cpp/cppAstTools.ml index e91c26e41be..fec3281336e 100644 --- a/src/generators/cpp/cppAstTools.ml +++ b/src/generators/cpp/cppAstTools.ml @@ -311,7 +311,7 @@ let rec s_tcpp = function | CppCall (FuncInstance (obj, inst, field, _), _) -> (match inst with | InstObjC -> "CppCallObjCInstance(" - | InstPtr -> "CppCallInstance(" + | InstPtr _ -> "CppCallInstance(" | _ -> "CppCallStruct(") ^ tcpp_to_string obj.cpptype ^ "," ^ field.cf_name ^ ")" | CppCall (FuncInterface _, _) -> "CppCallInterface" diff --git a/src/generators/cpp/cppRetyper.ml b/src/generators/cpp/cppRetyper.ml index 1ebfe7e8b94..4e34ecd760b 100644 --- a/src/generators/cpp/cppRetyper.ml +++ b/src/generators/cpp/cppRetyper.ml @@ -611,7 +611,7 @@ let expression ctx request_type function_args function_type expression_tree forI let clazzType = cpp_instance_type cls params with_reference_value_type in let retyper_ctx, retypedObj = retype retyper_ctx clazzType obj in let handler = if is_marshalling_native_value_class cls then with_stack_value_type else with_promoted_value_type in - let access = if cpp_is_struct_access retypedObj.cpptype then InstStruct else InstPtr in + let access = if cpp_is_struct_access retypedObj.cpptype then InstStruct else InstPtr clazzType in let func_return = cpp_type_of_with handler ret in let exprType = cpp_type_of_with handler t in ( retyper_ctx, CppFunction (FuncInstance (retypedObj, access, member, template_types), func_return), exprType ) @@ -664,7 +664,7 @@ let expression ctx request_type function_args function_type expression_tree forI else if retypedObj.cpptype = TCppDynamic && not (has_class_flag clazz CInterface) then if is_internal_member member.cf_name then ( retyper_ctx, - CppFunction (FuncInstance (retypedObj, InstPtr, member, []), funcReturn), + CppFunction (FuncInstance (retypedObj, InstPtr clazzType, member, []), funcReturn), exprType ) else (retyper_ctx, CppDynamicField (retypedObj, member.cf_name), TCppVariant (Some exprType)) @@ -767,7 +767,7 @@ let expression ctx request_type function_args function_type expression_tree forI CppFunction ( FuncInstance ( retypedObj, - (if is_objc then InstObjC else InstPtr), + (if is_objc then InstObjC else InstPtr clazzType), member, [] ), funcReturn ), @@ -894,19 +894,19 @@ let expression ctx request_type function_args function_type expression_tree forI | CppEnumIndex _ -> (* Not actually a TCall...*) (retyper_ctx, retypedFunc.cppexpr, retypedFunc.cpptype) - | CppFunction (FuncInstance (obj, InstPtr, member, template_params), _) + | CppFunction (FuncInstance (obj, InstPtr tcpp, member, template_params), _) when (not forCppia) && return_type = TCppVoid && is_array_splice_call obj member -> let arg_types = List.map (fun a -> cpp_type_of a.etype) args in let retyper_ctx, retypedArgs = retype_function_args retyper_ctx args arg_types in ( retyper_ctx, - CppCall ( FuncInstance (obj, InstPtr, { member with cf_name = "removeRange" }, template_params), retypedArgs ), + CppCall ( FuncInstance (obj, InstPtr tcpp, { member with cf_name = "removeRange" }, template_params), retypedArgs ), TCppVoid ) - | CppFunction (FuncInstance (obj, InstPtr, member, template_params), _) + | CppFunction (FuncInstance (obj, InstPtr tcpp, member, template_params), _) when is_array_concat_call obj member -> let arg_types = List.map (fun _ -> obj.cpptype) args in let retyper_ctx, retypedArgs = retype_function_args retyper_ctx args arg_types in ( retyper_ctx, - CppCall (FuncInstance (obj, InstPtr, member, template_params), retypedArgs), + CppCall (FuncInstance (obj, InstPtr tcpp, member, template_params), retypedArgs), return_type ) | CppFunction (FuncStatic (obj, false, member, _), _) when member.cf_name = "::hx::AddressOf" -> @@ -951,7 +951,7 @@ let expression ctx request_type function_args function_type expression_tree forI abort "First parameter of template function must be a Class" retypedFunc.cpppos) - | CppFunction (FuncInstance (obj, InstPtr, member, template_params), _) + | CppFunction (FuncInstance (obj, InstPtr tcpp, member, template_params), _) when is_map_get_call obj member -> let arg_types = List.map (fun a -> cpp_type_of a.etype) args in let retyper_ctx, retypedArgs = retype_function_args retyper_ctx args arg_types in @@ -974,7 +974,7 @@ let expression ctx request_type function_args function_type expression_tree forI | _ -> ("get", TCppDynamic) in let func = - FuncInstance (obj, InstPtr, { member with cf_name = fname }, template_params) + FuncInstance (obj, InstPtr tcpp, { member with cf_name = fname }, template_params) in (* if cpp_can_static_cast cppType return_type then begin @@ -983,7 +983,7 @@ let expression ctx request_type function_args function_type expression_tree forI end else *) (retyper_ctx, CppCall (func, retypedArgs), cppType) - | CppFunction (FuncInstance (obj, InstPtr, member, template_params), _) + | CppFunction (FuncInstance (obj, InstPtr tcpp, member, template_params), _) when forCppia && is_map_set_call obj member -> let arg_types = List.map (fun a -> cpp_type_of a.etype) args in let retyper_ctx, retypedArgs = retype_function_args retyper_ctx args arg_types in @@ -997,10 +997,10 @@ let expression ctx request_type function_args function_type expression_tree forI | [ _; { cpptype = TCppString } ] -> "setString" | _ -> "set" in - let func = FuncInstance (obj, InstPtr, { member with cf_name = fname }, template_params) in + let func = FuncInstance (obj, InstPtr tcpp, { member with cf_name = fname }, template_params) in (retyper_ctx, CppCall (func, retypedArgs), cppType) | CppFunction - ((FuncInstance (obj, InstPtr, member, template_params) as func), returnType) + ((FuncInstance (obj, InstPtr tcpp, member, template_params) as func), returnType) when cpp_can_static_cast returnType cppType -> let arg_types = List.map (fun a -> cpp_type_of a.etype) args in let retyper_ctx, retypedArgs = retype_function_args retyper_ctx args arg_types in From d672dad49cb902603c940e12e6001c371bac7307 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 16 Dec 2025 14:09:40 +0000 Subject: [PATCH 04/12] add mad typedef thing --- src/generators/cpp/cppRetyper.ml | 40 ++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/generators/cpp/cppRetyper.ml b/src/generators/cpp/cppRetyper.ml index 4e34ecd760b..594d882599e 100644 --- a/src/generators/cpp/cppRetyper.ml +++ b/src/generators/cpp/cppRetyper.ml @@ -98,8 +98,44 @@ let rec cpp_type_of stack value_type_handler haxe_type = | None -> TCppScalar (join_class_path a.a_path "::") else TCppDynamic) | TType (type_def, params) -> - cpp_type_from_path stack type_def.t_path params value_type_handler (fun () -> - cpp_type_of stack value_type_handler (apply_typedef type_def params)) + (* Can't really remember why / what this is doing *) + (* I only have vague memories of nightmares about trying to stop recursive typedefs turning stuff dynamic *) + let rec find s t = + if List.exists (fast_eq t) s then begin + true + end else + let s = t :: s in + match t with + | TMono r -> + (match r.tm_type with + | None -> false + | Some t -> find s t) + | TEnum (_,tl) | TInst (_,tl) -> + List.exists (find s) tl + | TAbstract (abs,tl) -> + if not (Meta.has Meta.CoreType abs.a_meta) && (find s (Abstract.get_underlying_type ~return_first:true abs tl)) then + true + else + List.exists (find s) tl + | TType (tdef,tl) -> + find s (apply_typedef tdef tl) + | TFun (tl,r) -> + if (find s r) then + true + else begin + List.exists (fun (_,_,targ) -> (find s targ)) tl + end + | TLazy f -> + find s (lazy_type f) + | TDynamic (Some t2) -> + find s t2 + | _ -> + false + in + if find [] haxe_type then + cpp_type_from_path stack type_def.t_path params value_type_handler (fun () -> TCppDynamic) + else + cpp_type_from_path stack type_def.t_path params value_type_handler (fun () -> cpp_type_of stack value_type_handler (apply_typedef type_def params)) | TFun _ -> TCppObject | TAnon _ -> TCppObject | TDynamic _ -> TCppDynamic From 839e2e6601d5509ae6868997c03ea09b99e637c2 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 16 Dec 2025 14:16:44 +0000 Subject: [PATCH 05/12] rename CppClosure to CppCallable --- src/generators/cpp/cppAst.ml | 2 +- src/generators/cpp/cppAstTools.ml | 2 +- src/generators/cpp/cppRetyper.ml | 2 +- src/generators/cpp/gen/cppCppia.ml | 2 +- src/generators/cpp/gen/cppGen.ml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/generators/cpp/cppAst.ml b/src/generators/cpp/cppAst.ml index 8584d793c46..2dbe8f487b6 100644 --- a/src/generators/cpp/cppAst.ml +++ b/src/generators/cpp/cppAst.ml @@ -164,7 +164,7 @@ and tcpp_expr_expr = | CppThis of tcppthis | CppSuper of tcppthis | CppCode of string * tcppexpr list - | CppClosure of tcpp_closure + | CppCallable of tcpp_closure | CppVar of tcppvarloc | CppExtern of string * bool | CppDynamicField of tcppexpr * string diff --git a/src/generators/cpp/cppAstTools.ml b/src/generators/cpp/cppAstTools.ml index fec3281336e..d1922296131 100644 --- a/src/generators/cpp/cppAstTools.ml +++ b/src/generators/cpp/cppAstTools.ml @@ -291,7 +291,7 @@ let rec s_tcpp = function | CppThis _ -> "CppThis" | CppSuper _ -> "CppSuper" | CppCode _ -> "CppCode" - | CppClosure _ -> "CppClosure" + | CppCallable _ -> "CppCallable" | CppVar (VarLocal _) -> "CppVarLocal" | CppVar (VarClosure _) -> "CppVarClosure" | CppVar (VarThis _) -> "CppVarThis" diff --git a/src/generators/cpp/cppRetyper.ml b/src/generators/cpp/cppRetyper.ml index 594d882599e..4ff3c111a73 100644 --- a/src/generators/cpp/cppRetyper.ml +++ b/src/generators/cpp/cppRetyper.ml @@ -1183,7 +1183,7 @@ let expression ctx request_type function_args function_type expression_tree forI uses_this = if new_ctx.uses_this != None then Some retyper_ctx.this_real else retyper_ctx.uses_this; } in - (retyper_ctx, CppClosure result, TCppDynamic) + (retyper_ctx, CppCallable result, TCppDynamic) | TArray (e1, e2) -> let retyper_ctx, arrayExpr , elemType = match cpp_is_native_array_access (cpp_type_of e1.etype) with diff --git a/src/generators/cpp/gen/cppCppia.ml b/src/generators/cpp/gen/cppCppia.ml index 0519316d4da..9811c19be6e 100644 --- a/src/generators/cpp/gen/cppCppia.ml +++ b/src/generators/cpp/gen/cppCppia.ml @@ -1583,7 +1583,7 @@ class script_writer ctx filename asciiOut = ^ this#typeTextString "Dynamic" ^ string_of_int index ^ "\n"); gen_expression obj - | CppClosure closure -> + | CppCallable closure -> this#write (this#op IaFun ^ this#astType closure.close_type diff --git a/src/generators/cpp/gen/cppGen.ml b/src/generators/cpp/gen/cppGen.ml index 7d96860b628..f07f19e2b90 100644 --- a/src/generators/cpp/gen/cppGen.ml +++ b/src/generators/cpp/gen/cppGen.ml @@ -995,7 +995,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ else if path = "::Array" then out "::hx::ArrayBase::__mClass" else out ("::hx::ClassOf< " ^ path ^ " >()") | CppVar loc -> gen_val_loc loc - | CppClosure closure -> + | CppCallable closure -> out (" ::Dynamic(new _hx_Closure_" ^ string_of_int closure.close_id ^ "("); let separator = ref "" in From 78760898e0572e5089498a11c4b8ec9cbe372ebb Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 16 Dec 2025 23:48:31 +0000 Subject: [PATCH 06/12] unit tests passing --- src/generators/cpp/cppAst.ml | 1 + src/generators/cpp/cppAstTools.ml | 20 +- src/generators/cpp/cppRetyper.ml | 50 +++- .../cpp/filters/cppFilterAutoCast.ml | 2 + src/generators/cpp/gen/cppCppia.ml | 2 +- src/generators/cpp/gen/cppGen.ml | 126 ++++++--- src/generators/cpp/gen/cppGenClassHeader.ml | 11 +- .../cpp/gen/cppGenClassImplementation.ml | 251 ++++++++++-------- .../cpp/gen/cppGenInterfaceHeader.ml | 13 +- .../cpp/gen/cppGenInterfaceImplementation.ml | 23 ++ src/generators/gencpp.ml | 10 +- 11 files changed, 327 insertions(+), 182 deletions(-) diff --git a/src/generators/cpp/cppAst.ml b/src/generators/cpp/cppAst.ml index 2dbe8f487b6..786ab8116ea 100644 --- a/src/generators/cpp/cppAst.ml +++ b/src/generators/cpp/cppAst.ml @@ -86,6 +86,7 @@ and tcpp = | TCppProtocol of tclass | TCppClass | TCppGlobal + | TCppCallable of tcpp list * tcpp and tcppexpr = { cppexpr : tcpp_expr_expr; cpptype : tcpp; cpppos : pos } diff --git a/src/generators/cpp/cppAstTools.ml b/src/generators/cpp/cppAstTools.ml index d1922296131..d4a4df6e637 100644 --- a/src/generators/cpp/cppAstTools.ml +++ b/src/generators/cpp/cppAstTools.ml @@ -467,6 +467,12 @@ and tcpp_to_string_suffix suffix tcpp = | TCppMarshalNativeType ((ValueClass _ | ValueEnum _) as value_type, Stack) -> get_native_marshalled_type value_type |> Printf.sprintf "::cpp::marshal::ValueType< %s >" + | TCppCallable (arguments, return) -> + let return_str = tcpp_to_string return in + let arguments_str = arguments |> List.map tcpp_to_string |> String.concat "," in + + Printf.sprintf "::hx::Callable< %s (%s) >" return_str arguments_str + and build_type path pos params meta target parameter_handler = let get_meta_field field = match Meta.get target meta with @@ -791,9 +797,15 @@ let rec cpp_is_native_array_access t = | TCppInst ({ cl_array_access = Some _ } as klass, _) when is_extern_class klass && Meta.has Meta.NativeArrayAccess klass.cl_meta -> true | _ -> false -let cpp_is_dynamic_type = function - | TCppDynamic | TCppObject | TCppVariant _ | TCppGlobal | TCppNull +let cpp_is_dynamic_type t = + match t with + | TCppDynamic + | TCppObject + | TCppVariant _ + | TCppGlobal + | TCppNull | TCppInterface _ + | TCppCallable _ -> true | _ -> false @@ -815,6 +827,7 @@ let is_object_element member_type = | TCppObjectArray _ | TCppScalarArray _ | TCppClass + | TCppCallable _ -> true | _ -> false @@ -843,7 +856,8 @@ let cpp_variant_type_of t = match t with | TCppClass | TCppGlobal | TCppNull - | TCppEnum _ -> TCppDynamic + | TCppEnum _ + | TCppCallable _ -> TCppDynamic | TCppString -> TCppString | TCppFunction _ | TCppNativePointer _ diff --git a/src/generators/cpp/cppRetyper.ml b/src/generators/cpp/cppRetyper.ml index 4ff3c111a73..e32ce520ee8 100644 --- a/src/generators/cpp/cppRetyper.ml +++ b/src/generators/cpp/cppRetyper.ml @@ -136,7 +136,10 @@ let rec cpp_type_of stack value_type_handler haxe_type = cpp_type_from_path stack type_def.t_path params value_type_handler (fun () -> TCppDynamic) else cpp_type_from_path stack type_def.t_path params value_type_handler (fun () -> cpp_type_of stack value_type_handler (apply_typedef type_def params)) - | TFun _ -> TCppObject + | TFun (arguments, return) -> + let retyped_arguments = List.map (fun (_, o, t) -> cpp_tfun_arg_type_of stack o value_type_handler t) arguments in + let retyped_return = cpp_type_of stack value_type_handler return in + TCppCallable (retyped_arguments, retyped_return) | TAnon _ -> TCppObject | TDynamic _ -> TCppDynamic | TLazy func -> cpp_type_of stack value_type_handler (lazy_type func) @@ -207,7 +210,7 @@ and cpp_type_from_path stack path params value_type_handler default = | TCppObject | TCppObjectPtr | TCppReference _ | TCppStruct _ | TCppStar _ | TCppEnum _ | TCppInst _ | TCppInterface _ | TCppProtocol _ | TCppClass | TCppDynamicArray | TCppObjectArray _ | TCppScalarArray _ | TCppMarshalNativeType _ - | TCppMarshalManagedType _ -> + | TCppMarshalManagedType _ | TCppCallable _ -> TCppObjectArray arrayOf | _ -> TCppScalarArray arrayOf) | ([], "Null"), [ p ] -> cpp_type_of_null stack value_type_handler p @@ -226,10 +229,10 @@ and cpp_type_of_pointer stack value_type_handler p = | x -> cpp_type_of stack value_type_handler x (* Optional types are Dynamic if they norally could not be null *) -and cpp_fun_arg_type_of stack tvar opt value_type_handler = +and cpp_fun_arg_type_of tvar opt value_type_handler = match opt with - | Some _ -> cpp_type_of_null stack value_type_handler tvar.t_type - | _ -> cpp_type_of stack value_type_handler tvar.t_type + | Some _ -> cpp_type_of_null [] value_type_handler tvar.v_type + | _ -> cpp_type_of [] value_type_handler tvar.v_type and cpp_tfun_arg_type_of stack opt value_type_handler t = if opt then cpp_type_of_null stack value_type_handler t else cpp_type_of stack value_type_handler t @@ -776,10 +779,16 @@ let expression ctx request_type function_args function_type expression_tree forI let funcReturn = if isArrayObj then match member.cf_name with - | "map" -> TCppDynamicArray + | "map" -> + (match expr.etype with + | TFun (_, return) -> + cpp_type_of_with handler return + | _ -> + cpp_abort InternalError member.cf_pos) | "splice" | "slice" | "concat" | "copy" | "filter" -> retypedObj.cpptype - | _ -> funcReturn + | _ -> + funcReturn else match (retypedObj.cpptype, funcReturn) with | TCppPointer (_, t), TCppDynamic @@ -907,6 +916,12 @@ let expression ctx request_type function_args function_type expression_tree forI | TCppObjCBlock (argTypes, retType) -> let retyper_ctx, retypedArgs = retype_function_args retyper_ctx args argTypes in (retyper_ctx, CppCall (FuncExpression retypedFunc, retypedArgs), retType) + (* If the return type is variant of a callable make sure it gets property retyped as a callable *) + (* Otherwise dynamic calling will occur through the variant *) + | TCppVariant Some TCppCallable (argument_types, return_type) -> + let retyper_ctx, retyped_args = retype_function_args retyper_ctx args argument_types in + let retyper_ctx, retyped_call = retype retyper_ctx (TCppCallable (argument_types, return_type)) func in + (retyper_ctx, CppCall (FuncExpression retyped_call, retyped_args), return_type) | _ -> ( let cppType = cpp_type_of expr.etype in match retypedFunc.cppexpr with @@ -1183,7 +1198,10 @@ let expression ctx request_type function_args function_type expression_tree forI uses_this = if new_ctx.uses_this != None then Some retyper_ctx.this_real else retyper_ctx.uses_this; } in - (retyper_ctx, CppCallable result, TCppDynamic) + let args = result.close_args |> List.map fst |> List.map (fun v -> v.tcppv_type) in + let return = result.close_type in + + (retyper_ctx, CppCallable result, TCppCallable (args, return) ) | TArray (e1, e2) -> let retyper_ctx, arrayExpr , elemType = match cpp_is_native_array_access (cpp_type_of e1.etype) with @@ -1880,6 +1898,20 @@ let rec tcpp_class_from_tclass ctx ids slots class_def class_params = gc_container variables parent Current in + (* Static functions can have their closure objects pre-allocated, do that in the boot section of the class *) + let wants_closures = + let needs_closures func = + match get_meta_string func.tcf_field.cf_meta Meta.Native with + | Some _ -> + false + | _ when (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective -> + true + | _ -> + false + in + List.exists needs_closures static_functions + in + let flags = 0 |> (fun f -> if scriptable && not class_def.cl_private then set_tcpp_class_flag f Scriptable else f) |> (fun f -> if can_quick_alloc class_def then set_tcpp_class_flag f QuickAlloc else f) @@ -1889,7 +1921,7 @@ let rec tcpp_class_from_tclass ctx ids slots class_def class_params = |> (fun f -> if has_set_static_field class_def then set_tcpp_class_flag f StaticSet else f) |> (fun f -> if has_get_fields class_def then set_tcpp_class_flag f GetFields else f) |> (fun f -> if has_compare_field class_def then set_tcpp_class_flag f Compare else f) - |> (fun f -> if has_boot_field class_def then set_tcpp_class_flag f Boot else f) + |> (fun f -> if has_boot_field class_def || wants_closures then set_tcpp_class_flag f Boot else f) in let meta_field = List.find_opt (fun field -> field.cf_name = "__meta__") class_def.cl_ordered_statics |> Option.map (fun f -> Option.get f.cf_expr) in diff --git a/src/generators/cpp/filters/cppFilterAutoCast.ml b/src/generators/cpp/filters/cppFilterAutoCast.ml index d7e59441fde..3d533e6cdb3 100644 --- a/src/generators/cpp/filters/cppFilterAutoCast.ml +++ b/src/generators/cpp/filters/cppFilterAutoCast.ml @@ -70,6 +70,8 @@ let autocast_filter for_cppia return_type cppexpr = mk_cppexpr (CppCastVariant cppexpr) return_type | TCppDynamic when is_variant cppexpr.cpptype -> mk_cppexpr (CppCastVariant cppexpr) return_type + | TCppCallable _ when is_variant cppexpr.cpptype -> + mk_cppexpr (CppCast(cppexpr, return_type)) return_type | TCppStar (t, const) as ptr -> let ptr_type = TCppPointer ((if const then "ConstPointer" else "Pointer"), t) in let ptr_cast = mk_cppexpr (CppCast (cppexpr, ptr_type)) ptr_type in diff --git a/src/generators/cpp/gen/cppCppia.ml b/src/generators/cpp/gen/cppCppia.ml index 9811c19be6e..2ef8a64d948 100644 --- a/src/generators/cpp/gen/cppCppia.ml +++ b/src/generators/cpp/gen/cppCppia.ml @@ -96,7 +96,7 @@ let rec script_type_string haxe_type = let rec script_cpptype_string cppType = match cppType with - | TCppDynamic | TCppUnchanged | TCppObject | TCppMarshalManagedType _ -> "Dynamic" + | TCppDynamic | TCppUnchanged | TCppObject | TCppMarshalManagedType _ | TCppCallable _ -> "Dynamic" | TCppObjectPtr -> ".*.hx.Object*" | TCppReference t -> ".ref." ^ script_cpptype_string t | TCppStruct t -> ".struct." ^ script_cpptype_string t diff --git a/src/generators/cpp/gen/cppGen.ml b/src/generators/cpp/gen/cppGen.ml index f07f19e2b90..960442e0f13 100644 --- a/src/generators/cpp/gen/cppGen.ml +++ b/src/generators/cpp/gen/cppGen.ml @@ -10,6 +10,7 @@ open CppAstTools open CppSourceWriter open CppContext open CppMarshalling +open CppError type tinject = { inj_prologue : bool -> unit; @@ -105,7 +106,28 @@ let cpp_no_debug_synbol ctx var = String.length name > 4 && String.sub name 0 4 = "_hx_" let cpp_debug_var_visible ctx var = not (cpp_no_debug_synbol ctx (fst var)) -(* let cpp_var_type_of var = tcpp_to_string (cpp_type_of var.v_type) *) + +let cpp_callable_args arguments prefix = + let make_arg (v, o) = + let return = CppRetyper.cpp_fun_arg_type_of v.tcppv_var o CppRetyper.with_stack_value_type |> tcpp_to_string in + let prefixed = match o with + | Some {eexpr = TConst TNull} -> v.tcppv_name + | Some _ -> prefix ^ v.tcppv_name + | None -> v.tcppv_name in + return ^ " " ^ prefixed + in + arguments |> List.map make_arg |> String.concat "," + +let cpp_callable_signaure closure = + let return = tcpp_to_string closure.close_type in + let arguments = cpp_callable_args closure.close_args "" in + Printf.sprintf "%s(%s)" return arguments + +let func_to_callable_string wrapper func = + let return_str = tcpp_to_string func.tcf_return in + let arguments_str = func.tcf_args |> List.map (fun (v, o) -> CppRetyper.cpp_fun_arg_type_of v.tcppv_var o CppRetyper.with_stack_value_type) |> List.map tcpp_to_string |> String.concat "," in + + Printf.sprintf "%s< %s (%s) >" wrapper return_str arguments_str let mk_injection prologue set_var tail = Some { inj_prologue = prologue; inj_setvar = set_var; inj_tail = tail } @@ -521,16 +543,35 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ out ".StaticCast< ::hx::EnumBase >()"; out "->_hx_getIndex()" | CppNullAccess -> out ("::hx::Throw(" ^ strq "Null access" ^ ")") - | CppFunction (func, _) -> ( + | CppFunction (func, tcpp) -> ( match func with | FuncThis (field, _) -> out ("this->" ^ cpp_member_name_of field ^ "_dyn()") | FuncInstance (expr, inst, field, _) -> + (* array map is a special case as it is implemented as a templated function *) + (* so we need to figure out the target array type of the map function to generate the template params *) + let template_extra = + if (field.cf_name="map") then + match inst with + | InstPtr (TCppObjectArray _) + | InstPtr (TCppScalarArray _) + | InstPtr TCppDynamicArray -> + (match tcpp with + | TCppObjectArray el + | TCppScalarArray el -> + Printf.sprintf "< %s >" (tcpp_to_string el) + | TCppDynamicArray -> + tcpp_to_string TCppDynamic + | _ -> + cpp_abort InternalError expr.cpppos) + | _ -> + "" + else + "" + in + let access = if expr.cpptype = TCppString || inst = InstStruct then "." else "->" in gen expr; - out - ((if expr.cpptype = TCppString || inst = InstStruct then "." - else "->") - ^ cpp_member_name_of field ^ "_dyn()") + out (Printf.sprintf "%s%s_dyn%s()" access (cpp_member_name_of field) template_extra) | FuncInterface (expr, _, field) -> gen expr; out ("->__Field(" ^ strq field.cf_name ^ ", ::hx::paccDynamic)") @@ -996,23 +1037,18 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ else out ("::hx::ClassOf< " ^ path ^ " >()") | CppVar loc -> gen_val_loc loc | CppCallable closure -> - out - (" ::Dynamic(new _hx_Closure_" ^ string_of_int closure.close_id ^ "("); - let separator = ref "" in - (match closure.close_this with - | Some this -> - out (if this = ThisReal then "this" else "__this"); - separator := "," - | _ -> ()); - - IntMap.iter - (fun _ var -> - let name = var.tcppv_name in - out !separator; - separator := ","; - out name) - closure.close_undeclared; - out "))" + let captured = + closure.close_undeclared + |> IntMap.to_list + |> List.map snd + |> List.map (fun v -> v.tcppv_name) + |> String.concat "," + in + Printf.sprintf + "::hx::Callable< %s >(new _hx_Closure_%i(%s))" + (cpp_callable_signaure closure) + closure.close_id + captured |> out; | CppObjectDecl (values, isStruct) -> let length = List.length values in let lengthStr = string_of_int length in @@ -1525,29 +1561,34 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ and gen_closure closure = let argc = IntMap.bindings closure.close_undeclared |> List.length in - let size = string_of_int argc in if argc >= 62 then (* Limited by c++ macro size of 128 args *) abort "Too many capture variables" closure.close_expr.cpppos; if argc >= 20 || List.length closure.close_args >= 20 then writer#add_big_closures; let argsCount = list_num closure.close_args in - output_i ("HX_BEGIN_LOCAL_FUNC_S" ^ size ^ "("); - out - (if closure.close_this != None then "::hx::LocalThisFunc," - else "::hx::LocalFunc,"); - out ("_hx_Closure_" ^ string_of_int closure.close_id); - IntMap.iter - (fun _ var -> - let str = cpp_macro_var_type_of var in - out ("," ^ str ^ "," ^ var.tcppv_debug_name)) - closure.close_undeclared; - out (") HXARGC(" ^ argsCount ^ ")\n"); + let signature = cpp_callable_signaure closure in + let captured = + match closure.close_undeclared |> IntMap.to_list with + | [] -> "" + | some -> + ", " ^ (some + |> List.map snd + |> List.map (fun v -> Printf.sprintf "%s,%s" (cpp_macro_var_type_of v) v.tcppv_debug_name) + |> String.concat ",") + in + + Printf.sprintf + "HX_BEGIN_LOCAL_FUNC_S%i(::hx::AutoCallable_obj< %s >, _hx_Closure_%i%s)\n" + argc + signature + closure.close_id + captured |> out; Printf.sprintf "%s _hx_run( %s )" (tcpp_to_string closure.close_type) - (print_arg_list closure.close_args "__o_") |> output_i; + (cpp_callable_args closure.close_args "__o_") |> output_i; let prologue = function | gc_stack -> @@ -1556,19 +1597,18 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ hx_stack_push ctx output_i class_name func_name closure.close_expr.cpppos gc_stack; if ctx.ctx_debug_level >= 2 then ( - if closure.close_this != None then - output_i "HX_STACK_THIS(__this.mPtr)\n"; - List.iter - (fun (v, _) -> - output_i - ("HX_STACK_ARG(" ^ v.tcppv_name ^ ",\"" ^ v.tcppv_debug_name ^ "\")\n")) - (List.filter (cpp_debug_var_visible ctx) closure.close_args); + closure.close_args + |> List.filter (cpp_debug_var_visible ctx) + |> List.iter (fun (v, _) -> output_i ("HX_STACK_ARG(" ^ v.tcppv_name ^ ",\"" ^ v.tcppv_debug_name ^ "\")\n")); let line = Lexer.get_error_line closure.close_expr.cpppos in let lineName = Printf.sprintf "%4d" line in out ("HXLINE(" ^ lineName ^ ")\n")) in gen_with_injection (mk_injection prologue "" "") closure.close_expr true; + output_i "int __Compare(const ::hx::Object* inRhs) const override {\n"; + output_i (Printf.sprintf "\treturn dynamic_cast(inRhs) ? 0 : -1;\n" closure.close_id); + output_i "}\n"; let return = match closure.close_type with TCppVoid -> "(void)" | _ -> "return" diff --git a/src/generators/cpp/gen/cppGenClassHeader.ml b/src/generators/cpp/gen/cppGenClassHeader.ml index 67e6c9644b6..15efbde62b2 100644 --- a/src/generators/cpp/gen/cppGenClassHeader.ml +++ b/src/generators/cpp/gen/cppGenClassHeader.ml @@ -28,10 +28,11 @@ let gen_member_variable ctx is_static var = tcpp_str var.tcv_name tcpp_str get_ptr var.tcv_name |> output;) let gen_dynamic_function ctx class_def is_static func = - let output = ctx.ctx_output in - let prefix = if is_static then "\t\tstatic " else "\t\t" in + let output = ctx.ctx_output in + let prefix = if is_static then "\t\tstatic " else "\t\t" in + let signature = func_to_callable_string "::hx::Callable" func in - Printf.sprintf "%sinline ::Dynamic& %s_dyn() { return %s; }\n" prefix func.tcf_name func.tcf_name |> output + Printf.sprintf "%sinline %s& %s_dyn() { return %s; }\n" prefix signature func.tcf_name func.tcf_name |> output let gen_member_function ctx class_def is_static func = let output = ctx.ctx_output in @@ -68,7 +69,9 @@ let gen_member_function ctx class_def is_static func = Printf.sprintf "\t\t%s %s %s(%s);\n" attributes return_type_str func.tcf_name (print_arg_list func.tcf_args "") |> output; if (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective then - Printf.sprintf "\t\t%s::Dynamic %s_dyn();\n" (if is_static then "static " else "") func.tcf_name |> output; + let prefix = if is_static then "static " else "" in + let signature = func_to_callable_string "::hx::Callable" func in + Printf.sprintf "\t\t%s%s %s_dyn();\n" prefix signature func.tcf_name |> output; output "\n" diff --git a/src/generators/cpp/gen/cppGenClassImplementation.ml b/src/generators/cpp/gen/cppGenClassImplementation.ml index fa32e891480..2475c174bd9 100644 --- a/src/generators/cpp/gen/cppGenClassImplementation.ml +++ b/src/generators/cpp/gen/cppGenClassImplementation.ml @@ -9,7 +9,39 @@ open CppSourceWriter open CppContext open CppGen -let gen_function ctx class_def class_name is_static func = +let write_callable_header callable_name captures func return_type_str prefix output = + let signature = func_to_callable_string "::hx::AutoCallable_obj" func in + + Printf.sprintf "struct %s final : public %s {\n" callable_name signature |> output; + (match captures with + | Some obj_name -> + Printf.sprintf "\t::hx::ObjectPtr<%s> __this;\n" obj_name |> output; + Printf.sprintf "\t%s(::hx::ObjectPtr<%s> obj = null()) : __this(obj) {} \n" callable_name obj_name |> output + | None -> + Printf.sprintf "\t%s() {} \n" callable_name |> output); + + output "\tint __Compare(const ::hx::Object* inRhs) const override {\n"; + Printf.sprintf "\t\tauto casted = dynamic_cast(inRhs);\n" callable_name |> output; + output "\t\tif (!casted) { return -1; }\n"; + if Option.is_some captures then + output "\t\tif (__this != casted->__this) return 1;\n"; + output "\t\treturn 0;\n"; + output "\t}\n"; + + Printf.sprintf "\t%s HX_LOCAL_RUN(%s) override {\n" return_type_str (cpp_callable_args func.tcf_args prefix) |> output + +let write_callable_trailer captures output = + output "\t}\n"; + if Option.is_some captures then begin + output "\tvoid __Mark(hx::MarkContext* __inCtx) override { HX_MARK_MEMBER(__this); }\n"; + output "#ifdef HXCPP_VISIT_ALLOCS\n"; + output "\tvoid __Visit(hx::VisitContext* __inCtx) override { HX_VISIT_MEMBER(__this); }\n"; + output "#endif\n"; + end; + + output "};\n\n" + +let gen_function ctx tcpp_class is_static func = let output = ctx.ctx_output in let return_type = cpp_type_of func.tcf_func.tf_type in @@ -19,22 +51,12 @@ let gen_function ctx class_def class_name is_static func = "(void)", true, "void" | other -> "return ", false, tcpp_to_string other in - let needsWrapper t = - match t with - | TCppStar _ - | TCppMarshalNativeType (_, (Stack | Promoted)) -> true - | TCppInst (t, _) -> Meta.has Meta.StructAccess t.cl_meta - | _ -> false - in (* The actual function definition *) output return_type_str; - output (" " ^ class_name ^ "::" ^ func.tcf_name ^ "("); + output (" " ^ tcpp_class.tcl_name ^ "::" ^ func.tcf_name ^ "("); output (print_arg_list func.tcf_args "__o_"); output ")"; - ctx.ctx_real_this_ptr <- true; - let code = get_code func.tcf_field.cf_meta Meta.FunctionCode in - let tail_code = get_code func.tcf_field.cf_meta Meta.FunctionTailCode in begin match get_meta_string func.tcf_field.cf_meta Meta.Native with | Some nativeImpl when is_static -> @@ -45,104 +67,99 @@ let gen_function ctx class_def class_name is_static func = ^ ");\n"); output "}\n\n" | _ -> + ctx.ctx_real_this_ptr <- true; + let code = get_code func.tcf_field.cf_meta Meta.FunctionCode in + let tail_code = get_code func.tcf_field.cf_meta Meta.FunctionTailCode in + with_debug ctx func.tcf_field.cf_meta - (gen_cpp_function_body ctx class_def is_static func.tcf_field.cf_name func code tail_code); + (gen_cpp_function_body ctx tcpp_class.tcl_class is_static func.tcf_field.cf_name func code tail_code); end; output "\n\n"; (* generate dynamic version too ... *) if (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective then - let tcpp_args = List.map (fun (v, _) -> CppRetyper.cpp_type_of CppRetyper.with_promoted_value_type v.v_type) func.tcf_func.tf_args in - let wrap = needsWrapper return_type || List.exists needsWrapper tcpp_args in - - if wrap then ( - let wrapName = "_hx_wrap" ^ class_name ^ "_" ^ func.tcf_name in - output ("static ::Dynamic " ^ wrapName ^ "( "); - - let initial = if is_static then [] else [ "::hx::Object *obj" ] in - - initial @ (List.init (List.length tcpp_args) (fun idx -> Printf.sprintf "const ::Dynamic &a%i" idx)) - |> String.concat "," - |> output; - - output ") {\n\t"; - (if not is_void then - match return_type with - | TCppStar _ -> - output "return (cpp::Pointer) " - | TCppInst (t, _) when Meta.has Meta.StructAccess t.cl_meta -> - output ("return (cpp::Struct< " ^ tcpp_to_string return_type ^ " >) ") - | TCppMarshalNativeType (value_type, _) -> - TCppMarshalNativeType (value_type, Reference) |> tcpp_to_string |> Printf.sprintf "return (%s) " |> output - | _ -> - output "return "); - - if is_static then - output (class_name ^ "::" ^ func.tcf_name ^ "(") - else - output ("reinterpret_cast< " ^ class_name ^ " *>(obj)->" ^ func.tcf_name ^ "("); - - let cast_prefix idx arg = - match arg with - | TCppStar (t, const) -> - Printf.sprintf "(::cpp::%sPointer< %s >) a%i" (if const then "Const" else "") (tcpp_to_string t) idx - | TCppInst (t, _) when Meta.has Meta.StructAccess t.cl_meta -> - Printf.sprintf "(::cpp::Struct< %s >) a%i" (tcpp_to_string arg) idx - | TCppMarshalNativeType (value_type, _) -> - Printf.sprintf "(%s) a%i" (TCppMarshalNativeType (value_type, Reference) |> tcpp_to_string) idx - | _ -> - Printf.sprintf "a%i" idx in - - tcpp_args - |> ExtList.List.mapi cast_prefix - |> String.concat ", " - |> output; - - output ");\n"; - - if is_void then output "\treturn null();\n"; - output "}\n"; - let nName = string_of_int (List.length tcpp_args) in - output - ("::Dynamic " ^ class_name ^ "::" ^ func.tcf_name ^ "_dyn() {\n\treturn "); - if is_static then - output - ("::hx::CreateStaticFunction" ^ nName ^ "(\"" ^ func.tcf_name ^ "\"," ^ wrapName ^ ");") - else - output - ("::hx::CreateMemberFunction" ^ nName ^ "(\"" ^ func.tcf_name ^ "\",this," ^ wrapName ^ ");"); - output "}\n") + let callable_name = Printf.sprintf "__%s%s" tcpp_class.tcl_name func.tcf_name in + let signature = func_to_callable_string "::hx::Callable" func in + if is_static then + Printf.sprintf + "%s %s::%s_dyn() { return _hx_alloc%s; }\n\n" + signature + tcpp_class.tcl_name + func.tcf_name + callable_name |> output else - let prefix = if is_static then "STATIC_" else "" in - Printf.sprintf "%sHX_DEFINE_DYNAMIC_FUNC%i(%s, %s, %s)\n\n" prefix (List.length func.tcf_func.tf_args) class_name func.tcf_name ret |> output - -let gen_dynamic_function ctx class_def class_name is_static is_for_static_var func = - let output = ctx.ctx_output in - let func_name = "__default_" ^ func.tcf_name in - let nargs = string_of_int (List.length func.tcf_func.tf_args) in - let return_type = CppRetyper.cpp_type_of CppRetyper.with_promoted_value_type func.tcf_func.tf_type in - let no_debug = Meta.has Meta.NoDebug func.tcf_field.cf_meta in - let is_void = return_type = TCppVoid in - let ret = if is_void then "(void)" else "return " in + Printf.sprintf + "%s %s::%s_dyn() { return new %s(this); }\n\n" + signature + tcpp_class.tcl_name + func.tcf_name + callable_name |> output + +let gen_function_closures ctx tcpp_class is_static func = + match get_meta_string func.tcf_field.cf_meta Meta.Native with + | Some _ when is_static -> + () + | _ when (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective -> + let output = ctx.ctx_output in + let return_type_str = type_to_string func.tcf_func.tf_type in + let return_type = cpp_type_of func.tcf_func.tf_type in + let is_void = return_type = TCppVoid in + let callable_name = Printf.sprintf "__%s%s" tcpp_class.tcl_name func.tcf_name in + let full_name = (tcpp_class.tcl_class.cl_path |> fst |> List.map keyword_remap |> String.concat "::") ^ "::" ^ tcpp_class.tcl_name in + let captures = if is_static then None else Some full_name in + + write_callable_header callable_name captures func return_type_str "" output; + + let args_pass = func.tcf_args |> List.map fst |> List.map (fun v -> v.tcppv_name) |> String.concat ", " in + let prefix = if is_void then "\t\t" else "\t\treturn " in + if is_static then + Printf.sprintf "%s%s::%s(%s);\n" prefix full_name func.tcf_name args_pass |> output + else + Printf.sprintf "%s__this->%s(%s);\n" prefix func.tcf_name args_pass |> output; + + write_callable_trailer captures output; + + if is_static then + let signature = func_to_callable_string "::hx::Callable" func in + Printf.sprintf "%s _hx_alloc%s;\n\n" signature callable_name |> output + | _ -> + () + +let gen_static_closure_alloc ctx tcpp_class func = + match get_meta_string func.tcf_field.cf_meta Meta.Native with + | Some _ -> + () + | _ when (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective -> + let output = ctx.ctx_output in + let callable_name = Printf.sprintf "__%s%s" tcpp_class.tcl_name func.tcf_name in + Printf.sprintf "_hx_alloc%s = new (::hx::NewObjectType::NewObjConst) %s();\n\n" callable_name callable_name |> output + | _ -> + () + +let gen_dynamic_function ctx tcpp_class is_static func = + let output = ctx.ctx_output in + let func_name = "__default_" ^ func.tcf_name in + let no_debug = Meta.has Meta.NoDebug func.tcf_field.cf_meta in + let return_type_str = CppRetyper.cpp_type_of CppRetyper.with_stack_value_type func.tcf_func.tf_type |> tcpp_to_string in + let captures = Some ((tcpp_class.tcl_class.cl_path |> fst |> List.map keyword_remap |> String.concat "::") ^ "::" ^ tcpp_class.tcl_name) in + + write_callable_header func_name captures func return_type_str "__o_" output; ctx.ctx_real_this_ptr <- false; - Printf.sprintf "HX_BEGIN_DEFAULT_FUNC(%s, %s)\n" func_name class_name |> output; - Printf.sprintf "%s _hx_run(%s)" (tcpp_to_string return_type) (print_arg_list func.tcf_args "__o_") |> output; - gen_cpp_function_body ctx class_def is_static func_name func "" "" no_debug; + gen_cpp_function_body ctx tcpp_class.tcl_class is_static func_name func "" "" no_debug; - output ("HX_END_LOCAL_FUNC" ^ nargs ^ "(" ^ ret ^ ")\n"); - output "HX_END_DEFAULT_FUNC\n\n" + write_callable_trailer captures output -let gen_static_variable ctx class_def class_name var = +let gen_static_variable ctx tcpp_class var = let output = ctx.ctx_output in let tcpp_str = var.tcv_type |> CppRetyper.cpp_type_of CppRetyper.with_promoted_value_type |> tcpp_to_string in - Printf.sprintf "%s %s::%s;\n\n" tcpp_str class_name var.tcv_name |> output + Printf.sprintf "%s %s::%s;\n\n" tcpp_str tcpp_class.tcl_name var.tcv_name |> output -let gen_dynamic_function_init ctx class_def func = +let gen_dynamic_function_init ctx func = match func.tcf_field.cf_expr with | Some { eexpr = TFunction function_def } -> Printf.sprintf "\t%s = new %s;\n\n" func.tcf_name ("__default_" ^ func.tcf_name) |> ctx.ctx_output @@ -173,8 +190,12 @@ let gen_boot_field ctx output_cpp tcpp_class = | Some expr -> gen_cpp_init ctx dot_name "boot" "__mClass->__rtti__ = " expr | None -> ()); + (* Allocating static function lambdas must be done first *) + (* Init functionality might depend on these being assigned *) + List.iter (gen_static_closure_alloc ctx tcpp_class) tcpp_class.tcl_static_functions; + List.iter (gen_var_init ctx tcpp_class.tcl_class) tcpp_class.tcl_static_variables; - List.iter (gen_dynamic_function_init ctx tcpp_class.tcl_class) tcpp_class.tcl_static_dynamic_functions; + List.iter (gen_dynamic_function_init ctx) tcpp_class.tcl_static_dynamic_functions; output_cpp "}\n\n") @@ -268,21 +289,27 @@ let generate_native_class base_ctx tcpp_class = let printer inc = output_cpp ("#include \"" ^ inc ^ "\"\n") in List.iter printer includes; - begin_namespace output_cpp class_path; output_cpp "\n"; + output_cpp "namespace {\n\n"; - output_cpp (get_class_code class_def Meta.CppNamespaceCode); + List.iter (gen_dynamic_function ctx tcpp_class false) tcpp_class.tcl_dynamic_functions; + List.iter (gen_dynamic_function ctx tcpp_class true) tcpp_class.tcl_static_dynamic_functions; - let class_name = tcpp_class.tcl_name in + List.iter (gen_function_closures ctx tcpp_class false) tcpp_class.tcl_functions; + List.iter (gen_function_closures ctx tcpp_class true) tcpp_class.tcl_static_functions; + + output_cpp "}\n\n"; + + begin_namespace output_cpp class_path; + + output_cpp (get_class_code class_def Meta.CppNamespaceCode); gen_init_function ctx output_cpp tcpp_class; - List.iter (gen_function ctx class_def class_name false) tcpp_class.tcl_functions; - List.iter (gen_dynamic_function ctx class_def class_name false false) tcpp_class.tcl_dynamic_functions; + List.iter (gen_function ctx tcpp_class false) tcpp_class.tcl_functions; - List.iter (gen_function ctx class_def class_name true) tcpp_class.tcl_static_functions; - List.iter (gen_dynamic_function ctx class_def class_name true false) tcpp_class.tcl_static_dynamic_functions; - List.iter (gen_static_variable ctx class_def class_name) tcpp_class.tcl_static_variables; + List.iter (gen_function ctx tcpp_class true) tcpp_class.tcl_static_functions; + List.iter (gen_static_variable ctx tcpp_class) tcpp_class.tcl_static_variables; output_cpp "\n"; @@ -331,6 +358,17 @@ let generate_managed_class base_ctx tcpp_class = let printer inc = output_cpp ("#include \"" ^ inc ^ "\"\n") in List.iter printer includes; + output_cpp "\n"; + output_cpp "namespace {\n\n"; + + List.iter (gen_function_closures ctx tcpp_class false) tcpp_class.tcl_functions; + List.iter (gen_function_closures ctx tcpp_class true) tcpp_class.tcl_static_functions; + + List.iter (gen_dynamic_function ctx tcpp_class false) tcpp_class.tcl_dynamic_functions; + List.iter (gen_dynamic_function ctx tcpp_class true) tcpp_class.tcl_static_dynamic_functions; + + output_cpp "}\n\n"; + begin_namespace output_cpp class_path; output_cpp "\n"; @@ -348,6 +386,9 @@ let generate_managed_class base_ctx tcpp_class = ("void " ^ class_name ^ "::__construct(" ^ constructor_type_args ^ ")"); (match tcpp_class.tcl_constructor with | Some constructor -> + (* Ensure we reset this real this ptr flag, it may have been set to false in the above gen_dynamic_function *) + ctx.ctx_real_this_ptr <- true; + let cb no_debug = gen_cpp_function_body ctx class_def false "new" constructor "" "" no_debug; @@ -499,12 +540,10 @@ let generate_managed_class base_ctx tcpp_class = gen_init_function ctx output_cpp tcpp_class; - List.iter (gen_function ctx class_def class_name false) tcpp_class.tcl_functions; - List.iter (gen_dynamic_function ctx class_def class_name false false) tcpp_class.tcl_dynamic_functions; + List.iter (gen_function ctx tcpp_class false) tcpp_class.tcl_functions; - List.iter (gen_function ctx class_def class_name true) tcpp_class.tcl_static_functions; - List.iter (gen_dynamic_function ctx class_def class_name true false) tcpp_class.tcl_static_dynamic_functions; - List.iter (gen_static_variable ctx class_def class_name) tcpp_class.tcl_static_variables; + List.iter (gen_function ctx tcpp_class true) tcpp_class.tcl_static_functions; + List.iter (gen_static_variable ctx tcpp_class) tcpp_class.tcl_static_variables; output_cpp "\n"; diff --git a/src/generators/cpp/gen/cppGenInterfaceHeader.ml b/src/generators/cpp/gen/cppGenInterfaceHeader.ml index 5f044085869..6a4a872ccd7 100644 --- a/src/generators/cpp/gen/cppGenInterfaceHeader.ml +++ b/src/generators/cpp/gen/cppGenInterfaceHeader.ml @@ -37,21 +37,10 @@ let gen_function ctx interface func = | other -> tcpp_to_string other in - let returnStr = if returnType = "void" then "" else "return " in let commaArgList = if argList = "" then argList else "," ^ argList in - let cast = Printf.sprintf "::hx::interface_cast< ::%s_obj *>" (join_class_path_remap interface.if_class.cl_path "::") in Printf.sprintf "\t\t%s (::hx::Object :: *_hx_%s)(%s);\n" returnType func.iff_name argList |> output; - Printf.sprintf "\t\tstatic inline %s %s( ::Dynamic _hx_%s ){\n" returnType func.iff_name commaArgList |> output; - output "\t\t\t#ifdef HXCPP_CHECK_POINTER\n"; - output "\t\t\tif (::hx::IsNull(_hx_)) ::hx::NullReference(\"Object\", false);\n"; - output "\t\t\t#ifdef HXCPP_GC_CHECK_POINTER\n"; - output "\t\t\t\tGCCheckPointer(_hx_.mPtr);\n"; - output "\t\t\t#endif\n"; - output "\t\t\t#endif\n"; - Printf.sprintf - "\t\t\t%s( _hx_.mPtr->*( %s(_hx_.mPtr->_hx_getInterface(%s)))->_hx_%s )(%s);\n\t\t}\n" - returnStr cast interface.if_hash func.iff_name (print_arg_names func.iff_args) |> output + Printf.sprintf "\t\tstatic %s %s( ::Dynamic _hx_%s );\n" returnType func.iff_name commaArgList |> output let gen_includes h_file interface_def = let add_class_includes cls = diff --git a/src/generators/cpp/gen/cppGenInterfaceImplementation.ml b/src/generators/cpp/gen/cppGenInterfaceImplementation.ml index ef1ad8eadf9..7d1afe51daa 100644 --- a/src/generators/cpp/gen/cppGenInterfaceImplementation.ml +++ b/src/generators/cpp/gen/cppGenInterfaceImplementation.ml @@ -104,6 +104,29 @@ let generate_managed_interface base_ctx tcpp_interface = begin_namespace output_cpp class_path; output_cpp "\n"; + let gen_function func = + let argList = print_retyped_tfun_arg_list true func.iff_args in + let returnType = tcpp_to_string func.iff_return in + let returnStr = if returnType = "void" then "" else "return " in + let commaArgList = if argList = "" then argList else "," ^ argList in + let cast = Printf.sprintf "::hx::interface_cast< %s *>" tcpp_interface.if_name in + + Printf.sprintf "%s %s::%s( ::Dynamic _hx_%s ) {\n" returnType tcpp_interface.if_name func.iff_name commaArgList |> output_cpp; + output_cpp "#ifdef HXCPP_CHECK_POINTER\n"; + output_cpp "\tif (::hx::IsNull(_hx_)) ::hx::NullReference(\"Object\", false);\n"; + output_cpp "#ifdef HXCPP_GC_CHECK_POINTER\n"; + output_cpp "\tGCCheckPointer(_hx_.mPtr);\n"; + output_cpp "#endif\n"; + output_cpp "#endif\n"; + Printf.sprintf + "\t%s( _hx_.mPtr->*( %s(_hx_.mPtr->_hx_getInterface(%s)))->_hx_%s )(%s);\n}\n" + returnStr cast tcpp_interface.if_hash func.iff_name (print_arg_names func.iff_args) |> output_cpp + in + + all_interface_functions tcpp_interface |> List.iter gen_function; + + output_cpp "\n"; + output_cpp (get_class_code tcpp_interface.if_class Meta.CppNamespaceCode); output_cpp "\n"; diff --git a/src/generators/gencpp.ml b/src/generators/gencpp.ml index b764c06c8a6..eb9f742d5a0 100644 --- a/src/generators/gencpp.ml +++ b/src/generators/gencpp.ml @@ -315,19 +315,21 @@ let generate_source ctx = | TClassDecl class_def -> let native_gen = Meta.has Meta.NativeGen class_def.cl_meta in - let decl, slots, ids = + let bootable, decl, slots, ids = match has_class_flag class_def CInterface with | true -> let (slots, iface) = CppRetyper.tcpp_interface_from_tclass ctx acc.slots class_def in - if native_gen then (NativeInterface iface, slots, acc.ids) else (ManagedInterface iface, slots, acc.ids) + let bootable = has_boot_field class_def in + if native_gen then (bootable, NativeInterface iface, slots, acc.ids) else (bootable, ManagedInterface iface, slots, acc.ids) | false -> let (slots, ids, cls) = CppRetyper.tcpp_class_from_tclass ctx acc.ids acc.slots class_def [] in - if native_gen then (NativeClass cls, slots, ids) else (ManagedClass cls, slots, ids) in + let bootable = has_tcpp_class_flag cls Boot in + if native_gen then (bootable, NativeClass cls, slots, ids) else (bootable, ManagedClass cls, slots, ids) in let acc_decls = decl :: acc.decls in let acc_build_xml = acc.build_xml ^ (CppGen.get_class_code class_def Meta.BuildXml) in let acc_init_classes = if has_init_field class_def then class_def.cl_path :: acc.init_classes else acc.init_classes in - let acc_boot_classes = if has_boot_field class_def then class_def.cl_path :: acc.boot_classes else acc.boot_classes in + let acc_boot_classes = if bootable then class_def.cl_path :: acc.boot_classes else acc.boot_classes in let acc_nonboot_classes = if Meta.has Meta.NativeGen class_def.cl_meta then acc.nonboot_classes else class_def.cl_path :: acc.nonboot_classes in let acc_exe_classes = if (has_class_flag class_def CInterface) && (is_native_gen_class class_def) then From d1e91e3ce1f8a64360fc401c5e55c4d21555753e Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 17 Dec 2025 00:03:04 +0000 Subject: [PATCH 07/12] dont exclude native annotated functions from closure generation --- .../cpp/gen/cppGenClassImplementation.ml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/generators/cpp/gen/cppGenClassImplementation.ml b/src/generators/cpp/gen/cppGenClassImplementation.ml index 2475c174bd9..67356ee9b45 100644 --- a/src/generators/cpp/gen/cppGenClassImplementation.ml +++ b/src/generators/cpp/gen/cppGenClassImplementation.ml @@ -99,10 +99,7 @@ let gen_function ctx tcpp_class is_static func = callable_name |> output let gen_function_closures ctx tcpp_class is_static func = - match get_meta_string func.tcf_field.cf_meta Meta.Native with - | Some _ when is_static -> - () - | _ when (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective -> + if (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective then let output = ctx.ctx_output in let return_type_str = type_to_string func.tcf_func.tf_type in let return_type = cpp_type_of func.tcf_func.tf_type in @@ -125,19 +122,12 @@ let gen_function_closures ctx tcpp_class is_static func = if is_static then let signature = func_to_callable_string "::hx::Callable" func in Printf.sprintf "%s _hx_alloc%s;\n\n" signature callable_name |> output - | _ -> - () let gen_static_closure_alloc ctx tcpp_class func = - match get_meta_string func.tcf_field.cf_meta Meta.Native with - | Some _ -> - () - | _ when (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective -> + if (not func.tcf_is_virtual || not func.tcf_is_overriding) && func.tcf_is_reflective then let output = ctx.ctx_output in let callable_name = Printf.sprintf "__%s%s" tcpp_class.tcl_name func.tcf_name in Printf.sprintf "_hx_alloc%s = new (::hx::NewObjectType::NewObjConst) %s();\n\n" callable_name callable_name |> output - | _ -> - () let gen_dynamic_function ctx tcpp_class is_static func = let output = ctx.ctx_output in From de777167f6881def34c99cbf37d27b289b453f51 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 17 Dec 2025 21:33:17 +0000 Subject: [PATCH 08/12] Various cleanup and fixes surrounded marshalling callables --- src/generators/cpp/cppAst.ml | 2 +- src/generators/cpp/cppRetyper.ml | 91 +++++++++++++------ src/generators/cpp/gen/cppGen.ml | 6 +- src/generators/cpp/gen/cppGenClassHeader.ml | 11 +-- .../cpp/gen/cppGenClassImplementation.ml | 22 ++--- 5 files changed, 80 insertions(+), 52 deletions(-) diff --git a/src/generators/cpp/cppAst.ml b/src/generators/cpp/cppAst.ml index 786ab8116ea..6c13df211b0 100644 --- a/src/generators/cpp/cppAst.ml +++ b/src/generators/cpp/cppAst.ml @@ -246,7 +246,7 @@ and tcpp_class_function = { and tcpp_class_variable = { tcv_field : tclass_field; tcv_name : string; - tcv_type : t; + tcv_type : tcpp; tcv_default : texpr option; tcv_has_getter : bool; diff --git a/src/generators/cpp/cppRetyper.ml b/src/generators/cpp/cppRetyper.ml index e32ce520ee8..5f6367b36f7 100644 --- a/src/generators/cpp/cppRetyper.ml +++ b/src/generators/cpp/cppRetyper.ml @@ -137,8 +137,8 @@ let rec cpp_type_of stack value_type_handler haxe_type = else cpp_type_from_path stack type_def.t_path params value_type_handler (fun () -> cpp_type_of stack value_type_handler (apply_typedef type_def params)) | TFun (arguments, return) -> - let retyped_arguments = List.map (fun (_, o, t) -> cpp_tfun_arg_type_of stack o value_type_handler t) arguments in - let retyped_return = cpp_type_of stack value_type_handler return in + let retyped_arguments = List.map (fun (_, o, t) -> cpp_tfun_arg_type_of stack o with_reference_value_type t) arguments in + let retyped_return = cpp_type_of stack with_stack_value_type return in TCppCallable (retyped_arguments, retyped_return) | TAnon _ -> TCppObject | TDynamic _ -> TCppDynamic @@ -314,6 +314,13 @@ type retyper_ctx = { loop_stack : (int * bool) list; } +let sanitise_stack_only_type pos tcpp = + match tcpp with + | TCppMarshalNativeType (ValueClass (cls, _), Promoted) when is_stack_only_marshalling_native_value_class cls -> + cpp_abort PromotedStackOnlyValueType pos + | _ -> + tcpp + let retype_tvar tvar = let copying_var = match tvar.v_kind with @@ -328,17 +335,20 @@ let retype_tvar tvar = else with_reference_value_type in - let sanitise tcpp = - match tcpp with - | TCppMarshalNativeType (ValueClass (cls, _), Promoted) when is_stack_only_marshalling_native_value_class cls -> - cpp_abort PromotedStackOnlyValueType tvar.v_pos - | _ -> - tcpp - in { tcppv_var = tvar; - tcppv_type = cpp_type_of handler tvar.v_type |> sanitise; + tcppv_type = cpp_type_of handler tvar.v_type |> sanitise_stack_only_type tvar.v_pos; + tcppv_name = cpp_var_name_of tvar; + tcppv_debug_name = keyword_remap tvar.v_name + } + +let retype_func_arg tvar expr = + let handler = if has_var_flag tvar VCaptured then with_promoted_value_type else with_stack_value_type in + + { + tcppv_var = tvar; + tcppv_type = cpp_fun_arg_type_of tvar expr handler |> sanitise_stack_only_type tvar.v_pos; tcppv_name = cpp_var_name_of tvar; tcppv_debug_name = keyword_remap tvar.v_name } @@ -1689,36 +1699,56 @@ let native_field_name_remap field = let rec tcpp_class_from_tclass ctx ids slots class_def class_params = let scriptable = Gctx.defined ctx.ctx_common Define.Scriptable in - let create_function field handler func = { + let create_function field func = { tcf_field = field; tcf_name = native_field_name_remap field; - tcf_args = List.map (fun (v, i) -> retype_tvar v, i) func.tf_args; + tcf_args = List.map (fun (v, i) -> retype_func_arg v i, i) func.tf_args; tcf_func = func; tcf_is_virtual = not (has_meta Meta.NonVirtual field.cf_meta); tcf_is_reflective = reflective class_def field; tcf_is_external = not (is_internal_member field.cf_name); tcf_is_overriding = is_override field; tcf_is_scriptable = scriptable; - tcf_return = cpp_type_of handler func.tf_type + tcf_return = cpp_type_of with_stack_value_type func.tf_type } in - let create_variable field = { - tcv_field = field; - tcv_name = native_field_name_remap field; - tcv_type = field.cf_type; - tcv_default = None; + let create_variable field = + let tcpp = cpp_type_of with_promoted_value_type field.cf_type in + + { + tcv_field = field; + tcv_name = native_field_name_remap field; + tcv_type = tcpp; + tcv_default = None; + + tcv_has_getter = (match field.cf_kind with | Var { v_read = AccCall | AccPrivateCall } -> true | _ -> false); + tcv_is_stackonly = has_meta Meta.StackOnly field.cf_meta; + tcv_is_reflective = reflective class_def field; + tcv_is_gc_element = is_gc_element ctx tcpp; + } in - tcv_has_getter = (match field.cf_kind with | Var { v_read = AccCall | AccPrivateCall } -> true | _ -> false); - tcv_is_stackonly = has_meta Meta.StackOnly field.cf_meta; - tcv_is_reflective = reflective class_def field; - tcv_is_gc_element = cpp_type_of with_promoted_value_type field.cf_type |> is_gc_element ctx; - } in + let create_dynamic_func_variable field func = + let args = func.tf_args |> List.map (fun (v, i) -> retype_func_arg v i) |> List.map (fun v -> v.tcppv_type) in + let ret = cpp_type_of with_stack_value_type func.tf_type in + let tcpp = TCppCallable (args, ret) in + + { + tcv_field = { field with cf_expr = None; cf_kind = Var ({ v_read = AccNormal; v_write = AccNormal }) }; + tcv_name = native_field_name_remap field; + tcv_type = tcpp; + tcv_default = None; + + tcv_has_getter = false; + tcv_is_stackonly = false; + tcv_is_reflective = reflective class_def field; + tcv_is_gc_element = true; + } in let filter_functions is_static field = if should_implement_field field then match (field.cf_kind, field.cf_expr) with | Method (MethNormal | MethInline), Some { eexpr = TFunction func } -> - Some (create_function field with_stack_value_type func) + Some (create_function field func) | Method MethNormal, _ when has_class_field_flag field CfAbstract -> (* We need to fetch the default values for abstract functions from the @:Value meta *) let abstract_tfunc = @@ -1759,7 +1789,7 @@ let rec tcpp_class_from_tclass ctx ids slots class_def class_params = die "expected abstract field type to be TFun" __LOC__ in - Some (create_function field with_stack_value_type abstract_tfunc) + Some (create_function field abstract_tfunc) | _ -> None else @@ -1770,10 +1800,10 @@ let rec tcpp_class_from_tclass ctx ids slots class_def class_params = if should_implement_field field then match (field.cf_kind, field.cf_expr) with | Method MethDynamic, Some { eexpr = TFunction func } -> - Some (create_function field with_promoted_value_type func) + Some (create_function field func) (* static variables with a default function value get a dynamic function generated as the implementation *) | Var _, Some { eexpr = TFunction func } when func_for_static_field -> - Some (create_function field with_promoted_value_type func) + Some (create_function field func) | _ -> None else @@ -1791,7 +1821,8 @@ let rec tcpp_class_from_tclass ctx ids slots class_def class_params = Some (create_variable field)) (* Dynamic methods are implemented as a physical field holding a closure *) | Method MethDynamic, Some { eexpr = TFunction func } -> - Some (create_variable { field with cf_expr = None; cf_kind = Var ({ v_read = AccNormal; v_write = AccNormal }) }) + Some (create_dynamic_func_variable field func) + (* Some (create_variable { field with cf_expr = None; cf_kind = Var ({ v_read = AccNormal; v_write = AccNormal }) }) *) (* Below should cause abstracts which have functions with no implementation to be generated as a field *) (* See Int32.hx as an example *) | Method (MethNormal | MethInline), None when not (has_class_field_flag field CfAbstract) -> @@ -1848,7 +1879,7 @@ let rec tcpp_class_from_tclass ctx ids slots class_def class_params = let constructor = match class_def.cl_constructor with | Some ({ cf_expr = Some { eexpr = TFunction definition } } as field) -> - Some (create_function field with_stack_value_type definition) + Some (create_function field definition) | _ -> None in @@ -1889,7 +1920,7 @@ let rec tcpp_class_from_tclass ctx ids slots class_def class_params = match cpp_type_of with_promoted_value_type t with TCppScalar _ -> true | _ -> false in let rec gc_container variables super v = - match List.exists (fun v -> not (type_cant_be_null v.tcv_type)) variables, super with + match List.exists (fun v -> not (type_cant_be_null v.tcv_field.cf_type)) variables, super with | true, _ -> Some v | false, Some super -> gc_container super.tcl_variables super.tcl_super Parent | false, None -> None diff --git a/src/generators/cpp/gen/cppGen.ml b/src/generators/cpp/gen/cppGen.ml index 960442e0f13..cb38388e6ff 100644 --- a/src/generators/cpp/gen/cppGen.ml +++ b/src/generators/cpp/gen/cppGen.ml @@ -109,7 +109,7 @@ let cpp_debug_var_visible ctx var = not (cpp_no_debug_synbol ctx (fst var)) let cpp_callable_args arguments prefix = let make_arg (v, o) = - let return = CppRetyper.cpp_fun_arg_type_of v.tcppv_var o CppRetyper.with_stack_value_type |> tcpp_to_string in + let return = tcpp_to_string v.tcppv_type in let prefixed = match o with | Some {eexpr = TConst TNull} -> v.tcppv_name | Some _ -> prefix ^ v.tcppv_name @@ -125,7 +125,7 @@ let cpp_callable_signaure closure = let func_to_callable_string wrapper func = let return_str = tcpp_to_string func.tcf_return in - let arguments_str = func.tcf_args |> List.map (fun (v, o) -> CppRetyper.cpp_fun_arg_type_of v.tcppv_var o CppRetyper.with_stack_value_type) |> List.map tcpp_to_string |> String.concat "," in + let arguments_str = func.tcf_args |> List.map (fun (v, _) -> v.tcppv_type) |> List.map tcpp_to_string |> String.concat "," in Printf.sprintf "%s< %s (%s) >" wrapper return_str arguments_str @@ -1586,7 +1586,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ captured |> out; Printf.sprintf - "%s _hx_run( %s )" + "%s HX_LOCAL_RUN( %s )" (tcpp_to_string closure.close_type) (cpp_callable_args closure.close_args "__o_") |> output_i; diff --git a/src/generators/cpp/gen/cppGenClassHeader.ml b/src/generators/cpp/gen/cppGenClassHeader.ml index 15efbde62b2..a7acf1e8814 100644 --- a/src/generators/cpp/gen/cppGenClassHeader.ml +++ b/src/generators/cpp/gen/cppGenClassHeader.ml @@ -10,11 +10,10 @@ open CppContext open CppGen let gen_member_variable ctx is_static var = - let tcpp = CppRetyper.cpp_type_of CppRetyper.with_promoted_value_type var.tcv_type in - let tcpp_str = tcpp_to_string tcpp in + let tcpp_str = tcpp_to_string var.tcv_type in if not is_static && var.tcv_is_stackonly then - abort (Printf.sprintf "%s is marked as stack only and therefor cannot be used as the type for a non static variable" (Printer.s_type var.tcv_type)) var.tcv_field.cf_pos; + abort (Printf.sprintf "%s is marked as stack only and therefor cannot be used as the type for a non static variable" (Printer.s_type var.tcv_field.cf_type)) var.tcv_field.cf_pos; let output = ctx.ctx_output in let suffix = if is_static then "\t\tstatic " else "\t\t" in @@ -22,7 +21,7 @@ let gen_member_variable ctx is_static var = Printf.sprintf "%s%s %s;\n" suffix tcpp_str var.tcv_name |> output; if not is_static && var.tcv_is_gc_element then ( - let get_ptr = match tcpp with TCppString -> ".raw_ref()" | _ -> ".mPtr" in + let get_ptr = match var.tcv_type with TCppString -> ".raw_ref()" | _ -> ".mPtr" in Printf.sprintf "\t\tinline %s _hx_set_%s(::hx::StackContext* _hx_ctx, %s _hx_v) { HX_OBJ_WB(this, _hx_v%s) return %s = _hx_v; }\n" tcpp_str var.tcv_name tcpp_str get_ptr var.tcv_name |> output;) @@ -58,9 +57,7 @@ let gen_member_function ctx class_def is_static func = in let return_type_str = - match cpp_type_of func.tcf_func.tf_type with - | TCppMarshalNativeType (value_type, (Reference | Promoted)) -> - TCppMarshalNativeType (value_type, Stack) |> tcpp_to_string + match func.tcf_return with | TCppVoid -> "void" | other -> diff --git a/src/generators/cpp/gen/cppGenClassImplementation.ml b/src/generators/cpp/gen/cppGenClassImplementation.ml index 67356ee9b45..e9eac62e698 100644 --- a/src/generators/cpp/gen/cppGenClassImplementation.ml +++ b/src/generators/cpp/gen/cppGenClassImplementation.ml @@ -133,7 +133,7 @@ let gen_dynamic_function ctx tcpp_class is_static func = let output = ctx.ctx_output in let func_name = "__default_" ^ func.tcf_name in let no_debug = Meta.has Meta.NoDebug func.tcf_field.cf_meta in - let return_type_str = CppRetyper.cpp_type_of CppRetyper.with_stack_value_type func.tcf_func.tf_type |> tcpp_to_string in + let return_type_str = func.tcf_return |> tcpp_to_string in let captures = Some ((tcpp_class.tcl_class.cl_path |> fst |> List.map keyword_remap |> String.concat "::") ^ "::" ^ tcpp_class.tcl_name) in write_callable_header func_name captures func return_type_str "__o_" output; @@ -146,7 +146,7 @@ let gen_dynamic_function ctx tcpp_class is_static func = let gen_static_variable ctx tcpp_class var = let output = ctx.ctx_output in - let tcpp_str = var.tcv_type |> CppRetyper.cpp_type_of CppRetyper.with_promoted_value_type |> tcpp_to_string in + let tcpp_str = var.tcv_type |> tcpp_to_string in Printf.sprintf "%s %s::%s;\n\n" tcpp_str tcpp_class.tcl_name var.tcv_name |> output let gen_dynamic_function_init ctx func = @@ -660,8 +660,8 @@ let generate_managed_class base_ctx tcpp_class = acc in - let castable f = - match CppRetyper.cpp_type_of CppRetyper.with_promoted_value_type f.cf_type with + let castable var = + match var.tcv_type with | TCppInst (t, _) as inst when Meta.has Meta.StructAccess t.cl_meta -> "cpp::Struct< " ^ tcpp_to_string inst ^ " > " | TCppStar (t, _) -> @@ -708,9 +708,9 @@ let generate_managed_class base_ctx tcpp_class = if has_tcpp_class_flag tcpp_class MemberSet then ( Printf.sprintf "::hx::Val %s::__SetField(const ::String& inName, const ::hx::Val& inValue, ::hx::PropertyAccess inCallProp)\n{\n" class_name |> output_cpp; - let fold_variable (var:tcpp_class_variable) acc = + let fold_variable var acc = if var.tcv_is_reflective && not (is_abstract_impl class_def) then - let casted = castable var.tcv_field in + let casted = castable var in let default = if var.tcv_is_gc_element then Printf.sprintf "_hx_set_%s(HX_CTX_GET, inValue.Cast< %s >()); return inValue;" var.tcv_name casted else @@ -731,9 +731,9 @@ let generate_managed_class base_ctx tcpp_class = acc in - let fold_property (var:tcpp_class_variable) acc = + let fold_property var acc = if var.tcv_is_reflective && not (is_abstract_impl class_def) then - let casted = castable var.tcv_field in + let casted = castable var in match var.tcv_field.cf_kind with | Var { v_write = AccCall | AccPrivateCall } -> @@ -760,7 +760,7 @@ let generate_managed_class base_ctx tcpp_class = let fold_variable (var:tcpp_class_variable) acc = if var.tcv_is_reflective && not (is_abstract_impl class_def) then - let casted = castable var.tcv_field in + let casted = castable var in match var.tcv_field.cf_kind with | Var { v_write = AccCall | AccPrivateCall } -> @@ -777,13 +777,13 @@ let generate_managed_class base_ctx tcpp_class = acc in - let fold_property (var:tcpp_class_variable) acc = + let fold_property var acc = if var.tcv_is_reflective && not (is_abstract_impl class_def) then match var.tcv_field.cf_kind with | Var { v_write = AccCall | AccPrivateCall } -> let prop_call = checkPropCall var.tcv_field in let setter = Printf.sprintf "set_%s" var.tcv_field.cf_name |> get_wrapper var.tcv_field in - let casted = castable var.tcv_field in + let casted = castable var in (var.tcv_field.cf_name, String.length var.tcv_field.cf_name, Printf.sprintf "if (%s) { ioValue = %s(ioValue.Cast< %s >()); }" prop_call setter casted) :: acc | _ -> From fbfeb8d9d05ea0c94f63968626637349cc2bae8e Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 17 Dec 2025 22:03:59 +0000 Subject: [PATCH 09/12] Fix abstract this not being a reference marshalling type --- src/generators/cpp/cppRetyper.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/generators/cpp/cppRetyper.ml b/src/generators/cpp/cppRetyper.ml index 5f6367b36f7..4eb3ad9b6f2 100644 --- a/src/generators/cpp/cppRetyper.ml +++ b/src/generators/cpp/cppRetyper.ml @@ -344,7 +344,11 @@ let retype_tvar tvar = } let retype_func_arg tvar expr = - let handler = if has_var_flag tvar VCaptured then with_promoted_value_type else with_stack_value_type in + let handler = + match tvar.v_kind with + | VAbstractThis -> with_reference_value_type + | _ -> if has_var_flag tvar VCaptured then with_promoted_value_type else with_stack_value_type + in { tcppv_var = tvar; From ca08bc8d4f15529dad645cd3a3ba05562acab0e0 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 17 Dec 2025 22:20:07 +0000 Subject: [PATCH 10/12] update cpp ci hxcpp fork --- tests/runci/targets/Cpp.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runci/targets/Cpp.hx b/tests/runci/targets/Cpp.hx index 9bf4ff2ca0b..e58c4696fad 100644 --- a/tests/runci/targets/Cpp.hx +++ b/tests/runci/targets/Cpp.hx @@ -27,7 +27,7 @@ class Cpp { final path = getHaxelibPath("hxcpp"); infoMsg('hxcpp has already been installed in $path.'); } catch(e:Dynamic) { - haxelibInstallGit("HaxeFoundation", "hxcpp", true); + haxelibInstallGit("Aidan63", "hxcpp", "typed-functions", true); final oldDir = Sys.getCwd(); changeDirectory(getHaxelibPath("hxcpp") + "tools/hxcpp/"); runCommand("haxe", ["-D", "source-header=''", "compile.hxml"]); From 4f7a038798a1f1dcce115bd9699f45d25c9025f8 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 17 Dec 2025 23:01:08 +0000 Subject: [PATCH 11/12] Use correct retyping function for lambdas --- src/generators/cpp/cppRetyper.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generators/cpp/cppRetyper.ml b/src/generators/cpp/cppRetyper.ml index 4eb3ad9b6f2..9452eb4b946 100644 --- a/src/generators/cpp/cppRetyper.ml +++ b/src/generators/cpp/cppRetyper.ml @@ -1173,7 +1173,7 @@ let expression ctx request_type function_args function_type expression_tree forI let new_ctx = { retyper_ctx with - declarations = func.tf_args |> List.map (fun (t, _) -> t.v_id, retype_tvar t) |> int_map_of_list; + declarations = func.tf_args |> List.map (fun (t, o) -> t.v_id, retype_func_arg t o) |> int_map_of_list; undeclared = IntMap.empty; this_real = ThisFake; uses_this = None; @@ -1187,7 +1187,7 @@ let expression ctx request_type function_args function_type expression_tree forI close_id = retyper_ctx.closure_id; close_undeclared = new_ctx.undeclared; close_type = new_ctx.function_return_type; - close_args = func.tf_args |> List.map (fun (t, e) -> retype_tvar t, e); + close_args = func.tf_args |> List.map (fun (t, o) -> retype_func_arg t o, o); close_this = new_ctx.uses_this; } in From ae056a26aa0ad21c9af995cb6468b419508ce7c5 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 18 Jan 2026 14:15:52 +0000 Subject: [PATCH 12/12] revert back to hf hxcpp for ci --- tests/runci/targets/Cpp.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runci/targets/Cpp.hx b/tests/runci/targets/Cpp.hx index b8ec8177627..5fae7825012 100644 --- a/tests/runci/targets/Cpp.hx +++ b/tests/runci/targets/Cpp.hx @@ -27,7 +27,7 @@ class Cpp { final path = getHaxelibPath("hxcpp"); infoMsg('hxcpp has already been installed in $path.'); } catch(e:Dynamic) { - haxelibInstallGit("Aidan63", "hxcpp", "typed-functions", true); + haxelibInstallGit("HaxeFoundation", "hxcpp", true); final oldDir = Sys.getCwd(); changeDirectory(getHaxelibPath("hxcpp") + "tools/hxcpp/"); runCommand("haxe", ["-D", "source-header=''", "compile.hxml"]);