Browse Source

[cpp] Marshalling Extern Types (#11981)

* Initial class, interface, and enum separation

* fold init stuff

* Move interface header generation into its own module

* reduce some duplication

* managed interface implementation gen in its own module

* cache dependencies in the ctx

* move to gencpp with the other context data func

* remove interface code from class gen modules

* Use option for reference wildcard

* path Map

* Add back objc guard

* calculate IDs up front

* separate id lookup table

* Object IDs module to hide cache

* remap enum constructors

* more interface dead code removal

* tcpp interface type

* name, flags, and debug level in tcpp_class

* remove unused constructor var list return item

* separate out header field generation

* separate managed and native header gen functions

* move header stuff into shared function

* break class impl field gen function down

* add converted fields to tcpp_class

* Initial split for managed and native class impl

* map for haxe and native implementations

* use a list for haxe and native implementations

* use tcpp_class field variables

* field rename and meta / rtti filtering

* create fields and default functions at class transform

* use container flag

* Mark and visit using variables and fix inverted container flag

* static mark and visit use static variables list

* print reflective fields

* don't duplicate boot generation code

* don't duplicate init function generation

* don't duplicate dynamic function allocation generation

* generate properties and __Field function

* fold right member get fields

* static get fields

* shared member and static get fold functions

* static set function uses ordered fields

* member set uses organised fields

* turn abstract functions into normal functions

* cppia gen uses organised functions

* simplify ScriptNamedFunction generation

* bit of simplification of more cppia stuff

* GetFields uses organised fields

* move class retyping into retyper

* remap interface functions

* store interface hash

* store meta and rtti fields in remapped interface

* dead code removal

* tcpp interfaces only store their functions

* remapped enum fields rename for consistency

* calculate interface slots ahead of time

* remap interface arg names

* retype the interfaces stored on retyped classes

* retype tcpp_class supers

* find_class_implementation uses tcpp_class

* folds for class interface code

* other minor cleanup

* use flags in class generation to selectively generate some funcs

* retype class functions

* retype class variables

* dedicated var and dyn function boot functions

* dead code cleanup

* use bindings instead of to_list

* own implementation of of_list

* replace another to_list

* Fix pointer and struct wrapping

* fix debug level not being reset between classes

* add space after static

* remove unused variable

* ensure SourceFile paths are made absolute

* some debugging

* remove debugging prints and store class params

* don't use already mangled name when generating the getter name in reflection

* same for setters

* dont use new gc references function

* better handling of static and virtual attributes

* generate scriptable class using tcpp class function lists

* go back to type cant be null

* Container flag refers to entire inheritance tree

* allow code to easily distinguish between the different container types

* remove accidentally tracked file

* pass a context object around the retyper

* closures tracked in retyper ctx

* injection stored in retyper ctx

* declarations track by retyper ctx

* this handling moved into ctx

* gc stack handled by retyper ctx

* function return type handled by retyper ctx

* move loop goto management into retyper ctx

* consistent retyper ctx variable name

* move remaining counter into the fold

* shared string_map_of_list function

* initial value type support

* generic templates and correct return types

* Boxing of captured locals and use marshalling struct helper

* cast dynamic to a reference object

* always use a reference object instead of sometimes directly a boxed object

* cast variant to value type

* error on to value type field closures

* Use dedicated new marshal types

* Update forgotten about old cpp reference

* use _hx_vt as a prefix

* support namespace field

* omit brackets for stack constructors which have no arguments

* Fix alignment of reference declarations in closures

* default to creating boxed value types and deal with the few special cases

* some nullable support

* move auto cast into a separate file

* retype tvar to tcpp specific type

* retype tvar to simplify code and fix closure argument assignment

* promote function and lambda args if captured

* unify closure and function arg generation

* initial attempt at assigning value types a state

* some cleanup surrounding value type state assignment

* remove the two variable creation system

* implement class fields and statics

* wrap value type arguments for new non based struct value type

* cleanup of code and default values

* support enums

* treat abstract this variable as a reference and cast with a promoted type

* pointer type interop support

* ensure arrays of value types are boxed

* treat nullable value types as promoted

* default to heap construction for references

* treat extern value type fields of extern value types as refences

* avoid double :: when no namespace is specified

* another pass to catch some missing :: prefixes

* Initial enum support and comparison operator support

* correct enum casting

* handle extern value type field access and assignment correctly

* fallback to stack allocation instead of heap

* Allow creating reference state values types on the stack

* require reference semantics metadata

* Don't use the package if no namespace is provided

* add inheritance and casting tests

* support star of and dereference native functions

* Initial support for pointer types

* Add forgotten meta json change

* make sure all boxed pointer vars are allocated

* handle adding pointer stars once

* Use custom marshal pointer type for pointer references

* pointer and value specific reference cpp types

* don't retype args with dynamic

* bits of cleanup and specifying some types more

* Remove need for assignment filter, now fixed at source

* remove useless argument

* retype null promoted pointers into boxed objects

* inheritance casting with pointer types as well

* Look for include meta on extern abstracts

* don't add * to pointer type and references

* Don't use subscript operator for pointers of marshal types

* less code duplication and unwrap marshal type params

* do something for cppia

* require reference semantics on pointer types

* Don't allow constructors on pointer types

* Initial support for managed externs

* first pass of the _obj handling

* Handle static functions and variable

* Fix incorrect template handling with standard naming

* another standard naming fix

* allow static fields on extern pointers

* better static handling and helper function name consistency

* Exclude marshal types from having debug info generated

* rename marshal type enum for consistency

* add managed marshal type to cppia enum

* don't follow away marshalling enum abstracts to ensure we see meta

* More generic extern abstract following

* Add a bunch of errors

* Fix error position

* Move meta up and fill in doc comment

* try a different way of dealing with extern abstracts metadata

* actually fix include and abstract issue

* Ensure all marshal types are object returns in cppia wrapper classes

* I knew arguments were hiding in there somewhere...

* use proper marshalling state

* deal with args in the return call as well

* do same for interfaces

* forgotten bracket

* fix call dump

* rework cppia glue generation

* do similar cleanup for interfaces

* store the interface return type as a tcpp

* store interface args as retyped versions

* bloody submodules

* require value semantics instead

* Deal with generated temporaries which need to be value types

Also a quick fix for templated return types

* less string maps

* Support array access on marshaling types

* initial templated function support

* Guard against unresolved extern parameters

* reinterpreting to value types

* Fix pointer to pointer types, and add view extern

* static function template types

* Document some marshal functions

* Document marshal toString functions

* ViewExtensions convenience functions

* view compare and marshal read / write helpers

* bit of code shuffling and checking for stack only types in classes and enums

* store errors in one place

* make view stack only and use size_t for length

* Guard again promoting stack only value type in expressions

* endian specific read and write functions, plus ref to view

* view based FPHelper

* Dodge pointer vs user var fusion issue

* Change the public api to use int64 over size_t

* throw when converting big view to haxe type

* view based byte implementation

* test using hxcpp fork

* set docgen to use hxcpp fork as well

* Revert "set docgen to use hxcpp fork as well"

This reverts commit fcd3c1add5b52fe7ea562a5b98a063557447ce5c.

* Revert "test using hxcpp fork"

This reverts commit 31ecd0bf1d0c02da5f908131a07fe6bc66f94886.
Aidan Lee 1 ngày trước cách đây
mục cha
commit
33fb5c0ab3

+ 27 - 6
src-json/meta.json

@@ -1013,6 +1013,33 @@
 		"platforms": ["cpp"],
 		"targets": ["TClass"]
 	},
+	{
+		"name": "NativeArrayAccess",
+		"metadata": ":nativeArrayAccess",
+		"doc": "When used on an extern class which implements haxe.ArrayAccess native array access syntax will be generated",
+		"platforms": ["cpp"]
+	},
+	{
+		"name": "CppValueType",
+		"metadata": ":cpp.ValueType",
+		"doc": "Indicates that the externed type should be treated as a value type",
+		"platforms": ["cpp"],
+		"targets": [ "TClass", "TAbstract" ]
+	},
+	{
+		"name": "CppPointerType",
+		"metadata": ":cpp.PointerType",
+		"doc": "Indicates that the externed type should be treated as a pointer",
+		"platforms": ["cpp"],
+		"targets": [ "TClass" ]
+	},
+	{
+		"name": "CppManagedType",
+		"metadata": ":cpp.ManagedType",
+		"doc": "Indicates that the externed type is a sub class of ::hx::Object",
+		"platforms": ["cpp"],
+		"targets": ["TClass"]
+	},
 	{
 		"name": "StructInit",
 		"metadata": ":structInit",
@@ -1138,11 +1165,5 @@
 		"metadata": ":exceptionTypeCheck",
 		"doc": "Internally used for transformed exception type check wrt to `catch`.",
 		"internal": true
-	},
-	{
-		"name": "NativeArrayAccess",
-		"metadata": ":nativeArrayAccess",
-		"doc": "When used on an extern class which implements haxe.ArrayAccess native array access syntax will be generated",
-		"platforms": ["cpp"]
 	}
 ]

+ 41 - 12
src/generators/cpp/cppAst.ml

@@ -40,7 +40,17 @@ module InterfaceSlots = struct
     StringMap.find_opt name slots.hash
 end
 
-type tcpp =
+type marshal_type_state =
+  | Stack
+  | Promoted
+  | Reference
+
+and native_type = 
+  | ValueClass of tclass * tcpp list
+  | ValueEnum of tabstract
+  | Pointer of tclass * tcpp list
+
+and tcpp =
   | TCppDynamic
   | TCppUnchanged
   | TCppObject
@@ -58,6 +68,8 @@ type tcpp =
   | TCppRest of tcpp
   | TCppReference of tcpp
   | TCppStruct of tcpp
+  | TCppMarshalNativeType of native_type * marshal_type_state
+  | TCppMarshalManagedType of tclass * tcpp list
   | TCppStar of tcpp * bool
   | TCppVoidStar
   | TCppVarArg
@@ -78,12 +90,19 @@ type tcpp =
 
 and tcppexpr = { cppexpr : tcpp_expr_expr; cpptype : tcpp; cpppos : pos }
 
+and tcppvar = {
+  tcppv_type : tcpp;
+  tcppv_var : tvar;
+  tcppv_name : string;
+  tcppv_debug_name : string;
+}
+
 and tcpp_closure = {
   close_type : tcpp;
-  close_args : (tvar * texpr option) list;
+  close_args : (tcppvar * texpr option) list;
   close_expr : tcppexpr;
   close_id : int;
-  close_undeclared : tvar StringMap.t;
+  close_undeclared : tcppvar IntMap.t;
   close_this : tcppthis option;
 }
 
@@ -92,8 +111,8 @@ and tcppunop = CppNeg | CppNegBits | CppNot
 and tcppthis = ThisReal | ThisFake | ThisDynamic
 
 and tcppvarloc =
-  | VarLocal of tvar
-  | VarClosure of tvar
+  | VarLocal of tcppvar
+  | VarClosure of tcppvar
   | VarThis of tclass_field * tcpp
   | VarInstance of tcppexpr * tclass_field * string * string
   | VarInterface of tcppexpr * tclass_field
@@ -104,8 +123,8 @@ and tcppinst = InstPtr | InstObjC | InstStruct
 
 and tcppfuncloc =
   | FuncThis of tclass_field * tcpp
-  | FuncInstance of tcppexpr * tcppinst * tclass_field
-  | FuncStatic of tclass * bool * tclass_field
+  | FuncInstance of tcppexpr * tcppinst * tclass_field * tcpp list
+  | FuncStatic of tclass * bool * tclass_field * tcpp list
   | FuncTemplate of tclass * tclass_field * path * bool
   | FuncInterface of tcppexpr * tclass * tclass_field
   | FuncEnumConstruct of tenum * tenum_field
@@ -166,15 +185,15 @@ and tcpp_expr_expr =
   | CppPosition of string * int32 * string * string
   | CppArrayDecl of tcppexpr list
   | CppUnop of tcppunop * tcppexpr
-  | CppVarDecl of tvar * tcppexpr option
+  | CppVarDecl of tcppvar * tcppexpr option
   | CppBlock of tcppexpr list * tcpp_closure list * bool
-  | CppFor of tvar * tcppexpr * tcppexpr
+  | CppFor of tcppvar * tcppexpr * tcppexpr
   | CppIf of tcppexpr * tcppexpr * tcppexpr option
   | CppWhile of tcppexpr * tcppexpr * Ast.while_flag * int
   | CppIntSwitch of tcppexpr * (Int32.t list * tcppexpr) list * tcppexpr option
   | CppSwitch of
       tcppexpr * tcpp * (tcppexpr list * tcppexpr) list * tcppexpr option * int
-  | CppTry of tcppexpr * (tvar * tcppexpr) list
+  | CppTry of tcppexpr * (tcppvar * tcppexpr) list
   | CppBreak
   | CppContinue
   | CppClassOf of path * bool
@@ -211,6 +230,8 @@ and tcpp_class_function = {
   tcf_field : tclass_field;
   tcf_name : string;
   tcf_func : tfunc;
+  tcf_args : (tcppvar * texpr option) list;
+  tcf_return : tcpp;
 
   tcf_is_virtual : bool;
   tcf_is_reflective : bool;
@@ -240,6 +261,7 @@ and tcpp_class = {
   tcl_debug_level : int;
   tcl_super : tcpp_class option;
   tcl_container : tcpp_class_container option;
+  tcl_constructor : tcpp_class_function option;
 
   tcl_haxe_interfaces : tcpp_interface list;
   tcl_native_interfaces : tcpp_interface list;
@@ -262,8 +284,8 @@ and tcpp_class = {
 and tcpp_interface_function = {
   iff_field : tclass_field;
   iff_name : string;
-  iff_args : (string * bool * t) list;
-  iff_return : t;
+  iff_args : tcpp_tfun_arg list;
+  iff_return : tcpp;
   iff_script_slot : int option;
 }
 
@@ -280,9 +302,16 @@ and tcpp_interface = {
   if_scriptable : bool;
 }
 
+and tcpp_tfun_arg = {
+  tfa_name : string;
+  tfa_type : tcpp;
+  tfa_optional : bool;
+}
+
 and tcpp_enum_field = {
   tef_field : tenum_field;
   tef_name : string;
+  tef_args : tcpp_tfun_arg list option;
   tef_hash : string;
 }
 

+ 164 - 13
src/generators/cpp/cppAstTools.ml

@@ -1,13 +1,18 @@
 open Ast
 open Type
 open Globals
+open Error
 open CppAst
 open CppTypeUtils
+open CppMarshalling
+open CppError
 
 let follow = Abstract.follow_with_abstracts
 
 let string_map_of_list bs = List.fold_left (fun m (k, v) -> StringMap.add k v m) StringMap.empty bs
 
+let int_map_of_list bs = List.fold_left (fun m (k, v) -> IntMap.add k v m) IntMap.empty bs
+
 (*
    A class_path is made from a package (array of strings) and a class name.
    Join these together, inclding a separator.  eg, "/" for includes : pack1/pack2/Name or "::"
@@ -249,6 +254,16 @@ let keyword_remap name =
       "_hx_" ^ name
     | x -> x
 
+let cpp_var_name_of var =
+   match get_meta_string var.v_meta Meta.Native with
+   | Some n -> n
+   | None -> keyword_remap var.v_name
+
+let cpp_var_debug_name_of v =
+   match get_meta_string v.v_meta Meta.RealPath with
+   | Some n -> n
+   | None -> v.v_name
+
 let remap_class_path class_path =
   let path_remap with_keywords name =
     let len = String.length name in
@@ -293,14 +308,14 @@ let rec s_tcpp = function
   | CppEnumField _ -> "CppEnumField"
   | CppNullAccess -> "CppNullAccess"
   | CppCall (FuncThis _, _) -> "CppCallThis"
-  | CppCall (FuncInstance (obj, inst, field), _) ->
+  | CppCall (FuncInstance (obj, inst, field, _), _) ->
       (match inst with
       | InstObjC -> "CppCallObjCInstance("
       | InstPtr -> "CppCallInstance("
       | _ -> "CppCallStruct(")
       ^ tcpp_to_string obj.cpptype ^ "," ^ field.cf_name ^ ")"
   | CppCall (FuncInterface _, _) -> "CppCallInterface"
-  | CppCall (FuncStatic (_, objC, _), _) ->
+  | CppCall (FuncStatic (_, objC, _, _), _) ->
       if objC then "CppCallStaticObjC" else "CppCallStatic"
   | CppCall (FuncTemplate _, _) -> "CppCallTemplate"
   | CppCall (FuncEnumConstruct _, _) -> "CppCallEnumConstruct"
@@ -357,8 +372,12 @@ and tcpp_to_string_suffix suffix tcpp =
   | TCppUnchanged -> " ::Dynamic/*Unchanged*/"
   | TCppObject -> " ::Dynamic"
   | TCppObjectPtr -> " ::hx::Object *"
-  | TCppReference t -> tcpp_to_string t ^ " &"
   | TCppStruct t -> "cpp::Struct< " ^ tcpp_to_string t ^ " >"
+  | TCppReference (TCppMarshalNativeType (value_type, _)) -> Printf.sprintf "%s&" (get_native_marshalled_type value_type)
+  | TCppReference t -> tcpp_to_string t ^ " &"
+  | TCppStar (TCppMarshalNativeType (value_type, _), const) ->
+    let suffix = match value_type with Pointer _ -> "*" | _ -> "" in
+    Printf.sprintf "%s%s*%s" (if const then "const " else "") (get_native_marshalled_type value_type) suffix
   | TCppStar (t, const) ->
       (if const then "const " else "") ^ tcpp_to_string t ^ " *"
   | TCppVoid -> "void"
@@ -372,8 +391,14 @@ and tcpp_to_string_suffix suffix tcpp =
   | TCppString -> "::String"
   | TCppFastIterator it ->
       "::cpp::FastIterator" ^ suffix ^ "< " ^ tcpp_to_string it ^ " >"
+  | TCppPointer (ptrType, TCppMarshalNativeType (value_type, _)) ->
+    let suffix = match value_type with Pointer _ -> "*" | _ -> "" in
+    Printf.sprintf "::cpp::%s< %s%s >" ptrType (get_native_marshalled_type value_type) suffix
   | TCppPointer (ptrType, valueType) ->
       "::cpp::" ^ ptrType ^ "< " ^ tcpp_to_string valueType ^ " >"
+  | TCppRawPointer (constName, TCppMarshalNativeType (value_type, _)) ->
+    let suffix = match value_type with Pointer _ -> "*" | _ -> "" in
+    Printf.sprintf "%s%s*%s" constName (get_native_marshalled_type value_type) suffix
   | TCppRawPointer (constName, valueType) ->
       constName ^ tcpp_to_string valueType ^ "*"
   | TCppFunction (argTypes, retType, abi) ->
@@ -411,6 +436,121 @@ and tcpp_to_string_suffix suffix tcpp =
   | TCppNull -> " ::Dynamic"
   | TCppCode _ -> "Code"
 
+  | TCppMarshalManagedType (cls, params) ->
+    let type_str, flags = build_type cls.cl_path cls.cl_pos params cls.cl_meta Meta.CppManagedType tcpp_to_string in
+    let standard_naming = List.exists (fun f -> f = "StandardNaming") flags in
+    let wrapped  =
+      if suffix = "_obj" then
+        if standard_naming then
+          type_str ^ suffix
+        else
+          type_str
+      else
+        if standard_naming then
+          type_str
+        else
+          Printf.sprintf "::hx::ObjectPtr< %s >" type_str
+      in
+    wrapped
+
+  | TCppMarshalNativeType (Pointer _ as value_type, Promoted) ->
+    get_native_marshalled_type value_type |> Printf.sprintf "::cpp::marshal::Boxed< %s* >"
+  | TCppMarshalNativeType (Pointer _ as value_type, Reference) ->
+    get_native_marshalled_type value_type |> Printf.sprintf "::cpp::marshal::PointerReference< %s >"
+  | TCppMarshalNativeType (Pointer _ as value_type, Stack) ->
+    get_native_marshalled_type value_type |> Printf.sprintf "::cpp::marshal::PointerType< %s >"
+
+  | TCppMarshalNativeType ((ValueClass _ | ValueEnum _) as value_type, Promoted) ->
+    get_native_marshalled_type value_type |> Printf.sprintf "::cpp::marshal::Boxed< %s >"
+  | TCppMarshalNativeType ((ValueClass _ | ValueEnum _) as value_type, Reference) ->
+    get_native_marshalled_type value_type |> Printf.sprintf "::cpp::marshal::ValueReference< %s >"
+  | TCppMarshalNativeType ((ValueClass _ | ValueEnum _) as value_type, Stack) ->
+    get_native_marshalled_type value_type |> Printf.sprintf "::cpp::marshal::ValueType< %s >"
+
+and build_type path pos params meta target parameter_handler =
+  let get_meta_field field =
+    match Meta.get target meta with
+    | _, [ (EObjectDecl decls, _) ], _ ->  
+      List.find_opt (fun ((n, _, _), _) -> n = field) decls
+    | _ ->
+      None
+  in
+  let typeParams =
+    match params with
+    | [] -> ""
+    | _ -> "< " ^ String.concat "," (List.map parameter_handler params) ^ " >"
+  in
+  let namespace_error pos =
+    cpp_abort InvalidNamespaceField pos
+  in
+  let flag_error pos =
+    cpp_abort InvalidFlagsField pos
+  in
+  let namespace =
+    match get_meta_field "namespace" with
+    | Some (_,( EArrayDecl ([]), _)) -> ""
+    | Some (_,( EArrayDecl (els), _)) ->
+      "::" ^ (els
+      |> List.filter_map (fun (e, pos) -> match e with | EConst (String (s, _)) -> Some s | _ -> namespace_error pos)
+      |> String.concat "::")
+    | Some ((_, pos, _), _) ->
+      namespace_error pos
+    | _ ->
+      ""
+  in
+  let t = match get_meta_field "type" with
+  | Some (_, (EConst (String (s, _)), _) ) ->
+    s ^ typeParams
+  | Some ((_, pos, _), _) ->
+    cpp_abort InvalidTypeField pos
+  | _ ->
+    snd path ^ typeParams
+  in
+  let flags = match get_meta_field "flags" with
+  | Some (_, (EArrayDecl decls, _) ) ->
+    decls |> List.filter_map (fun (e, pos) -> match e with | EConst (Ident c) -> Some c | _ -> flag_error pos)
+  | Some ((_, pos, _), _) ->
+    flag_error pos
+  | _ ->
+    []
+  in
+  
+  Printf.sprintf "%s::%s" namespace t, flags
+
+and get_extern_value_type_boxed value_type =
+  let p = get_native_marshalled_type value_type in
+  let suffix =
+    match value_type with
+    | Pointer _ -> "*"
+    | _ -> ""
+  in
+
+  Printf.sprintf "::cpp::marshal::Boxed< %s%s >" p suffix, Printf.sprintf "::cpp::marshal::Boxed_obj< %s%s >" p suffix
+
+and get_native_marshalled_type value_type =
+  let marshal_type_parameter_to_string pos tcpp =
+    match tcpp with
+    | TCppMarshalNativeType ((Pointer _) as value_type, _) -> get_native_marshalled_type value_type ^ "*"
+    | TCppMarshalNativeType (value_type, _) -> get_native_marshalled_type value_type
+    | TCppScalar _
+    | TCppPointer _
+    | TCppRawPointer _
+    | TCppStar _
+    | TCppVoidStar
+    | TCppStruct _ ->
+      tcpp_to_string_suffix "" tcpp
+    | _ ->
+      cpp_abort InvalidMarshallingTypeParameter pos
+  in
+
+  match value_type with
+  | ValueClass (cls, params) ->
+    build_type cls.cl_path cls.cl_pos params cls.cl_meta Meta.CppValueType (marshal_type_parameter_to_string cls.cl_pos) |> fst
+  | ValueEnum abs ->
+    build_type abs.a_path abs.a_pos [] abs.a_meta Meta.CppValueType (marshal_type_parameter_to_string abs.a_pos) |> fst
+  | Pointer (cls, params) ->
+    build_type cls.cl_path cls.cl_pos params cls.cl_meta Meta.CppPointerType (marshal_type_parameter_to_string cls.cl_pos) |> fst
+
 and tcpp_objc_block_struct argTypes retType =
   let args = String.concat "," (List.map tcpp_to_string argTypes) in
   let ret = tcpp_to_string retType in
@@ -424,15 +564,18 @@ and tcpp_objc_block_struct argTypes retType =
 and tcpp_to_string tcpp = tcpp_to_string_suffix "" tcpp
 
 and cpp_class_path_of klass params =
-  match get_meta_string klass.cl_meta Meta.Native with
-  | Some s ->
-      let typeParams =
-        match params with
-        | [] -> ""
-        | _ -> "< " ^ String.concat "," (List.map tcpp_to_string params) ^ " >"
-      in
-      " " ^ join_class_path_remap klass.cl_path "::" ^ typeParams
-  | None -> " ::" ^ join_class_path_remap klass.cl_path "::"
+   if is_marshalling_native_value_class klass then
+    get_native_marshalled_type (ValueClass (klass, params))
+   else
+      match get_meta_string klass.cl_meta Meta.Native with
+      | Some s ->
+         let typeParams =
+            match params with
+            | [] -> ""
+            | _ -> "< " ^ String.concat "," (List.map tcpp_to_string params) ^ " >"
+            in
+         " " ^ join_class_path_remap klass.cl_path "::" ^ typeParams
+      | None -> " ::" ^ join_class_path_remap klass.cl_path "::"
 
 (*  Get a string to represent a type.
    The "suffix" will be nothing or "_obj", depending if we want the name of the
@@ -636,11 +779,13 @@ let rec cpp_is_struct_access t =
    | TCppFunction _ -> true
    | TCppStruct _-> false
    | TCppInst (class_def, _) -> Meta.has Meta.StructAccess class_def.cl_meta
+   | TCppReference (TCppMarshalNativeType _) -> true
    | TCppReference (r) -> cpp_is_struct_access r
    | _ -> false
 
 let rec cpp_is_native_array_access t =
    match t with
+   | TCppMarshalNativeType _ -> true
    | TCppStruct s -> cpp_is_native_array_access s
    | TCppReference s -> cpp_is_native_array_access s
    | TCppInst ({ cl_array_access = Some _ } as klass, _) when is_extern_class klass && Meta.has Meta.NativeArrayAccess klass.cl_meta -> true
@@ -654,6 +799,9 @@ let cpp_is_dynamic_type = function
 
 let is_object_element member_type =
   match member_type with
+   | TCppMarshalManagedType _
+   | TCppMarshalNativeType (_, Promoted) ->
+      true
    | TCppInst (x, _)
    | TCppInterface x
        -> not (is_extern_class x)
@@ -678,6 +826,8 @@ let cpp_variant_type_of t = match t with
   | TCppObjectPtr
   | TCppReference _
   | TCppStruct _
+  | TCppMarshalNativeType _
+  | TCppMarshalManagedType _
   | TCppStar _
   | TCppVoid
   | TCppFastIterator _
@@ -719,7 +869,8 @@ let cpp_cast_variant_type_of t = match t with
   | TCppDynamicArray
   | TCppClass
   | TCppEnum _
-  | TCppInst _ -> t
+  | TCppInst _
+  | TCppMarshalManagedType _ -> t
   | _ -> cpp_variant_type_of t
 
 let enum_getter_type t =

+ 35 - 0
src/generators/cpp/cppError.ml

@@ -0,0 +1,35 @@
+open Error
+
+type cppError =
+    | InternalError
+    | MissingValueSemantics
+    | NativeMarshallingFunctionClosures
+    | InvalidMarshallingTypeParameter
+    | PointerTypeConstructor
+    | ValueTypeUndefined
+    | InvalidNamespaceField
+    | InvalidTypeField
+    | InvalidFlagsField
+    | ExtendingManagedType
+    | UnresolvedTypeParameter of string
+    | PromotedStackOnlyValueType
+
+let cpp_abort error pos =
+    let print = Printf.sprintf "CPP%0*i: %s" 4 in
+    let str =
+        match error with
+        | InternalError -> print 0 "Internal compiler error"
+        | MissingValueSemantics -> print 1 "Marshalling type extern must be annotated with value semantics"
+        | NativeMarshallingFunctionClosures -> print 2 "Native marshalling types cannot have function closures created for them"
+        | InvalidMarshallingTypeParameter -> print 3 "Invalid parameter for a marshalling type"
+        | PointerTypeConstructor -> print 4 "Pointer type cannot have a constructor"
+        | ValueTypeUndefined -> print 5 "Marshalling value type extern cannot be used for a variable declaration with no expression"
+        | InvalidNamespaceField -> print 6 "Namespace field must be an array declaration of string literals"
+        | InvalidTypeField -> print 7 "Type field must be a string literal"
+        | InvalidFlagsField -> print 8 "Flags field must be an array of identifiers"
+        | ExtendingManagedType -> print 9 "Class cannot extend a managed type extern"
+        | UnresolvedTypeParameter s -> print 10 (Printf.sprintf "Unable to resolve parameter %s, consider adding a type hint" s)
+        | PromotedStackOnlyValueType -> print 11 "Marshalling value type with the StackOnly flag cannot be promoted to the heap"
+    in
+
+    abort str pos

+ 47 - 0
src/generators/cpp/cppMarshalling.ml

@@ -0,0 +1,47 @@
+open Type
+open Ast
+open CppError
+
+let is_marshalling_managed_class cls =
+  has_class_flag cls CExtern && has_meta Meta.CppManagedType cls.cl_meta
+
+let is_marshalling_native_enum a =
+  a.a_enum && a.a_extern && has_meta Meta.CppValueType a.a_meta
+
+let is_marshalling_native_value_class cls =
+  has_class_flag cls CExtern && has_meta Meta.CppValueType cls.cl_meta
+
+let is_stack_only_marshalling_native_value_class cls =
+  if is_marshalling_native_value_class cls then
+    let get_meta_field field =
+      match Meta.get Meta.CppValueType cls.cl_meta with
+      | _, [ (EObjectDecl decls, _) ], _ ->  
+        List.find_opt (fun ((n, _, _), _) -> n = field) decls
+      | _ ->
+        None
+    in
+    let flag_error pos =
+      cpp_abort InvalidFlagsField pos
+    in
+    let flags =
+      match get_meta_field "flags" with
+      | Some (_, (EArrayDecl decls, _) ) ->
+        decls |> List.filter_map (fun (e, pos) -> match e with | EConst (Ident c) -> Some c | _ -> flag_error pos)
+      | Some ((_, pos, _), _) ->
+        flag_error pos
+      | _ ->
+        []
+      in
+    List.exists (fun v -> v = "StackOnly") flags
+  else
+    false
+
+let is_marshalling_native_pointer cls =
+  has_class_flag cls CExtern && has_meta Meta.CppPointerType cls.cl_meta
+
+let is_marshalling_native_value_class_tvar tvar =
+  match follow tvar.v_type with
+  | TInst (cls, _) ->
+   is_marshalling_native_value_class cls
+  | _ ->
+    false

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 412 - 171
src/generators/cpp/cppRetyper.ml


+ 22 - 1
src/generators/cpp/cppTypeUtils.ml

@@ -2,6 +2,7 @@
 (* functions in here operate on standard haxe ast types, not gencpp ast types *)
 
 open Type
+open CppMarshalling
 
 let follow = Abstract.follow_with_abstracts
 
@@ -50,6 +51,7 @@ let is_internal_class = function
    | [ "cpp" ], "Int8"
    | [ "cpp" ], "UInt8"
    | [ "cpp" ], "Char"
+   | [ "cpp" ], "Char16"
    | [ "cpp" ], "Int16"
    | [ "cpp" ], "UInt16"
    | [ "cpp" ], "Int32"
@@ -63,7 +65,25 @@ let is_internal_class = function
       false
 
 let is_native_class class_def =
-   (is_extern_class class_def || is_native_gen_class class_def) && not (is_internal_class class_def.cl_path)
+   (is_extern_class class_def || is_native_gen_class class_def) && not (is_internal_class class_def.cl_path) && not (is_marshalling_native_value_class class_def)
+
+let can_quick_alloc klass =
+   let rec implements_native_interface class_def =
+      List.exists
+        (fun (intf_def, _) -> is_native_gen_class intf_def || implements_native_interface intf_def) class_def.cl_implements ||
+      match class_def.cl_super with
+      | Some (i, _) -> implements_native_interface i
+      | _ -> false
+   in
+
+  (not (is_native_class klass)) && not (implements_native_interface klass) && not (is_marshalling_managed_class klass)
+
+let real_interfaces classes =
+   List.filter (function t, pl ->
+      (match (t, pl) with
+      | { cl_path = [ "cpp"; "rtti" ], _ }, [] -> false
+      | _ -> true))
+   classes
 
 let can_quick_alloc klass =
    let rec implements_native_interface class_def =
@@ -134,6 +154,7 @@ let is_numeric t =
    | TAbstract({ a_path = ([], "Float") }, [])
    | TAbstract({ a_path = ([], "Single") }, [])
    | TAbstract({ a_path = (["cpp"], "Char") }, [])
+   | TAbstract({ a_path = (["cpp"], "Char16") }, [])
    | TAbstract({ a_path = (["cpp"], "Float32") }, [])
    | TAbstract({ a_path = (["cpp"], "Float64") }, [])
    | TAbstract({ a_path = (["cpp"], "Int8") }, [])

+ 199 - 0
src/generators/cpp/filters/cppFilterAutoCast.ml

@@ -0,0 +1,199 @@
+open Type
+open CppTypeUtils
+open CppAst
+open CppAstTools
+open CppError
+
+let autocast_filter for_cppia return_type cppexpr =
+  let object_expression =
+    match cppexpr.cpptype with
+    | TCppVariant
+    | TCppDynamic
+    | TCppObject -> true
+    | _ -> false
+  in
+
+  let mk_cppexpr new_expr new_type =
+    { cppexpr = new_expr; cpptype = new_type; cpppos = cppexpr.cpppos }
+  in
+
+  let cast_to_var_args () =
+    match cpp_variant_type_of cppexpr.cpptype with
+    | TCppVoidStar
+    | TCppScalar _ ->
+      cppexpr
+    | TCppString ->
+      mk_cppexpr
+        (CppVar (VarInternal (cppexpr, ".", "raw_ptr()") ))
+        (TCppPointer ("ConstPointer", TCppScalar "char"))
+    | TCppDynamic ->
+      mk_cppexpr (CppCastNative cppexpr) TCppVoidStar
+    | _ ->
+      let to_dynamic = mk_cppexpr (CppCast (cppexpr, TCppDynamic)) TCppDynamic in
+      mk_cppexpr (CppCastNative to_dynamic) TCppVoidStar
+  in
+
+  let cast_from_object () =
+    match return_type with
+    | TCppUnchanged ->
+      cppexpr
+    | TCppInst (t, _) as inst when Meta.has Meta.StructAccess t.cl_meta ->
+      let struct_type = TCppStruct inst in
+      let struct_cast =
+        mk_cppexpr (CppCast (cppexpr, struct_type)) struct_type
+      in
+      mk_cppexpr (CppCast (struct_cast, inst)) inst
+    | TCppObjectArray _
+    | TCppScalarArray _
+    | TCppNativePointer _
+    | TCppDynamicArray
+    | TCppObjectPtr
+    | TCppVarArg
+    | TCppMarshalManagedType _
+    | TCppInst _ ->
+      mk_cppexpr (CppCast (cppexpr, return_type)) return_type
+    | TCppObjC k ->
+      mk_cppexpr (CppCastObjC (cppexpr, k)) return_type
+    | TCppObjCBlock (ret, args) ->
+      mk_cppexpr (CppCastObjCBlock (cppexpr, ret, args)) return_type
+    | TCppScalar scalar ->
+      mk_cppexpr (CppCastScalar (cppexpr, scalar)) return_type
+    | TCppString ->
+      mk_cppexpr (CppCastScalar (cppexpr, "::String")) return_type
+    | TCppInterface _ when cppexpr.cpptype = TCppVariant ->
+      mk_cppexpr (CppCastVariant cppexpr) return_type
+    | TCppDynamic when cppexpr.cpptype = TCppVariant ->
+      mk_cppexpr (CppCastVariant cppexpr) 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
+      mk_cppexpr (CppCast (ptr_cast, ptr)) ptr
+    (* When going from a dynamic or variant add an explicit cast so the ::cpp::marshal::Reference constructor
+     * takes care of checking the dynamic type *)
+    | TCppMarshalNativeType (_, _) ->
+      mk_cppexpr (CppCast (cppexpr, return_type)) return_type
+    | _ ->
+      cppexpr
+  in
+
+  let cast_other () =
+    match (cppexpr.cpptype, return_type) with
+    | _, TCppUnchanged ->
+      cppexpr
+    (*
+      Using the 'typedef hack', where we use typedef X<T> = T, allows the
+      haxe compiler to use these types interchangeably. We then work
+      out the correct way to convert between them when one is expected, but another provided.
+
+      TCppFunction: these do not really interact with the haxe function type, T
+      Since they are implemented with cpp::Function, conversion to/from Dynamic should happen automatically
+        CallableData<T> = T;
+        FunctionData<T,ABI> = T;
+
+      TCppObjCBlock can move in and out of Dyanmic
+        ObjcBlock<T> = T;
+
+      TCppProtocol can move in and out of Dyanmic, via delegate creation
+        Protocol<T /*:interface*/ > = T;
+
+      Explicitly wrapped type - already interacts well with Dynamic and T
+        Struct<T> = T;
+
+      TCppStar, TCppStruct, TCppReference - for interacting with native code
+        Star<T> = T;
+        ConstStar<T> = T;
+        Reference<T> = T;
+        T may be an extern class, with @:structAccess - in which case
+          Dynamic interaction must be handled explicitly
+      These types, plus Dynamic can be used interchangeably by haxe
+      Derived/inherited types may also be mixed in
+    *)
+    | TCppAutoCast, _
+    | TCppObjC _, TCppDynamic
+    | TCppObjCBlock _, TCppDynamic ->
+      mk_cppexpr (CppCast (cppexpr, return_type)) return_type
+    (* Infer type from right-hand-side for pointer or reference to Dynamic *)
+    | TCppReference TCppDynamic, TCppReference _ ->
+      cppexpr
+    | TCppReference TCppDynamic, t ->
+      mk_cppexpr cppexpr.cppexpr (TCppReference t)
+    | TCppStar (TCppDynamic, _), TCppStar (_, _) ->
+      cppexpr
+    | TCppStar (TCppDynamic, const), t ->
+      mk_cppexpr cppexpr.cppexpr (TCppStar (t, const))
+    | TCppStar (t, const), TCppDynamic ->
+      let ptr_type = TCppPointer ((if const then "ConstPointer" else "Pointer"), t) in
+      let ptr_cast = mk_cppexpr (CppCast (cppexpr, ptr_type)) ptr_type in
+      mk_cppexpr (CppCast (ptr_cast, TCppDynamic)) TCppDynamic
+    | TCppStar (t, const), TCppReference _
+    | TCppStar (t, const), TCppInst _
+    | TCppStar (t, const), TCppMarshalManagedType _
+    | TCppStar (t, const), TCppStruct _ ->
+      mk_cppexpr (CppDereference cppexpr) return_type
+    | TCppInst (t, _), TCppStar _ when is_native_class t && match cppexpr.cppexpr with | CppCall (FuncNew _, _) -> true | _ -> false ->
+      mk_cppexpr (CppNewNative cppexpr) return_type
+    | TCppInst _, TCppStar (p, const)
+    | TCppMarshalManagedType _, TCppStar (p, const)
+    | TCppStruct _, TCppStar (p, const) ->
+      mk_cppexpr (CppAddressOf cppexpr) return_type
+    | TCppObjectPtr, TCppObjectPtr ->
+      cppexpr
+    | TCppObjectPtr, _ ->
+      mk_cppexpr (CppCast (cppexpr, TCppDynamic)) TCppDynamic
+    | TCppProtocol _, TCppProtocol _ ->
+      cppexpr
+    | t, TCppProtocol protocol ->
+      mk_cppexpr (CppCastProtocol (cppexpr, protocol)) return_type
+    | TCppInst (t, _) as inst, TCppDynamic when Meta.has Meta.StructAccess t.cl_meta ->
+      let struct_type = TCppStruct inst in
+      let struct_cast = mk_cppexpr (CppCast (cppexpr, struct_type)) struct_type in
+      mk_cppexpr (CppCast (struct_cast, TCppDynamic)) TCppDynamic
+    | _, TCppObjectPtr ->
+      mk_cppexpr (CppCast (cppexpr, TCppObjectPtr)) TCppObjectPtr
+    | TCppDynamicArray, TCppScalarArray _
+    | TCppDynamicArray, TCppObjectArray _
+    | TCppScalarArray _, TCppDynamicArray
+    | TCppObjectArray _, TCppDynamicArray when for_cppia ->
+      mk_cppexpr (CppCast (cppexpr, return_type)) return_type
+    | TCppScalar from, TCppScalar too when from <> too ->
+      mk_cppexpr (CppCastScalar (cppexpr, too)) return_type
+
+    (* If we are going between two pointers or value type classes which mismatch add a cast so the reference type reinterprets the pointer *)
+    (* This happens in inheritance related situations *)
+    | TCppMarshalNativeType ((ValueClass (fst_cls, fst_params) | Pointer (fst_cls, fst_params)), _), TCppMarshalNativeType ((ValueClass (snd_cls, snd_params) | Pointer (snd_cls, snd_params)) as dst, _) when not (fast_eq (TInst (fst_cls, [])) (TInst (snd_cls, []))) ->
+      let reference = TCppMarshalNativeType(dst, Reference) in
+      mk_cppexpr (CppCast (cppexpr, reference)) reference
+
+    (* Ensure we wrap any access to the stack or promoted type in a reference object. *)
+    (* TIdents are wrapped at retyping but array access and others won't be, so this will wrap them. *)
+    | TCppMarshalNativeType (ValueClass (cls, _), (Stack | Reference)), other when CppMarshalling.is_stack_only_marshalling_native_value_class cls && is_object_element other ->
+      cpp_abort PromotedStackOnlyValueType cppexpr.cpppos
+    | TCppMarshalNativeType (value_type, Stack), (TCppPointer _)
+    | TCppMarshalNativeType (value_type, Stack), (TCppRawPointer _)
+    | TCppMarshalNativeType (value_type, Stack), (TCppStar _)
+    | TCppMarshalNativeType (value_type, Stack), (TCppReference _)
+    | TCppMarshalNativeType (_, Stack), TCppMarshalNativeType (value_type, (Promoted)) ->
+      let reference = TCppMarshalNativeType(value_type, Reference) in
+      mk_cppexpr (CppCast (cppexpr, reference)) reference
+    | TCppMarshalNativeType (value_type, Promoted), (TCppPointer _)
+    | TCppMarshalNativeType (value_type, Promoted), (TCppRawPointer _)
+    | TCppMarshalNativeType (value_type, Promoted), (TCppStar _)
+    | TCppMarshalNativeType (value_type, Promoted), (TCppReference _)
+    | 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) ->
+      let reference = TCppMarshalNativeType(value_type, Reference) in
+      mk_cppexpr (CppCast (cppexpr, reference)) reference
+    | _ -> cppexpr
+  in
+
+  match return_type with
+  | TCppVoid ->
+    mk_cppexpr cppexpr.cppexpr TCppVoid
+  | TCppVarArg ->
+    cast_to_var_args ()
+  | _ when object_expression ->
+    cast_from_object ()
+  | _ ->
+    cast_other ()

+ 74 - 0
src/generators/cpp/filters/cppFilterValueType.ml

@@ -0,0 +1,74 @@
+open CppAst
+open CppAstTools
+
+(* If we are constructing a value type of reference state, inspect the surrounding context and choose a more appropriate construction *)
+let filter_determine_construction return_type cppexpr =
+  let mk_cppexpr new_expr new_type =
+    { cppexpr = new_expr; cpptype = new_type; cpppos = cppexpr.cpppos }
+  in
+
+  match cppexpr.cpptype, return_type, cppexpr.cppexpr with
+  | TCppMarshalNativeType (value_type, Reference), TCppMarshalNativeType (_, Stack), CppCall ((FuncNew _), args) ->
+    let stack = TCppMarshalNativeType (value_type, Stack) in
+    { cppexpr with cpptype = stack; cppexpr = CppCall ((FuncNew stack), args) }
+  | TCppMarshalNativeType (value_type, Reference), TCppMarshalNativeType (_, Promoted), CppCall ((FuncNew _), args) ->
+    let promoted = TCppMarshalNativeType (value_type, Promoted) in
+    { cppexpr with cpptype = promoted; cppexpr = CppCall ((FuncNew promoted), args) }
+  (* When constructing to a reference we lack enough info to make a more precise choice *)
+  (* So just allocate on the stack and wrap in a reference *)
+  (* This comes up with function calls e.g. foo(new MyValueType()) *)
+  (* TFun does not give us enough info to make a more precise allocation *)
+  | TCppMarshalNativeType (value_type, Reference), _, CppCall ((FuncNew _), args) ->
+    let stack     = TCppMarshalNativeType(value_type, Stack) in
+    let reference = TCppMarshalNativeType(value_type, Reference) in
+    mk_cppexpr (CppCast ({ cppexpr with cpptype = stack; cppexpr = CppCall ((FuncNew stack), args) }, reference)) reference
+  | _ ->
+    cppexpr
+
+(* Handle casting to and from value type enums and scalar values *)
+let rec filter_value_enum_casting return_type cppexpr =
+  let mk_cppexpr new_expr new_type =
+    { cppexpr = new_expr; cpptype = new_type; cpppos = cppexpr.cpppos }
+  in
+
+  match cppexpr.cpptype, return_type with
+  (* Casting from from a scalar to a value type enum *)
+  | TCppScalar s, (TCppMarshalNativeType ((ValueEnum abs), (Stack | Promoted))) ->
+    let casted = mk_cppexpr (CppCastScalar (cppexpr, get_native_marshalled_type (ValueEnum abs))) return_type in
+    mk_cppexpr (CppCall ((FuncNew return_type), [ casted ])) return_type
+
+  | TCppScalar s, (TCppMarshalNativeType ((ValueEnum _ as e), Reference)) ->
+    let promoted = filter_value_enum_casting (TCppMarshalNativeType (e, Promoted)) cppexpr in
+    mk_cppexpr (CppCast (promoted, return_type)) return_type
+
+  (* Casting going from a value type enum to a scalar *)
+  | TCppMarshalNativeType ((ValueEnum _ as e), (Stack | Promoted)), TCppScalar s ->
+    let reference = TCppMarshalNativeType(e, Reference) in
+    let casted = mk_cppexpr (CppCast (cppexpr, reference)) reference in
+    filter_value_enum_casting return_type casted
+  | TCppMarshalNativeType ((ValueEnum _), Reference), TCppScalar s ->
+    let dereference = mk_cppexpr (CppDereference (cppexpr)) cppexpr.cpptype in
+    mk_cppexpr (CppCastScalar (dereference, s)) return_type
+  | _ ->
+    cppexpr
+
+let filter_add_boxed_pointer_construction return_type cppexpr =
+  let mk_cppexpr new_expr new_type =
+    { cppexpr = new_expr; cpptype = new_type; cpppos = cppexpr.cpppos }
+  in
+
+  match return_type, cppexpr.cppexpr with
+  (* | CppVarDecl (var, Some expr) when is_pointer_type var.tcppv_type ->
+    let construct = mk_cppexpr (CppCall ((FuncNew var.tcppv_type), [ expr ])) var.tcppv_type in
+    { cppexpr with cppexpr = CppVarDecl(var, Some construct) }
+  | CppVarDecl (var, None) when is_pointer_type var.tcppv_type ->
+    let construct = mk_cppexpr (CppCall ((FuncNew var.tcppv_type), [])) var.tcppv_type in
+    { cppexpr with cppexpr = CppVarDecl(var, Some construct) } *)
+  | TCppMarshalNativeType ((Pointer _), (Stack | Promoted)), CppNull ->
+    mk_cppexpr (CppCall ((FuncNew return_type), [ cppexpr ])) return_type
+  | TCppMarshalNativeType ((Pointer _ as value_type), Reference), CppNull ->
+    let stack = TCppMarshalNativeType (value_type, Stack) in
+    let ctor  = mk_cppexpr (CppCall ((FuncNew stack), [ cppexpr ])) stack in
+    mk_cppexpr (CppCast (ctor, return_type)) return_type
+  | _ ->
+    cppexpr

+ 76 - 52
src/generators/cpp/gen/cppCppia.ml

@@ -7,37 +7,56 @@ open CppAst
 open CppAstTools
 open CppContext
 
-let cpp_type_of = CppRetyper.cpp_type_of
-
-let script_type t optional = if optional then begin
-  match type_string t with
-  | "::String" -> "String"
-  | _ -> "Object"
-  end else match type_string t with
-  | "bool" -> "Int"
-  | "int" | "::cpp::Int32" -> "Int"
-  | "Float" -> "Float"
-  | "::String" -> "String"
-  | "Null" -> "Void"
-  | "Void" -> "Void"
-  | "float" | "::cpp::Float32" | "::cpp::Float64" -> "Float"
-  | "::cpp::Int64" | "::cpp::UInt64" -> "Object"
-  | _ -> "Object"
-
-let script_signature t optional = match script_type t optional with
-  | "Bool" -> "b"
-  | "Int" -> "i"
-  | "Float" -> "f"
-  | "String" -> "s"
-  | "Void" -> "v"
-  | "void" -> "v"
-  | _ -> "o"
-
-let script_size_type t optional = match script_type t optional with
-  | "Object" -> "void *"
-  | "Int" -> "int"
-  | "Bool" -> "bool"
-  | x -> x
+type script_type = 
+  | ScriptBool
+  | ScriptInt
+  | ScriptFloat
+  | ScriptString
+  | ScriptObject
+  | ScriptVoid
+
+let cpp_type_of = CppRetyper.cpp_type_of CppRetyper.with_reference_value_type
+
+let to_script_type tcpp =
+  match tcpp with
+  | TCppScalar "bool" -> ScriptBool
+  | TCppScalar "int"
+  | TCppScalar "::cpp::Int32" -> ScriptInt
+  | TCppScalar "float"
+  | TCppScalar "double"
+  | TCppScalar "Float"
+  | TCppScalar "::cpp::Float32"
+  | TCppScalar "::cpp::Float64" -> ScriptFloat
+  | TCppString -> ScriptString
+  | TCppVoid -> ScriptVoid
+  | _ -> ScriptObject
+
+let to_script_type_signature script_type =
+  match script_type with
+  | ScriptBool -> "b"
+  | ScriptInt -> "i"
+  | ScriptFloat -> "f"
+  | ScriptString -> "s"
+  | ScriptVoid -> "v"
+  | ScriptObject -> "o"
+
+let to_script_type_string script_type =
+  match script_type with
+  | ScriptBool
+  | ScriptInt -> "Int"
+  | ScriptFloat -> "Float"
+  | ScriptString -> "String"
+  | ScriptVoid -> "Void"
+  | ScriptObject -> "Object"
+
+let to_script_type_size script_type =
+  match script_type with
+  | ScriptBool
+  | ScriptInt -> "int"
+  | ScriptObject -> "void*"
+  | ScriptFloat -> "Float"
+  | ScriptString -> "String"
+  | v -> to_script_type_string v
 
 let rec script_type_string haxe_type =
   match haxe_type with
@@ -77,7 +96,7 @@ let rec script_type_string haxe_type =
 
 let rec script_cpptype_string cppType =
   match cppType with
-  | TCppDynamic | TCppUnchanged | TCppWrapped _ | TCppObject -> "Dynamic"
+  | TCppDynamic | TCppUnchanged | TCppWrapped _ | TCppObject | TCppMarshalManagedType _ -> "Dynamic"
   | TCppObjectPtr -> ".*.hx.Object*"
   | TCppReference t -> ".ref." ^ script_cpptype_string t
   | TCppStruct t -> ".struct." ^ script_cpptype_string t
@@ -96,6 +115,12 @@ let rec script_cpptype_string cppType =
       "cpp.Pointer." ^ script_cpptype_string valueType
   | TCppRawPointer (_, valueType) ->
       "cpp.RawPointer." ^ script_cpptype_string valueType
+  | TCppMarshalNativeType (ValueClass (cls, _), _) ->
+    "cpp.MarshalValueClass." ^ (join_class_path cls.cl_path ".")
+  | TCppMarshalNativeType (ValueEnum abs, _) ->
+    "cpp.MarshalValueEnum." ^ join_class_path abs.a_path "."
+  | TCppMarshalNativeType (Pointer (cls, _), _) ->
+    "cpp.MarshalPointer." ^ join_class_path cls.cl_path "."
   | TCppFunction _ -> "cpp.Function"
   | TCppObjCBlock _ -> "cpp.ObjCBlock"
   | TCppDynamicArray -> "Array.Any"
@@ -730,9 +755,9 @@ class script_writer ctx filename asciiOut =
         match fieldExpression with
         | Some ({ eexpr = TFunction function_def } as e) ->
             if cppiaAst then (
-              let args = List.map fst function_def.tf_args in
+              let args = List.map (fun (v, e) -> (CppRetyper.retype_tvar v), e) function_def.tf_args in
               let cppExpr =
-                CppRetyper.expression ctx TCppVoid args function_def.tf_type
+                CppRetyper.expression ctx TCppVoid args (cpp_type_of function_def.tf_type)
                   function_def.tf_expr false
               in
               this#begin_expr;
@@ -742,7 +767,7 @@ class script_writer ctx filename asciiOut =
                 ^ this#typeText function_def.tf_type
                 ^ string_of_int (List.length args)
                 ^ "\n");
-              let close = this#gen_func_args function_def.tf_args in
+              let close = this#gen_func_args args in
               this#gen_expression_tree cppExpr;
               this#end_expr;
               close ())
@@ -766,7 +791,7 @@ class script_writer ctx filename asciiOut =
           if cppiaAst then
             let varType = cpp_type_of expression.etype in
             let cppExpr =
-              CppRetyper.expression ctx varType [] t_dynamic expression false
+              CppRetyper.expression ctx varType [] TCppDynamic expression false
             in
             this#gen_expression_tree cppExpr
           else this#gen_expression expression
@@ -863,7 +888,7 @@ class script_writer ctx filename asciiOut =
       List.iter
         (fun (arg, init) ->
           this#write (indent ^ indent_str);
-          this#writeVar arg;
+          this#writeVar arg.tcppv_var;
           match init with
           | Some { eexpr = TConst TNull } -> this#write "0\n"
           | Some const ->
@@ -893,8 +918,8 @@ class script_writer ctx filename asciiOut =
               this#begin_expr;
               this#writePos const;
               this#write
-                (this#op IaVar ^ string_of_int arg.v_id
-               ^ this#commentOf arg.v_name);
+                (this#op IaVar ^ string_of_int arg.tcppv_var.v_id
+               ^ this#commentOf arg.tcppv_var.v_name);
               this#end_expr
             in
 
@@ -929,7 +954,7 @@ class script_writer ctx filename asciiOut =
             ^ this#typeText function_def.tf_type
             ^ string_of_int (List.length function_def.tf_args)
             ^ "\n");
-          let close = this#gen_func_args function_def.tf_args in
+          let close = this#gen_func_args (List.map (fun (v, e) -> CppRetyper.retype_tvar v, e) function_def.tf_args) in
           let pop = this#pushReturn function_def.tf_type in
           this#gen_expression function_def.tf_expr;
           pop ();
@@ -1313,19 +1338,18 @@ class script_writer ctx filename asciiOut =
               this#writeList (this#op IaBlock) (List.length exprs);
               List.iter gen_expression exprs
           | CppVarDecl (var, init) -> (
-              let name = CppGen.cpp_var_name_of var in
               this#write
                 (this#op IaTVars ^ string_of_int 1
-                ^ this#commentOf (name ^ ":" ^ script_type_string var.v_type)
+                ^ this#commentOf (var.tcppv_name ^ ":" ^ script_type_string var.tcppv_var.v_type)
                 ^ "\n");
               this#write ("\t\t" ^ indent);
               match init with
               | None ->
                   this#writeOp IaVarDecl;
-                  this#writeVar var
+                  this#writeVar var.tcppv_var
               | Some init ->
                   this#writeOp IaVarDeclI;
-                  this#writeVar var;
+                  this#writeVar var.tcppv_var;
                   this#write (" " ^ this#astType init.cpptype);
                   this#write "\n";
                   gen_expression init)
@@ -1384,7 +1408,7 @@ class script_writer ctx filename asciiOut =
                   this#write
                     (this#op IaCallThis ^ this#astType inst ^ " "
                    ^ this#stringText name ^ argN ^ this#commentOf name ^ "\n")
-              | FuncInstance (expr, _, field) | FuncInterface (expr, _, field)
+              | FuncInstance (expr, _, field, _) | FuncInterface (expr, _, field)
                 ->
                   this#write
                     (this#op IaCallMember ^ this#astType expr.cpptype ^ " "
@@ -1393,7 +1417,7 @@ class script_writer ctx filename asciiOut =
                     ^ this#commentOf field.cf_name
                     ^ "\n");
                   gen_expression expr
-              | FuncStatic (class_def, _, field) ->
+              | FuncStatic (class_def, _, field, _) ->
                   this#write
                     (this#op IaCallStatic ^ this#cppInstText class_def ^ " "
                     ^ this#stringText field.cf_name
@@ -1473,7 +1497,7 @@ class script_writer ctx filename asciiOut =
                         ^ "." ^ name)
                     ^ "\n");
                   gen_expression expr
-              | FuncInstance (expr, _, field) | FuncInterface (expr, _, field)
+              | FuncInstance (expr, _, field, _) | FuncInterface (expr, _, field)
                 ->
                   this#write
                     (this#op IaFName ^ this#astType expr.cpptype ^ " "
@@ -1483,7 +1507,7 @@ class script_writer ctx filename asciiOut =
                         ^ "." ^ field.cf_name)
                     ^ "\n");
                   gen_expression expr
-              | FuncStatic (class_def, _, field) ->
+              | FuncStatic (class_def, _, field, _) ->
                   this#write
                     (this#op IaFStatic ^ this#cppInstText class_def ^ " "
                     ^ this#stringText field.cf_name
@@ -1606,9 +1630,9 @@ class script_writer ctx filename asciiOut =
               this#writeList (this#op IaTry) (List.length catches);
               gen_expression block;
               List.iter
-                (fun (tvar, catch_expr) ->
+                (fun (var, catch_expr) ->
                   this#write ("\t\t\t" ^ indent);
-                  this#writeVar tvar;
+                  this#writeVar var.tcppv_var;
                   this#write "\n";
                   gen_expression catch_expr)
                 catches
@@ -1715,8 +1739,8 @@ class script_writer ctx filename asciiOut =
         match loc with
         | VarClosure var | VarLocal var ->
             this#write
-              (this#op IaVar ^ string_of_int var.v_id
-             ^ this#commentOf var.v_name)
+              (this#op IaVar ^ string_of_int var.tcppv_var.v_id
+             ^ this#commentOf var.tcppv_var.v_name)
         | VarStatic (class_def, _, field) ->
             this#write
               (this#op IaFStatic ^ this#cppInstText class_def ^ " "

+ 272 - 220
src/generators/cpp/gen/cppGen.ml

@@ -9,6 +9,7 @@ open CppAst
 open CppAstTools
 open CppSourceWriter
 open CppContext
+open CppMarshalling
 
 type tinject = {
   inj_prologue : bool -> unit;
@@ -16,60 +17,50 @@ type tinject = {
   inj_tail : string;
 }
 
-let cpp_type_of = CppRetyper.cpp_type_of
+let cpp_type_of = CppRetyper.cpp_type_of CppRetyper.with_stack_value_type
 let cpp_type_of_null = CppRetyper.cpp_type_of_null
 let cpp_instance_type = CppRetyper.cpp_instance_type
 let type_to_string haxe_type = tcpp_to_string (cpp_type_of haxe_type)
 
-let type_cant_be_null haxe_type =
-  match cpp_type_of haxe_type with TCppScalar _ -> true | _ -> false
+let type_cant_be_null tcpp =
+  match tcpp with TCppScalar _ -> true | _ -> false
+
+let type_arg_to_string v default_val prefix =
+  let remap_name = v.tcppv_name in
+  let type_str   = tcpp_to_string v.tcppv_type in
 
-let type_arg_to_string name default_val arg_type prefix =
-  let remap_name = keyword_remap name in
-  let type_str = type_to_string arg_type in
   match default_val with
   | Some { eexpr = TConst TNull } -> (type_str, remap_name)
-  | Some constant when type_cant_be_null arg_type ->
+  | Some constant when match v.tcppv_type with TCppScalar _ -> true | _ -> false ->
       ("::hx::Null< " ^ type_str ^ " > ", prefix ^ remap_name)
   | Some constant -> (type_str, prefix ^ remap_name)
   | _ -> (type_str, remap_name)
 
-let cpp_var_name_of var =
-  match get_meta_string var.v_meta Meta.Native with
-  | Some n -> n
-  | None -> keyword_remap var.v_name
-
-let cpp_var_debug_name_of v =
-  match get_meta_string v.v_meta Meta.RealPath with
-  | Some n -> n
-  | None -> v.v_name
-
 (* Generate prototype text, including allowing default values to be null *)
-let print_arg name default_val arg_type prefix =
-  let n, t = type_arg_to_string name default_val arg_type prefix in
+let print_arg v default_val prefix =
+  let n, t = type_arg_to_string v default_val prefix in
   n ^ " " ^ t
 
 (* Generate prototype text, including allowing default values to be null *)
-let print_arg_name name default_val arg_type prefix =
-  let n, _ = type_arg_to_string name default_val arg_type prefix in
-  n
+let print_arg_name v default_val prefix =
+  type_arg_to_string v default_val prefix |> fst
 
 let print_arg_list arg_list prefix =
   String.concat ","
-    (List.map (fun (v, o) -> print_arg v.v_name o v.v_type prefix) arg_list)
+    (List.map (fun (v, o) -> print_arg v o prefix) arg_list)
 
 let print_arg_list_name arg_list prefix =
   String.concat ","
     (List.map
-       (fun (v, o) -> print_arg_name v.v_name o v.v_type prefix)
+       (fun (v, o) -> print_arg_name v o prefix)
        arg_list)
 
 let print_arg_names args =
-  String.concat "," (List.map (fun (name, _, _) -> keyword_remap name) args)
+  args |> List.map (fun arg -> arg.tfa_name) |> String.concat ", "
 
-let print_tfun_arg_list include_names arg_list =
+let print_retyped_tfun_arg_list include_names arg_list =
   let oType o arg_type =
-    let type_str = type_to_string arg_type in
+    let type_str = tcpp_to_string arg_type in
     (* type_str may have already converted Null<X> to Dynamic because of NotNull tag ... *)
     if o && type_cant_be_null arg_type && type_str <> "Dynamic" then
       "::hx::Null< " ^ type_str ^ " > "
@@ -77,7 +68,7 @@ let print_tfun_arg_list include_names arg_list =
       type_str
   in
   arg_list
-  |> List.map (fun (name, o, arg_type) -> (oType o arg_type) ^ (if include_names then " " ^ keyword_remap name else ""))
+  |> List.map (fun arg -> (oType arg.tfa_optional arg.tfa_type) ^ (if include_names then " " ^ arg.tfa_name else ""))
   |> String.concat ","
 
 let cpp_member_name_of member =
@@ -86,6 +77,12 @@ let cpp_member_name_of member =
   | None -> keyword_remap member.cf_name
 
 let function_signature include_names tfun abi =
+  let print_tfun_arg_list include_names arg_list =
+    arg_list
+    |> List.map (CppRetyper.retype_arg CppRetyper.with_stack_value_type)
+    |> print_retyped_tfun_arg_list include_names
+  in
+
   match follow tfun with
   | TFun (args, ret) ->
       type_to_string ret ^ " " ^ abi ^ "("
@@ -95,64 +92,49 @@ let function_signature include_names tfun abi =
 
 let cpp_no_debug_synbol ctx var =
   ctx.ctx_debug_level <= 1
-  || (match var.v_kind with VUser _ -> false | _ -> true)
+  || (match var.tcppv_var.v_kind with VUser _ -> false | _ -> true)
   ||
-  match cpp_type_of var.v_type with
-  | TCppStar _ | TCppReference _ -> true
+  match var.tcppv_type with
+  | TCppStar _ | TCppReference _ | TCppMarshalNativeType _ -> true
   | TCppInst (class_def, _) when Meta.has Meta.StructAccess class_def.cl_meta ->
       true
   | TCppInst (class_def, _) when Meta.has Meta.Unreflective class_def.cl_meta ->
       true
   | _ ->
-      let name = cpp_var_debug_name_of var in
+      let name = cpp_var_debug_name_of var.tcppv_var in
       String.length name > 4 && String.sub name 0 4 = "_hx_"
 
-let cpp_debug_name_of var = keyword_remap var.v_name
 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_var_type_of var = tcpp_to_string (cpp_type_of var.v_type) *)
 
 let mk_injection prologue set_var tail =
   Some { inj_prologue = prologue; inj_setvar = set_var; inj_tail = tail }
 
-let tvar_arg_to_string tvar default_val prefix =
-  let remap_name = cpp_var_name_of tvar in
-  let type_str = cpp_var_type_of tvar in
-  match default_val with
-  | Some { eexpr = TConst TNull } ->
-      (tcpp_to_string (cpp_type_of_null tvar.v_type), remap_name)
-  | Some constant ->
-      (tcpp_to_string (cpp_type_of_null tvar.v_type), prefix ^ remap_name)
-  | _ -> (type_str, remap_name)
-
-(* Generate prototype text, including allowing default values to be null *)
-let cpp_arg_string tvar default_val prefix =
-  let t, n = tvar_arg_to_string tvar default_val prefix in
-  t ^ " " ^ n
-
-let cpp_arg_list args prefix =
-  String.concat "," (List.map (fun (v, o) -> cpp_arg_string v o prefix) args)
-
 let gen_type ctx haxe_type = ctx.ctx_output (type_to_string haxe_type)
 
 let cpp_macro_var_type_of var =
-  let t = tcpp_to_string (cpp_type_of var.v_type) in
+  let t = tcpp_to_string var.tcppv_type in
   if String.contains t ',' then
     Str.global_replace (Str.regexp ",") " HX_COMMA " t
   else t
 
 let cpp_class_name klass =
-  let globalNamespace =
-    match get_meta_string klass.cl_meta Meta.Native with
-    | Some _ -> ""
-    | None -> "::"
-  in
-  let path = globalNamespace ^ join_class_path_remap klass.cl_path "::" in
-  if is_native_class klass || path = "::String" then path else path ^ "_obj"
-
-let only_stack_access haxe_type =
-  match cpp_type_of haxe_type with
-  | TCppInst (klass, _) -> Meta.has Meta.StackOnly klass.cl_meta
-  | _ -> false
+  if is_marshalling_native_value_class klass then
+    get_native_marshalled_type (ValueClass (klass, []))
+  else if is_marshalling_native_pointer klass then
+    get_native_marshalled_type (Pointer (klass, []))
+  else if is_marshalling_managed_class klass then
+    let type_str, flags = build_type klass.cl_path klass.cl_pos [] klass.cl_meta Meta.CppManagedType tcpp_to_string in
+    let standard_naming = List.exists (fun f -> f = "StandardNaming") flags in
+    if standard_naming then type_str ^ "_obj" else type_str
+  else
+    let globalNamespace =
+      match get_meta_string klass.cl_meta Meta.Native with
+      | Some _ -> ""
+      | None -> "::"
+    in
+    let path = globalNamespace ^ join_class_path_remap klass.cl_path "::" in
+    if is_native_class klass || path = "::String" then path else path ^ "_obj"
 
 let cpp_is_static_extension member =
   Meta.has Meta.NativeStaticExtension member.cf_meta
@@ -178,34 +160,28 @@ let default_value_string ctx value =
 
 let cpp_gen_default_values ctx args prefix =
   List.iter
-    (fun (tvar, o) ->
-      let vtype = cpp_type_of tvar.v_type in
+    (fun (var, o) ->
       let not_null =
-        type_has_meta_key Meta.NotNull tvar.v_type || is_cpp_scalar vtype
+        type_has_meta_key Meta.NotNull var.tcppv_var.v_type || is_cpp_scalar var.tcppv_type
       in
       match o with
       | Some { eexpr = TConst TNull } -> ()
       | Some const ->
-          let name = cpp_var_name_of tvar in
-          let spacer =
-            if ctx.ctx_debug_level > 0 then "            \t" else ""
-          in
-          let pname = prefix ^ name in
+          let spacer = if ctx.ctx_debug_level > 0 then "            \t" else "" in
+          let pname = prefix ^ var.tcppv_name in
           ctx.ctx_output
-            (spacer ^ "\t" ^ tcpp_to_string vtype ^ " " ^ name ^ " = " ^ pname);
+            (spacer ^ "\t" ^ tcpp_to_string var.tcppv_type ^ " " ^ var.tcppv_name ^ " = " ^ pname);
           ctx.ctx_output
             (if not_null then
                ".Default(" ^ default_value_string ctx.ctx_common const ^ ");\n"
              else
-               ";\n" ^ spacer ^ "\tif (::hx::IsNull(" ^ pname ^ ")) " ^ name
+               ";\n" ^ spacer ^ "\tif (::hx::IsNull(" ^ pname ^ ")) " ^ var.tcppv_name
                ^ " = "
                ^ default_value_string ctx.ctx_common const
                ^ ";\n")
       | _ -> ())
     args
 
-let ctx_default_values ctx args prefix = cpp_gen_default_values ctx args prefix
-
 let cpp_class_hash interface =
   gen_hash 0 (join_class_path interface.cl_path "::")
 
@@ -399,14 +375,14 @@ let end_header_file output_h def_string =
   output_h ("\n#endif /* INCLUDED_" ^ def_string ^ " */ \n")
 
 let cpp_tfun_signature include_names args return_type =
-  let argList = print_tfun_arg_list include_names args in
-  let returnType = type_to_string return_type in
+  let argList = print_retyped_tfun_arg_list include_names args in
+  let returnType = tcpp_to_string return_type in
   "( " ^ returnType ^ " (::hx::Object::*)(" ^ argList ^ "))"
 
 let find_class_implementation func tcpp_class =
   let rec find def =
     match List.find_opt (fun f -> f.tcf_name = func.iff_name) def.tcl_functions with
-    | Some f -> Some f.tcf_field
+    | Some f -> Some f
     | None ->
       match def.tcl_super with
       | Some s -> find s
@@ -414,8 +390,8 @@ let find_class_implementation func tcpp_class =
   in
 
   match find tcpp_class with
-  | Some { cf_type = TFun (args, ret) } -> 
-    cpp_tfun_signature false args ret
+  | Some func -> 
+    print_arg_list func.tcf_args ""
   | _ ->
     ""
 
@@ -442,8 +418,7 @@ let needed_interface_functions implemented_instance_fields native_implementation
   |> List.fold_left iface_folder (have, [])
   |> snd
 
-let gen_cpp_ast_expression_tree ctx class_name func_name function_args
-    function_type injection tree =
+let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_type injection tree =
   let writer = ctx.ctx_writer in
   let out = ctx.ctx_output in
   let lastLine = ref (-1) in
@@ -523,24 +498,23 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
     | CppBreak -> out "break"
     | CppContinue -> out "continue"
     | CppGoto label -> out ("goto " ^ label_name label)
-    | CppVarDecl (var, init) -> (
-        let name = cpp_var_name_of var in
-        (if cpp_no_debug_synbol ctx var then
-           out (cpp_var_type_of var ^ " " ^ name)
-         else
-           let dbgName = cpp_var_debug_name_of var in
-           let macro = if init = None then "HX_VAR" else "HX_VARI" in
-           let varType = cpp_macro_var_type_of var in
-           if name <> dbgName then
-             out
-               (macro ^ "_NAME( " ^ varType ^ "," ^ name ^ ",\"" ^ dbgName
-              ^ "\")")
-           else out (macro ^ "( " ^ varType ^ "," ^ name ^ ")"));
-        match init with
-        | Some init ->
-            out " = ";
-            gen init
-        | _ -> ())
+    | CppVarDecl (var, init) ->
+      (if cpp_no_debug_synbol ctx var then
+        out (tcpp_to_string var.tcppv_type ^ " " ^ var.tcppv_name)
+      else
+        let dbgName = cpp_var_debug_name_of var.tcppv_var in
+        let macro   = if init = None then "HX_VAR" else "HX_VARI" in
+        let varType = cpp_macro_var_type_of var in
+        if var.tcppv_name <> dbgName then
+          out
+            (macro ^ "_NAME( " ^ varType ^ "," ^ var.tcppv_name ^ ",\"" ^ dbgName
+          ^ "\")")
+        else out (macro ^ "( " ^ varType ^ "," ^ var.tcppv_name ^ ")"));
+      (match init with
+      | Some init ->
+          out " = ";
+          gen init
+      | _ -> ())
     | CppEnumIndex obj ->
         gen obj;
         if cpp_is_dynamic_type obj.cpptype then
@@ -551,7 +525,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         match func with
         | FuncThis (field, _) ->
             out ("this->" ^ cpp_member_name_of field ^ "_dyn()")
-        | FuncInstance (expr, inst, field) ->
+        | FuncInstance (expr, inst, field, _) ->
             gen expr;
             out
               ((if expr.cpptype = TCppString || inst = InstStruct then "."
@@ -560,7 +534,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         | FuncInterface (expr, _, field) ->
             gen expr;
             out ("->__Field(" ^ strq field.cf_name ^ ", ::hx::paccDynamic)")
-        | FuncStatic (clazz, _, field) -> (
+        | FuncStatic (clazz, _, field, _) -> (
             match get_meta_string field.cf_meta Meta.Native with
             | Some n -> out n
             | None ->
@@ -593,12 +567,12 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
             gen arg)
           args;
         out ")"
-    | CppCall ((FuncStatic (_, true, field) as func), arg_list)
-    | CppCall ((FuncInstance (_, InstObjC, field) as func), arg_list) ->
+    | CppCall ((FuncStatic (_, true, field, _) as func), arg_list)
+    | CppCall ((FuncInstance (_, InstObjC, field, _) as func), arg_list) ->
         out "[ ";
         (match func with
-        | FuncStatic (cl, _, _) -> out (join_class_path_remap cl.cl_path "::")
-        | FuncInstance (expr, _, _) -> gen expr
+        | FuncStatic (cl, _, _, _) -> out (join_class_path_remap cl.cl_path "::")
+        | FuncInstance (expr, _, _, params) -> gen expr
         | _ -> ());
 
         let names = ExtString.String.nsplit field.cf_name ":" in
@@ -649,18 +623,27 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         let argsRef = ref args in
         (match func with
         | FuncThis (field, _) -> out ("this->" ^ cpp_member_name_of field)
-        | FuncInstance (expr, inst, field) ->
+        | FuncInstance (expr, inst, field, template_types) ->
             let operator =
               if expr.cpptype = TCppString || inst = InstStruct then "."
               else "->"
             in
+            let printer tcpp =
+              match tcpp with
+              | TCppMarshalNativeType ((Pointer _) as value_type, _) -> get_native_marshalled_type value_type ^ "*"
+              | TCppMarshalNativeType (value_type, _) -> get_native_marshalled_type value_type
+              | other -> tcpp_to_string other
+            in
+            let template =
+              match template_types with
+              | [] -> ""
+              | types -> types |> List.map (printer) |> String.concat ", " |> Printf.sprintf "< %s >" in
             gen expr;
-            out (operator ^ cpp_member_name_of field)
+            out (operator ^ cpp_member_name_of field ^ template)
         | FuncInterface (expr, _, field) ->
             gen expr;
             out ("->" ^ cpp_member_name_of field)
-        | FuncStatic (clazz, false, field) when cpp_is_static_extension field
-          -> (
+        | FuncStatic (clazz, false, field, _) when cpp_is_static_extension field -> (
             match args with
             | fst :: remaining ->
                 argsRef := remaining;
@@ -669,7 +652,25 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
             | _ ->
                 abort "Native static extensions must have at least 1 argument"
                   expr.cpppos)
-        | FuncStatic (clazz, _, field) -> (
+        | FuncStatic (clazz, _, field, template_types) when is_marshalling_native_value_class clazz || is_marshalling_native_pointer clazz ->
+          let func_name =
+            match get_meta_string field.cf_meta Meta.Native with
+            | Some renamed -> renamed
+            | None -> cpp_member_name_of field
+          in
+          let printer tcpp =
+            match tcpp with
+            | TCppMarshalNativeType ((Pointer _) as value_type, _) -> get_native_marshalled_type value_type ^ "*"
+            | TCppMarshalNativeType (value_type, _) -> get_native_marshalled_type value_type
+            | other -> tcpp_to_string other
+          in
+          let template =
+            match template_types with
+            | [] -> ""
+            | types -> types |> List.map (printer) |> String.concat ", " |> Printf.sprintf "< %s >"
+          in
+          Printf.sprintf "%s::%s%s" (cpp_class_name clazz) func_name template |> out
+        | FuncStatic (clazz, _, field, _) -> (
             match get_meta_string field.cf_meta Meta.Native with
             | Some rename ->
                 (* This is the case if you use @:native('new foo').  c++ wil group the space undesirably *)
@@ -719,15 +720,38 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
                   "::Array_obj< " ^ tcpp_to_string value ^ " >::__new"
               | TCppObjC klass -> cpp_class_path_of klass [] ^ "_obj::__new"
               | TCppNativePointer klass -> "new " ^ cpp_class_path_of klass []
+              | TCppMarshalNativeType (value_type, Promoted) ->
+                closeCall := ")";
+                let ptr, obj = get_extern_value_type_boxed value_type in
+                Printf.sprintf "%s( new %s " ptr obj
+              | TCppMarshalManagedType (cls, params) ->
+                let type_str, flags = build_type cls.cl_path cls.cl_pos params cls.cl_meta Meta.CppManagedType tcpp_to_string in
+                let standard_naming = List.exists (fun f -> f = "StandardNaming") flags in
+                let ptr =
+                  if standard_naming then
+                    type_str
+                  else
+                    Printf.sprintf "::hx::ObjectPtr< %s >" type_str
+                in
+                let obj =
+                  if standard_naming then
+                    type_str ^ "_obj"
+                  else
+                    type_str
+                in
+                closeCall := ")";
+                Printf.sprintf "%s( new %s " ptr obj
+              | TCppMarshalNativeType (value_type, Stack) ->
+                newType |> tcpp_to_string
               | TCppInst (klass, p) when is_native_class klass ->
                   cpp_class_path_of klass p
               | TCppInst (klass, p) -> cpp_class_path_of klass p ^ "_obj::__new"
               | TCppClass -> "::hx::Class_obj::__new"
               | TCppFunction _ -> tcpp_to_string newType
               | _ ->
-                  abort
-                    ("Unknown 'new' target " ^ tcpp_to_string newType)
-                    expr.cpppos
+                abort
+                  ("Unknown 'new' target " ^ tcpp_to_string newType)
+                  expr.cpppos
             in
             out objName
         | FuncInternal (func, name, join) ->
@@ -750,10 +774,18 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
     | CppNewNative e ->
         out "new ";
         gen e
+    | CppAddressOf ({ cpptype = TCppMarshalNativeType (_, Reference) } as e) ->
+        out "(";
+        gen e;
+        out ".ptr)"
     | CppAddressOf e ->
         out "&(";
         gen e;
         out ")"
+    | CppDereference ({ cpptype = TCppMarshalNativeType (_, Reference) } as e) ->
+        out "(*(";
+        gen e;
+        out ").ptr)"
     | CppDereference e ->
         out "(*(";
         gen e;
@@ -773,6 +805,26 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         out ("->__Field(" ^ strq name ^ ",::hx::paccDynamic)")
     | CppArray arrayLoc -> (
         match arrayLoc with
+        (* Special case for pointers to marshal type pointers *)
+        (* ::cpp::Pointer array access returns a T& but we want a T* for the marhsal pointer type reference *)
+        (* So do some manual pointer arithmatic *)
+        | ArrayPointer ({ cpptype = TCppPointer (_, TCppMarshalNativeType (Pointer _, _)) } as arrayObj, index) ->
+          gen arrayObj;
+          out ".ptr + ";
+          gen index
+        | ArrayRawPointer ({ cpptype = TCppRawPointer (_, TCppMarshalNativeType (Pointer _, _)) } as arrayObj, index) ->
+          gen arrayObj;
+          out " + ";
+          gen index
+
+        (* The reference wrappers use templated get and set functions instead of the subscript operator due to templated []operator being a bit of a pain in c++ *)
+        (* Treat is as the special case it is here. *)
+        | ArrayRawPointer ({ cpptype = TCppMarshalNativeType (_, Reference) } as arrayObj, index) ->
+          gen arrayObj;
+          out (Printf.sprintf ".get< %s >(" (tcpp_to_string expr.cpptype));
+          gen index;
+          out ")";
+
         | ArrayTyped (arrayObj, index, _) ->
             gen arrayObj;
             out "->__get(";
@@ -824,8 +876,8 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         in
         (match lvalue with
         | CppVarRef (VarClosure var)
-          when is_gc_element ctx (cpp_type_of var.v_type) ->
-            out ("this->_hx_set_" ^ cpp_var_name_of var ^ "(HX_CTX, ");
+          when is_gc_element ctx var.tcppv_type ->
+            out ("this->_hx_set_" ^ var.tcppv_name ^ "(HX_CTX, ");
             gen rvalue;
             out ")"
         | CppVarRef (VarThis (member, _))
@@ -843,7 +895,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
             gen obj;
             out (operator ^ member)
         | CppVarRef varLoc ->
-            gen_val_loc varLoc true;
+            gen_val_loc varLoc;
             out " = ";
             gen rvalue
         | CppArrayRef arrayLoc -> (
@@ -863,6 +915,16 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
                 out ",";
                 gen rvalue;
                 out ")"
+
+            (* The reference wrappers use templated get and set functions instead of the subscript operator due to templated []operator being a bit of a pain in c++ *)
+            (* Treat is as the special case it is here. *)
+            | ArrayRawPointer ({ cpptype = TCppMarshalNativeType (_, Reference) } as arrayObj, index) ->
+                gen arrayObj;
+                out (Printf.sprintf ".set< %s >(" (tcpp_to_string rvalue.cpptype));
+                gen index;
+                out ",";
+                gen rvalue;
+                out ")";
             | ArrayObject (arrayObj, index, _)
             | ArrayTyped (arrayObj, index, _)
             | ArrayRawPointer (arrayObj, index) ->
@@ -932,7 +994,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         if native then out "null()"
         else if path = "::Array" then out "::hx::ArrayBase::__mClass"
         else out ("::hx::ClassOf< " ^ path ^ " >()")
-    | CppVar loc -> gen_val_loc loc false
+    | CppVar loc -> gen_val_loc loc
     | CppClosure closure ->
         out
           (" ::Dynamic(new _hx_Closure_" ^ string_of_int closure.close_id ^ "(");
@@ -943,11 +1005,12 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
             separator := ","
         | _ -> ());
 
-        StringMap.iter
-          (fun name value ->
+        IntMap.iter
+          (fun _ var ->
+            let name = var.tcppv_name in
             out !separator;
             separator := ",";
-            out (keyword_remap name))
+            out name)
           closure.close_undeclared;
         out "))"
     | CppObjectDecl (values, isStruct) ->
@@ -1099,7 +1162,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         out ("->_hx_get" ^ baseType ^ "(" ^ string_of_int index ^ ")");
         match valueType with
         | TCppObjectArray _ | TCppScalarArray _ | TCppDynamicArray | TCppClass
-        | TCppEnum _ | TCppInst _ ->
+        | TCppEnum _ | TCppInst _ | TCppMarshalManagedType _ ->
             out (".StaticCast< " ^ tcpp_to_string valueType ^ " >()")
         | _ -> ())
     | CppIntSwitch (condition, cases, defVal) ->
@@ -1192,15 +1255,15 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         gen block;
         out " : ";
         gen elze
-    | CppFor (tvar, init, loop) ->
-        let varType = cpp_var_type_of tvar in
+    | CppFor (var, init, loop) ->
+        let varType = tcpp_to_string var.tcppv_type in
         out
           ("for(::cpp::FastIterator_obj< " ^ varType
          ^ " > *__it = ::cpp::CreateFastIterator< " ^ varType ^ " >(");
         gen init;
         out ");  __it->hasNext(); )";
         let prologue _ =
-          output_i (varType ^ " " ^ cpp_var_name_of tvar ^ " = __it->next();\n")
+          output_i (varType ^ " " ^ var.tcppv_name ^ " = __it->next();\n")
         in
         gen_with_injection (mk_injection prologue "" "") loop true
     | CppTry (block, catches) ->
@@ -1226,8 +1289,8 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
           let else_str = ref "" in
           List.iter
             (fun (v, catch) ->
-              let type_name = cpp_var_type_of v in
-              (match cpp_type_of v.v_type with
+              let type_name = tcpp_to_string v.tcppv_type in
+              (match v.tcppv_type with
               | TCppInterface klass ->
                   let hash = cpp_class_hash klass in
                   output_i
@@ -1250,7 +1313,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
                 | _ ->
                     output_i "HX_STACK_BEGIN_CATCH\n";
                     output_i
-                      (type_name ^ " " ^ cpp_var_name_of v ^ " = _hx_e;\n")
+                      (type_name ^ " " ^ v.tcppv_name ^ " = _hx_e;\n")
               in
               gen_with_injection (mk_injection prologue "" "") catch true;
               else_str := "else ")
@@ -1349,7 +1412,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
   and gen expr = gen_with_injection None expr true
   and gen_lvalue lvalue =
     match lvalue with
-    | CppVarRef varLoc -> gen_val_loc varLoc true
+    | CppVarRef varLoc -> gen_val_loc varLoc
     | CppArrayRef arrayLoc -> (
         match arrayLoc with
         | ArrayObject (arrayObj, index, _) ->
@@ -1395,10 +1458,10 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
         out "::hx::FieldRef((";
         gen expr;
         out (")" ^ objPtr ^ "," ^ strq name ^ ")")
-  and gen_val_loc loc lvalue =
+  and gen_val_loc loc =
     match loc with
-    | VarClosure var -> out (cpp_var_name_of var)
-    | VarLocal local -> out (cpp_var_name_of local)
+    | VarClosure var
+    | VarLocal var -> out var.tcppv_name
     | VarStatic (clazz, objc, member) -> (
         match get_meta_string member.cf_meta Meta.Native with
         | Some n -> out n
@@ -1461,7 +1524,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
     | OpAssign | OpAssignOp _ -> abort "Unprocessed OpAssign" pos
 
   and gen_closure closure =
-    let argc = StringMap.bindings closure.close_undeclared |> List.length in
+    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 *)
@@ -1474,19 +1537,22 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
       (if closure.close_this != None then "::hx::LocalThisFunc,"
        else "::hx::LocalFunc,");
     out ("_hx_Closure_" ^ string_of_int closure.close_id);
-    StringMap.iter
-      (fun name var ->
-        out ("," ^ cpp_macro_var_type_of var ^ "," ^ keyword_remap name))
+    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 func_type = tcpp_to_string closure.close_type in
-    output_i
-      (func_type ^ " _hx_run(" ^ cpp_arg_list closure.close_args "__o_" ^ ")");
+    Printf.sprintf
+      "%s _hx_run( %s )"
+      (tcpp_to_string closure.close_type)
+      (print_arg_list closure.close_args "__o_") |> output_i;
 
     let prologue = function
       | gc_stack ->
           cpp_gen_default_values ctx closure.close_args "__o_";
+
           hx_stack_push ctx output_i class_name func_name
             closure.close_expr.cpppos gc_stack;
           if ctx.ctx_debug_level >= 2 then (
@@ -1495,8 +1561,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args
             List.iter
               (fun (v, _) ->
                 output_i
-                  ("HX_STACK_ARG(" ^ cpp_var_name_of v ^ ",\""
-                 ^ cpp_debug_name_of v ^ "\")\n"))
+                  ("HX_STACK_ARG(" ^ v.tcppv_name ^ ",\"" ^ v.tcppv_debug_name ^ "\")\n"))
               (List.filter (cpp_debug_var_visible ctx) closure.close_args);
 
             let line = Lexer.get_error_line closure.close_expr.cpppos in
@@ -1525,8 +1590,7 @@ let gen_cpp_init ctx dot_name func_name var_name expr =
         hx_stack_push ctx output_i dot_name func_name expr.epos gc_stack
   in
   let injection = mk_injection prologue var_name "" in
-  gen_cpp_ast_expression_tree ctx dot_name func_name [] t_dynamic injection
-    (mk_block expr)
+  gen_cpp_ast_expression_tree ctx dot_name func_name [] TCppDynamic injection (mk_block expr)
 
 let generate_main_header output_main =
   output_main "#include <hxcpp.h>\n\n";
@@ -1723,8 +1787,7 @@ let generate_files common_ctx file_info =
 
   files_file#close
 
-let gen_cpp_function_body ctx clazz is_static func_name function_def head_code
-    tail_code no_debug =
+let gen_cpp_function_body ctx clazz is_static func_name function_def head_code tail_code no_debug =
   let output = ctx.ctx_output in
   let dot_name = join_class_path clazz.cl_path "." in
   if no_debug then ctx.ctx_debug_level <- 0;
@@ -1732,8 +1795,8 @@ let gen_cpp_function_body ctx clazz is_static func_name function_def head_code
     | gc_stack ->
         let spacer = if no_debug then "\t" else "            \t" in
         let output_i s = output (spacer ^ s) in
-        ctx_default_values ctx function_def.tf_args "__o_";
-        hx_stack_push ctx output_i dot_name func_name function_def.tf_expr.epos
+        cpp_gen_default_values ctx function_def.tcf_args "__o_";
+        hx_stack_push ctx output_i dot_name func_name function_def.tcf_func.tf_expr.epos
           gc_stack;
         if ctx.ctx_debug_level >= 2 then (
           if not is_static then
@@ -1745,32 +1808,26 @@ let gen_cpp_function_body ctx clazz is_static func_name function_def head_code
             (fun (v, _) ->
               if not (cpp_no_debug_synbol ctx v) then
                 output_i
-                  ("HX_STACK_ARG(" ^ cpp_var_name_of v ^ ",\"" ^ v.v_name
-                 ^ "\")\n"))
-            function_def.tf_args;
+                  ("HX_STACK_ARG(" ^ v.tcppv_name ^ ",\"" ^ v.tcppv_debug_name ^ "\")\n"))
+                  function_def.tcf_args;
 
-          let line = Lexer.get_error_line function_def.tf_expr.epos in
+          let line = Lexer.get_error_line function_def.tcf_func.tf_expr.epos in
           let lineName = Printf.sprintf "%4d" line in
           output ("HXLINE(" ^ lineName ^ ")\n"));
         if head_code <> "" then output_i (head_code ^ "\n")
   in
-  let args = List.map fst function_def.tf_args in
 
   let injection = mk_injection prologue "" tail_code in
-  gen_cpp_ast_expression_tree ctx dot_name func_name args function_def.tf_type
-    injection
-    (mk_block function_def.tf_expr)
+  gen_cpp_ast_expression_tree ctx dot_name func_name function_def.tcf_args function_def.tcf_return injection (mk_block function_def.tcf_func.tf_expr)
 
-let constructor_arg_var_list class_def =
-  match class_def.cl_constructor with
-  | Some { cf_expr = Some { eexpr = TFunction function_def } } ->
-    List.map
-      (fun (v, o) -> type_arg_to_string v.v_name o v.v_type "__o_")
-      function_def.tf_args
-  | Some definition ->
+let constructor_arg_var_list tcpp_class =
+  match tcpp_class.tcl_constructor with
+  | Some constructor ->
+    List.map (fun (v, o) -> type_arg_to_string v o "__o_") constructor.tcf_args
+  (* | Some definition ->
     (match follow definition.cf_type with
     | TFun (args, _) -> List.map (fun (a, _, t) -> type_to_string t, a) args
-    | _ -> [])
+    | _ -> []) *)
   | _ -> []
 
 let generate_constructor ctx out tcpp_class isHeader =
@@ -1778,7 +1835,7 @@ let generate_constructor ctx out tcpp_class isHeader =
   let ptr_name = class_pointer tcpp_class.tcl_class in
   let can_quick_alloc = has_tcpp_class_flag tcpp_class QuickAlloc in
   let gcName = gen_gc_name tcpp_class.tcl_class.cl_path in
-  let cargs = constructor_arg_var_list tcpp_class.tcl_class in
+  let cargs = constructor_arg_var_list tcpp_class in
   let constructor_type_args =
     String.concat ","
       (List.map (fun (t, a) -> t ^ " " ^ a) cargs)
@@ -1819,70 +1876,65 @@ let generate_constructor ctx out tcpp_class isHeader =
     dump_dynamic tcpp_class.tcl_class;
 
     if isHeader then
-      match tcpp_class.tcl_class.cl_constructor with
-      | Some
-          ({ cf_expr = Some { eexpr = TFunction function_def } } as definition)
-        ->
-          with_debug ctx definition.cf_meta (fun no_debug ->
-              ctx.ctx_real_this_ptr <- false;
-              gen_cpp_function_body ctx tcpp_class.tcl_class false "new" function_def "" ""
-                no_debug;
-              out "\n")
+      match tcpp_class.tcl_constructor with
+      | Some constructor ->
+        let cb no_debug = 
+          ctx.ctx_real_this_ptr <- false;
+          gen_cpp_function_body ctx tcpp_class.tcl_class false "new" constructor "" "" no_debug;
+          out "\n";
+        in
+        with_debug ctx constructor.tcf_field.cf_meta cb
       | _ -> ()
     else out ("\t__this->__construct(" ^ constructor_args ^ ");\n");
 
     out "\treturn __this;\n";
     out "}\n\n")
 
-let generate_native_constructor ctx out class_def isHeader =
+let generate_native_constructor ctx out tcpp_class isHeader =
   let constructor_type_args =
-    class_def
+    tcpp_class
       |> constructor_arg_var_list
       |> List.map (fun (t, a) -> Printf.sprintf "%s %s" t a)
       |> String.concat "," in
 
-  let class_name = class_name class_def in
+  match tcpp_class.tcl_constructor with
+  | Some constructor ->
+    if isHeader then
+      out ("\t\t" ^ tcpp_class.tcl_name ^ "(" ^ constructor_type_args ^ ");\n\n")
+    else
+      let cb no_debug =
+        ctx.ctx_real_this_ptr <- true;
+        out (tcpp_class.tcl_name ^ "::" ^ tcpp_class.tcl_name ^ "(" ^ constructor_type_args ^ ")");
+
+        (match tcpp_class.tcl_super with
+        | Some klass -> (
+            let rec find_super_args = function
+              | TCall ({ eexpr = TConst TSuper }, args) :: _ -> Some args
+              | (TParenthesis e | TMeta (_, e) | TCast (e, None)) :: rest ->
+                  find_super_args (e.eexpr :: rest)
+              | TBlock e :: rest ->
+                  find_super_args (List.map (fun e -> e.eexpr) e @ rest)
+              | _ :: rest -> find_super_args rest
+              | _ -> None
+            in
+            match find_super_args [ constructor.tcf_func.tf_expr.eexpr ] with
+            | Some args ->
+                out ("\n:" ^ (cpp_class_path_of klass.tcl_class []) ^ "(");
+                let sep = ref "" in
+                List.iter
+                  (fun arg ->
+                    out !sep;
+                    sep := ",";
+                    gen_cpp_ast_expression_tree ctx "" "" [] TCppDynamic None
+                      arg)
+                  args;
+                out ")\n"
+            | _ -> ())
+        | _ -> ());
 
-  match class_def.cl_constructor with
-  | Some ({ cf_expr = Some { eexpr = TFunction function_def } } as definition)
-    ->
-      if isHeader then
-        out ("\t\t" ^ class_name ^ "(" ^ constructor_type_args ^ ");\n\n")
-      else
-        with_debug ctx definition.cf_meta (fun no_debug ->
-            ctx.ctx_real_this_ptr <- true;
-            out
-              (class_name ^ "::" ^ class_name ^ "(" ^ constructor_type_args
-             ^ ")");
-
-            (match class_def.cl_super with
-            | Some (klass, _) -> (
-                let rec find_super_args = function
-                  | TCall ({ eexpr = TConst TSuper }, args) :: _ -> Some args
-                  | (TParenthesis e | TMeta (_, e) | TCast (e, None)) :: rest ->
-                      find_super_args (e.eexpr :: rest)
-                  | TBlock e :: rest ->
-                      find_super_args (List.map (fun e -> e.eexpr) e @ rest)
-                  | _ :: rest -> find_super_args rest
-                  | _ -> None
-                in
-                match find_super_args [ function_def.tf_expr.eexpr ] with
-                | Some args ->
-                    out ("\n:" ^ cpp_class_path_of klass [] ^ "(");
-                    let sep = ref "" in
-                    List.iter
-                      (fun arg ->
-                        out !sep;
-                        sep := ",";
-                        gen_cpp_ast_expression_tree ctx "" "" [] t_dynamic None
-                          arg)
-                      args;
-                    out ")\n"
-                | _ -> ())
-            | _ -> ());
-
-            let head_code = get_code definition.cf_meta Meta.FunctionCode in
-            let tail_code = get_code definition.cf_meta Meta.FunctionTailCode in
-            gen_cpp_function_body ctx class_def false "new" function_def
-              head_code tail_code no_debug)
+        let head_code = get_code constructor.tcf_field.cf_meta Meta.FunctionCode in
+        let tail_code = get_code constructor.tcf_field.cf_meta Meta.FunctionTailCode in
+        gen_cpp_function_body ctx tcpp_class.tcl_class false "new" constructor head_code tail_code no_debug
+      in
+      with_debug ctx constructor.tcf_field.cf_meta cb
   | _ -> ()

+ 28 - 21
src/generators/cpp/gen/cppGenClassHeader.ml

@@ -9,12 +9,12 @@ open CppSourceWriter
 open CppContext
 open CppGen
 
-let gen_member_variable ctx class_def is_static (var:tcpp_class_variable) =
-  let tcpp     = cpp_type_of var.tcv_type in
+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
 
   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" tcpp_str) 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_type)) var.tcv_field.cf_pos;
 
   let output = ctx.ctx_output in
   let suffix = if is_static then "\t\tstatic " else "\t\t" in
@@ -56,9 +56,16 @@ let gen_member_function ctx class_def is_static func =
     |> String.concat " "
   in
 
-  let return_type     = type_to_string func.tcf_func.tf_type in
-  let return_type_str = if return_type = "Void" then "void" else return_type in
-  Printf.sprintf "\t\t%s %s %s(%s);\n" attributes return_type_str func.tcf_name (print_arg_list func.tcf_func.tf_args "") |> output;
+  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
+    | TCppVoid ->
+      "void"
+    | other ->
+      tcpp_to_string other in
+
+  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;
@@ -156,7 +163,7 @@ let generate_native_header base_ctx tcpp_class =
     match class_def.cl_super with
     | Some (klass, params) ->
         let name =
-          tcpp_to_string_suffix "_obj" (cpp_instance_type klass params)
+          tcpp_to_string_suffix "_obj" (cpp_instance_type klass params CppRetyper.with_stack_value_type)
         in
         ( name, name )
     | None -> ("", "")
@@ -166,12 +173,12 @@ let generate_native_header base_ctx tcpp_class =
 
   gen_class_header ctx tcpp_class h_file scriptable (if super = "" then [] else [ (Printf.sprintf "public %s" parent) ]);
       
-  CppGen.generate_native_constructor ctx output_h class_def true;
+  CppGen.generate_native_constructor ctx output_h tcpp_class true;
 
   if has_tcpp_class_flag tcpp_class Boot then output_h "\t\tstatic void __boot();\n";
 
   tcpp_class.tcl_static_variables
-  |> List.iter (gen_member_variable ctx class_def true);
+  |> List.iter (gen_member_variable ctx true);
 
   tcpp_class.tcl_static_functions
   |> List.iter (gen_member_function ctx class_def true);
@@ -180,7 +187,7 @@ let generate_native_header base_ctx tcpp_class =
   |> List.iter (gen_dynamic_function ctx class_def true);
 
   tcpp_class.tcl_variables
-  |> List.iter (gen_member_variable ctx class_def false);
+  |> List.iter (gen_member_variable ctx false);
 
   tcpp_class.tcl_functions
   |> List.iter (gen_member_function ctx class_def false);
@@ -209,7 +216,7 @@ let generate_managed_header base_ctx tcpp_class =
   let gcName = gen_gc_name class_def.cl_path in
 
   let constructor_type_args =
-    tcpp_class.tcl_class
+    tcpp_class
       |> constructor_arg_var_list
       |> List.map (fun (t, a) -> Printf.sprintf "%s %s" t a)
       |> String.concat "," in
@@ -221,7 +228,7 @@ let generate_managed_header base_ctx tcpp_class =
   let parent, super =
     match tcpp_class.tcl_super with
     | Some super ->
-        let name = tcpp_to_string_suffix "_obj" (cpp_instance_type super.tcl_class super.tcl_params) in
+        let name = tcpp_to_string_suffix "_obj" (cpp_instance_type super.tcl_class super.tcl_params CppRetyper.with_stack_value_type) in
         ( name, name )
     | None -> ("::hx::Object", "::hx::Object")
   in
@@ -304,13 +311,13 @@ let generate_managed_header base_ctx tcpp_class =
     tcpp_class.tcl_native_interfaces
     |> CppGen.needed_interface_functions tcpp_class.tcl_functions
     |> List.iter (fun func ->
-      let retVal   = type_to_string func.iff_return in
+      let retVal   = tcpp_to_string func.iff_return in
       let ret      = if retVal = "void" then "" else "return " in
-      let argNames = List.map (fun (name, _, _) -> name) func.iff_args in
+      let argNames = print_arg_names func.iff_args in
       output_h
-        ("\t\t" ^ retVal ^ " " ^ func.iff_name ^ "( " ^ print_tfun_arg_list true func.iff_args ^ ") {\n");
+        ("\t\t" ^ retVal ^ " " ^ func.iff_name ^ "( " ^ print_retyped_tfun_arg_list true func.iff_args ^ ") {\n");
       output_h
-        ("\t\t\t" ^ ret ^ "super::" ^ func.iff_name ^ "( " ^ String.concat "," argNames ^ ");\n\t\t}\n"));
+        ("\t\t\t" ^ ret ^ "super::" ^ func.iff_name ^ "( " ^ argNames ^ ");\n\t\t}\n"));
 
     output_h "\n");
 
@@ -321,7 +328,7 @@ let generate_managed_header base_ctx tcpp_class =
     let alreadyGlued = Hashtbl.create 0 in
     List.iter
       (fun src ->
-        let rec check_interface (interface:tcpp_interface) =
+        let rec check_interface interface =
           let check_field func =
             let cast = cpp_tfun_signature false func.iff_args func.iff_return in
             let class_implementation = find_class_implementation func tcpp_class
@@ -341,8 +348,8 @@ let generate_managed_header base_ctx tcpp_class =
               let glue = Printf.sprintf "%s_%08lx" func.iff_field.cf_name (gen_hash32 0 cast) in
               if not (Hashtbl.mem alreadyGlued castKey) then (
                 Hashtbl.replace alreadyGlued castKey ();
-                let argList = print_tfun_arg_list true func.iff_args in
-                let returnType = type_to_string func.iff_return in
+                let argList = print_retyped_tfun_arg_list true func.iff_args in
+                let returnType = tcpp_to_string func.iff_return in
                 let headerCode = "\t\t" ^ returnType ^ " " ^ glue ^ "(" ^ argList ^ ");\n" in
                 output_h headerCode;
                 output_h "\n")
@@ -368,7 +375,7 @@ let generate_managed_header base_ctx tcpp_class =
   |> List.iter (gen_dynamic_function ctx class_def true);
 
   tcpp_class.tcl_static_variables
-  |> List.iter (gen_member_variable ctx class_def true);
+  |> List.iter (gen_member_variable ctx true);
 
   tcpp_class.tcl_functions
   |> List.iter (gen_member_function ctx class_def false);
@@ -377,7 +384,7 @@ let generate_managed_header base_ctx tcpp_class =
   |> List.iter (gen_dynamic_function ctx class_def false);
 
   tcpp_class.tcl_variables
-  |> List.iter (fun field -> gen_member_variable ctx class_def false field);
+  |> List.iter (fun field -> gen_member_variable ctx false field);
 
   output_h (get_class_code class_def Meta.HeaderClassCode);
   output_h "};\n\n";

+ 163 - 129
src/generators/cpp/gen/cppGenClassImplementation.ml

@@ -1,6 +1,5 @@
 open Ast
 open Type
-open Error
 open Globals
 open CppStrings
 open CppTypeUtils
@@ -11,22 +10,27 @@ open CppContext
 open CppGen
 
 let gen_function ctx class_def class_name is_static func =
-  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 ret             = if is_void then "(void)" else "return " in
+  let output      = ctx.ctx_output in
+  let return_type = cpp_type_of func.tcf_func.tf_type in
+
+  let ret, is_void, return_type_str =
+    match return_type with
+    | TCppVoid ->
+      "(void)", true, "void"
+    | other ->
+      "return ", false, tcpp_to_string other in
   let needsWrapper t =
     match t with
-    | TCppStar _ -> true
+    | TCppStar _
+    | TCppMarshalNativeType (_, (Stack | Promoted)) -> true
     | TCppInst (t, _) -> Meta.has Meta.StructAccess t.cl_meta
     | _ -> false
   in
 
   (* The actual function definition *)
-  output (if is_void then "void" else return_type_str);
+  output return_type_str;
   output (" " ^ class_name ^ "::" ^ func.tcf_name ^ "(");
-  output (print_arg_list func.tcf_func.tf_args "__o_");
+  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
@@ -37,20 +41,20 @@ let gen_function ctx class_def class_name is_static func =
     output " {\n";
     output
       ("\t" ^ ret ^ "::" ^ nativeImpl ^ "("
-      ^ print_arg_list_name func.tcf_func.tf_args "__o_"
+      ^ print_arg_list_name func.tcf_args "__o_"
       ^ ");\n");
     output "}\n\n"
   | _ ->
     with_debug
       ctx
       func.tcf_field.cf_meta
-      (gen_cpp_function_body ctx class_def is_static func.tcf_field.cf_name func.tcf_func code tail_code);
+      (gen_cpp_function_body ctx class_def is_static func.tcf_field.cf_name func code tail_code);
 
     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, _) -> cpp_type_of v.v_type) func.tcf_func.tf_args in
+      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 (
@@ -66,11 +70,14 @@ let gen_function ctx class_def class_name is_static func =
         output ") {\n\t";
         (if not is_void then
             match return_type with
-            | TCppStar _ -> output "return (cpp::Pointer<const void *>) "
-            | TCppInst (t, _) when Meta.has Meta.StructAccess t.cl_meta
-              ->
-                output ("return (cpp::Struct< " ^ tcpp_to_string return_type ^ " >) ")
-            | _ -> output "return ");
+            | TCppStar _ ->
+              output "return (cpp::Pointer<const void *>) "
+            | 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 ^ "(")
@@ -80,9 +87,11 @@ let gen_function ctx class_def class_name is_static func =
         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
+            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
 
@@ -109,28 +118,28 @@ let gen_function ctx class_def class_name is_static func =
         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:tcpp_class_function) =
+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_str = type_to_string func.tcf_func.tf_type in
-  let return_type = cpp_type_of func.tcf_func.tf_type 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
 
   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)" return_type_str (print_arg_list func.tcf_func.tf_args "__o_") |> 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.tcf_func "" "" no_debug;
+  gen_cpp_function_body ctx class_def is_static func_name func "" "" no_debug;
 
   output ("HX_END_LOCAL_FUNC" ^ nargs ^ "(" ^ ret ^ ")\n");
   output "HX_END_DEFAULT_FUNC\n\n"
 
-let gen_static_variable ctx class_def class_name (var:tcpp_class_variable) =
-  let output = ctx.ctx_output in
-  Printf.sprintf "%s %s::%s;\n\n" (type_to_string var.tcv_type) class_name var.tcv_name |> output
+let gen_static_variable ctx class_def class_name 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
 
 let gen_dynamic_function_init ctx class_def func =
   match func.tcf_field.cf_expr with
@@ -139,14 +148,18 @@ let gen_dynamic_function_init ctx class_def func =
   | _ ->
     ()
 
-let gen_var_init ctx class_def var =
-  match var.tcv_field.cf_expr with
-  | Some expr ->
-    gen_cpp_init ctx (join_class_path class_def.cl_path ".") "boot" (var.tcv_name ^ " = ") expr
-  | _ -> ()
-
 let gen_boot_field ctx output_cpp tcpp_class =
   if has_tcpp_class_flag tcpp_class Boot then (
+    let gen_var_init ctx class_def var =
+      match var.tcv_field.cf_expr with
+      | Some expr ->
+        let dst = Builder.make_static_field class_def var.tcv_field var.tcv_field.cf_pos in
+        let op  = Builder.binop OpAssign dst expr expr.etype expr.epos in
+        
+        gen_cpp_init ctx (join_class_path class_def.cl_path ".") "boot" "" op
+      | _ -> ()
+    in
+
     output_cpp ("void " ^ tcpp_class.tcl_name ^ "::__boot()\n{\n");
 
     let dot_name = join_class_path tcpp_class.tcl_class.cl_path "." in
@@ -273,8 +286,8 @@ let generate_native_class base_ctx tcpp_class =
   output_cpp "\n";
 
   gen_dynamic_function_allocator ctx output_cpp tcpp_class;
-
-  generate_native_constructor ctx output_cpp class_def false;
+  
+  generate_native_constructor ctx output_cpp tcpp_class false;
   gen_boot_field ctx output_cpp tcpp_class;
 
   end_namespace output_cpp class_path;
@@ -296,7 +309,7 @@ let generate_managed_class base_ctx tcpp_class =
   let class_super_name =
     match class_def.cl_super with
     | Some (klass, params) ->
-        tcpp_to_string_suffix "_obj" (cpp_instance_type klass params)
+        tcpp_to_string_suffix "_obj" (cpp_instance_type klass params CppRetyper.with_stack_value_type)
     | _ -> ""
   in
 
@@ -323,7 +336,7 @@ let generate_managed_class base_ctx tcpp_class =
   output_cpp (get_class_code class_def Meta.CppNamespaceCode);
 
   let class_name = tcpp_class.tcl_name in
-  let cargs = constructor_arg_var_list class_def in
+  let cargs = constructor_arg_var_list tcpp_class in
   let constructor_var_list = List.map snd cargs in
   let constructor_type_args =
     cargs
@@ -332,13 +345,14 @@ let generate_managed_class base_ctx tcpp_class =
 
   output_cpp
     ("void " ^ class_name ^ "::__construct(" ^ constructor_type_args ^ ")");
-  (match class_def.cl_constructor with
-  | Some ({ cf_expr = Some { eexpr = TFunction function_def } } as definition)
-    ->
-      with_debug ctx definition.cf_meta (fun no_debug ->
-          gen_cpp_function_body ctx class_def false "new" function_def "" ""
-            no_debug;
-          output_cpp "\n")
+  (match tcpp_class.tcl_constructor with
+  | Some constructor ->
+    let cb no_debug =
+      gen_cpp_function_body ctx class_def false "new" constructor "" ""
+      no_debug;
+      output_cpp "\n"
+    in
+    with_debug ctx constructor.tcf_field.cf_meta cb
   | _ -> output_cpp " { }\n\n");
 
   (* Destructor goes in the cpp file so we can "see" the full definition of the member vars *)
@@ -420,8 +434,8 @@ let generate_managed_class base_ctx tcpp_class =
               if StringMap.mem cast_key glued then
                 glued
               else
-                let arg_list    = print_tfun_arg_list true func.iff_args in
-                let return_type = type_to_string func.iff_return in
+                let arg_list    = print_retyped_tfun_arg_list true func.iff_args in
+                let return_type = tcpp_to_string func.iff_return in
                 let return_str  = if return_type = "void" then "" else "return " in
                 let cpp_code    =
                   Printf.sprintf
@@ -512,7 +526,7 @@ let generate_managed_class base_ctx tcpp_class =
     let rec find_next_super_iteration cls =
       match cls.tcl_super with
       | Some ({ tcl_container = Some Current } as super) ->
-        Some (tcpp_to_string_suffix "_obj" (cpp_instance_type super.tcl_class super.tcl_params))
+        Some (tcpp_to_string_suffix "_obj" (cpp_instance_type super.tcl_class super.tcl_params CppRetyper.with_stack_value_type))
       | Some super ->
         find_next_super_iteration super
       | None ->
@@ -573,7 +587,7 @@ let generate_managed_class base_ctx tcpp_class =
   in
 
   let get_wrapper field value =
-    match cpp_type_of field.cf_type with
+    match CppRetyper.cpp_type_of CppRetyper.with_promoted_value_type field.cf_type with
     | TCppInst (t, _) as inst when Meta.has Meta.StructAccess t.cl_meta ->
       Printf.sprintf "(::cpp::Struct< %s >) %s" (tcpp_to_string inst) value
     | TCppStar _ ->
@@ -617,11 +631,13 @@ let generate_managed_class base_ctx tcpp_class =
   in
 
   let castable f =
-    match cpp_type_of f.cf_type with
+    match CppRetyper.cpp_type_of CppRetyper.with_promoted_value_type f.cf_type with
     | TCppInst (t, _) as inst when Meta.has Meta.StructAccess t.cl_meta ->
-        "cpp::Struct< " ^ tcpp_to_string inst ^ " > "
-    | TCppStar (t, _) -> "cpp::Pointer< " ^ tcpp_to_string t ^ " >"
-    | _ -> type_to_string f.cf_type
+      "cpp::Struct< " ^ tcpp_to_string inst ^ " > "
+    | TCppStar (t, _) ->
+      "cpp::Pointer< " ^ tcpp_to_string t ^ " >"
+    | other ->
+      tcpp_to_string other
   in
 
   if has_tcpp_class_flag tcpp_class MemberGet then (
@@ -831,92 +847,110 @@ let generate_managed_class base_ctx tcpp_class =
     output_cpp "#endif\n\n");
 
   let generate_script_function isStatic field scriptName callName =
-    match follow field.cf_type with
-    | TFun (args, return_type) when not (is_data_member field) ->
-        let isTemplated = not isStatic in
-        if isTemplated then output_cpp "\ntemplate<bool _HX_SUPER=false>";
-        output_cpp
-          ("\nstatic void CPPIA_CALL " ^ scriptName
-          ^ "(::hx::CppiaCtx *ctx) {\n");
-        let ret =
-          match cpp_type_of return_type with
-          | TCppScalar "bool" -> "b"
-          | _ -> CppCppia.script_signature return_type false
-        in
-        if ret <> "v" then
-          output_cpp
-            ("ctx->return" ^ CppCppia.script_type return_type false ^ "(");
+    let isTemplated = not isStatic in
+    if isTemplated then output_cpp "\ntemplate<bool _HX_SUPER=false>";
+    output_cpp
+      ("\nstatic void CPPIA_CALL " ^ scriptName
+      ^ "(::hx::CppiaCtx *ctx) {\n");
 
-        let dump_call cast =
-          if isStatic then
-            output_cpp (class_name ^ "::" ^ callName ^ "(")
-          else
-            output_cpp
-              ("((" ^ class_name ^ "*)ctx->getThis())->" ^ cast ^ callName ^ "(");
-
-          let signature, _, _ =
-            List.fold_left
-              (fun (signature, sep, size) (_, opt, t) ->
-                output_cpp
-                  (sep ^ "ctx->get" ^ CppCppia.script_type t opt ^ "(" ^ size
-                  ^ ")");
-                ( signature ^ CppCppia.script_signature t opt,
-                  ",",
-                  size ^ "+sizeof(" ^ CppCppia.script_size_type t opt ^ ")" ))
-              (ret, "", "sizeof(void*)") args
-          in
-          output_cpp ")";
-          signature
-        in
-        let signature =
-          if isTemplated then (
-            output_cpp " _HX_SUPER ? ";
-            ignore (dump_call (class_name ^ "::"));
-            output_cpp " : ";
-            dump_call "")
-          else dump_call ""
+    let script_return_type = CppCppia.to_script_type field.tcf_return in
+
+    (match field.tcf_return with
+    | TCppVoid ->
+      ()
+    | TCppMarshalNativeType (native_type, _) ->
+      Printf.sprintf "ctx->return%s(%s(" (CppCppia.to_script_type_string script_return_type) (TCppMarshalNativeType (native_type, Reference) |> tcpp_to_string) |> output_cpp
+    | _ ->
+      Printf.sprintf "ctx->return%s(" (CppCppia.to_script_type_string script_return_type) |> output_cpp);
+
+    let dump_call cast =
+      if isStatic then
+        Printf.sprintf "%s::%s(" class_name callName |> output_cpp
+      else
+        Printf.sprintf "((%s*)ctx->getThis())->%s%s(" class_name cast callName |> output_cpp;
+
+      let folder (signature, sep, size) (var, expr) =
+        let script_type =
+          match CppCppia.to_script_type var.tcppv_type with
+          | (CppCppia.ScriptInt | CppCppia.ScriptFloat | CppCppia.ScriptBool) when expr <> None -> CppCppia.ScriptObject
+          | other -> other
         in
+        Printf.sprintf "%sctx->get%s(%s)" sep (CppCppia.to_script_type_string script_type) size |> output_cpp;
+        signature ^ CppCppia.to_script_type_signature script_type,
+        ",",
+        size ^ "+sizeof(" ^ CppCppia.to_script_type_size script_type ^ ")"
+      in
+      let signature, _, _ =
+        List.fold_left folder (CppCppia.to_script_type_signature script_return_type, "", "sizeof(void*)") field.tcf_args
+      in
+      output_cpp ")";
+      signature
+    in
+    let signature =
+      if isTemplated then (
+        output_cpp " _HX_SUPER ? ";
+        ignore (dump_call (class_name ^ "::"));
+        output_cpp " : ";
+        dump_call "")
+      else dump_call ""
+    in
 
-        if ret <> "v" then output_cpp ")";
-        output_cpp ";\n}\n";
-        signature
-    | _ -> ""
+    (match field.tcf_return with
+    | TCppVoid ->
+      ()
+    | TCppMarshalNativeType (native_type, _) ->
+      output_cpp "))"
+    | _ ->
+      output_cpp ")");
+    output_cpp ";\n}\n";
+    signature
   in
 
   if scriptable then (
     let dump_script_func idx func =
-      match func.tcf_field.cf_type with
-      | TFun (f_args, _) ->
-        let args = print_tfun_arg_list true f_args in
-        let return_type = type_to_string func.tcf_func.tf_type in
-        let ret = if return_type = "Void" || return_type = "void" then " " else "return " in
-        let vtable = Printf.sprintf "__scriptVTable[%i]" (idx + 1) in
-
-        Printf.sprintf "\t%s %s(%s) {\n" return_type func.tcf_name args |> output_cpp;
-        Printf.sprintf ("\tif (%s) {\n") vtable |> output_cpp;
-        output_cpp "\t\t::hx::CppiaCtx *__ctx = ::hx::CppiaCtx::getCurrent();\n";
-        output_cpp "\t\t::hx::AutoStack __as(__ctx);\n";
-        output_cpp ("\t\t__ctx->pushObject( this );\n");
-
-        List.iter
-          (fun (name, opt, t) ->
-            Printf.sprintf "\t\t__ctx->push%s(%s);\n" (CppCppia.script_type t opt) (keyword_remap name) |> output_cpp)
-        f_args;
+      let args        = print_arg_list func.tcf_args "" in
+      let return_type = tcpp_to_string func.tcf_return in
+      let ret         = if return_type = "Void" || return_type = "void" then " " else "return " in
+      let vtable      = Printf.sprintf "__scriptVTable[%i]" (idx + 1) in
+
+      Printf.sprintf "\t%s %s(%s) {\n" return_type func.tcf_name args |> output_cpp;
+      Printf.sprintf ("\tif (%s) {\n") vtable |> output_cpp;
+      output_cpp "\t\t::hx::CppiaCtx *__ctx = ::hx::CppiaCtx::getCurrent();\n";
+      output_cpp "\t\t::hx::AutoStack __as(__ctx);\n";
+      output_cpp ("\t\t__ctx->pushObject( this );\n");
+
+      let wrap var =
+        match var.tcppv_type with
+        | TCppMarshalNativeType (native_type, _) ->
+          Printf.sprintf "%s(%s)" (tcpp_to_string (TCppMarshalNativeType (native_type, Reference))) var.tcppv_name
+        | _ ->
+          var.tcppv_name
+      in
 
-        output_cpp
-          ("\t\t" ^ ret ^ "__ctx->run" ^ CppCppia.script_type func.tcf_func.tf_type false ^ "(" ^ vtable ^ ");\n");
-        output_cpp ("\t}  else " ^ ret);
+      func.tcf_args
+      |> List.map
+        (fun (var, expr) ->
+          let script_type =
+            match CppCppia.to_script_type var.tcppv_type with
+            | (CppCppia.ScriptInt | CppCppia.ScriptFloat | CppCppia.ScriptBool) when expr <> None -> CppCppia.ScriptObject
+            | other -> other
+          in
+          Printf.sprintf "\t\t__ctx->push%s(%s);" (CppCppia.to_script_type_string script_type) (wrap var))
+      |> String.concat "\n"
+      |> output_cpp;
 
-        let names = List.map (fun (n, _, _) -> keyword_remap n) f_args in
+      output_cpp "\n";
+      output_cpp ("\t\t" ^ ret ^ "__ctx->run" ^ (func.tcf_return |> CppCppia.to_script_type |> CppCppia.to_script_type_string) ^ "(" ^ vtable ^ ");\n");
+      output_cpp ("\t}  else " ^ ret);
 
-        output_cpp
-          (class_name ^ "::" ^ func.tcf_name ^ "(" ^ String.concat "," names ^ ");");
+      let names = List.map (fun (var, _) -> wrap var) func.tcf_args in
+
+      output_cpp
+        (class_name ^ "::" ^ func.tcf_name ^ "(" ^ String.concat "," names ^ ");");
 
-        if return_type <> "void" then output_cpp "return null();";
+      if return_type <> "void" then output_cpp "return null();";
 
-        output_cpp "}\n";
-      | _ ->
-        abort "expected function type to be tfun" func.tcf_field.cf_pos
+      output_cpp "}\n"
     in
 
     let script_name = class_name ^ "__scriptable" in
@@ -978,7 +1012,7 @@ let generate_managed_class base_ctx tcpp_class =
 
       let dump_script is_static f acc =
         if not f.tcf_is_overriding && f.tcf_name <> "toString" then (* toString implicitly overrides hx::Object::toString *)
-          let signature = generate_script_function is_static f.tcf_field ("__s_" ^ f.tcf_field.cf_name) f.tcf_name in
+          let signature = generate_script_function is_static f ("__s_" ^ f.tcf_field.cf_name) f.tcf_name in
           let superCall = if is_static then "0" else "__s_" ^ f.tcf_field.cf_name ^ "<true>" in
           let named =
             Printf.sprintf
@@ -1013,10 +1047,10 @@ let generate_managed_class base_ctx tcpp_class =
   (* Remap the specialised "extern" classes back to the generic names *)
   output_cpp ("::hx::Class " ^ class_name ^ "::__mClass;\n\n");
   (if scriptable then
-      match class_def.cl_constructor with
-      | Some field ->
+      match tcpp_class.tcl_constructor with
+      | Some f ->
           let signature =
-            generate_script_function false field "__script_construct_func"
+            generate_script_function false f "__script_construct_func"
               "__construct"
           in
           output_cpp

+ 11 - 11
src/generators/cpp/gen/cppGenEnum.ml

@@ -12,17 +12,17 @@ let constructor_arg_count constructor =
   | _ -> 0
 
 let gen_enum_constructor remap_class_name class_name output_cpp constructor =
-  match constructor.tef_field.ef_type with
-  | TFun (args, _) ->
-    Printf.sprintf "%s %s::%s(%s)\n" remap_class_name class_name constructor.tef_name (print_tfun_arg_list true args) |> output_cpp;
+  match constructor.tef_args with
+  | Some args ->
+    Printf.sprintf "%s %s::%s(%s)\n" remap_class_name class_name constructor.tef_name (print_retyped_tfun_arg_list true args) |> output_cpp;
     Printf.sprintf "{\n\treturn ::hx::CreateEnum<%s>(%s,%i,%i)" class_name constructor.tef_hash constructor.tef_field.ef_index (List.length args) |> output_cpp;
 
     args
-      |> List.mapi (fun i (arg, _, _) -> Printf.sprintf "->_hx_init(%i,%s)" i (keyword_remap arg))
+      |> List.mapi (fun i arg -> Printf.sprintf "->_hx_init(%i,%s)" i arg.tfa_name)
       |> List.iter output_cpp;
 
     output_cpp ";\n}\n\n"
-  | _ ->
+  | None ->
     output_cpp ( remap_class_name ^ " " ^ class_name ^ "::" ^ constructor.tef_name ^ ";\n\n" )
 
 let gen_static_reflection class_name output_cpp constructor =
@@ -133,10 +133,10 @@ let generate base_ctx tcpp_enum =
 
   List.iter
     (fun constructor ->
-      match constructor.tef_field.ef_type with
-      | TFun (_,_) ->
+      match constructor.tef_args with
+      | Some _ ->
         ()
-      | _ ->
+      | None ->
         Printf.sprintf "%s = ::hx::CreateConstEnum<%s>(%s, %i);\n" constructor.tef_name class_name constructor.tef_hash constructor.tef_field.ef_index |> output_cpp)
     tcpp_enum.te_constructors;
 
@@ -177,9 +177,9 @@ let generate base_ctx tcpp_enum =
   List.iter
     (fun constructor ->
       Printf.sprintf "\t\tstatic %s %s" remap_class_name constructor.tef_name |> output_h;
-      match constructor.tef_field.ef_type with
-      | TFun (args,_) ->
-        Printf.sprintf "(%s);\n" (print_tfun_arg_list true args) |> output_h;
+      match constructor.tef_args with
+      | Some args ->
+        Printf.sprintf "(%s);\n" (print_retyped_tfun_arg_list true args) |> output_h;
         Printf.sprintf "\t\tstatic ::Dynamic %s_dyn();\n" constructor.tef_name |> output_h;
       | _ ->
         output_h ";\n";

+ 11 - 8
src/generators/cpp/gen/cppGenInterfaceHeader.ml

@@ -15,10 +15,10 @@ let attribs common_ctx = match Gctx.defined common_ctx Define.DllExport with
 
 let gen_native_function ctx interface func =
   let output   = ctx.ctx_output in
-  let gen_args = print_tfun_arg_list true in
+  let gen_args = print_retyped_tfun_arg_list true in
   let strq     = strq ctx.ctx_common in
 
-  Printf.sprintf "\t\tvirtual %s %s(%s)=0;\n" (type_to_string func.iff_return) func.iff_name (gen_args func.iff_args) |> output;
+  Printf.sprintf "\t\tvirtual %s %s(%s)=0;\n" (tcpp_to_string func.iff_return) func.iff_name (gen_args func.iff_args) |> output;
   if reflective interface.if_class func.iff_field then
     if Gctx.defined ctx.ctx_common Define.DynamicInterfaceClosures then
       Printf.sprintf
@@ -30,8 +30,13 @@ let gen_native_function ctx interface func =
 
 let gen_function ctx interface func =
   let output       = ctx.ctx_output in
-  let argList      = print_tfun_arg_list true func.iff_args in
-  let returnType   = type_to_string func.iff_return in
+  let argList      = print_retyped_tfun_arg_list true func.iff_args in
+  let returnType   = match func.iff_return with
+  | TCppMarshalNativeType (value_type, (Reference | Promoted)) ->
+    TCppMarshalNativeType (value_type, Stack) |> tcpp_to_string
+  | 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
@@ -103,7 +108,7 @@ let generate_native_interface base_ctx tcpp_interface =
   let parent, super =
     match tcpp_interface.if_class.cl_super with
     | Some (klass, params) ->
-      let name = tcpp_to_string_suffix "_obj" (cpp_instance_type klass params) in
+      let name = tcpp_to_string_suffix "_obj" (cpp_instance_type klass params CppRetyper.with_stack_value_type) in
       ( "virtual " ^ name, name )
     | None ->
       ("virtual ::hx::NativeInterface", "::hx::NativeInterface")
@@ -134,8 +139,6 @@ let generate_native_interface base_ctx tcpp_interface =
   output_h ("\t\ttypedef " ^ super ^ " super;\n");
   output_h ("\t\ttypedef " ^ tcpp_interface.if_name ^ " OBJ_;\n");
 
-  CppGen.generate_native_constructor ctx output_h tcpp_interface.if_class true;
-
   gen_body tcpp_interface ctx output_h (gen_native_function ctx tcpp_interface);
   
   output_h "};\n\n";
@@ -152,7 +155,7 @@ let generate_managed_interface base_ctx tcpp_interface =
   let super =
     match tcpp_interface.if_class.cl_super with
     | Some (klass, params) ->
-      tcpp_to_string_suffix "_obj" (cpp_instance_type klass params)
+      tcpp_to_string_suffix "_obj" (cpp_instance_type klass params CppRetyper.with_stack_value_type)
     | None ->
       "::hx::Object"
   in

+ 49 - 26
src/generators/cpp/gen/cppGenInterfaceImplementation.ml

@@ -31,35 +31,35 @@ let generate_protocol_delegate ctx protocol full_class_name functions output =
   output "}\n\n";
 
   let dump_delegate func =
-    let retStr = type_to_string func.iff_return in
+    let retStr = tcpp_to_string func.iff_return in
     let fieldName, argNames =
       match get_meta_string func.iff_field.cf_meta Meta.ObjcProtocol with
       | Some nativeName ->
         let parts = ExtString.String.nsplit nativeName ":" in
         (List.hd parts, parts)
-      | None -> (func.iff_field.cf_name, List.map (fun (n, _, _) -> n) func.iff_args)
+      | None -> (func.iff_name, List.map (fun a -> a.tfa_name) func.iff_args)
     in
     output ("- (" ^ retStr ^ ") " ^ fieldName);
 
     let first = ref true in
     (try
         List.iter2
-          (fun (name, _, argType) signature_name ->
+          (fun arg signature_name ->
             if !first then
-              output (" :(" ^ type_to_string argType ^ ")" ^ name)
+              output (" :(" ^ tcpp_to_string arg.tfa_type ^ ")" ^ name)
             else
               output
-                (" " ^ signature_name ^ ":(" ^ type_to_string argType ^ ")"
+                (" " ^ signature_name ^ ":(" ^ tcpp_to_string arg.tfa_type ^ ")"
               ^ name);
             first := false)
           func.iff_args argNames
       with Invalid_argument _ ->
         abort
           (let argString =
-            String.concat "," (List.map (fun (name, _, _) -> name) func.iff_args)
+            String.concat "," (List.map (fun arg -> arg.tfa_name) func.iff_args)
           in
-          "Invalid arg count in delegate in " ^ func.iff_field.cf_name ^ " '"
-          ^ func.iff_field.cf_name ^ "," ^ argString ^ "' != '"
+          "Invalid arg count in delegate in " ^ func.iff_name ^ " '"
+          ^ func.iff_name ^ "," ^ argString ^ "' != '"
           ^ String.concat "," argNames ^ "'")
           func.iff_field.cf_pos);
     output " {\n";
@@ -69,7 +69,7 @@ let generate_protocol_delegate ctx protocol full_class_name functions output =
       ^ full_class_name ^ "::"
       ^ func.iff_name
       ^ "(haxeObj");
-    List.iter (fun (name, _, _) -> output ("," ^ name)) func.iff_args;
+    List.iter (fun arg -> output ("," ^ arg.tfa_name)) func.iff_args;
     output ");\n}\n\n"
   in
   List.iter dump_delegate functions;
@@ -134,8 +134,8 @@ let generate_managed_interface base_ctx tcpp_interface =
 
   if tcpp_interface.if_scriptable then (
     let dump_script_field idx func =
-      let args = print_tfun_arg_list true func.iff_args in
-      let return_type = type_to_string func.iff_return in
+      let args = print_retyped_tfun_arg_list true func.iff_args in
+      let return_type = tcpp_to_string func.iff_return in
       let ret = if return_type = "Void" || return_type = "void" then " " else "return " in
 
       output_cpp ("\t" ^ return_type ^ " " ^ func.iff_name ^ "( " ^ args ^ " ) {\n");
@@ -143,14 +143,18 @@ let generate_managed_interface base_ctx tcpp_interface =
       output_cpp "\t\t::hx::AutoStack __as(__ctx);\n";
       output_cpp "\t\t__ctx->pushObject(this);\n";
       List.iter
-        (fun (name, opt, t) ->
-          output_cpp
-            ("\t\t__ctx->push" ^ CppCppia.script_type t opt ^ "(" ^ name ^ ");\n"))
+        (fun arg ->
+          let script_type =
+            match arg.tfa_type |> CppCppia.to_script_type with
+            | (CppCppia.ScriptInt | CppCppia.ScriptFloat | CppCppia.ScriptBool) when arg.tfa_optional -> CppCppia.ScriptObject
+            | other -> other
+          in
+          Printf.sprintf "\t\t__ctx->push%s(%s);\n" (CppCppia.to_script_type_string script_type) arg.tfa_name |> output_cpp)
         func.iff_args;
       let interfaceSlot = string_of_int (func.iff_script_slot |> Option.map (fun v -> -v) |>  Option.default 0) in
       output_cpp
         ("\t\t" ^ ret ^ "__ctx->run"
-        ^ CppCppia.script_type func.iff_return false
+        ^ (func.iff_return |> CppCppia.to_script_type |> CppCppia.to_script_type_string)
         ^ "(__GetScriptVTable()[" ^ interfaceSlot ^ "]);\n");
       output_cpp "\t}\n";
     in
@@ -167,27 +171,46 @@ let generate_managed_interface base_ctx tcpp_interface =
       let scriptName = ("__s_" ^ func.iff_field.cf_name) in
 
       output_cpp ("\nstatic void CPPIA_CALL " ^ scriptName ^ "(::hx::CppiaCtx *ctx) {\n");
-      let ret =
-        match cpp_type_of func.iff_return with
-        | TCppScalar "bool" -> "b"
-        | _ -> CppCppia.script_signature func.iff_return false in
-      if ret <> "v" then
-        output_cpp ("ctx->return" ^ CppCppia.script_type func.iff_return false ^ "(");
+
+      let script_return_type = CppCppia.to_script_type func.iff_return in
+
+      (match func.iff_return with
+      | TCppVoid ->
+        ()
+      | TCppMarshalNativeType (native_type, _) ->
+        Printf.sprintf "ctx->return%s(%s(" (CppCppia.to_script_type_string script_return_type) (TCppMarshalNativeType (native_type, Reference) |> tcpp_to_string) |> output_cpp
+      | _ ->
+        Printf.sprintf "ctx->return%s(" (CppCppia.to_script_type_string script_return_type) |> output_cpp);
 
       let signature =
         output_cpp (tcpp_interface.if_name ^ "::" ^ func.iff_name ^ "(ctx->getThis()" ^ if List.length func.iff_args > 0 then "," else "");
 
+        let folder (signature, sep, size) arg =
+          let script_type =
+            match arg.tfa_type |> CppCppia.to_script_type with
+            | (CppCppia.ScriptInt | CppCppia.ScriptFloat | CppCppia.ScriptBool) when arg.tfa_optional -> CppCppia.ScriptObject
+            | other -> other
+          in
+          Printf.sprintf "%sctx->get%s(%s)" sep (CppCppia.to_script_type_string script_type) size |> output_cpp;
+          signature ^ CppCppia.to_script_type_signature script_type,
+          ",",
+          size ^ "+sizeof(" ^ CppCppia.to_script_type_size script_type ^ ")"
+        in
         let signature, _, _ =
           List.fold_left
-            (fun (signature, sep, size) (_, opt, t) ->
-              output_cpp (sep ^ "ctx->get" ^ CppCppia.script_type t opt ^ "(" ^ size ^ ")");
-              ( signature ^ CppCppia.script_signature t opt, ",", size ^ "+sizeof(" ^ CppCppia.script_size_type t opt ^ ")" ))
-            (ret, "", "sizeof(void*)") func.iff_args in
+            folder
+            (CppCppia.to_script_type_signature script_return_type, "", "sizeof(void*)") func.iff_args in
         output_cpp ")";
         signature
       in
 
-      if ret <> "v" then output_cpp ")";
+      (match func.iff_return with
+      | TCppVoid ->
+        ()
+      | TCppMarshalNativeType (native_type, _) ->
+        output_cpp "))"
+      | _ ->
+        output_cpp ")");
       output_cpp ";\n}\n";
       (signature, func)
     in

+ 19 - 4
src/generators/cpp/gen/cppReferences.ml

@@ -4,6 +4,7 @@ open CppStrings
 open CppTypeUtils
 open CppAstTools
 open CppContext
+open CppMarshalling
 
 (*
    Get a list of all classes referred to by the class/enum definition
@@ -70,6 +71,7 @@ let find_referenced_types_flags ctx obj filter super_deps constructor_deps heade
 
   let add_extern_class klass = add_extern_type (TClassDecl klass) in
   let add_extern_enum enum = add_extern_type (TEnumDecl enum) in
+  let add_extern_abstract abstract = add_extern_type (TAbstractDecl abstract) in
   let add_native_gen_class klass =
     let include_files =
       get_all_meta_string_path klass.cl_meta
@@ -87,9 +89,20 @@ let find_referenced_types_flags ctx obj filter super_deps constructor_deps heade
   in
   let visited = ref [] in
   let rec visit_type in_type =
+    let rec find_base t =
+      match TFunctions.follow t with
+      | TAbstract (a, _) as t when is_scalar_abstract a ->
+        t
+      | TAbstract ({ a_extern = true } as a, _) as t when is_marshalling_native_enum a ->
+        t
+      | TAbstract (a, tl) ->
+        find_base (Abstract.get_underlying_type a tl)
+      | other ->
+        follow other
+      in
     if not (List.exists (fun t2 -> Type.fast_eq in_type t2) !visited) then (
       visited := in_type :: !visited;
-      (match follow in_type with
+      (match find_base in_type with
       | TMono r -> ( match r.tm_type with None -> () | Some t -> visit_type t)
       | TEnum (enum, _) -> (
           match is_extern_enum enum with
@@ -116,8 +129,10 @@ let find_referenced_types_flags ctx obj filter super_deps constructor_deps heade
               match klass.cl_kind with
               | KTypeParameter _ -> ()
               | _ -> add_type klass.cl_path))
-      | TAbstract (a, params) when is_scalar_abstract a ->
-          add_extern_type (TAbstractDecl a)
+      | TAbstract (a, _) when is_scalar_abstract a ->
+          add_extern_abstract a
+      | TAbstract ({ a_extern = true } as a, _) when is_marshalling_native_enum a ->
+          add_extern_abstract a
       | TFun (args, haxe_type) ->
           visit_type haxe_type;
           List.iter (fun (_, _, t) -> visit_type t) args
@@ -171,7 +186,7 @@ let find_referenced_types_flags ctx obj filter super_deps constructor_deps heade
           | _ ->
               print_endline
                 ("TSuper : Odd etype ?"
-                ^ (CppRetyper.cpp_type_of expression.etype |> tcpp_to_string)))
+                ^ (CppRetyper.cpp_type_of CppRetyper.with_reference_value_type expression.etype |> tcpp_to_string)))
       | _ -> ());
       Type.iter visit_expression expression;
       visit_type (follow expression.etype)

+ 14 - 0
src/generators/gencpp.ml

@@ -27,6 +27,8 @@ open CppTypeUtils
 open CppAstTools
 open CppSourceWriter
 open CppContext
+open CppMarshalling
+open CppError
 
 let make_base_directory dir =
    Path.mkdir_recursive "" ( ( Str.split_delim (Str.regexp "[\\/]+") dir ) )
@@ -280,6 +282,10 @@ let generate_source ctx =
    } in
 
    let folder acc cur =
+      let no_semantics_meta pos =
+         cpp_abort MissingValueSemantics pos
+      in
+
       (if not (Gctx.defined common_ctx Define.Objc) then
          match cur with
          | TClassDecl class_def when Meta.has Meta.Objc class_def.cl_meta ->
@@ -287,7 +293,15 @@ let generate_source ctx =
          | _ -> ());
 
       match cur with
+      | TAbstractDecl abs when is_marshalling_native_enum abs && not (ExtType.has_value_semantics (TAbstract (abs, []))) ->
+         no_semantics_meta abs.a_pos
       | TClassDecl class_def when is_extern_class class_def ->
+         if (is_marshalling_native_value_class class_def || is_marshalling_native_pointer class_def) && not (ExtType.has_value_semantics (TInst (class_def, []))) then
+            no_semantics_meta class_def.cl_pos;
+
+         if is_marshalling_native_pointer class_def && class_def.cl_constructor |> Option.is_some then
+            cpp_abort PointerTypeConstructor class_def.cl_pos;
+
          let acc_build_xml  = acc.build_xml ^ (CppGen.get_class_code class_def Meta.BuildXml) in
          let acc_extern_src =
             match Ast.get_meta_string class_def.cl_meta Meta.SourceFile with

+ 25 - 0
std/cpp/Char16.hx

@@ -0,0 +1,25 @@
+/*
+ * Copyright (C)2005-2019 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+package cpp;
+
+@:coreType @:notNull @:runtimeValue @:defaultValue(0) abstract Char16 from Int to Int {}

+ 295 - 0
std/cpp/_std/haxe/io/Bytes.hx

@@ -0,0 +1,295 @@
+/*
+ * Copyright (C)2005-2019 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+package haxe.io;
+
+import cpp.NativeArray;
+import cpp.marshal.View;
+import haxe.iterators.StringIterator;
+
+using cpp.marshal.Marshal;
+using cpp.marshal.ViewExtensions;
+
+class Bytes {
+	public var length(default, null):Int;
+
+	final b:BytesData;
+
+	function new(length, b) {
+		this.length = length;
+		this.b      = b;
+	}
+
+	/**
+		Returns the byte at index `pos`.
+	**/
+	public function get(pos:Int):Int {
+		return this.asView().slice(pos).readUInt8();
+	}
+
+	/**
+		Stores the given byte `v` at the given position `pos`.
+	**/
+	public function set(pos:Int, v:Int):Void {
+		this.asView().slice(pos).writeUInt8(v);
+	}
+
+	/**
+		Copies `len` bytes from `src` into this instance.
+		@param pos Zero-based location in `this` instance at which to start writing
+			bytes.
+		@param src Source `Bytes` instance from which to copy bytes.
+		@param srcpos Zero-based location at `src` from which bytes will be copied.
+		@param len Number of bytes to be copied.
+	**/
+	public function blit(pos:Int, src:Bytes, srcpos:Int, len:Int):Void {
+		final srcView = src.asView().slice(srcpos, len);
+		final dstView = this.asView().slice(pos);
+
+		srcView.copyTo(dstView);
+	}
+
+	/**
+		Sets `len` consecutive bytes starting from index `pos` of `this` instance
+		to `value`.
+	**/
+	public function fill(pos:Int, len:Int, value:Int) {
+		this.asView().slice(pos, len).fill(value);
+	}
+
+	/**
+		Returns a new `Bytes` instance that contains a copy of `len` bytes of
+		`this` instance, starting at index `pos`.
+	**/
+	public function sub(pos:Int, len:Int):Bytes {
+		return this.asView().slice(pos, len).toBytes();
+	}
+
+	/**
+		Returns `0` if the bytes of `this` instance and the bytes of `other` are
+		identical.
+
+		Returns a negative value if the `length` of `this` instance is less than
+		the `length` of `other`, or a positive value if the `length` of `this`
+		instance is greater than the `length` of `other`.
+
+		In case of equal `length`s, returns a negative value if the first different
+		value in `other` is greater than the corresponding value in `this`
+		instance; otherwise returns a positive value.
+	**/
+	public function compare(other:Bytes):Int {
+		final fst = this.asView();
+		final snd = other.asView();
+
+		return fst.compare(snd);
+	}
+
+	/**
+		Returns the IEEE double-precision value at the given position `pos` (in
+		little-endian encoding). Result is unspecified if `pos` is outside the
+		bounds.
+	**/
+	public function getDouble(pos:Int):Float {
+		return this.asView().slice(pos).readFloat64();
+	}
+
+	/**
+		Returns the IEEE single-precision value at the given position `pos` (in
+		little-endian encoding). Result is unspecified if `pos` is outside the
+		bounds.
+	**/
+	public function getFloat(pos:Int):Float {
+		return this.asView().slice(pos).readFloat32();
+	}
+
+	/**
+		Stores the given IEEE double-precision value `v` at the given position
+		`pos` in little-endian encoding. Result is unspecified if writing outside
+		of bounds.
+	**/
+	public function setDouble(pos:Int, v:Float):Void {
+		this.asView().slice(pos).writeFloat64(v);
+	}
+
+	/**
+		Stores the given IEEE single-precision value `v` at the given position
+		`pos` in little-endian encoding. Result is unspecified if writing outside
+		of bounds.
+	**/
+	public function setFloat(pos:Int, v:Float):Void {
+		this.asView().slice(pos).writeFloat32(v);
+	}
+
+	/**
+		Returns the 16-bit unsigned integer at the given position `pos` (in
+		little-endian encoding).
+	**/
+	public function getUInt16(pos:Int):Int {
+		return this.asView().slice(pos).readUInt16();
+	}
+
+	/**
+		Stores the given 16-bit unsigned integer `v` at the given position `pos`
+		(in little-endian encoding).
+	**/
+	public function setUInt16(pos:Int, v:Int):Void {
+		this.asView().slice(pos).writeUInt16(v);
+	}
+
+	/**
+		Returns the 32-bit integer at the given position `pos` (in little-endian
+		encoding).
+	**/
+	public function getInt32(pos:Int):Int {
+		return this.asView().slice(pos).readInt32();
+	}
+
+	/**
+		Returns the 64-bit integer at the given position `pos` (in little-endian
+		encoding).
+	**/
+	public function getInt64(pos:Int):haxe.Int64 {
+		return this.asView().slice(pos).readInt64();
+	}
+
+	/**
+		Stores the given 32-bit integer `v` at the given position `pos` (in
+		little-endian encoding).
+	**/
+	public function setInt32(pos:Int, v:Int):Void {
+		this.asView().slice(pos).writeInt32(v);
+	}
+
+	/**
+		Stores the given 64-bit integer `v` at the given position `pos` (in
+		little-endian encoding).
+	**/
+	public function setInt64(pos:Int, v:haxe.Int64):Void {
+		this.asView().slice(pos).writeInt64(v);
+	}
+
+	/**
+		Returns the `len`-bytes long string stored at the given position `pos`,
+		interpreted with the given `encoding` (UTF-8 by default).
+	**/
+	public function getString(pos:Int, len:Int, ?encoding:Encoding):String {
+		final chars : View<cpp.Char> = this.asView().reinterpret();
+
+		return chars.slice(pos, len).toString();
+	}
+
+	@:deprecated("readString is deprecated, use getString instead")
+	@:noCompletion
+	public function readString(pos:Int, len:Int):String {
+		return getString(pos, len);
+	}
+
+	/**
+		Returns a `String` representation of the bytes interpreted as UTF-8.
+	**/
+	public function toString():String {
+		return getString(0, length);
+	}
+
+	/**
+		Returns a hexadecimal `String` representation of the bytes of `this`
+		instance.
+	**/
+	public function toHex():String {
+		static final chars = [ for (c in new StringIterator("0123456789abcdef")) c ];
+
+		final s = new StringBuf();
+
+		for (i in 0...length) {
+			final c = get(i);
+			s.addChar(chars[c >> 4]);
+			s.addChar(chars[c & 15]);
+		}
+
+		return s.toString();
+	}
+
+	/**
+		Returns the bytes of `this` instance as `BytesData`.
+	**/
+	public function getData():BytesData {
+		return b;
+	}
+
+	/**
+		Returns a new `Bytes` instance with the given `length`. The values of the
+		bytes are not initialized and may not be zero.
+	**/
+	public static function alloc(length:Int):Bytes {
+		return new Bytes(length, cpp.NativeArray.create(length));
+	}
+
+	/**
+		Returns the `Bytes` representation of the given `String`, using the
+		specified encoding (UTF-8 by default).
+	**/
+	@:pure
+	public static function ofString(s:String, ?encoding:Encoding):Bytes {
+		final chars = s.toCharView();
+
+		return chars.slice(0, chars.length - 1).asBytesView().toBytes();
+	}
+
+	/**
+		Returns the `Bytes` representation of the given `BytesData`.
+	**/
+	public static function ofData(b:BytesData) {
+		return new Bytes(b.length, b);
+	}
+
+	/**
+		Converts the given hexadecimal `String` to `Bytes`. `s` must be a string of
+		even length consisting only of hexadecimal digits. For example:
+		`"0FDA14058916052309"`.
+	**/
+	public static function ofHex(s:String):Bytes {
+		if ((s.length & 1) != 0) {
+			throw new haxe.exceptions.ArgumentException("s", "Not a hex string (odd number of digits)");
+		}
+
+		final output = Bytes.alloc(s.length >> 1);
+		for (i in 0...output.length) {
+			final highCode = StringTools.fastCodeAt(s, i * 2);
+			final lowCode  = StringTools.fastCodeAt(s, i * 2 + 1);
+			final high     = (highCode & 0xF) + ((highCode & 0x40) >> 6) * 9;
+			final low      = (lowCode & 0xF) + ((lowCode & 0x40) >> 6) * 9;
+
+			output.set(i, ((high << 4) | low) & 0xFF);
+		}
+
+		return output;
+	}
+
+	/**
+		Reads the `pos`-th byte of the given `b` bytes, in the most efficient way
+		possible. Behavior when reading outside of the available data is
+		unspecified.
+	**/
+	public static function fastGet(b:BytesData, pos:Int):Int {
+		return b.asView().ptr[pos];
+	}
+}

+ 71 - 0
std/cpp/_std/haxe/io/FPHelper.hx

@@ -0,0 +1,71 @@
+/*
+ * Copyright (C)2005-2019 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+package haxe.io;
+
+import cpp.Pointer;
+import cpp.marshal.View;
+
+using cpp.marshal.Marshal;
+using cpp.marshal.ViewExtensions;
+
+/**
+	Helper that converts between floating point and binary representation.
+	Always works in low-endian encoding.
+**/
+class FPHelper {
+	public static function i32ToFloat(i:Int):Float {
+		return i.refAsView().asBytesView().readFloat32();
+	}
+
+	@:analyzer(no_user_var_fusion) public static function floatToI32(f:Float):Int {
+		// With user_var_fusion the f32 variable is elimiated and the cpp.Pointer.addressOf generated by the cpp.Reference<T>
+		// will attempt to get the address of a cast, which is invalid C++.
+		// This is an existing issue
+		final f32 : cpp.Float32 = f;
+
+		return f32.refAsView().asBytesView().readInt32();
+	}
+
+	public static function i64ToDouble(low:Int, high:Int):Float {
+		final value = 0f64;
+		final view  = value.refAsView().asBytesView();
+
+		view.writeLittleEndianInt32(low);
+		view.slice(4).writeLittleEndianInt32(high);
+
+		return value;
+	}
+
+	/**
+		Returns an Int64 representing the bytes representation of the double precision IEEE float value.
+		WARNING : for performance reason, the same Int64 value might be reused every time. Copy its low/high values before calling again.
+		We still ensure that this is safe to use in a multithread environment
+	**/
+	public static function doubleToI64(v:Float):Int64 {
+		final view = v.refAsView().asBytesView();
+		final low  = view.readLittleEndianInt32();
+		final high = view.slice(4).readLittleEndianInt32();
+
+		return Int64.make(high, low);
+	}
+}

+ 140 - 0
std/cpp/marshal/Marshal.hx

@@ -0,0 +1,140 @@
+package cpp.marshal;
+
+import cpp.Char;
+import cpp.Char16;
+import cpp.Float32;
+import cpp.Float64;
+import cpp.UInt8;
+import cpp.UInt16;
+import cpp.UInt32;
+import cpp.UInt64;
+import cpp.Int8;
+import cpp.Int16;
+import cpp.Int32;
+import cpp.Int64;
+import cpp.Pointer;
+
+@:semantics(value)
+@:cpp.ValueType({ namespace : [ 'cpp', 'marshal' ] })
+final extern class Marshal {
+	/**
+	 * Returns a view to UTF8 encoded characters of the given string. The characters in the view will be null terminated.
+	 * 
+	 * Depending on the internal incoding of `s` this function may allocate GC bytes.
+	 * 
+	 * @param s String to return the view of.
+	 */
+	static overload function toCharView(s:String):View<Char>;
+
+	/**
+	 * Fills `buffer` with `s` encoded as UTF8 characters. The characters in the view will be null terminated.
+	 * 
+	 * @param s The string to encode into the buffer.
+	 * @param buffer The view to write into.
+	 * @returns The number of characters written into `buffer`.
+	 *
+	 * @throws InvalidViewLength If `buffer` does not have enough space.
+	 */
+	static overload function toCharView(s:String, buffer:View<Char>):Int;
+
+	/**
+	 * Returns a view to UTF16 encoded characters of the given string. The characters in the view will be null terminated.
+	 * 
+	 * Depending on the internal incoding of `s` this function may allocate GC bytes.
+	 * 
+	 * @param s String to return the view of.
+	 */
+	static overload function toWideCharView(s:String):View<Char16>;
+
+	/**
+	 * Fills `buffer` with `s` encoded as UTF16 characters. The characters in the view will be null terminated.
+	 * 
+	 * @param s The string to encode into the buffer.
+	 * @param buffer The view to write into.
+	 * @returns The number of characters written into `buffer`.
+	 *
+	 * @throws InvalidViewLength If `buffer` does not have enough space.
+	 */
+	static overload function toWideCharView(s:String, buffer:View<Char16>):Int;
+
+	/**
+	 * Allocates a string from the provided utf8 characters.
+	 *
+	 * @param buffer Buffer to characters, does not need to be null terminated.
+	 */
+	static overload function toString(buffer:View<Char>):String;
+
+	/**
+	 * Allocates a string from the provided utf16 characters.
+	 *
+	 * @param buffer Buffer to characters, does not need to be null terminated.
+	 */
+	static overload function toString(buffer:View<Char16>):String;
+
+	static function read<T>(view:View<UInt8>):T;
+
+	static function readPointer<T>(view:View<UInt8>):Pointer<T>;
+	static function readInt8(view:View<UInt8>):Int8;
+	static function readInt16(view:View<UInt8>):Int16;
+	static function readInt32(view:View<UInt8>):Int32;
+	static function readInt64(view:View<UInt8>):Int64;
+	static function readUInt8(view:View<UInt8>):UInt8;
+	static function readUInt16(view:View<UInt8>):UInt16;
+	static function readUInt32(view:View<UInt8>):UInt32;
+	static function readUInt64(view:View<UInt8>):UInt64;
+	static function readFloat32(view:View<UInt8>):Float32;
+	static function readFloat64(view:View<UInt8>):Float64;
+
+	static function readLittleEndianPointer<T>(view:View<UInt8>):Pointer<T>;
+	static function readLittleEndianInt16(view:View<UInt8>):Int16;
+	static function readLittleEndianInt32(view:View<UInt8>):Int32;
+	static function readLittleEndianInt64(view:View<UInt8>):Int64;
+	static function readLittleEndianUInt16(view:View<UInt8>):UInt16;
+	static function readLittleEndianUInt32(view:View<UInt8>):UInt32;
+	static function readLittleEndianUInt64(view:View<UInt8>):UInt64;
+	static function readLittleEndianFloat32(view:View<UInt8>):Float32;
+	static function readLittleEndianFloat64(view:View<UInt8>):Float64;
+
+	static function readBigEndianPointer<T>(view:View<UInt8>):Pointer<T>;
+	static function readBigEndianInt16(view:View<UInt8>):Int16;
+	static function readBigEndianInt32(view:View<UInt8>):Int32;
+	static function readBigEndianInt64(view:View<UInt8>):Int64;
+	static function readBigEndianUInt16(view:View<UInt8>):UInt16;
+	static function readBigEndianUInt32(view:View<UInt8>):UInt32;
+	static function readBigEndianUInt64(view:View<UInt8>):UInt64;
+	static function readBigEndianFloat32(view:View<UInt8>):Float32;
+	static function readBigEndianFloat64(view:View<UInt8>):Float64;
+
+	static function write<T>(view:View<UInt8>, value:T):Void;
+	static function writePointer<T>(view:View<UInt8>, value:Pointer<T>):Void;
+	static function writeInt8(view:View<UInt8>, value:Int8):Void;
+	static function writeInt16(view:View<UInt8>, value:Int16):Void;
+	static function writeInt32(view:View<UInt8>, value:Int32):Void;
+	static function writeInt64(view:View<UInt8>, value:Int64):Void;
+	static function writeUInt8(view:View<UInt8>, value:UInt8):Void;
+	static function writeUInt16(view:View<UInt8>, value:UInt16):Void;
+	static function writeUInt32(view:View<UInt8>, value:UInt32):Void;
+	static function writeUInt64(view:View<UInt8>, value:UInt64):Void;
+	static function writeFloat32(view:View<UInt8>, value:Float32):Void;
+	static function writeFloat64(view:View<UInt8>, value:Float64):Void;
+
+	static function writeLittleEndianPointer<T>(view:View<UInt8>, value:Pointer<T>):Void;
+	static function writeLittleEndianInt16(view:View<UInt8>, value:Int16):Void;
+	static function writeLittleEndianInt32(view:View<UInt8>, value:Int32):Void;
+	static function writeLittleEndianInt64(view:View<UInt8>, value:Int64):Void;
+	static function writeLittleEndianUInt16(view:View<UInt8>, value:UInt16):Void;
+	static function writeLittleEndianUInt32(view:View<UInt8>, value:UInt32):Void;
+	static function writeLittleEndianUInt64(view:View<UInt8>, value:UInt64):Void;
+	static function writeLittleEndianFloat32(view:View<UInt8>, value:Float32):Void;
+	static function writeLittleEndianFloat64(view:View<UInt8>, value:Float64):Void;
+
+	static function writeBigEndianPointer<T>(view:View<UInt8>, value:Pointer<T>):Void;
+	static function writeBigEndianInt16(view:View<UInt8>, value:Int16):Void;
+	static function writeBigEndianInt32(view:View<UInt8>, value:Int32):Void;
+	static function writeBigEndianInt64(view:View<UInt8>, value:Int64):Void;
+	static function writeBigEndianUInt16(view:View<UInt8>, value:UInt16):Void;
+	static function writeBigEndianUInt32(view:View<UInt8>, value:UInt32):Void;
+	static function writeBigEndianUInt64(view:View<UInt8>, value:UInt64):Void;
+	static function writeBigEndianFloat32(view:View<UInt8>, value:Float32):Void;
+	static function writeBigEndianFloat64(view:View<UInt8>, value:Float64):Void;
+}

+ 69 - 0
std/cpp/marshal/View.hx

@@ -0,0 +1,69 @@
+package cpp.marshal;
+
+import cpp.SizeT;
+import haxe.Int64;
+import haxe.ds.Vector;
+import haxe.exceptions.ArgumentException;
+
+@:semantics(value)
+@:cpp.ValueType({ namespace:['cpp', 'marshal'], flags: [ StackOnly ] })
+extern final class View<T> implements ArrayAccess<T> {
+    final length : SizeT;
+	final ptr : Pointer<T>;
+
+	function new(ptr:Pointer<T>, length:SizeT):Void;
+
+	/**
+	 * Attempts to copy the data from the current view to the destination view.
+	 * If the destination is smaller than the current view this function returns false and no data is written to the destination.
+	 * @param destination Target of the copy operation.
+	 */
+	function tryCopyTo(destination:View<T>):Bool;
+
+	/**
+	 * Copies the the from the current view to the destination view.
+	 * @param destination Target of the copy operation
+	 * @throws ArgumentException If the destination is smaller than the current view.
+	 */
+	inline function copyTo(destination:View<T>) {
+		if (tryCopyTo(destination) == false) {
+			throw new ArgumentException("destination", "Not enough space in the destination view");
+		}
+	}
+
+	/**
+	 * Sets all items in the current view to their default value.
+	 */
+	function clear():Void;
+
+	/**
+	 * Sets all items in the current view to the specified value.
+	 * @param value The value assigned to each item in the view.
+	 */
+	function fill(value:T):Void;
+
+	/**
+	 * Create a slice of the current view which starts at the specified index.
+	 * @param start Zero based index to start the slice at.
+	 */
+	overload function slice(start:Int64):View<T>;
+
+	/**
+	 * Create a slice of the current view which starts at the specified index and runs for the specified length.
+	 * @param start Zero based index to start the slice at.
+	 * @param length Length of the slice.
+	 */
+	overload function slice(start:Int64, length:Int64):View<T>;
+
+	/**
+	 * Returns if the current view is empty.
+	 */
+	function isEmpty():Bool;
+
+	/**
+	 * Return a view interpreting this views content as a different type.
+	 */
+	function reinterpret<K>():View<K>;
+
+	function compare(rhs:View<T>):Int;
+}

+ 126 - 0
std/cpp/marshal/ViewExtensions.hx

@@ -0,0 +1,126 @@
+package cpp.marshal;
+
+import cpp.Pointer;
+import cpp.Star;
+import cpp.RawPointer;
+import cpp.Char;
+import cpp.UInt8;
+import cpp.NativeString;
+import haxe.io.Bytes;
+import haxe.io.ArrayBufferView;
+import haxe.io.Float32Array;
+import haxe.io.Float64Array;
+import haxe.io.Int32Array;
+import haxe.io.UInt32Array;
+import haxe.io.UInt16Array;
+import haxe.io.UInt8Array;
+import haxe.ds.Vector;
+import haxe.extern.AsVar;
+import haxe.exceptions.ArgumentException;
+
+final class ViewExtensions {
+	public static inline overload extern function asView<T>(source:Pointer<T>, length:Int):View<T> {
+		return new View(source, length);
+	}
+
+	public static inline overload extern function asView<T>(source:Star<T>, length:Int):View<T> {
+		return new View(Pointer.fromStar(source), length);
+	}
+
+	public static inline overload extern function asView<T>(source:RawPointer<T>, length:Int):View<T> {
+		return new View(Pointer.fromRaw(source), length);
+	}
+
+	public static inline overload extern function asView<T>(source:Array<T>):View<T> {
+		return new View(Pointer.ofArray(source), source.length);
+	}
+
+	public static inline overload extern function asView<T>(source:Vector<T>):View<T> {
+		return new View(Pointer.ofArray(source.toData()), source.length);
+	}
+
+	public static inline overload extern function asView(source:Bytes):View<UInt8> {
+		return new View(Pointer.ofArray(source.getData()), source.length);
+	}
+
+	public static inline overload extern function asView(source:ArrayBufferView):View<UInt8> {
+		return asView(source.buffer).slice(source.byteOffset, source.byteLength);
+	}
+
+	public static inline overload extern function asView(source:Float32Array):View<cpp.Float32> {
+		return asView(source.view).reinterpret();
+	}
+
+	public static inline overload extern function asView(source:Float64Array):View<cpp.Float64> {
+		return asView(source.view).reinterpret();
+	}
+
+	public static inline overload extern function asView(source:Int32Array):View<cpp.Int32> {
+		return asView(source.view).reinterpret();
+	}
+
+	public static inline overload extern function asView(source:UInt32Array):View<cpp.UInt32> {
+		return asView(source.view).reinterpret();
+	}
+
+	public static inline overload extern function asView(source:UInt16Array):View<cpp.UInt16> {
+		return asView(source.view).reinterpret();
+	}
+
+	public static inline overload extern function asView(source:UInt8Array):View<cpp.UInt8> {
+		return asView(source.view).reinterpret();
+	}
+
+	public static inline extern function refAsView<T>(source:AsVar<T>):View<T> {
+		return new View(Pointer.addressOf(source), 1);
+	}
+
+	public static inline extern function empty<T>():View<T> {
+		return new View(null, 0);
+	}
+
+	public static inline extern function asBytesView<T>(source:View<T>):View<UInt8> {
+		return source.reinterpret();
+	}
+
+	@:unreflective @:generic public static function toArray<T>(source:View<T>):Array<T> {
+		if (source.length > 2147483647) {
+			throw new ArgumentException("source");
+		}
+
+		final output      = cpp.NativeArray.create(source.length);
+		final destination = asView(output);
+
+		source.copyTo(destination);
+
+		return output;
+	}
+
+	@:unreflective @:generic public static function toVector<T>(source:View<T>):Vector<T> {
+		if (source.length > 2147483647) {
+			throw new ArgumentException("source");
+		}
+
+		final output      = new Vector(source.length);
+		final destination = asView(output);
+
+		source.copyTo(destination);
+
+		return output;
+	}
+
+	@:unreflective @:generic public static function toBytes<T>(source:View<T>):Bytes {
+		final bytes = asBytesView(source);
+		
+		if (bytes.length > 2147483647) {
+			throw new ArgumentException("source");
+		}
+
+		final output      = Bytes.alloc(bytes.length);
+		final destination = ViewExtensions.asView(output);
+
+		bytes.copyTo(destination);
+
+		return output;
+	}
+}

+ 2 - 48
std/haxe/io/Bytes.hx

@@ -22,10 +22,6 @@
 
 package haxe.io;
 
-#if cpp
-using cpp.NativeArray;
-#end
-
 class Bytes {
 	public var length(default, null):Int;
 
@@ -47,8 +43,6 @@ class Bytes {
 		return untyped $sget(b, pos);
 		#elseif flash
 		return b[pos];
-		#elseif cpp
-		return untyped b[pos];
 		#elseif java
 		return untyped b[pos] & 0xFF;
 		#elseif python
@@ -66,8 +60,6 @@ class Bytes {
 		untyped $sset(b, pos, v);
 		#elseif flash
 		b[pos] = v;
-		#elseif cpp
-		untyped b[pos] = v;
 		#elseif java
 		b[pos] = cast v;
 		#elseif python
@@ -103,8 +95,6 @@ class Bytes {
 		java.lang.System.arraycopy(src.b, srcpos, b, pos, len);
 		#elseif python
 		python.Syntax.code("self.b[{0}:{0}+{1}] = src.b[srcpos:srcpos+{1}]", pos, len);
-		#elseif cpp
-		b.blit(pos, src.b, srcpos, len);
 		#else
 		var b1 = b;
 		var b2 = src.b;
@@ -136,8 +126,6 @@ class Bytes {
 		pos += len & ~3;
 		for (i in 0...len & 3)
 			set(pos++, value);
-		#elseif cpp
-		untyped __global__.__hxcpp_memory_memset(b, pos, len, value);
 		#else
 		for (i in 0...len)
 			set(pos++, value);
@@ -212,9 +200,6 @@ class Bytes {
 		b1.endian = flash.utils.Endian.LITTLE_ENDIAN;
 		b2.endian = flash.utils.Endian.LITTLE_ENDIAN;
 		return length - other.length;
-		// TODO: memcmp if unsafe flag is on
-		#elseif cpp
-		return b.memcmp(other.b);
 		#else
 		var b1 = b;
 		var b2 = other.b;
@@ -231,7 +216,7 @@ class Bytes {
 		little-endian encoding). Result is unspecified if `pos` is outside the
 		bounds.
 	**/
-	#if (neko_v21 || (cpp && !cppia) || flash)
+	#if (neko_v21 || flash)
 	inline
 	#end
 	public function getDouble(pos:Int):Float {
@@ -240,10 +225,6 @@ class Bytes {
 		#elseif flash
 		b.position = pos;
 		return b.readDouble();
-		#elseif cpp
-		if (pos < 0 || pos + 8 > length)
-			throw Error.OutsideBounds;
-		return untyped __global__.__hxcpp_memory_get_double(b, pos);
 		#else
 		return FPHelper.i64ToDouble(getInt32(pos), getInt32(pos + 4));
 		#end
@@ -254,7 +235,7 @@ class Bytes {
 		little-endian encoding). Result is unspecified if `pos` is outside the
 		bounds.
 	**/
-	#if (neko_v21 || (cpp && !cppia) || flash)
+	#if (neko_v21 || flash)
 	inline
 	#end
 	public function getFloat(pos:Int):Float {
@@ -263,10 +244,6 @@ class Bytes {
 		#elseif flash
 		b.position = pos;
 		return b.readFloat();
-		#elseif cpp
-		if (pos < 0 || pos + 4 > length)
-			throw Error.OutsideBounds;
-		return untyped __global__.__hxcpp_memory_get_float(b, pos);
 		#else
 		return FPHelper.i32ToFloat(getInt32(pos));
 		#end
@@ -288,10 +265,6 @@ class Bytes {
 		#elseif flash
 		b.position = pos;
 		b.writeDouble(v);
-		#elseif cpp
-		if (pos < 0 || pos + 8 > length)
-			throw Error.OutsideBounds;
-		untyped __global__.__hxcpp_memory_set_double(b, pos, v);
 		#else
 		var i = FPHelper.doubleToI64(v);
 		setInt32(pos, i.low);
@@ -315,10 +288,6 @@ class Bytes {
 		#elseif flash
 		b.position = pos;
 		b.writeFloat(v);
-		#elseif cpp
-		if (pos < 0 || pos + 4 > length)
-			throw Error.OutsideBounds;
-		untyped __global__.__hxcpp_memory_set_float(b, pos, v);
 		#else
 		setInt32(pos, FPHelper.floatToI32(v));
 		#end
@@ -413,10 +382,6 @@ class Bytes {
 		#elseif flash
 		b.position = pos;
 		return encoding == RawNative ? b.readMultiByte(len, "unicode") : b.readUTFBytes(len);
-		#elseif cpp
-		var result:String = "";
-		untyped __global__.__hxcpp_string_of_bytes(b, result, pos, len);
-		return result;
 		#elseif java
 		try {
 			switch (encoding) {
@@ -533,11 +498,6 @@ class Bytes {
 		var b = new flash.utils.ByteArray();
 		b.length = length;
 		return new Bytes(length, b);
-		#elseif cpp
-		var a = new BytesData();
-		if (length > 0)
-			cpp.NativeArray.setSize(a, length);
-		return new Bytes(length, a);
 		#elseif java
 		return new Bytes(length, new java.NativeArray(length));
 		#elseif python
@@ -565,10 +525,6 @@ class Bytes {
 		else
 			b.writeUTFBytes(s);
 		return new Bytes(b.length, b);
-		#elseif cpp
-		var a = new BytesData();
-		untyped __global__.__hxcpp_bytes_of_string(a, s);
-		return new Bytes(a.length, a);
 		#elseif java
 		try {
 			var b:BytesData = switch (encoding) {
@@ -664,8 +620,6 @@ class Bytes {
 		return untyped __dollar__sget(b, pos);
 		#elseif flash
 		return b[pos];
-		#elseif cpp
-		return untyped b.unsafeGet(pos);
 		#elseif java
 		return untyped b[pos] & 0xFF;
 		#else

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác