Bläddra i källkod

Merge branch 'development' into avoid-object-anons

Simon Krajewski 9 månader sedan
förälder
incheckning
ba528b1d8d
100 ändrade filer med 11167 tillägg och 7744 borttagningar
  1. 1 3
      .github/workflows/main.yml
  2. 4 1
      .vscode/tasks.json
  3. 11 0
      extra/CHANGES.txt
  4. 23 3
      extra/LICENSE.txt
  5. 0 1
      extra/github-actions/build-mac.yml
  6. 1 2
      extra/github-actions/workflows/main.yml
  7. 1 1
      extra/haxelib_src
  8. 1 1
      haxe.opam
  9. 501 0
      libs/extlib-leftovers/LICENSE
  10. 47 0
      libs/mbedtls/mbedtls_stubs.c
  11. 7 0
      libs/objsize/LICENSE
  12. 1 1
      src-json/meta.json
  13. 6 0
      src-json/warning.json
  14. 15 0
      src-prebuild/prebuild.ml
  15. 4 11
      src/codegen/codegen.ml
  16. 4 4
      src/codegen/javaModern.ml
  17. 15 6
      src/compiler/compiler.ml
  18. 2 2
      src/compiler/displayProcessing.ml
  19. 4 4
      src/compiler/generate.ml
  20. 2 2
      src/compiler/server.ml
  21. 1 1
      src/context/abstractCast.ml
  22. 33 119
      src/context/common.ml
  23. 1 10
      src/context/display/display.ml
  24. 2 1
      src/context/display/displayException.ml
  25. 3 3
      src/context/display/displayJson.ml
  26. 2 1
      src/context/display/displayTexpr.ml
  27. 5 1
      src/context/nativeLibraries.ml
  28. 0 11
      src/context/resolution.ml
  29. 1 2
      src/context/sourcemaps.ml
  30. 4 4
      src/context/typecore.ml
  31. 88 1
      src/core/stringHelper.ml
  32. 2 1
      src/core/tFunctions.ml
  33. 3 1
      src/core/tType.ml
  34. 1 0
      src/core/texpr.ml
  35. 11 8
      src/core/warning.ml
  36. 37 8
      src/core/withType.ml
  37. 1 1
      src/filters/ES6Ctors.ml
  38. 1 1
      src/filters/capturedVars.ml
  39. 35 18
      src/filters/exceptions.ml
  40. 61 59
      src/filters/filters.ml
  41. 13 13
      src/filters/filtersCommon.ml
  42. 2 1
      src/filters/localStatic.ml
  43. 154 0
      src/generators/cpp/cppAst.ml
  44. 727 0
      src/generators/cpp/cppAstTools.ml
  45. 96 0
      src/generators/cpp/cppContext.ml
  46. 19 0
      src/generators/cpp/cppExprUtils.ml
  47. 1431 0
      src/generators/cpp/cppRetyper.ml
  48. 183 0
      src/generators/cpp/cppSourceWriter.ml
  49. 131 0
      src/generators/cpp/cppStrings.ml
  50. 353 0
      src/generators/cpp/cppTypeUtils.ml
  51. 1928 0
      src/generators/cpp/gen/cppCppia.ml
  52. 2047 0
      src/generators/cpp/gen/cppGen.ml
  53. 551 0
      src/generators/cpp/gen/cppGenClassHeader.ml
  54. 1391 0
      src/generators/cpp/gen/cppGenClassImplementation.ml
  55. 205 0
      src/generators/cpp/gen/cppGenEnum.ml
  56. 229 0
      src/generators/cpp/gen/cppReferences.ml
  57. 119 0
      src/generators/gctx.ml
  58. 21 6894
      src/generators/gencpp.ml
  59. 53 47
      src/generators/genhl.ml
  60. 25 47
      src/generators/genjs.ml
  61. 56 49
      src/generators/genjvm.ml
  62. 31 29
      src/generators/genlua.ml
  63. 11 11
      src/generators/genneko.ml
  64. 11 13
      src/generators/genphp7.ml
  65. 12 13
      src/generators/genpy.ml
  66. 52 32
      src/generators/genswf.ml
  67. 10 10
      src/generators/genswf9.ml
  68. 14 12
      src/generators/hl2c.ml
  69. 18 5
      src/generators/hlcode.ml
  70. 20 16
      src/generators/hlinterp.ml
  71. 1 1
      src/generators/hlopt.ml
  72. 2 3
      src/generators/jsSourcemap.ml
  73. 0 4
      src/macro/eval/evalContext.ml
  74. 4 4
      src/macro/eval/evalDebugSocket.ml
  75. 1 6
      src/macro/eval/evalEncode.ml
  76. 8 1
      src/macro/eval/evalExceptions.ml
  77. 8 4
      src/macro/eval/evalLuv.ml
  78. 1 1
      src/macro/eval/evalMain.ml
  79. 4 4
      src/macro/eval/evalMisc.ml
  80. 1 1
      src/macro/eval/evalPrinting.ml
  81. 7 4
      src/macro/eval/evalStdLib.ml
  82. 4 4
      src/macro/eval/evalValue.ml
  83. 38 25
      src/macro/macroApi.ml
  84. 1 1
      src/optimization/dce.ml
  85. 1 1
      src/optimization/inline.ml
  86. 6 1
      src/syntax/reification.ml
  87. 17 4
      src/typing/calls.ml
  88. 5 0
      src/typing/fields.ml
  89. 15 8
      src/typing/finalization.ml
  90. 65 35
      src/typing/forLoop.ml
  91. 13 17
      src/typing/generic.ml
  92. 20 28
      src/typing/macroContext.ml
  93. 9 3
      src/typing/matcher/texprConverter.ml
  94. 8 3
      src/typing/operators.ml
  95. 1 1
      src/typing/strictMeta.ml
  96. 22 42
      src/typing/typeload.ml
  97. 29 36
      src/typing/typeloadFields.ml
  98. 9 15
      src/typing/typer.ml
  99. 11 1
      src/typing/typerBase.ml
  100. 1 1
      src/typing/typerDisplay.ml

+ 1 - 3
.github/workflows/main.yml

@@ -461,7 +461,6 @@ jobs:
       OPAMYES: 1
       MACOSX_DEPLOYMENT_TARGET: 10.13
       OCAML_VERSION: 5.1.1
-      CTYPES: 0.21.1
     steps:
       - uses: actions/checkout@main
         with:
@@ -472,7 +471,7 @@ jobs:
         uses: actions/cache@v4
         with:
           path: ~/.opam/
-          key: ${{ matrix.os }}-${{ hashFiles('./haxe.opam', './libs/') }}
+          key: ${{ matrix.os }}-${{ hashFiles('./haxe.opam', './libs/') }}-1
 
       - name: Install Neko from S3
         run: |
@@ -529,7 +528,6 @@ jobs:
           opam switch create ${{env.OCAML_VERSION}}
           eval $(opam env)
           opam env
-          opam pin add ctypes ${{env.CTYPES}} --yes
           opam pin add haxe . --no-action
           opam install haxe --deps-only --assume-depexts
           opam list

+ 4 - 1
.vscode/tasks.json

@@ -5,6 +5,9 @@
 			"label": "make: haxe",
 			"type": "shell",
 			"command": "make ADD_REVISION=1 -s -j haxe",
+			"osx": {
+				"command": "eval $(opam env) && make ADD_REVISION=1 -s -j haxe",
+			},
 			"windows": {
 				"command": "make ADD_REVISION=1 -f Makefile.win -s -j haxe"
 			},
@@ -48,4 +51,4 @@
 			"problemMatcher": []
 		}
 	]
-}
+}

+ 11 - 0
extra/CHANGES.txt

@@ -1,3 +1,14 @@
+2024-08-07 4.3.6
+
+	Bugfixes:
+
+	display : do not define "display" for json rpc diagnostics (#11746)
+	cpp : null check interfaces (#11743)
+	hl : ignore WANT_READ/WANT_WRITE errors when the socket is known to be blocking (#11655)
+	hl : fix weird compiler error (#11690)
+	jvm : fix --java out -D jvm deprecation warning (#11739)
+	macro : Context.reportError should not abort build macros (#11741)
+
 2024-07-18 4.3.5
 
 	General improvements:

+ 23 - 3
extra/LICENSE.txt

@@ -1,9 +1,29 @@
 Haxe Licenses
 -------------
 
-For details about Haxe Licenses, please read http://haxe.org/foundation/open-source.html
+The Haxe toolkit is Free and Open-Source software that uses several licenses.
 
-The Haxe Standard Library MIT License :
+The Haxe compiler is licensed under the GNU GPL v2+ license (SPDX: GPL-2.0-or-later).
+
+The compiler is built around the Haxe source code base.
+
+If a file does not have a license header or does not fall under one of the exceptions listed below, 
+it should be assumed to be licensed under the GNU GPL v2+ license with the standard copyright notice:  
+Copyright (C) 2005-2024 Haxe Foundation.
+
+- The Haxe Standard Library is licensed under the MIT License, which is reproduced below.  
+  It is located in the `std/` directory, and the MIT license applies to this part of Haxe.
+
+- Haxe contains third-party source code, some of which is located in the `libs/` directory.  
+  Each third-party module includes its own license.  
+  For integration with Haxe, these modules may contain Haxe-related files such as a "dune" file
+  or other files for integration with Haxe or OCaml.
+  These files are licensed under the Haxe Compiler license (GNU GPL v2+).
+
+For a summary of Haxe licenses, please read [http://haxe.org/foundation/open-source.html](http://haxe.org/foundation/open-source.html).
+
+
+The Haxe Standard Library MIT License:
 --------------------------
 
 Copyright (C)2005-2016 Haxe Foundation
@@ -26,7 +46,7 @@ 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.
 
-The Haxe compiler GPL License :
+The Haxe compiler GPL License:
 -------------------------------
 
 		    GNU GENERAL PUBLIC LICENSE

+ 0 - 1
extra/github-actions/build-mac.yml

@@ -34,7 +34,6 @@
     opam switch create ${{env.OCAML_VERSION}}
     eval $(opam env)
     opam env
-    opam pin add ctypes ${{env.CTYPES}} --yes
     opam pin add haxe . --no-action
     opam install haxe --deps-only --assume-depexts
     opam list

+ 1 - 2
extra/github-actions/workflows/main.yml

@@ -315,7 +315,6 @@ jobs:
       OPAMYES: 1
       MACOSX_DEPLOYMENT_TARGET: 10.13
       OCAML_VERSION: 5.1.1
-      CTYPES: 0.21.1
     steps:
       - uses: actions/checkout@main
         with:
@@ -326,7 +325,7 @@ jobs:
         uses: actions/cache@v4
         with:
           path: ~/.opam/
-          key: ${{ matrix.os }}-${{ hashFiles('./haxe.opam', './libs/') }}
+          key: ${{ matrix.os }}-${{ hashFiles('./haxe.opam', './libs/') }}-1
 
       @import install-neko-unix.yml
       @import build-mac.yml

+ 1 - 1
extra/haxelib_src

@@ -1 +1 @@
-Subproject commit 98637027327d8cf385d302acaaf104bd6107d2bf
+Subproject commit 5a836287828fdaeb6aa91695a5eb399cee0f6640

+ 1 - 1
haxe.opam

@@ -31,7 +31,7 @@ depends: [
   "conf-libpcre2-8"
   "conf-zlib"
   "conf-neko"
-  "luv" {= "0.5.12"}
+  "luv" {>= "0.5.13"}
   "ipaddr"
   "terminal_size"
 ]

+ 501 - 0
libs/extlib-leftovers/LICENSE

@@ -0,0 +1,501 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Moe Ghoul>, 1 April 1990
+  Moe Ghoul, President of Vice
+
+That's all there is to it!

+ 47 - 0
libs/mbedtls/mbedtls_stubs.c

@@ -302,12 +302,59 @@ static struct custom_operations ssl_config_ops = {
 	.deserialize = custom_deserialize_default,
 };
 
+#ifdef _WIN32
+static int verify_callback(void* param, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
+	if (*flags == 0 || *flags & MBEDTLS_X509_BADCERT_CN_MISMATCH) {
+		return 0;
+	}
+
+	HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL);
+	if(store == NULL) {
+		return MBEDTLS_ERR_X509_FATAL_ERROR;
+	}
+	PCCERT_CONTEXT primary_context = {0};
+	if(!CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, crt->raw.p, crt->raw.len, CERT_STORE_ADD_REPLACE_EXISTING, &primary_context)) {
+		CertCloseStore(store, 0);
+		return MBEDTLS_ERR_X509_FATAL_ERROR;
+	}
+	PCCERT_CHAIN_CONTEXT chain_context = {0};
+	CERT_CHAIN_PARA parameters = {0};
+	if(!CertGetCertificateChain(NULL, primary_context, NULL, store, &parameters, 0, NULL, &chain_context)) {
+		CertFreeCertificateContext(primary_context);
+		CertCloseStore(store, 0);
+		return MBEDTLS_ERR_X509_FATAL_ERROR;
+	}
+	CERT_CHAIN_POLICY_PARA policy_parameters = {0};
+	CERT_CHAIN_POLICY_STATUS policy_status = {0};
+	if(!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context, &policy_parameters, &policy_status)) {
+		CertFreeCertificateChain(chain_context);
+		CertFreeCertificateContext(primary_context);
+		CertCloseStore(store, 0);
+		return MBEDTLS_ERR_X509_FATAL_ERROR;
+	}
+	if(policy_status.dwError == 0) {
+		*flags = 0;
+	} else {
+		// if we ever want to read the verification result,
+		// we need to properly map dwError to flags
+		*flags |= MBEDTLS_X509_BADCERT_OTHER;
+	}
+	CertFreeCertificateChain(chain_context);
+	CertFreeCertificateContext(primary_context);
+	CertCloseStore(store, 0);
+	return 0;
+}
+#endif
+
 CAMLprim value ml_mbedtls_ssl_config_init(void) {
 	CAMLparam0();
 	CAMLlocal1(obj);
 	obj = caml_alloc_custom(&ssl_config_ops, sizeof(mbedtls_ssl_config*), 0, 1);
 	mbedtls_ssl_config* ssl_config = malloc(sizeof(mbedtls_ssl_config));
 	mbedtls_ssl_config_init(ssl_config);
+	#ifdef _WIN32
+	mbedtls_ssl_conf_verify(ssl_config, verify_callback, NULL);
+	#endif
 	Config_val(obj) = ssl_config;
 	CAMLreturn(obj);
 }

+ 7 - 0
libs/objsize/LICENSE

@@ -0,0 +1,7 @@
+According to the README and to [README from backup of objsize new version](https://github.com/ygrek/objsize), 
+objsize is licensed either under BSD 3 Clause License or any version of GNU GENERAL PUBLIC LICENSE 
+published by Free Software Foundation.
+
+For use in Haxe, it was incorporated under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.

+ 1 - 1
src-json/meta.json

@@ -487,7 +487,7 @@
 		"name": "InheritDoc",
 		"metadata": ":inheritDoc",
 		"doc": "Append documentation from a parent field or class (if used without an argument) or from a specified class or field (if used like @:inheritDoc(pack.Some.field)).",
-		"targets": ["TClass", "TClass", "TEnum", "TAbstract", "TAnyField"]
+		"targets": ["TClass", "TEnum", "TAbstract", "TAnyField"]
 	},
 	{
 		"name": "InitPackage",

+ 6 - 0
src-json/warning.json

@@ -118,6 +118,12 @@
 		"doc": "Constructor call could not be inlined because a field is uninitialized",
 		"parent": "WTyper"
 	},
+	{
+		"name": "WUnsafeEnumEquality",
+		"doc": "Equality operations on enums with parameters might not work as expected",
+		"parent": "WTyper",
+		"enabled": false
+	},
 	{
 		"name": "WHxb",
 		"doc": "Hxb (either --hxb output or haxe compiler cache) related warnings"

+ 15 - 0
src-prebuild/prebuild.ml

@@ -7,6 +7,7 @@ type parsed_warning = {
 	w_doc : string;
 	w_parent : string option;
 	w_generic : bool;
+	w_enabled : bool;
 }
 
 type parsed_meta = {
@@ -143,6 +144,7 @@ let parse_warning json =
 		w_doc = get_field "doc" as_string fields;
 		w_parent = get_optional_field2 "parent" as_string fields;
 		w_generic = get_optional_field "generic" as_bool false fields;
+		w_enabled = get_optional_field "enabled" as_bool true fields;
 	}
 
 let parse_file_array path map =
@@ -255,6 +257,15 @@ let gen_warning_obj warnings =
 	) warnings in
 	String.concat "\n" warning_str
 
+let gen_disabled_warnings warnings =
+	let warning_str = ExtList.List.filter_map (fun w ->
+		if w.w_enabled then
+			None
+		else
+			Some w.w_name
+	) warnings in
+	String.concat ";" warning_str
+
 let autogen_header = "(* This file is auto-generated using prebuild from files in src-json *)
 (* Do not edit manually! *)
 "
@@ -355,6 +366,10 @@ match Array.to_list (Sys.argv) with
 		print_endline "";
 		print_endline "let warning_obj = function";
 		print_endline (gen_warning_obj warnings);
+		print_endline ";;";
+		print_endline "let disabled_warnings = [";
+		print_endline (gen_disabled_warnings warnings);
+		print_endline "];;";
 		print_endline "";
 		print_endline "let from_string = function";
 		print_endline (gen_warning_parse warnings);

+ 4 - 11
src/codegen/codegen.ml

@@ -418,13 +418,12 @@ end
 	Build a default safe-cast expression :
 	{ var $t = <e>; if( Std.is($t,<t>) ) $t else throw "Class cast error"; }
 *)
-let default_cast ?(vtmp="$t") com e texpr t p =
-	let api = com.basic in
+let default_cast ?(vtmp="$t") api std e texpr t p =
 	let vtmp = alloc_var VGenerated vtmp e.etype e.epos in
 	let var = mk (TVar (vtmp,Some e)) api.tvoid p in
 	let vexpr = mk (TLocal vtmp) e.etype p in
 	let texpr = Texpr.Builder.make_typeexpr texpr p in
-	let is = Texpr.Builder.resolve_and_make_static_call com.std "isOfType" [vexpr;texpr] p in
+	let is = Texpr.Builder.resolve_and_make_static_call std "isOfType" [vexpr;texpr] p in
 	let enull = Texpr.Builder.make_null vexpr.etype p in
 	let eop = Texpr.Builder.binop OpEq vexpr enull api.tbool p in
 	let echeck = Texpr.Builder.binop OpBoolOr is eop api.tbool p in
@@ -453,12 +452,12 @@ module UnificationCallback = struct
 			List.map (fun e -> f e t_dynamic) el
 end;;
 
-let interpolate_code com code tl f_string f_expr p =
+let interpolate_code error code tl f_string f_expr p =
 	let exprs = Array.of_list tl in
 	let i = ref 0 in
 	let err msg =
 		let pos = { p with pmin = p.pmin + !i } in
-		com.error msg pos
+		error msg pos
 	in
 	let regex = Str.regexp "[{}]" in
 	let rec loop m = match m with
@@ -487,12 +486,6 @@ let interpolate_code com code tl f_string f_expr p =
 	in
 	loop (Str.full_split regex code)
 
-let map_source_header com f =
-	match Common.defined_value_safe com Define.SourceHeader with
-	| "" -> ()
-	| s -> f s
-
-
 (* Static extensions for classes *)
 module ExtClass = struct
 	let add_static_init c cf e p =

+ 4 - 4
src/codegen/javaModern.ml

@@ -672,13 +672,13 @@ module SignatureConverter = struct
 
 	and convert_signature ctx p jsig =
 		match jsig with
-		| TByte -> mk_type_path (["java"; "types"], "Int8") [] p
-		| TChar -> mk_type_path (["java"; "types"], "Char16") [] p
+		| TByte -> mk_type_path (["jvm"], "Int8") [] p
+		| TChar -> mk_type_path (["jvm"], "Char16") [] p
 		| TDouble -> mk_type_path ([], "Float") [] p
 		| TFloat -> mk_type_path ([], "Single") [] p
 		| TInt -> mk_type_path ([], "Int") [] p
 		| TLong -> mk_type_path (["haxe"], "Int64") [] p
-		| TShort -> mk_type_path (["java"; "types"], "Int16") [] p
+		| TShort -> mk_type_path (["jvm"], "Int16") [] p
 		| TBool -> mk_type_path ([], "Bool") [] p
 		| TObject ( (["haxe";"root"], name), args ) -> mk_type_path ([], name) (List.map (convert_arg ctx p) args) p
 		| TObject ( (["java";"lang"], "Object"), [] ) -> mk_type_path ([], "Dynamic") [] p
@@ -693,7 +693,7 @@ module SignatureConverter = struct
 			| _ -> die "" __LOC__ in
 			mk_type_path (pack, name ^ "$" ^ String.concat "$" (List.map fst inners)) (List.map (fun param -> convert_arg ctx p param) actual_param) p
 		| TObjectInner (pack, inners) -> die "" __LOC__
-		| TArray (jsig, _) -> mk_type_path (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig,p) ] p
+		| TArray (jsig, _) -> mk_type_path (["jvm"], "NativeArray") [ TPType (convert_signature ctx p jsig,p) ] p
 		| TMethod _ -> failwith "TMethod cannot be converted directly into Complex Type"
 		| TTypeParameter s ->
 			try

+ 15 - 6
src/compiler/compiler.ml

@@ -233,6 +233,7 @@ module Setup = struct
 		Common.define_value com Define.HaxeVer (Printf.sprintf "%.3f" (float_of_int Globals.version /. 1000.));
 		Common.raw_define com "haxe3";
 		Common.raw_define com "haxe4";
+		Common.raw_define com "haxe5";
 		Common.define_value com Define.Haxe s_version;
 		Common.raw_define com "true";
 		Common.define_value com Define.Dce "std";
@@ -240,7 +241,7 @@ module Setup = struct
 			message ctx (make_compiler_message ~from_macro msg p depth DKCompilerMessage Information)
 		);
 		com.warning <- (fun ?(depth=0) ?(from_macro=false) w options msg p ->
-			match Warning.get_mode w (com.warning_options @ options) with
+			match Warning.get_mode w (options @ com.warning_options) with
 			| WMEnable ->
 				let wobj = Warning.warning_obj w in
 				let msg = if wobj.w_generic then
@@ -328,18 +329,19 @@ let do_type ctx mctx actx display_file_dot_path =
 let finalize_typing ctx tctx =
 	let t = Timer.timer ["finalize"] in
 	let com = ctx.com in
+	let main_module = Finalization.maybe_load_main tctx in
 	enter_stage com CFilteringStart;
 	ServerMessage.compiler_stage com;
-	let main, types, modules = run_or_diagnose ctx (fun () -> Finalization.generate tctx) in
+	let main, types, modules = run_or_diagnose ctx (fun () -> Finalization.generate tctx main_module) in
 	com.main.main_expr <- main;
 	com.types <- types;
 	com.modules <- modules;
 	t()
 
-let filter ctx tctx before_destruction =
+let filter ctx tctx ectx before_destruction =
 	let t = Timer.timer ["filters"] in
 	DeprecationCheck.run ctx.com;
-	run_or_diagnose ctx (fun () -> Filters.run tctx ctx.com.main.main_expr before_destruction);
+	run_or_diagnose ctx (fun () -> Filters.run tctx ectx ctx.com.main.main_expr before_destruction);
 	t()
 
 let compile ctx actx callbacks =
@@ -381,6 +383,7 @@ let compile ctx actx callbacks =
 		(* Actual compilation starts here *)
 		let (tctx,display_file_dot_path) = do_type ctx mctx actx display_file_dot_path in
 		DisplayProcessing.handle_display_after_typing ctx tctx display_file_dot_path;
+		let ectx = Exceptions.create_exception_context tctx in
 		finalize_typing ctx tctx;
 		let is_compilation = is_compilation com in
 		com.callbacks#add_after_save (fun () ->
@@ -392,10 +395,10 @@ let compile ctx actx callbacks =
 					()
 		);
 		if is_diagnostics com then
-			filter ctx tctx (fun () -> DisplayProcessing.handle_display_after_finalization ctx tctx display_file_dot_path)
+			filter ctx tctx ectx (fun () -> DisplayProcessing.handle_display_after_finalization ctx tctx display_file_dot_path)
 		else begin
 			DisplayProcessing.handle_display_after_finalization ctx tctx display_file_dot_path;
-			filter ctx tctx (fun () -> ());
+			filter ctx tctx ectx (fun () -> ());
 		end;
 		if ctx.has_error then raise Abort;
 		if is_compilation then Generate.check_auxiliary_output com actx;
@@ -577,6 +580,7 @@ module HighLevel = struct
 		let args = !each_args @ args in
 		let added_libs = Hashtbl.create 0 in
 		let server_mode = ref SMNone in
+		let hxml_stack = ref [] in
 		let create_context args =
 			let ctx = create (server_api.on_context_create()) args in
 			ctx
@@ -636,6 +640,11 @@ module HighLevel = struct
 			| arg :: l ->
 				match List.rev (ExtString.String.nsplit arg ".") with
 				| "hxml" :: _ :: _ when (match acc with "-cmd" :: _ | "--cmd" :: _ -> false | _ -> true) ->
+					let full_path = Extc.get_full_path arg in
+					if List.mem full_path !hxml_stack then
+						raise (Arg.Bad (Printf.sprintf "Duplicate hxml inclusion: %s" full_path))
+					else
+						hxml_stack := full_path :: !hxml_stack;
 					let acc, l = (try acc, Helper.parse_hxml arg @ l with Not_found -> (arg ^ " (file not found)") :: acc, l) in
 					loop acc l
 				| _ ->

+ 2 - 2
src/compiler/displayProcessing.ml

@@ -96,7 +96,7 @@ let process_display_configuration ctx =
 			add_diagnostics_message ?depth com s p DKCompilerMessage Information
 		);
 		com.warning <- (fun ?(depth = 0) ?from_macro w options s p ->
-			match Warning.get_mode w (com.warning_options @ options) with
+			match Warning.get_mode w (options @ com.warning_options) with
 			| WMEnable ->
 				let wobj = Warning.warning_obj w in
 				add_diagnostics_message ~depth ~code:(Some wobj.w_name) com s p DKCompilerMessage Warning
@@ -348,7 +348,7 @@ let handle_display_after_finalization ctx tctx display_file_dot_path =
 		| None -> ()
 		| Some mctx ->
 			(* We don't need a full macro flush here because we're not going to run any macros. *)
-			let _, types, modules = Finalization.generate mctx in
+			let _, types, modules = Finalization.generate mctx (Finalization.maybe_load_main mctx) in
 			mctx.Typecore.com.types <- types;
 			mctx.Typecore.com.Common.modules <- modules
 	end;

+ 4 - 4
src/compiler/generate.ml

@@ -174,11 +174,11 @@ let generate ctx tctx ext actx =
 			with Not_found ->
 				None
 			in
-			Genswf.generate header,"swf"
+			Genswf.generate header com.Common.native_libs.swf_libs com.Common.flash_version,"swf"
 		| Neko ->
-			Genneko.generate,"neko"
+			Genneko.generate com.neko_lib_paths,"neko"
 		| Js ->
-			Genjs.generate,"js"
+			Genjs.generate com.js_gen,"js"
 		| Lua ->
 			Genlua.generate,"lua"
 		| Php ->
@@ -201,7 +201,7 @@ let generate ctx tctx ext actx =
 		else begin
 			Common.log com ("Generating " ^ name ^ ": " ^ com.file);
 			let t = Timer.timer ["generate";name] in
-			generate com;
+			generate (Common.to_gctx com);
 			t()
 		end
 	end

+ 2 - 2
src/compiler/server.ml

@@ -440,7 +440,7 @@ class hxb_reader_api_server
 			let is_display_file = DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key mc.mc_extra.m_file) in
 			let full_restore = com.is_macro_context || com.display.dms_full_typing || is_display_file in
 			let f_next chunks until =
-				let t_hxb = Timer.timer ["server";"module cache";"hxb read"] in
+				let t_hxb = Timer.timer ["server";"module cache";"hxb read";"until " ^ (string_of_chunk_kind until)] in
 				let r = reader#read_chunks_until (self :> HxbReaderApi.hxb_reader_api) chunks until (not full_restore) in
 				t_hxb();
 				r
@@ -590,7 +590,7 @@ and type_module sctx com delay mpath p =
 							api
 					in
 					let f_next chunks until =
-						let t_hxb = Timer.timer ["server";"module cache";"hxb read"] in
+						let t_hxb = Timer.timer ["server";"module cache";"hxb read";"until " ^ (string_of_chunk_kind until)] in
 						let r = reader#read_chunks_until api chunks until (not full_restore) in
 						t_hxb();
 						r

+ 1 - 1
src/context/abstractCast.ml

@@ -296,8 +296,8 @@ let handle_abstract_casts ctx e =
 					| TCast(e2,None) ->
 						{e1 with eexpr = TCast(find_field e2,None)}
 					| TField(e2,fa) ->
-						let e2 = loop e2 in
 						let a,pl,e2 = find_abstract e2 e2.etype in
+						let e2 = loop e2 in
 						let m = Abstract.get_underlying_type a pl in
 						let fname = field_name fa in
 						let el = List.map loop el in

+ 33 - 119
src/context/common.ml

@@ -16,7 +16,6 @@
 	along with this program; if not, write to the Free Software
 	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *)
-open Extlib_leftovers
 open Ast
 open Type
 open Globals
@@ -348,11 +347,6 @@ class virtual abstract_hxb_lib = object(self)
 	method virtual get_string_pool : string -> string array option
 end
 
-type context_main = {
-	mutable main_class : path option;
-	mutable main_expr : texpr option;
-}
-
 type context = {
 	compilation_step : int;
 	mutable stage : compiler_stage;
@@ -371,15 +365,15 @@ type context = {
 	mutable config : platform_config;
 	empty_class_path : ClassPath.class_path;
 	class_paths : ClassPaths.class_paths;
-	main : context_main;
+	main : Gctx.context_main;
 	mutable package_rules : (string,package_rule) PMap.t;
 	mutable report_mode : report_mode;
 	(* communication *)
 	mutable print : string -> unit;
-	mutable error : ?depth:int -> string -> pos -> unit;
+	mutable error : Gctx.error_function;
 	mutable error_ext : Error.error -> unit;
 	mutable info : ?depth:int -> ?from_macro:bool -> string -> pos -> unit;
-	mutable warning : ?depth:int -> ?from_macro:bool -> warning -> Warning.warning_option list list -> string -> pos -> unit;
+	mutable warning : Gctx.warning_function;
 	mutable warning_options : Warning.warning_option list list;
 	mutable get_messages : unit -> compiler_message list;
 	mutable filter_messages : (compiler_message -> bool) -> unit;
@@ -433,6 +427,32 @@ type context = {
 	mutable hxb_writer_config : HxbWriterConfig.t option;
 }
 
+let to_gctx com = {
+	Gctx.platform = com.platform;
+	defines = com.defines;
+	basic = com.basic;
+	class_paths = com.class_paths;
+	run_command = com.run_command;
+	run_command_args = com.run_command_args;
+	warning = com.warning;
+	error = com.error;
+	print = com.print;
+	debug = com.debug;
+	file = com.file;
+	version = com.version;
+	features = com.features;
+	modules = com.modules;
+	main = com.main;
+	types = com.types;
+	resources = com.resources;
+	native_libs = (match com.platform with
+		| Jvm -> (com.native_libs.java_libs :> NativeLibraries.native_library_base list)
+		| Flash -> (com.native_libs.swf_libs  :> NativeLibraries.native_library_base list)
+		| _ -> []);
+	include_files = com.include_files;
+	std = com.std;
+}
+
 let enter_stage com stage =
 	(* print_endline (Printf.sprintf "Entering stage %s" (s_compiler_stage stage)); *)
 	com.stage <- stage
@@ -522,9 +542,6 @@ let defines_for_external ctx =
 			| split -> PMap.add (String.concat "-" split) v added_underscore;
 	) ctx.defines.values PMap.empty
 
-let get_es_version com =
-	try int_of_string (defined_value com Define.JsEs) with _ -> 0
-
 let short_platform_name = function
 	| Cross -> "x"
 	| Js -> "js"
@@ -587,7 +604,7 @@ let get_config com =
 		(* impossible to reach. see update_platform_config *)
 		raise Exit
 	| Js ->
-		let es6 = get_es_version com >= 6 in
+		let es6 = Gctx.get_es_version com.defines >= 6 in
 		{
 			default_config with
 			pf_static = false;
@@ -827,7 +844,7 @@ let create compilation_step cs version args display_mode =
 		get_macros = (fun() -> None);
 		info = (fun ?depth ?from_macro _ _ -> die "" __LOC__);
 		warning = (fun ?depth ?from_macro _ _ _ -> die "" __LOC__);
-		warning_options = [];
+		warning_options = [List.map (fun w -> {wo_warning = w;wo_mode = WMDisable}) WarningList.disabled_warnings];
 		error = (fun ?depth _ _ -> die "" __LOC__);
 		error_ext = (fun _ -> die "" __LOC__);
 		get_messages = (fun() -> []);
@@ -842,6 +859,7 @@ let create compilation_step cs version args display_mode =
 			tstring = mk_mono();
 			tnull = (fun _ -> die "Could use locate abstract Null<T> (was it redefined?)" __LOC__);
 			tarray = (fun _ -> die "Could not locate class Array<T> (was it redefined?)" __LOC__);
+			titerator = (fun _ -> die "Could not locate typedef Iterator<T> (was it redefined?)" __LOC__);
 		};
 		std = null_class;
 		file_keys = new file_keys;
@@ -881,6 +899,7 @@ let clone com is_macro_context =
 	let t = com.basic in
 	{ com with
 		cache = None;
+		stage = CCreated;
 		basic = { t with
 			tvoid = mk_mono();
 			tany = mk_mono();
@@ -927,27 +946,6 @@ let flash_versions = List.map (fun v ->
 	v, string_of_int maj ^ (if min = 0 then "" else "_" ^ string_of_int min)
 ) [9.;10.;10.1;10.2;10.3;11.;11.1;11.2;11.3;11.4;11.5;11.6;11.7;11.8;11.9;12.0;13.0;14.0;15.0;16.0;17.0;18.0;19.0;20.0;21.0;22.0;23.0;24.0;25.0;26.0;27.0;28.0;29.0;31.0;32.0]
 
-let flash_version_tag = function
-	| 6. -> 6
-	| 7. -> 7
-	| 8. -> 8
-	| 9. -> 9
-	| 10. | 10.1 -> 10
-	| 10.2 -> 11
-	| 10.3 -> 12
-	| 11. -> 13
-	| 11.1 -> 14
-	| 11.2 -> 15
-	| 11.3 -> 16
-	| 11.4 -> 17
-	| 11.5 -> 18
-	| 11.6 -> 19
-	| 11.7 -> 20
-	| 11.8 -> 21
-	| 11.9 -> 22
-	| v when v >= 12.0 && float_of_int (int_of_float v) = v -> int_of_float v + 11
-	| v -> failwith ("Invalid SWF version " ^ string_of_float v)
-
 let update_platform_config com =
 	match com.platform with
 	| CustomTarget _ ->
@@ -1093,90 +1091,6 @@ let hash f =
 	done;
 	if Sys.word_size = 64 then Int32.to_int (Int32.shift_right (Int32.shift_left (Int32.of_int !h) 1) 1) else !h
 
-let url_encode s add_char =
-	let hex = "0123456789ABCDEF" in
-	for i = 0 to String.length s - 1 do
-		let c = String.unsafe_get s i in
-		match c with
-		| 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' | '-' | '.' ->
-			add_char c
-		| _ ->
-			add_char '%';
-			add_char (String.unsafe_get hex (int_of_char c lsr 4));
-			add_char (String.unsafe_get hex (int_of_char c land 0xF));
-	done
-
-let url_encode_s s =
-	let b = Buffer.create 0 in
-	url_encode s (Buffer.add_char b);
-	Buffer.contents b
-
-(* UTF8 *)
-
-let to_utf8 str p =
-	let u8 = try
-		UTF8.validate str;
-		str;
-	with
-		UTF8.Malformed_code ->
-			(* ISO to utf8 *)
-			let b = UTF8.Buf.create 0 in
-			String.iter (fun c -> UTF8.Buf.add_char b (UCharExt.of_char c)) str;
-			UTF8.Buf.contents b
-	in
-	let ccount = ref 0 in
-	UTF8.iter (fun c ->
-		let c = UCharExt.code c in
-		if (c >= 0xD800 && c <= 0xDFFF) || c >= 0x110000 then Error.abort "Invalid unicode char" p;
-		incr ccount;
-		if c > 0x10000 then incr ccount;
-	) u8;
-	u8, !ccount
-
-let utf16_add buf c =
-	let add c =
-		Buffer.add_char buf (char_of_int (c land 0xFF));
-		Buffer.add_char buf (char_of_int (c lsr 8));
-	in
-	if c >= 0 && c < 0x10000 then begin
-		if c >= 0xD800 && c <= 0xDFFF then failwith ("Invalid unicode char " ^ string_of_int c);
-		add c;
-	end else if c < 0x110000 then begin
-		let c = c - 0x10000 in
-		add ((c asr 10) + 0xD800);
-		add ((c land 1023) + 0xDC00);
-	end else
-		failwith ("Invalid unicode char " ^ string_of_int c)
-
-let utf8_to_utf16 str zt =
-	let b = Buffer.create (String.length str * 2) in
-	(try UTF8.iter (fun c -> utf16_add b (UCharExt.code c)) str with Invalid_argument _ | UCharExt.Out_of_range -> ()); (* if malformed *)
-	if zt then utf16_add b 0;
-	Buffer.contents b
-
-let utf16_to_utf8 str =
-	let b = Buffer.create 0 in
-	let add c = Buffer.add_char b (char_of_int (c land 0xFF)) in
-	let get i = int_of_char (String.unsafe_get str i) in
-	let rec loop i =
-		if i >= String.length str then ()
-		else begin
-			let c = get i in
-			if c < 0x80 then begin
-				add c;
-				loop (i + 2);
-			end else if c < 0x800 then begin
-				let c = c lor ((get (i + 1)) lsl 8) in
-				add c;
-				add (c lsr 8);
-				loop (i + 2);
-			end else
-				die "" __LOC__;
-		end
-	in
-	loop 0;
-	Buffer.contents b
-
 let add_diagnostics_message ?(depth = 0) ?(code = None) com s p kind sev =
 	if sev = MessageSeverity.Error then com.has_error <- true;
 	let di = com.shared.shared_display_information in

+ 1 - 10
src/context/display/display.ml

@@ -35,21 +35,12 @@ let preprocess_expr com e = match com.display.dms_kind with
 	| DMSignature -> ExprPreprocessing.find_display_call e
 	| _ -> e
 
-let get_expected_name with_type = match with_type with
-	| WithType.Value (Some src) | WithType.WithType(_,Some src) ->
-		(match src with
-		| WithType.FunctionArgument si -> Some si.si_name
-		| WithType.StructureField si -> Some si .si_name
-		| WithType.ImplicitReturn -> None
-		)
-	| _ -> None
-
 let sort_fields l with_type tk =
 	let p = match tk with
 		| TKExpr p | TKField p -> Some p
 		| _ -> None
 	in
-	let expected_name = get_expected_name with_type in
+	let expected_name = WithType.get_expected_name with_type in
 	let l = List.map (fun ci ->
 		let i = get_sort_index tk ci (Option.default Globals.null_pos p) expected_name in
 		ci,i

+ 2 - 1
src/context/display/displayException.ml

@@ -184,7 +184,8 @@ let to_json ctx de =
 		let named_source_kind = function
 			| WithType.FunctionArgument name -> (0, name)
 			| WithType.StructureField name -> (1, name)
-			| _ -> die "" __LOC__
+			| LocalVariable name -> (2, name)
+			| ImplicitReturn -> die "" __LOC__
 		in
 		let ctx = Genjson.create_context GMFull in
 		let generate_name kind =

+ 3 - 3
src/context/display/displayJson.ml

@@ -49,10 +49,10 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationCache.t)
 
 	method get_cs = cs
 
-	method enable_display mode =
+	method enable_display ?(skip_define=false) mode =
 		com.display <- create mode;
 		Parser.display_mode := mode;
-		Common.define_value com Define.Display "1"
+		if not skip_define then Common.define_value com Define.Display "1"
 
 	method set_display_file was_auto_triggered requires_offset =
 		let file = jsonrpc#get_opt_param (fun () ->
@@ -209,7 +209,7 @@ let handler =
 		);
 		"display/diagnostics", (fun hctx ->
 			hctx.display#set_display_file false false;
-			hctx.display#enable_display DMNone;
+			hctx.display#enable_display ~skip_define:true DMNone;
 			hctx.com.display <- { hctx.com.display with dms_display_file_policy = DFPAlso; dms_per_file = true; dms_populate_cache = true };
 			hctx.com.report_mode <- RMDiagnostics (List.map (fun (f,_) -> f) hctx.com.file_contents);
 		);

+ 2 - 1
src/context/display/displayTexpr.ml

@@ -62,7 +62,8 @@ let actually_check_display_field ctx c cff p =
 	let cff = TypeloadFields.transform_field (ctx,cctx) c cff (ref []) (pos cff.cff_name) in
 	let display_modifier = Typeload.check_field_access ctx cff in
 	let fctx = TypeloadFields.create_field_context ctx cctx cff true display_modifier in
-	let cf = TypeloadFields.init_field (ctx,cctx,fctx) cff in
+	let cf = TypeloadFields.create_class_field cctx cff in
+	TypeloadFields.init_field (ctx,cctx,fctx) cff cf;
 	flush_pass ctx.g PTypeField ("check_display_field",(fst c.cl_path @ [snd c.cl_path;fst cff.cff_name]));
 	ignore(follow cf.cf_type)
 

+ 5 - 1
src/context/nativeLibraries.ml

@@ -23,7 +23,7 @@ type native_lib_flags =
 	| FlagIsStd
 	| FlagIsExtern
 
-class virtual ['a,'data] native_library (name : string) (file_path : string) = object(self)
+class virtual native_library_base (name : string) (file_path : string) = object(self)
 	val mutable flags : native_lib_flags list = []
 
 	method add_flag flag = flags <- flag :: flags
@@ -31,6 +31,10 @@ class virtual ['a,'data] native_library (name : string) (file_path : string) = o
 
 	method get_name = name
 	method get_file_path = file_path
+end
+
+class virtual ['a,'data] native_library (name : string) (file_path : string) = object(self)
+	inherit native_library_base name file_path
 
 	method virtual build : path -> pos -> Ast.package option
 	method virtual close : unit

+ 0 - 11
src/context/resolution.ml

@@ -203,17 +203,6 @@ class resolution_list (id : string list) = object(self)
 		self#cache_type_imports;
 		StringMap.find alias type_import_cache
 
-	method find_type_import_weirdly pack name =
-		let rec find l = match l with
-			| [] ->
-				raise Not_found
-			| {r_kind = RTypeImport(alias,mt); r_pos = p} :: l ->
-				if  t_path mt = (pack,name) then (mt,p) else find l
-			| _ :: l ->
-				find l
-		in
-		find l
-
 	method extract_type_imports =
 		ExtList.List.filter_map (fun res -> match res.r_kind with
 			| RTypeImport(_,mt) ->

+ 1 - 2
src/context/sourcemaps.ml

@@ -1,6 +1,5 @@
 open Extlib_leftovers
 open Globals
-open Common
 
 (**
 	Characters used for base64 VLQ encoding
@@ -127,7 +126,7 @@ class sourcemap_writer (generated_file:string) =
 		output_string channel ("\"sources\":[" ^
 			(String.concat "," (List.map (fun s -> "\"" ^ to_url s ^ "\"") sources)) ^
 			"],\n");
-		if Common.defined com Define.SourceMapContent then begin
+		if Gctx.defined com Define.SourceMapContent then begin
 			output_string channel ("\"sourcesContent\":[" ^
 				(String.concat "," (List.map (fun s -> try "\"" ^ StringHelper.s_escape (Std.input_file ~bin:true s) ^ "\"" with _ -> "null") sources)) ^
 				"],\n");

+ 4 - 4
src/context/typecore.ml

@@ -76,7 +76,7 @@ type typer_module = {
 }
 
 type typer_class = {
-	mutable curclass : tclass; (* TODO: should not be mutable *)
+	curclass : tclass;
 	mutable tthis : t;
 	mutable get_build_infos : unit -> (module_type * t list * class_field list) option;
 }
@@ -150,7 +150,7 @@ and typer_expr = {
 }
 
 and typer_field = {
-	mutable curfield : tclass_field;
+	curfield : tclass_field;
 	mutable locals : (string, tvar) PMap.t;
 	mutable vthis : tvar option;
 	mutable untyped : bool;
@@ -165,7 +165,7 @@ and typer = {
 	com : context;
 	t : basic_types;
 	g : typer_globals;
-	mutable m : typer_module;
+	m : typer_module;
 	c : typer_class;
 	f : typer_field;
 	e : typer_expr;
@@ -358,7 +358,7 @@ let type_generic_function_ref : (typer -> field_access -> (unit -> texpr) field_
 let create_context_ref : (Common.context -> ((unit -> unit) * typer) option -> typer) ref = ref (fun _ -> assert false)
 
 let warning ?(depth=0) ctx w msg p =
-	let options = (Warning.from_meta ctx.c.curclass.cl_meta) @ (Warning.from_meta ctx.f.curfield.cf_meta) in
+	let options = (Warning.from_meta ctx.f.curfield.cf_meta) @ (Warning.from_meta ctx.c.curclass.cl_meta) in
 	match Warning.get_mode w options with
 	| WMEnable ->
 		module_warning ctx.com ctx.m.curmod w options msg p

+ 88 - 1
src/core/stringHelper.ml

@@ -1,3 +1,6 @@
+open Globals
+open Extlib_leftovers
+
 let uppercase s =
 	let bytes = Bytes.of_string s in
 	Bytes.iteri
@@ -68,4 +71,88 @@ let extension file =
 		let dot_pos = String.rindex file '.' in
 		String.sub file dot_pos (String.length file - dot_pos)
 	with Not_found ->
-		file
+		file
+
+(* UTF8 *)
+
+let to_utf8 str p =
+	let u8 = try
+		UTF8.validate str;
+		str;
+	with
+		UTF8.Malformed_code ->
+			(* ISO to utf8 *)
+			let b = UTF8.Buf.create 0 in
+			String.iter (fun c -> UTF8.Buf.add_char b (UCharExt.of_char c)) str;
+			UTF8.Buf.contents b
+	in
+	let ccount = ref 0 in
+	UTF8.iter (fun c ->
+		let c = UCharExt.code c in
+		if (c >= 0xD800 && c <= 0xDFFF) || c >= 0x110000 then failwith "Invalid unicode char";
+		incr ccount;
+		if c > 0x10000 then incr ccount;
+	) u8;
+	u8, !ccount
+
+let utf16_add buf c =
+	let add c =
+		Buffer.add_char buf (char_of_int (c land 0xFF));
+		Buffer.add_char buf (char_of_int (c lsr 8));
+	in
+	if c >= 0 && c < 0x10000 then begin
+		if c >= 0xD800 && c <= 0xDFFF then failwith ("Invalid unicode char " ^ string_of_int c);
+		add c;
+	end else if c < 0x110000 then begin
+		let c = c - 0x10000 in
+		add ((c asr 10) + 0xD800);
+		add ((c land 1023) + 0xDC00);
+	end else
+		failwith ("Invalid unicode char " ^ string_of_int c)
+
+let utf8_to_utf16 str zt =
+	let b = Buffer.create (String.length str * 2) in
+	(try UTF8.iter (fun c -> utf16_add b (UCharExt.code c)) str with Invalid_argument _ | UCharExt.Out_of_range -> ()); (* if malformed *)
+	if zt then utf16_add b 0;
+	Buffer.contents b
+
+let utf16_to_utf8 str =
+	let b = Buffer.create 0 in
+	let add c = Buffer.add_char b (char_of_int (c land 0xFF)) in
+	let get i = int_of_char (String.unsafe_get str i) in
+	let rec loop i =
+		if i >= String.length str then ()
+		else begin
+			let c = get i in
+			if c < 0x80 then begin
+				add c;
+				loop (i + 2);
+			end else if c < 0x800 then begin
+				let c = c lor ((get (i + 1)) lsl 8) in
+				add c;
+				add (c lsr 8);
+				loop (i + 2);
+			end else
+				die "" __LOC__;
+		end
+	in
+	loop 0;
+	Buffer.contents b
+
+let url_encode s add_char =
+	let hex = "0123456789ABCDEF" in
+	for i = 0 to String.length s - 1 do
+		let c = String.unsafe_get s i in
+		match c with
+		| 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' | '-' | '.' ->
+			add_char c
+		| _ ->
+			add_char '%';
+			add_char (String.unsafe_get hex (int_of_char c lsr 4));
+			add_char (String.unsafe_get hex (int_of_char c land 0xF));
+	done
+
+let url_encode_s s =
+	let b = Buffer.create 0 in
+	url_encode s (Buffer.add_char b);
+	Buffer.contents b

+ 2 - 1
src/core/tFunctions.ml

@@ -432,6 +432,7 @@ let dynamify_monos t =
 	loop t
 
 exception ApplyParamsRecursion
+exception ApplyParamsMismatch
 
 (* substitute parameters with other types *)
 let apply_params ?stack cparams params t =
@@ -442,7 +443,7 @@ let apply_params ?stack cparams params t =
 		match l1, l2 with
 		| [] , [] -> []
 		| ttp :: l1 , t2 :: l2 -> (ttp.ttp_class,t2) :: loop l1 l2
-		| _ -> die "" __LOC__
+		| _ -> raise ApplyParamsMismatch
 	in
 	let subst = loop cparams params in
 	let rec loop t =

+ 3 - 1
src/core/tType.ml

@@ -473,6 +473,7 @@ type basic_types = {
 	mutable tnull : t -> t;
 	mutable tstring : t;
 	mutable tarray : t -> t;
+	mutable titerator : t -> t
 }
 
 type class_field_scope =
@@ -505,10 +506,11 @@ type flag_tclass_field =
 	| CfPostProcessed (* Marker to indicate the field has been post-processed *)
 	| CfUsed (* Marker for DCE *)
 	| CfMaybeUsed (* Marker for DCE *)
+	| CfNoLookup (* Field cannot be accessed by-name. *)
 
 (* Order has to match declaration for printing*)
 let flag_tclass_field_names = [
-	"CfPublic";"CfStatic";"CfExtern";"CfFinal";"CfModifiesThis";"CfOverride";"CfAbstract";"CfOverload";"CfImpl";"CfEnum";"CfGeneric";"CfDefault";"CfPostProcessed";"CfUsed";"CfMaybeUsed"
+	"CfPublic";"CfStatic";"CfExtern";"CfFinal";"CfModifiesThis";"CfOverride";"CfAbstract";"CfOverload";"CfImpl";"CfEnum";"CfGeneric";"CfDefault";"CfPostProcessed";"CfUsed";"CfMaybeUsed";"CfNoLookup"
 ]
 
 type flag_tenum =

+ 1 - 0
src/core/texpr.ml

@@ -328,6 +328,7 @@ let duplicate_tvars f_this e =
 		let v2 = alloc_var v.v_kind v.v_name v.v_type v.v_pos in
 		v2.v_meta <- v.v_meta;
 		v2.v_extra <- v.v_extra;
+		v2.v_flags <- v.v_flags;
 		Hashtbl.add vars v.v_id v2;
 		v2;
 	in

+ 11 - 8
src/core/warning.ml

@@ -79,17 +79,20 @@ let get_mode w (l : warning_option list list) =
 			| None -> false
 			| Some w' -> matches w' id
 	in
-	let rec loop mode l = match l with
+	let rec loop l = match l with
 		| [] ->
-			mode
+			WMEnable
 		| l2 :: l ->
-			let rec loop2 mode l = match l with
+			let rec loop2 l = match l with
 				| [] ->
-					mode
+					None
 				| opt :: l ->
-					let mode = if matches w opt.wo_warning then opt.wo_mode else mode in
-					loop2 mode l
+					if matches w opt.wo_warning then Some opt.wo_mode else loop2 l
 			in
-			loop (loop2 mode l2) l
+			match loop2 l2 with
+			| None ->
+				loop l
+			| Some mode ->
+				mode
 	in
-	loop WMEnable (* ? *) l
+	loop l

+ 37 - 8
src/core/withType.ml

@@ -8,6 +8,7 @@ type with_type_source_information = {
 type with_type_source =
 	| FunctionArgument of with_type_source_information
 	| StructureField of with_type_source_information
+	| LocalVariable of with_type_source_information
 	| ImplicitReturn
 
 type t =
@@ -25,18 +26,46 @@ let of_implicit_return t = WithType(t,Some ImplicitReturn)
 let with_argument t name = WithType(t,Some(FunctionArgument (make_with_type_source_information name None)))
 let with_argument_and_doc t name doc = WithType(t,Some(FunctionArgument (make_with_type_source_information name (Some doc))))
 let with_structure_field t name = WithType(t,Some(StructureField (make_with_type_source_information name None)))
+let with_local_variable t name = WithType(t,Some(LocalVariable (make_with_type_source_information name None)))
 let value = Value None
 let named_argument name = Value (Some(FunctionArgument (make_with_type_source_information name None)))
 let named_structure_field name = Value (Some(StructureField (make_with_type_source_information name None)))
 let no_value = NoValue
 
+let get_source_info_name = function
+	| FunctionArgument si -> Some si.si_name
+	| StructureField si -> Some si.si_name
+	| LocalVariable si -> Some si.si_name
+	| ImplicitReturn -> None
+
+let string_of_with_type_source = function
+	| FunctionArgument si ->
+		Printf.sprintf "FunctionArgument(%s)" si.si_name
+	| StructureField si ->
+		Printf.sprintf "StructureField(%s)" si.si_name
+	| LocalVariable si ->
+		Printf.sprintf "LocalVariable(%s)" si.si_name
+	| ImplicitReturn ->
+		"ImplicitReturn"
+
+let get_expected_name with_type = match with_type with
+	| Value (Some si) | WithType(_,Some si) ->
+		get_source_info_name si
+	| _ ->
+		None
+
 let to_string = function
-	| NoValue -> "NoValue"
-	| Value (None | Some ImplicitReturn) -> "Value"
-	| Value (Some(FunctionArgument si | StructureField si)) -> "Value " ^ si.si_name
-	| WithType(t,s) ->
-		let name = match s with
-			| Some(FunctionArgument si | StructureField si) -> si.si_name
-			| _ -> "None"
+	| NoValue ->
+		"NoValue"
+	| Value None ->
+		"Value(None)"
+	| Value (Some wts) ->
+		Printf.sprintf "Value(Some(%s))" (string_of_with_type_source wts)
+	| WithType(t,wts) ->
+		let s = match wts with
+			| None ->
+				"None"
+			| Some wts ->
+				Printf.sprintf "Some(%s)" (string_of_with_type_source wts)
 		in
-		Printf.sprintf "WithType(%s, %s)" (s_type (print_context()) t) name
+		Printf.sprintf "WithType(%s, %s)" (s_type (print_context()) t) s

+ 1 - 1
src/filters/ES6Ctors.ml

@@ -16,7 +16,7 @@
 	along with this program; if not, write to the Free Software
 	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *)
-open Common
+open Gctx
 open Globals
 open Type
 open Texpr.Builder

+ 1 - 1
src/filters/capturedVars.ml

@@ -47,7 +47,7 @@ let captured_vars com e =
 	| Jvm ->
 		let cnativearray =
 			match (List.find (fun md -> match md with
-					| TClassDecl ({ cl_path = ["java"],"NativeArray" }) -> true
+					| TClassDecl ({ cl_path = ["jvm"],"NativeArray" }) -> true
 					| _ -> false
 				) com.types)
 			with TClassDecl cl -> cl | _ -> die "" __LOC__

+ 35 - 18
src/filters/exceptions.ml

@@ -492,12 +492,7 @@ let catch_native ctx catches t p =
 	in
 	transform [] None catches
 
-(**
-	Transform `throw` and `try..catch` expressions.
-	`rename_locals` is required to deal with the names of temp vars.
-*)
-let filter tctx =
-	let stub e = e in
+let create_exception_context tctx =
 	match tctx.com.platform with (* TODO: implement for all targets *)
 	| Php | Js | Jvm | Python | Lua | Eval | Neko | Flash | Hl | Cpp ->
 		let config = tctx.com.config.pf_exceptions in
@@ -549,6 +544,18 @@ let filter tctx =
 			value_exception_type = value_exception_type;
 			value_exception_class = value_exception_class;
 		} in
+		Some ctx
+	| Cross | CustomTarget _ ->
+		None
+
+(**
+	Transform `throw` and `try..catch` expressions.
+	`rename_locals` is required to deal with the names of temp vars.
+*)
+let filter ectx =
+	let stub e = e in
+	match ectx with
+	| Some ctx ->
 		let rec run e =
 			match e.eexpr with
 			| TThrow e1 ->
@@ -566,22 +573,18 @@ let filter tctx =
 			if contains_throw_or_try e then run e
 			else stub e
 		)
-	| Cross | CustomTarget _ -> stub
+	| None ->
+		stub
 
 (**
 	Inserts `haxe.NativeStackTrace.saveStack(e)` in non-haxe.Exception catches.
 *)
-let insert_save_stacks tctx =
+let insert_save_stacks ectx =
+	let tctx = ectx.typer in
 	if not (has_feature tctx.com "haxe.NativeStackTrace.exceptionStack") then
 		(fun e -> e)
 	else
-		let native_stack_trace_cls =
-			let tp = mk_type_path (["haxe"],"NativeStackTrace") in
-			match Typeload.load_type_def tctx null_pos tp with
-			| TClassDecl cls -> cls
-			| TAbstractDecl { a_impl = Some cls } -> cls
-			| _ -> raise_typing_error "haxe.NativeStackTrace is expected to be a class or an abstract" null_pos
-		in
+		let native_stack_trace_cls = ectx.haxe_native_stack_trace in
 		let rec contains_insertion_points e =
 			match e.eexpr with
 			| TTry (e, catches) ->
@@ -639,12 +642,19 @@ let insert_save_stacks tctx =
 			else e
 		)
 
+let insert_save_stacks tctx ectx =
+	match ectx with
+	| Some ctx ->
+		insert_save_stacks {ctx with typer = tctx}
+	| None ->
+		(fun e -> e)
+
 (**
 	Adds `this.__shiftStack()` calls to constructors of classes which extend `haxe.Exception`
 *)
-let patch_constructors tctx =
-	let tp = make_ptp (mk_type_path haxe_exception_type_path) null_pos in
-	match Typeload.load_instance tctx tp ParamSpawnMonos LoadNormal with
+let patch_constructors ectx =
+	let tctx = ectx.typer in
+	match ectx.haxe_exception_type with
 	(* Add only if `__shiftStack` method exists *)
 	| TInst(cls,_) when PMap.mem "__shiftStack" cls.cl_fields ->
 		(fun mt ->
@@ -694,3 +704,10 @@ let patch_constructors tctx =
 			| _ -> ()
 		)
 	| _ -> (fun _ -> ())
+
+let patch_constructors tctx ectx =
+	match ectx with
+	| Some ctx ->
+		patch_constructors {ctx with typer = tctx}
+	| None ->
+		(fun _ -> ())

+ 61 - 59
src/filters/filters.ml

@@ -251,27 +251,29 @@ let mark_switch_break_loops e =
 	in
 	run e
 
-let rec fix_return_dynamic_from_void_function return_is_void e =
-	match e.eexpr with
-	| TFunction fn ->
-		let is_void = ExtType.is_void (follow fn.tf_type) in
-		let body = fix_return_dynamic_from_void_function is_void fn.tf_expr in
-		{ e with eexpr = TFunction { fn with tf_expr = body } }
-	| TReturn (Some return_expr) when return_is_void && t_dynamic == follow return_expr.etype ->
-		let return_pos = { e.epos with pmax = return_expr.epos.pmin - 1 } in
-		let exprs = [
-			fix_return_dynamic_from_void_function return_is_void return_expr;
-			{ e with eexpr = TReturn None; epos = return_pos };
-		] in
-		{ e with
-			eexpr = TMeta (
-				(Meta.MergeBlock, [], null_pos),
-				mk (TBlock exprs) e.etype e.epos
-			);
-		}
-	| _ -> Type.map_expr (fix_return_dynamic_from_void_function return_is_void) e
-
-let check_abstract_as_value e =
+let fix_return_dynamic_from_void_function _ e =
+	let rec loop return_is_void e = match e.eexpr with
+		| TFunction fn ->
+			let is_void = ExtType.is_void (follow fn.tf_type) in
+			let body = loop is_void fn.tf_expr in
+			{ e with eexpr = TFunction { fn with tf_expr = body } }
+		| TReturn (Some return_expr) when return_is_void && t_dynamic == follow return_expr.etype ->
+			let return_pos = { e.epos with pmax = return_expr.epos.pmin - 1 } in
+			let exprs = [
+				loop return_is_void return_expr;
+				{ e with eexpr = TReturn None; epos = return_pos };
+			] in
+			{ e with
+				eexpr = TMeta (
+					(Meta.MergeBlock, [], null_pos),
+					mk (TBlock exprs) e.etype e.epos
+				);
+			}
+		| _ -> Type.map_expr (loop return_is_void) e
+	in
+	loop true e
+
+let check_abstract_as_value _ e =
 	let rec loop e =
 		match e.eexpr with
 		| TField ({ eexpr = TTypeExpr _ }, _) -> ()
@@ -441,7 +443,7 @@ module ForRemap = struct
 		| TFor(v,e1,e2) ->
 			let e1 = loop e1 in
 			let e2 = loop e2 in
-			let iterator = ForLoop.IterationKind.of_texpr ctx e1 (ForLoop.is_cheap_enough_t ctx e2) e.epos in
+			let iterator = ForLoop.IterationKind.of_texpr ctx e1 (ForLoop.get_unroll_params_t ctx e2) e.epos in
 			let restore = save_locals ctx in
 			let e = ForLoop.IterationKind.to_texpr ctx v iterator e2 e.epos in
 			restore();
@@ -457,7 +459,7 @@ end
 
 open FilterContext
 
-let destruction tctx detail_times main locals =
+let destruction tctx ectx detail_times main locals =
 	let com = tctx.com in
 	with_timer detail_times "type 2" None (fun () ->
 		(* PASS 2: type filters pre-DCE *)
@@ -489,30 +491,30 @@ let destruction tctx detail_times main locals =
 			tctx
 			detail_times
 			(* This has to run after DCE, or otherwise its condition always holds. *)
-			["insert_save_stacks",Exceptions.insert_save_stacks tctx]
+			["insert_save_stacks",(fun tctx -> Exceptions.insert_save_stacks tctx ectx)]
 		)
 		com.types;
 	let type_filters = [
-		Exceptions.patch_constructors tctx; (* TODO: I don't believe this should load_instance anything at this point... *)
-		check_private_path com;
-		Naming.apply_native_paths;
-		add_rtti com;
-		(match com.platform with | Jvm -> (fun _ -> ()) | _ -> (fun mt -> AddFieldInits.add_field_inits tctx.c.curclass.cl_path locals com mt));
-		(match com.platform with Hl -> (fun _ -> ()) | _ -> add_meta_field com);
-		check_void_field;
-		(match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ -> ()));
-		commit_features com;
-		(if com.config.pf_reserved_type_paths <> [] then check_reserved_type_paths com else (fun _ -> ()));
+		(fun tctx -> Exceptions.patch_constructors tctx ectx); (* TODO: I don't believe this should load_instance anything at this point... *)
+		(fun _ -> check_private_path com);
+		(fun _ -> Naming.apply_native_paths);
+		(fun _ -> add_rtti com);
+		(match com.platform with | Jvm -> (fun _ _ -> ()) | _ -> (fun tctx mt -> AddFieldInits.add_field_inits tctx.c.curclass.cl_path locals com mt));
+		(match com.platform with Hl -> (fun _ _ -> ()) | _ -> (fun _ -> add_meta_field com));
+		(fun _ -> check_void_field);
+		(fun _ -> (match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ -> ())));
+		(fun _ -> commit_features com);
+		(fun _ -> (if com.config.pf_reserved_type_paths <> [] then check_reserved_type_paths com else (fun _ -> ())));
 	] in
 	with_timer detail_times "type 3" None (fun () ->
 		List.iter (fun t ->
-			begin match t with
-			| TClassDecl c ->
-				tctx.c.curclass <- c
-			| _ ->
-				()
-			end;
-			List.iter (fun f -> f t) type_filters
+			let tctx = match t with
+				| TClassDecl c ->
+					TyperManager.clone_for_class tctx c
+				| _ ->
+					tctx
+			in
+			List.iter (fun f -> f tctx t) type_filters
 		) com.types;
 	);
 	com.callbacks#run com.error_ext com.callbacks#get_after_filters;
@@ -664,7 +666,7 @@ let might_need_cf_unoptimized c cf =
 	| _ ->
 		has_class_field_flag cf CfGeneric
 
-let run tctx main before_destruction =
+let run tctx ectx main before_destruction =
 	let com = tctx.com in
 	let detail_times = (try int_of_string (Common.defined_value_safe com ~default:"0" Define.FilterTimes) with _ -> 0) in
 	let new_types = List.filter (fun t ->
@@ -705,20 +707,20 @@ let run tctx main before_destruction =
 	NullSafety.run com new_types;
 	(* PASS 1: general expression filters *)
 	let filters = [
-		"ForRemap",ForRemap.apply tctx;
-		"handle_abstract_casts",AbstractCast.handle_abstract_casts tctx;
+		"ForRemap",ForRemap.apply;
+		"handle_abstract_casts",AbstractCast.handle_abstract_casts;
 	] in
 	List.iter (run_expression_filters tctx detail_times filters) new_types;
 	let filters = [
-		"local_statics",LocalStatic.run tctx;
-		"fix_return_dynamic_from_void_function",fix_return_dynamic_from_void_function true;
-		"check_local_vars_init",check_local_vars_init tctx;
+		"local_statics",LocalStatic.run;
+		"fix_return_dynamic_from_void_function",fix_return_dynamic_from_void_function;
+		"check_local_vars_init",check_local_vars_init;
 		"check_abstract_as_value",check_abstract_as_value;
-		"Tre",if defined com Define.AnalyzerOptimize then Tre.run tctx else (fun e -> e);
-		"reduce_expression",Optimizer.reduce_expression tctx;
-		"inline_constructors",InlineConstructors.inline_constructors tctx;
-		"Exceptions_filter",Exceptions.filter tctx;
-		"captured_vars",CapturedVars.captured_vars com;
+		"Tre",if defined com Define.AnalyzerOptimize then Tre.run else (fun _ e -> e);
+		"reduce_expression",Optimizer.reduce_expression;
+		"inline_constructors",InlineConstructors.inline_constructors;
+		"Exceptions_filter",(fun _ -> Exceptions.filter ectx);
+		"captured_vars",(fun _ -> CapturedVars.captured_vars com);
 	] in
 	List.iter (run_expression_filters tctx detail_times filters) new_types;
 	(* PASS 1.5: pre-analyzer type filters *)
@@ -739,13 +741,13 @@ let run tctx main before_destruction =
 	enter_stage com CAnalyzerDone;
 	let locals = RenameVars.init com in
 	let filters = [
-		"sanitize",Optimizer.sanitize com;
-		"add_final_return",if com.config.pf_add_final_return then add_final_return else (fun e -> e);
+		"sanitize",(fun _ e -> Optimizer.sanitize com e);
+		"add_final_return",(fun _ -> if com.config.pf_add_final_return then add_final_return else (fun e -> e));
 		"RenameVars",(match com.platform with
-		| Eval -> (fun e -> e)
-		| Jvm -> (fun e -> e)
-		| _ -> (fun e -> RenameVars.run tctx.c.curclass.cl_path locals e));
-		"mark_switch_break_loops",mark_switch_break_loops;
+		| Eval -> (fun _ e -> e)
+		| Jvm -> (fun _ e -> e)
+		| _ -> (fun tctx e -> RenameVars.run tctx.c.curclass.cl_path locals e));
+		"mark_switch_break_loops",(fun _ -> mark_switch_break_loops);
 	] in
 	List.iter (run_expression_filters tctx detail_times filters) new_types;
 	with_timer detail_times "callbacks" None (fun () ->
@@ -763,4 +765,4 @@ let run tctx main before_destruction =
 		com.callbacks#run com.error_ext com.callbacks#get_after_save;
 	);
 	before_destruction();
-	destruction tctx detail_times main locals
+	destruction tctx ectx detail_times main locals

+ 13 - 13
src/filters/filtersCommon.ml

@@ -55,26 +55,26 @@ let is_overridden cls field =
 
 let run_expression_filters ?(ignore_processed_status=false) ctx detail_times filters t =
 	let com = ctx.com in
-	let run identifier e =
+	let run (ctx : typer) identifier e =
 		List.fold_left (fun e (filter_name,f) ->
-			FilterContext.with_timer detail_times filter_name identifier (fun () -> f e)
+			FilterContext.with_timer detail_times filter_name identifier (fun () -> f ctx e)
 		) e filters
 	in
 	match t with
 	| TClassDecl c when is_removable_class c -> ()
 	| TClassDecl c ->
-		ctx.c.curclass <- c;
-		ctx.m <- TypeloadModule.make_curmod ctx.com ctx.g c.cl_module;
-		let rec process_field f =
-			if ignore_processed_status || not (has_class_field_flag f CfPostProcessed) then begin
-				ctx.f.curfield <- f;
-				(match f.cf_expr with
-				| Some e when not (is_removable_field com f) ->
-					let identifier = Printf.sprintf "%s.%s" (s_type_path c.cl_path) f.cf_name in
-					f.cf_expr <- Some (rec_stack_loop AbstractCast.cast_stack f (run (Some identifier)) e);
+		let ctx = TyperManager.clone_for_module ctx (TypeloadModule.make_curmod ctx.com ctx.g c.cl_module) in
+		let ctx = TyperManager.clone_for_class ctx c in
+		let rec process_field cf =
+			if ignore_processed_status || not (has_class_field_flag cf CfPostProcessed) then begin
+				let ctx = TyperManager.clone_for_field ctx cf cf.cf_params in
+				(match cf.cf_expr with
+				| Some e when not (is_removable_field com cf) ->
+					let identifier = Printf.sprintf "%s.%s" (s_type_path c.cl_path) cf.cf_name in
+					cf.cf_expr <- Some (rec_stack_loop AbstractCast.cast_stack cf (run ctx (Some identifier)) e);
 				| _ -> ());
 			end;
-			List.iter process_field f.cf_overloads
+			List.iter process_field cf.cf_overloads
 		in
 		List.iter process_field c.cl_ordered_fields;
 		List.iter process_field c.cl_ordered_statics;
@@ -85,7 +85,7 @@ let run_expression_filters ?(ignore_processed_status=false) ctx detail_times fil
 		| None -> ()
 		| Some e ->
 			let identifier = Printf.sprintf "%s.__init__" (s_type_path c.cl_path) in
-			TClass.set_cl_init c (run (Some identifier) e))
+			TClass.set_cl_init c (run ctx (Some identifier) e))
 	| TEnumDecl _ -> ()
 	| TTypeDecl _ -> ()
 	| TAbstractDecl _ -> ()

+ 2 - 1
src/filters/localStatic.ml

@@ -18,7 +18,8 @@ let promote_local_static lsctx run v eo =
 		] v.v_pos);
 	with Not_found ->
 		let cf = mk_field name ~static:true v.v_type v.v_pos v.v_pos in
-		cf.cf_meta <- v.v_meta;
+		cf.cf_meta <- (Meta.NoCompletion,[],Globals.null_pos) :: v.v_meta;
+		add_class_field_flag cf CfNoLookup;
 		begin match eo with
 		| None ->
 			()

+ 154 - 0
src/generators/cpp/cppAst.ml

@@ -0,0 +1,154 @@
+open Type
+open Globals
+
+type tcpp =
+  | TCppDynamic
+  | TCppUnchanged
+  | TCppObject
+  | TCppObjectPtr
+  | TCppVoid
+  | TCppNull
+  | TCppEnum of tenum
+  | TCppScalar of string
+  | TCppString
+  | TCppFastIterator of tcpp
+  | TCppPointer of string * tcpp
+  | TCppRawPointer of string * tcpp
+  | TCppFunction of tcpp list * tcpp * string
+  | TCppObjCBlock of tcpp list * tcpp
+  | TCppRest of tcpp
+  | TCppReference of tcpp
+  | TCppStruct of tcpp
+  | TCppStar of tcpp * bool
+  | TCppVoidStar
+  | TCppVarArg
+  | TCppAutoCast
+  | TCppDynamicArray
+  | TCppObjectArray of tcpp
+  | TCppWrapped of tcpp
+  | TCppScalarArray of tcpp
+  | TCppObjC of tclass
+  | TCppNativePointer of tclass
+  | TCppVariant
+  | TCppCode of tcpp
+  | TCppInst of tclass * tcpp list
+  | TCppInterface of tclass
+  | TCppProtocol of tclass
+  | TCppClass
+  | TCppGlobal
+
+and tcppexpr = { cppexpr : tcpp_expr_expr; cpptype : tcpp; cpppos : pos }
+
+and tcpp_closure = {
+  close_type : tcpp;
+  close_args : (tvar * texpr option) list;
+  close_expr : tcppexpr;
+  close_id : int;
+  close_undeclared : (string, tvar) Hashtbl.t;
+  close_this : tcppthis option;
+}
+
+and tcppcrementop = CppIncrement | CppDecrement
+and tcppunop = CppNeg | CppNegBits | CppNot
+and tcppthis = ThisReal | ThisFake | ThisDynamic
+
+and tcppvarloc =
+  | VarLocal of tvar
+  | VarClosure of tvar
+  | VarThis of tclass_field * tcpp
+  | VarInstance of tcppexpr * tclass_field * string * string
+  | VarInterface of tcppexpr * tclass_field
+  | VarStatic of tclass * bool * tclass_field
+  | VarInternal of tcppexpr * string * string
+
+and tcppinst = InstPtr | InstObjC | InstStruct
+
+and tcppfuncloc =
+  | FuncThis of tclass_field * tcpp
+  | FuncInstance of tcppexpr * tcppinst * tclass_field
+  | FuncStatic of tclass * bool * tclass_field
+  | FuncTemplate of tclass * tclass_field * path * bool
+  | FuncInterface of tcppexpr * tclass * tclass_field
+  | FuncEnumConstruct of tenum * tenum_field
+  | FuncSuperConstruct of tcpp
+  | FuncSuper of tcppthis * tcpp * tclass_field
+  | FuncNew of tcpp
+  | FuncExpression of tcppexpr
+  | FuncInternal of tcppexpr * string * string
+  | FuncExtern of string * bool
+  | FuncFromStaticFunction
+
+and tcpparrayloc =
+  | ArrayTyped of tcppexpr * tcppexpr * tcpp
+  | ArrayPointer of tcppexpr * tcppexpr
+  | ArrayRawPointer of tcppexpr * tcppexpr
+  | ArrayObject of tcppexpr * tcppexpr * tcpp
+  | ArrayVirtual of tcppexpr * tcppexpr
+  | ArrayImplements of tclass * tcppexpr * tcppexpr
+  | ArrayDynamic of tcppexpr * tcppexpr
+
+and tcpplvalue =
+  | CppVarRef of tcppvarloc
+  | CppArrayRef of tcpparrayloc
+  | CppDynamicRef of tcppexpr * string
+  | CppExternRef of string * bool
+
+and tcpp_expr_expr =
+  | CppInt of int32
+  | CppFloat of string
+  | CppString of string
+  | CppBool of bool
+  | CppNull
+  | CppNullAccess
+  | CppNil
+  | CppThis of tcppthis
+  | CppSuper of tcppthis
+  | CppCode of string * tcppexpr list
+  | CppClosure of tcpp_closure
+  | CppVar of tcppvarloc
+  | CppExtern of string * bool
+  | CppDynamicField of tcppexpr * string
+  | CppFunction of tcppfuncloc * tcpp
+  | CppEnumIndex of tcppexpr
+  | CppEnumField of tenum * tenum_field
+  | CppCall of tcppfuncloc * tcppexpr list
+  | CppFunctionAddress of tclass * tclass_field
+  | CppNewNative of tcppexpr
+  | CppAddressOf of tcppexpr
+  | CppDereference of tcppexpr
+  | CppArray of tcpparrayloc
+  | CppCrement of tcppcrementop * Ast.unop_flag * tcpplvalue
+  | CppSet of tcpplvalue * tcppexpr
+  | CppModify of Ast.binop * tcpplvalue * tcppexpr
+  | CppBinop of Ast.binop * tcppexpr * tcppexpr
+  | CppCompare of string * tcppexpr * tcppexpr * Ast.binop
+  | CppNullCompare of string * tcppexpr
+  | CppObjectDecl of (string * tcppexpr) list * bool
+  | CppPosition of string * int32 * string * string
+  | CppArrayDecl of tcppexpr list
+  | CppUnop of tcppunop * tcppexpr
+  | CppVarDecl of tvar * tcppexpr option
+  | CppBlock of tcppexpr list * tcpp_closure list * bool
+  | CppFor of tvar * 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
+  | CppBreak
+  | CppContinue
+  | CppClassOf of path * bool
+  | CppGoto of int
+  | CppReturn of tcppexpr option
+  | CppThrow of tcppexpr
+  | CppEnumParameter of tcppexpr * tenum_field * int
+  | CppTCast of tcppexpr * tcpp
+  | CppCast of tcppexpr * tcpp
+  | CppCastStatic of tcppexpr * tcpp
+  | CppCastScalar of tcppexpr * string
+  | CppCastVariant of tcppexpr
+  | CppCastObjC of tcppexpr * tclass
+  | CppCastObjCBlock of tcppexpr * tcpp list * tcpp
+  | CppCastProtocol of tcppexpr * tclass
+  | CppCastNative of tcppexpr

+ 727 - 0
src/generators/cpp/cppAstTools.ml

@@ -0,0 +1,727 @@
+open Ast
+open Type
+open Globals
+open CppAst
+open CppTypeUtils
+
+let follow = Abstract.follow_with_abstracts
+
+(*
+   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 "::"
+   for namespace "pack1::pack2::Name"
+*)
+let join_class_path path separator =
+  let result =
+    match (fst path, snd path) with
+    | [], s -> s
+    | el, s -> String.concat separator el ^ separator ^ s
+  in
+  if String.contains result '+' then
+    let idx = String.index result '+' in
+    String.sub result 0 idx
+    ^ String.sub result (idx + 1) (String.length result - idx - 1)
+  else result
+
+let class_text path = "::" ^ join_class_path path "::"
+
+let is_internal_member member =
+  member = "toString" || String.length member > 1 && String.sub member 0 2 = "__" &&
+  match member with
+  | "__ArgCount"
+  | "__ArrayImplRef"
+  | "__CStr"
+  | "__Compare"
+  | "__Create"
+  | "__CreateEmpty"
+  | "__FieldRef"
+  | "__FindArgCount"
+  | "__GetFieldMap"
+  | "__GetHandle"
+  | "__GetItem"
+  | "__GetScriptCallable"
+  | "__GetScriptVTable"
+  | "__Param"
+  | "__Remove"
+  | "__SGetClass"
+  | "__Set"
+  | "__SetItem"
+  | "__TArrayImplRef"
+  | "__ToDouble"
+  | "__ToInt"
+  | "__ToInterface"
+  | "__ToObject"
+  | "__Visit"
+  | "__WCStr"
+  | "__a"
+  | "__blit"
+  | "__boot"
+  | "__boot_all"
+  | "__compare"
+  | "__concat"
+  | "__construct"
+  | "__copy"
+  | "__filter"
+  | "__get_args"
+  | "__hx_dump_stack"
+  | "__hx_field_iter"
+  | "__hxt_gc_new"
+  | "__indexOf"
+  | "__insert"
+  | "__instanceof"
+  | "__int"
+  | "__iterator"
+  | "__join"
+  | "__lastIndexOf"
+  | "__loadprim"
+  | "__mClass"
+  | "__mDynamicFields"
+  | "__map"
+  | "__memcmp"
+  | "__new"
+  | "__pop"
+  | "__prime"
+  | "__push"
+  | "__qsort"
+  | "__unshift"
+  | "__unsafeStringReference"
+  | "__time_stamp"
+  | "__superString"
+  | "__splice"
+  | "__shift"
+  | "__slice"
+  | "__sort"
+  | "__s_id"
+  | "__run"
+  | "__root"
+  | "__register"
+  | "__remove"
+  | "__removeAt"
+  | "__reverse"
+  | "__zero"
+  | "__Field"
+  | "__IField"
+  | "__Run"
+  | "__Is"
+  | "__GetClass"
+  | "__GetType"
+  | "__ToString"
+  | "__s"
+  | "__GetPtr"
+  | "__SetField"
+  | "__length"
+  | "__IsArray"
+  | "__SetThis"
+  | "__Internal"
+  | "__EnumParams"
+  | "__Index"
+  | "__Tag"
+  | "__GetFields"
+  | "__HasField"
+  | "__get"
+  | "__set"
+  | "__unsafe_get"
+  | "__unsafe_set"
+  | "__global__"
+  | "__SetSize"
+  | "__trace"
+  | "__GetRealObject"
+  | "__SetSizeExact"
+  | "__cpp__"
+  | "__URLEncode"
+  | "__URLDecode"
+  | "__IsEnum" ->
+    true
+  | _ ->
+    String.length member > 4 && String.sub member 0 4 = "__hx"
+
+let is_known_member member =
+  match member with "__meta__" | "__rtti" | "_Compare" -> true | _ -> false
+
+(* Convert function names that can't be written in c++ ... *)
+let keyword_remap name =
+  if is_internal_member name || is_known_member name then name
+  else if String.length name > 1 && String.sub name 0 2 = "__" then
+    "_hx_" ^ name
+  else
+    match name with
+    | "int"
+    | "Int"
+    | "Bool"
+    | "super"
+    | "auto"
+    | "char"
+    | "const"
+    | "delete"
+    | "double"
+    | "Float"
+    | "enum"
+    | "extern"
+    | "float"
+    | "friend"
+    | "goto"
+    | "long"
+    | "operator"
+    | "protected"
+    | "register"
+    | "short"
+    | "signed"
+    | "sizeof"
+    | "template"
+    | "typedef"
+    | "union"
+    | "unsigned"
+    | "void"
+    | "volatile"
+    | "or"
+    | "and"
+    | "xor"
+    | "or_eq"
+    | "not"
+    | "and_eq"
+    | "xor_eq"
+    | "typeof"
+    | "stdin"
+    | "stdout"
+    | "stderr"
+    | "system"
+    | "BIG_ENDIAN"
+    | "LITTLE_ENDIAN"
+    | "assert"
+    | "NULL"
+    | "wchar_t"
+    | "EOF"
+    | "bool"
+    | "const_cast"
+    | "dynamic_cast"
+    | "explicit"
+    | "export"
+    | "mutable"
+    | "namespace"
+    | "reinterpret_cast"
+    | "static_cast"
+    | "typeid"
+    | "typename"
+    | "virtual"
+    | "_Complex"
+    | "INFINITY"
+    | "NAN"
+    | "INT_MIN"
+    | "INT_MAX"
+    | "INT8_MIN"
+    | "INT8_MAX"
+    | "UINT8_MAX"
+    | "INT16_MIN"
+    | "INT16_MAX"
+    | "UINT16_MAX"
+    | "INT32_MIN"
+    | "INT32_MAX"
+    | "UINT32_MAX"
+    | "asm"
+    | "near"
+    | "far"
+    | "_w64"
+    | "HX_"
+    | "HXLINE"
+    | "HXDLIN"
+    | "NO"
+    | "YES"
+    | "abstract"
+    | "decltype"
+    | "finally"
+    | "nullptr"
+    | "static_assert"
+    | "struct"
+    | "_Atomic"
+    | "constexpr"
+    | "consteval"
+    | "constinit"
+    | "co_await"
+    | "co_return"
+    | "co_yield"
+    | "alignas"
+    | "alignof"
+    | "_Alignas"
+    | "_Alignof"
+    | "requires" ->
+      "_hx_" ^ name
+    | x -> x
+
+let remap_class_path class_path =
+  let path_remap with_keywords name =
+    let len = String.length name in
+    if len > 3 && String.sub name 0 3 = " ::" then String.sub name 3 (len - 3)
+    else if len > 2 && String.sub name 0 2 = "::" then
+      String.sub name 2 (len - 2)
+    else if with_keywords then keyword_remap name
+    else name
+  in
+  ( List.map (path_remap true) (fst class_path),
+    path_remap false (snd class_path) )
+
+let join_class_path_remap path separator =
+  match join_class_path (remap_class_path path) separator with
+  | "Class" -> "hx::Class"
+  | x -> x
+
+let rec s_tcpp = function
+  | CppInt _ -> "CppInt"
+  | CppFloat _ -> "CppFloat"
+  | CppString _ -> "CppString"
+  | CppBool _ -> "CppBool"
+  | CppNull -> "CppNull"
+  | CppNil -> "CppNil"
+  | CppThis _ -> "CppThis"
+  | CppSuper _ -> "CppSuper"
+  | CppCode _ -> "CppCode"
+  | CppClosure _ -> "CppClosure"
+  | CppVar (VarLocal _) -> "CppVarLocal"
+  | CppVar (VarClosure _) -> "CppVarClosure"
+  | CppVar (VarThis _) -> "CppVarThis"
+  | CppVar (VarInstance (expr, field, clazz, op)) ->
+      "CppVarInstance(" ^ clazz ^ "::" ^ op ^ field.cf_name ^ ")"
+  | CppVar (VarInterface _) -> "CppVarInterface"
+  | CppVar (VarStatic (_, true, _)) -> "CppObjcVarStatic"
+  | CppVar (VarStatic _) -> "CppVarStatic"
+  | CppVar (VarInternal _) -> "CppVarInternal"
+  | CppDynamicField _ -> "CppDynamicField"
+  | CppExtern _ -> "CppExtern"
+  | CppFunction _ -> "CppFunction"
+  | CppEnumIndex _ -> "CppEnumIndex"
+  | CppEnumField _ -> "CppEnumField"
+  | CppNullAccess -> "CppNullAccess"
+  | CppCall (FuncThis _, _) -> "CppCallThis"
+  | 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, _), _) ->
+      if objC then "CppCallStaticObjC" else "CppCallStatic"
+  | CppCall (FuncTemplate _, _) -> "CppCallTemplate"
+  | CppCall (FuncEnumConstruct _, _) -> "CppCallEnumConstruct"
+  | CppCall (FuncSuperConstruct _, _) -> "CppCallSuperConstruct"
+  | CppCall (FuncSuper _, _) -> "CppCallSuper"
+  | CppCall (FuncNew _, _) -> "CppCallNew"
+  | CppCall (FuncExpression _, _) -> "CppCallExpression"
+  | CppCall (FuncInternal _, _) -> "CppCallInternal"
+  | CppCall (FuncExtern _, _) -> "CppCallExtern"
+  | CppCall (FuncFromStaticFunction, _) -> "CppCallFromStaticFunction"
+  | CppNewNative _ -> "CppNewNative"
+  | CppAddressOf _ -> "CppAddressOf"
+  | CppDereference _ -> "CppDereference"
+  | CppFunctionAddress _ -> "CppFunctionAddress"
+  | CppArray _ -> "CppArray"
+  | CppCrement _ -> "CppCrement"
+  | CppSet _ -> "CppSet"
+  | CppModify _ -> "CppModify"
+  | CppBinop _ -> "CppBinop"
+  | CppCompare _ -> "CppCompare"
+  | CppNullCompare _ -> "CppNullCompare"
+  | CppObjectDecl _ -> "CppObjectDecl"
+  | CppPosition _ -> "CppPosition"
+  | CppArrayDecl _ -> "CppArrayDecl"
+  | CppUnop _ -> "CppUnop"
+  | CppVarDecl _ -> "CppVarDecl"
+  | CppBlock _ -> "CppBlock"
+  | CppFor _ -> "CppFor"
+  | CppIf _ -> "CppIf"
+  | CppWhile _ -> "CppWhile"
+  | CppIntSwitch _ -> "CppIntSwitch"
+  | CppSwitch _ -> "CppSwitch"
+  | CppTry _ -> "CppTry"
+  | CppBreak -> "CppBreak"
+  | CppContinue -> "CppContinue"
+  | CppClassOf _ -> "CppClassOf"
+  | CppGoto _ -> "CppGoto"
+  | CppReturn _ -> "CppReturn"
+  | CppThrow _ -> "CppThrow"
+  | CppEnumParameter _ -> "CppEnumParameter"
+  | CppTCast _ -> "CppTCast"
+  | CppCast _ -> "CppCast"
+  | CppCastStatic _ -> "CppCastStatic"
+  | CppCastScalar _ -> "CppCastScalar"
+  | CppCastVariant _ -> "CppCastVariant"
+  | CppCastObjC _ -> "CppCastObjC"
+  | CppCastObjCBlock _ -> "CppCastObjCBlock"
+  | CppCastProtocol _ -> "CppCastProtocol"
+  | CppCastNative _ -> "CppCastNative"
+
+and tcpp_to_string_suffix suffix tcpp =
+  match tcpp with
+  | TCppDynamic -> " ::Dynamic"
+  | TCppUnchanged -> " ::Dynamic/*Unchanged*/"
+  | TCppObject -> " ::Dynamic"
+  | TCppObjectPtr -> " ::hx::Object *"
+  | TCppReference t -> tcpp_to_string t ^ " &"
+  | TCppStruct t -> "cpp::Struct< " ^ tcpp_to_string t ^ " >"
+  | TCppStar (t, const) ->
+      (if const then "const " else "") ^ tcpp_to_string t ^ " *"
+  | TCppVoid -> "void"
+  | TCppVoidStar -> "void *"
+  | TCppRest _ -> "vaarg_list"
+  | TCppVarArg -> "vararg"
+  | TCppAutoCast -> "::cpp::AutoCast"
+  | TCppVariant -> "::cpp::Variant"
+  | TCppEnum enum -> " ::" ^ join_class_path_remap enum.e_path "::" ^ suffix
+  | TCppScalar scalar -> scalar
+  | TCppString -> "::String"
+  | TCppFastIterator it ->
+      "::cpp::FastIterator" ^ suffix ^ "< " ^ tcpp_to_string it ^ " >"
+  | TCppPointer (ptrType, valueType) ->
+      "::cpp::" ^ ptrType ^ "< " ^ tcpp_to_string valueType ^ " >"
+  | TCppRawPointer (constName, valueType) ->
+      constName ^ tcpp_to_string valueType ^ "*"
+  | TCppFunction (argTypes, retType, abi) ->
+      let args = String.concat "," (List.map tcpp_to_string argTypes) in
+      "::cpp::Function< " ^ tcpp_to_string retType ^ " " ^ abi ^ " (" ^ args
+      ^ ") >"
+  | TCppObjCBlock (argTypes, retType) ->
+      tcpp_objc_block_struct argTypes retType ^ "::t"
+  | TCppDynamicArray -> "::cpp::VirtualArray" ^ suffix
+  | TCppObjectArray _ -> "::Array" ^ suffix ^ "< ::Dynamic>"
+  | TCppWrapped _ -> " ::Dynamic"
+  | TCppScalarArray value ->
+      "::Array" ^ suffix ^ "< " ^ tcpp_to_string value ^ " >"
+  | TCppObjC klass ->
+      let path = join_class_path_remap klass.cl_path "::" in
+      if has_class_flag klass CInterface then "id < " ^ path ^ ">"
+      else path ^ " *"
+  | TCppProtocol interface ->
+      let path =
+        match get_meta_string interface.cl_meta Meta.ObjcProtocol with
+        | Some p -> p
+        | None -> join_class_path_remap interface.cl_path "::"
+      in
+      "id < " ^ path ^ ">"
+  | TCppNativePointer klass ->
+      let name = join_class_path_remap klass.cl_path "::" in
+      if suffix = "_obj" then name else "::hx::Native< " ^ name ^ "* >"
+  | TCppInst (klass, p) ->
+      cpp_class_path_of klass p ^ if is_native_class klass then "" else suffix
+  | TCppInterface klass when suffix = "_obj" ->
+      cpp_class_path_of klass [] ^ suffix
+  | TCppInterface _ -> "::Dynamic"
+  | TCppClass -> "::hx::Class" ^ suffix
+  | TCppGlobal -> "::Dynamic"
+  | TCppNull -> " ::Dynamic"
+  | TCppCode _ -> "Code"
+
+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
+  let suffix = string_of_int (List.length argTypes) in
+  if ret = "void" then
+    if List.length argTypes = 0 then "::hx::TObjcBlockVoidVoid"
+    else "::hx::TObjcBlockVoidArgs" ^ suffix ^ "< " ^ args ^ " >"
+  else if List.length argTypes = 0 then "::hx::TObjcBlockRetVoid< " ^ ret ^ " >"
+  else "::hx::TObjcBlockRetArgs" ^ suffix ^ "< " ^ ret ^ "," ^ args ^ " >"
+
+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 "::"
+
+(*  Get a string to represent a type.
+   The "suffix" will be nothing or "_obj", depending if we want the name of the
+   pointer class or the pointee (_obj class *)
+let rec class_string klass suffix params remap =
+   let type_string = type_string_remap remap in
+   let join_class_path_remap = if remap then join_class_path_remap else join_class_path in
+   (match klass.cl_path with
+   (* Array class *)
+   |  ([],"Array") when is_dynamic_array_param (List.hd params) ->
+           "cpp::ArrayBase" ^ suffix
+           (*"cpp::VirtualArray" ^ suffix*)
+   |  ([],"Array") -> (snd klass.cl_path) ^ suffix ^ "< " ^ (String.concat ","
+               (List.map array_element_type params) ) ^ " >"
+   (* FastIterator class *)
+   |  (["cpp"],"FastIterator") -> "::cpp::FastIterator" ^ suffix ^ "< " ^ (String.concat ","
+               (List.map type_string  params) ) ^ " >"
+   |  (["cpp"],"Pointer")
+   |  (["cpp"],"ConstPointer") ->
+        "::cpp::Pointer< " ^ (String.concat "," (List.map type_string params) ) ^ " >"
+   |  (["cpp"],"RawPointer") ->
+        " " ^ (String.concat "," (List.map type_string params) ) ^ " * "
+   |  (["cpp"],"RawConstPointer") ->
+        " const " ^ (String.concat "," (List.map type_string params) ) ^ " * "
+   |  (["cpp"],"Function") ->
+        "::cpp::Function< " ^ (cpp_function_signature_params params) ^ " >"
+   | _ when is_dynamic_type_param klass.cl_kind -> "Dynamic"
+   |  ([],"#Int") -> "/* # */int"
+   |  (["cpp"],"UInt8") -> "unsigned char"
+   |  ([],"Class") -> "::hx::Class"
+   |  ([],"EnumValue") -> "Dynamic"
+   |  ([],"Null") -> (match params with
+         | [t] ->
+            (match follow t with
+            | TAbstract ({ a_path = [],"Int" },_)
+            | TAbstract ({ a_path = [],"Float" },_)
+            | TAbstract ({ a_path = [],"Bool" },_) -> "Dynamic"
+            | TAbstract ({ a_path = ["cpp"],"UInt8" },_) -> "Dynamic"
+            | t when type_has_meta_key Meta.NotNull t -> "Dynamic"
+            | _ -> "/*NULL*/" ^ (type_string t) )
+         | _ -> die "" __LOC__);
+   (* Objective-C class *)
+   | path when is_objc_type (TInst(klass,[])) ->
+      let str = join_class_path_remap klass.cl_path "::" in
+      if suffix = "_obj" then
+         str
+      else if (has_class_flag klass CInterface) then
+         "id < " ^ str ^ ">"
+      else
+         str ^ " *"
+   (* Native interface - use pointer *)
+   | _ when (has_class_flag klass CInterface) && is_native_gen_class klass ->
+            (join_class_path_remap klass.cl_path "::") ^ " *"
+   (* Normal class *)
+   | _ when is_native_class klass ->
+      let class_params = match params with
+      | [] -> ""
+      | _ -> "< " ^ (String.concat "," (List.map type_string params)) ^ " >" in
+      (join_class_path_remap klass.cl_path "::") ^ class_params
+   | _ ->
+      let globalNamespace = match get_meta_string klass.cl_meta Meta.Native with
+      | Some s -> s
+      | None -> "::" in
+      globalNamespace ^ (join_class_path_remap klass.cl_path "::") ^ suffix)
+
+and type_has_meta_key key haxe_type =
+   match follow haxe_type with
+   | TInst (klass,_) -> Meta.has key klass.cl_meta
+   | TType (type_def,_) -> Meta.has key type_def.t_meta
+   | TEnum (enum_def,_) -> Meta.has key enum_def.e_meta
+   | _ -> false
+
+and type_string_suff suffix haxe_type remap =
+   let type_string = type_string_remap remap in
+   let join_class_path_remap = if remap then join_class_path_remap else join_class_path in
+   (match haxe_type with
+   | TMono r -> (match r.tm_type with None -> "Dynamic" ^ suffix | Some t -> type_string_suff suffix t remap)
+   | TAbstract ({ a_path = ([],"Void") },[]) -> "Void"
+   | TAbstract ({ a_path = ([],"Bool") },[]) -> "bool"
+   | TAbstract ({ a_path = ([],"Float") },[]) -> "Float"
+   | TAbstract ({ a_path = ([],"Int") },[]) -> "int"
+   | TAbstract ({ a_path = (["cpp"],"UInt8") },[]) -> "unsigned char"
+   | TAbstract( { a_path = ([], "EnumValue") }, _  ) -> "Dynamic"
+   | TAbstract ({ a_path = ([],"Null") }, [t]) ->
+    (match follow t with
+    | TAbstract ({ a_path = [],"Int" },_)
+    | TAbstract ({ a_path = [],"Float" },_)
+    | TAbstract ({ a_path = [],"Bool" },_) -> "Dynamic" ^ suffix
+    | t when type_has_meta_key Meta.NotNull t -> "Dynamic" ^ suffix
+    | _ -> type_string_suff suffix t remap)
+   | TEnum (enum,_) ->  (cpp_enum_path_of enum) ^ suffix
+   | TInst (klass,params) ->  (class_string klass suffix params remap)
+   | TType (type_def,params) ->
+      (match type_def.t_path with
+      | [] , "Array" ->
+         (match params with
+         | [t] when (type_string (follow t) ) = "Dynamic" -> "Dynamic"
+         | [t] -> "Array< " ^ (type_string (follow t) ) ^ " >"
+         | _ -> die "" __LOC__)
+      | ["cpp"] , "FastIterator" ->
+         (match params with
+         | [t] -> "::cpp::FastIterator< " ^ (type_string (follow t) ) ^ " >"
+         | _ -> die "" __LOC__)
+      | ["cpp"] , "Pointer"
+      | ["cpp"] , "ConstPointer" ->
+         (match params with
+         | [t] -> "::cpp::Pointer< " ^ (type_string (follow t) ) ^ " >"
+         | _ -> die "" __LOC__)
+      | ["cpp"] , "RawPointer" ->
+         (match params with
+         | [t] -> " " ^ (type_string (follow t) ) ^ " *"
+         | _ -> die "" __LOC__)
+      | ["cpp"] , "RawConstPointer" ->
+         (match params with
+         | [t] -> "const " ^ (type_string (follow t) ) ^ " *"
+         | _ -> die "" __LOC__)
+      | ["cpp"] , "Function" ->
+         "::cpp::Function< " ^ (cpp_function_signature_params params ) ^ " >"
+      | _ ->  type_string_suff suffix (apply_typedef type_def params) remap
+      )
+   | TFun (args,haxe_type) -> "Dynamic" ^ suffix
+   | TAnon a -> "Dynamic"
+      (*
+      (match !(a.a_status) with
+      | ClassStatics c -> type_string_suff suffix (TInst (c,List.map snd c.cl_params))
+      | EnumStatics e -> type_string_suff suffix (TEnum (e,List.map snd e.e_params))
+      | _ -> "Dynamic"  ^ suffix )
+      *)
+   | TDynamic haxe_type -> "Dynamic" ^ suffix
+   | TLazy func -> type_string_suff suffix (lazy_type func) remap
+   | TAbstract (abs,pl) when abs.a_impl <> None ->
+      type_string_suff suffix (Abstract.get_underlying_type abs pl) remap
+   | TAbstract (abs,pl) ->
+      "::" ^ (join_class_path_remap abs.a_path "::") ^ suffix
+   )
+
+and type_string_remap remap haxe_type =
+   type_string_suff "" haxe_type remap
+
+and type_string haxe_type =
+   type_string_suff "" haxe_type true
+
+and cpp_enum_path_of enum =
+   let globalNamespace =
+      match get_meta_string enum.e_meta Meta.Native with
+      | Some s -> s
+      | None -> "::" in
+   globalNamespace ^ (join_class_path_remap enum.e_path "::")
+
+and array_element_type haxe_type =
+   match type_string haxe_type with
+   | x when cant_be_null haxe_type -> x
+   | x when is_interface_type (follow haxe_type) -> x
+   | "::String" -> "::String"
+   | _ -> "::Dynamic"
+
+and cpp_function_signature tfun abi =
+   match follow tfun with
+   | TFun(args,ret) -> (type_string ret) ^ " " ^ abi ^ "(" ^ (gen_tfun_interface_arg_list args) ^ ")"
+   | _ -> "void *"
+
+and cpp_function_signature_params params = match params with
+   | [t; abi] -> (match follow abi with
+       | TInst (klass,_) -> cpp_function_signature t (get_meta_string klass.cl_meta Meta.Abi |> Option.default "")
+       | _ -> print_endline (type_string abi);
+           die "" __LOC__ )
+   | _ ->
+      print_endline ("Params:" ^ (String.concat "," (List.map type_string params) ));
+      die "" __LOC__;
+
+and gen_interface_arg_type_name name opt typ =
+   let type_str = (type_string typ) in
+   (* type_str may have already converted Null<X> to Dynamic because of NotNull tag ... *)
+   (if (opt && (cant_be_null typ) && type_str<>"Dynamic" ) then
+      "::hx::Null< " ^ type_str ^ " > "
+   else
+      type_str ) ^ " " ^ (keyword_remap name)
+
+and gen_tfun_interface_arg_list args =
+   String.concat "," (List.map (fun (name,opt,typ) -> gen_interface_arg_type_name name opt typ) args)
+
+and cant_be_null haxe_type =
+   is_numeric haxe_type || (type_has_meta_key Meta.NotNull haxe_type )
+
+let is_cpp_scalar cpp_type =
+   match cpp_type with
+   | TCppScalar(_) -> true
+   | _ -> false
+
+let is_cpp_array_implementer cppType =
+   match cppType with
+   | TCppInst ({ cl_array_access = Some _ }, _)
+   | TCppInterface ({ cl_array_access = Some _ }) ->
+      true
+   | _ -> false
+
+let rec cpp_is_struct_access t =
+   match t with
+   | TCppFunction _ -> true
+   | TCppStruct _-> false
+   | TCppInst (class_def, _) -> Meta.has Meta.StructAccess class_def.cl_meta
+   | TCppReference (r) -> cpp_is_struct_access r
+   | _ -> false
+
+let rec cpp_is_native_array_access t =
+   match t with
+   | 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
+   | _ -> false
+
+let cpp_is_dynamic_type = function
+   | TCppDynamic | TCppObject | TCppVariant | TCppWrapped _ | TCppGlobal | TCppNull
+   | TCppInterface _
+      -> true
+   | _ -> false
+
+let is_object_element member_type =
+  match member_type with
+   | TCppInst (x, _)
+   | TCppInterface x
+       -> not (is_extern_class x)
+   | TCppDynamic
+   | TCppObject
+   | TCppObjectPtr
+   | TCppEnum _
+   | TCppString
+   | TCppFunction _
+   | TCppDynamicArray
+   | TCppObjectArray _
+   | TCppWrapped _
+   | TCppScalarArray _
+   | TCppClass
+       -> true
+   | _ -> false
+
+let cpp_variant_type_of t = match t with
+  | TCppDynamic
+  | TCppUnchanged
+  | TCppObject
+  | TCppObjectPtr
+  | TCppReference _
+  | TCppStruct _
+  | TCppStar _
+  | TCppVoid
+  | TCppFastIterator _
+  | TCppDynamicArray
+  | TCppObjectArray _
+  | TCppScalarArray _
+  | TCppWrapped _
+  | TCppObjC _
+  | TCppObjCBlock _
+  | TCppRest _
+  | TCppInst _
+  | TCppInterface _
+  | TCppProtocol _
+  | TCppCode _
+  | TCppClass
+  | TCppGlobal
+  | TCppNull
+  | TCppEnum _ -> TCppDynamic
+  | TCppString -> TCppString
+  | TCppFunction _
+  | TCppNativePointer _
+  | TCppPointer _
+  | TCppRawPointer _
+  | TCppAutoCast
+  | TCppVarArg
+  | TCppVoidStar -> TCppVoidStar
+  | TCppScalar "Int"
+  | TCppScalar "bool"
+  | TCppScalar "Float"  -> t
+  | TCppScalar "::cpp::Int64" -> TCppScalar("Int64")
+  | TCppScalar "double"
+  | TCppScalar "float" -> TCppScalar("Float")
+  | TCppScalar _  -> TCppScalar("int")
+  | TCppVariant -> TCppVariant
+
+let cpp_cast_variant_type_of t = match t with
+  | TCppObjectArray _
+  | TCppScalarArray _
+  | TCppDynamicArray
+  | TCppClass
+  | TCppEnum _
+  | TCppInst _ -> t
+  | _ -> cpp_variant_type_of t
+
+let enum_getter_type t =
+  match cpp_variant_type_of t with
+  | TCppString -> "String"
+  | TCppScalar "int"  -> "Int"
+  | TCppScalar "bool"  -> "Bool"
+  | TCppScalar x  -> x
+  | _  -> "Object"

+ 96 - 0
src/generators/cpp/cppContext.ml

@@ -0,0 +1,96 @@
+open Gctx
+open CppAstTools
+
+(* CPP code generation context *)
+(*
+  ctx_debug_level
+    0 = no debug
+    1 = function + line debug via macros, which can be activated at cpp compile-time
+    2 = include macros for HXCPP_DEBUGGER
+    3 = annotate source with additional info about AST and types
+    4 = console output at haxe compile-time
+
+   normal = 1
+*)
+type context = {
+  ctx_common : Gctx.t;
+  mutable ctx_debug_level : int;
+  (* cached as required *)
+  mutable ctx_file_info : (string, string) PMap.t ref;
+  ctx_type_ids : (string, Int32.t) Hashtbl.t;
+  (* Per file *)
+  ctx_output : string -> unit;
+  ctx_writer : CppSourceWriter.source_writer;
+  ctx_file_id : int ref;
+  ctx_is_header : bool;
+  ctx_interface_slot : (string, int) Hashtbl.t ref;
+  ctx_interface_slot_count : int ref;
+  (* This is for returning from the child nodes of TSwitch && TTry *)
+  mutable ctx_real_this_ptr : bool;
+  mutable ctx_class_member_types : (string, string) Hashtbl.t;
+}
+
+let new_context common_ctx debug file_info member_types =
+  let null_file =
+    new CppSourceWriter.source_writer common_ctx ignore ignore (fun () -> ())
+  in
+  let has_def def = Gctx.defined_value_safe common_ctx def <> "" in
+  let result =
+    {
+      ctx_common = common_ctx;
+      ctx_writer = null_file;
+      ctx_file_id = ref (-1);
+      ctx_type_ids = Hashtbl.create 0;
+      ctx_is_header = false;
+      ctx_output = null_file#write;
+      ctx_interface_slot = ref (Hashtbl.create 0);
+      ctx_interface_slot_count = ref 2;
+      ctx_debug_level =
+        (if has_def Define.AnnotateSource then 3
+         else if has_def Define.HxcppDebugger then 2
+         else debug);
+      ctx_real_this_ptr = true;
+      ctx_class_member_types = member_types;
+      ctx_file_info = file_info;
+    }
+  in
+  result
+
+let file_context ctx writer debug header =
+  {
+    ctx with
+    ctx_writer = writer;
+    ctx_output = writer#write;
+    ctx_is_header = header;
+    ctx_file_id = ref (-1);
+  }
+
+(* todo - is this how it's done? *)
+
+let pmap_keys pmap =
+  let key_list = ref [] in
+  PMap.iter (fun key _ -> key_list :=  key :: !key_list ) pmap;
+  !key_list
+
+let pmap_values pmap =
+  let value_list = ref [] in
+  PMap.iter (fun _ value -> value_list :=  value :: !value_list ) pmap;
+  !value_list
+
+(* The Hashtbl structure seems a little odd - but here is a helper function *)
+let hash_iterate hash visitor =
+  let result = ref [] in
+  Hashtbl.iter (fun key value -> result :=  (visitor key value) :: !result ) hash;
+  !result
+
+let hash_keys hash =
+  let key_list = ref [] in
+  Hashtbl.iter (fun key value -> key_list :=  key :: !key_list ) hash;
+  !key_list
+
+let is_gc_element ctx member_type =
+  Gctx.defined ctx.ctx_common Define.HxcppGcGenerational && (is_object_element member_type)
+
+let strip_file ctx file = match Gctx.defined ctx Define.AbsolutePath with
+  | true -> Path.get_full_path file
+  | false -> ctx.class_paths#relative_path file

+ 19 - 0
src/generators/cpp/cppExprUtils.ml

@@ -0,0 +1,19 @@
+open Type
+
+let rec remove_parens expression =
+  match expression.eexpr with
+  | TParenthesis e -> remove_parens e
+  | TMeta(_,e) -> remove_parens e
+  | _ -> expression
+
+let rec remove_parens_cast expression =
+  match expression.eexpr with
+  | TParenthesis e -> remove_parens_cast e
+  | TMeta(_,e) -> remove_parens_cast e
+  | TCast ( e,None) -> remove_parens_cast e
+  | _ -> expression
+
+let is_static_access obj =
+  match (remove_parens obj).eexpr with
+  | TTypeExpr _ -> true
+  | _ -> false

+ 1431 - 0
src/generators/cpp/cppRetyper.ml

@@ -0,0 +1,1431 @@
+open Ast
+open Type
+open Error
+open Globals
+open CppTypeUtils
+open CppAst
+open CppAstTools
+open CppContext
+
+let rec cpp_type_of stack haxe_type =
+  if List.exists (fast_eq haxe_type) stack then TCppDynamic
+  else
+    let stack = haxe_type :: stack in
+    match haxe_type with
+    | TMono r -> (
+        match r.tm_type with
+        | None -> TCppDynamic
+        | Some t -> cpp_type_of stack t)
+    | TEnum (enum, params) -> TCppEnum enum
+    | TInst ({ cl_path = [], "Array"; cl_kind = KTypeParameter _ }, _) ->
+        TCppObject
+    | TInst ({ cl_kind = KTypeParameter _ }, _) -> TCppDynamic
+    | TInst (klass, params) -> cpp_instance_type stack klass params
+    | TAbstract (abs, pl) when not (Meta.has Meta.CoreType abs.a_meta) ->
+        cpp_type_from_path stack abs.a_path pl (fun () ->
+            cpp_type_of stack
+              (Abstract.get_underlying_type ~return_first:true abs pl))
+    | TAbstract (a, params) ->
+        cpp_type_from_path stack a.a_path params (fun () ->
+            if is_scalar_abstract a then
+              match get_meta_string a.a_meta Meta.Native with
+              | Some s -> TCppScalar s
+              | None -> TCppScalar (join_class_path a.a_path "::")
+            else TCppDynamic)
+    | TType (type_def, params) ->
+        cpp_type_from_path stack type_def.t_path params (fun () ->
+            cpp_type_of stack (apply_typedef type_def params))
+    | TFun _ -> TCppObject
+    | TAnon _ -> TCppObject
+    | TDynamic _ -> TCppDynamic
+    | TLazy func -> cpp_type_of stack (lazy_type func)
+
+and cpp_type_from_path stack path params default =
+  match (path, params) with
+  | ([], "Void"), _ -> TCppVoid
+  | ([], "void"), _ -> TCppVoid (* for old code with @:void *)
+  | ([], "Bool"), _ -> TCppScalar "bool"
+  | ([], "Float"), _ -> TCppScalar "Float"
+  | ([], "Int"), _ -> TCppScalar "int"
+  | ([], "EnumValue"), _ -> TCppObject
+  | ([], "Class"), _ -> TCppClass
+  | ([], "Enum"), _ -> TCppClass
+  | ([], "Single"), _ -> TCppScalar "float"
+  | ([ "cpp" ], "Char"), _ -> TCppScalar "char"
+  | ([ "cpp" ], "Object"), _ -> TCppObjectPtr
+  | ([ "cpp" ], "Float32"), _ -> TCppScalar "float"
+  | ([ "cpp" ], "Float64"), _ -> TCppScalar "double"
+  | ([ "cpp" ], "Int8"), _ -> TCppScalar "signed char"
+  | ([ "cpp" ], "Int16"), _ -> TCppScalar "short"
+  | ([ "cpp" ], "Int32"), _ -> TCppScalar "int"
+  | ([ "cpp" ], "Int64"), _ -> TCppScalar "::cpp::Int64"
+  | ([ "cpp" ], "UInt8"), _ -> TCppScalar "unsigned char"
+  | ([ "cpp" ], "UInt16"), _ -> TCppScalar "unsigned short"
+  | ([ "cpp" ], "UInt32"), _ -> TCppScalar "unsigned int"
+  | ([ "cpp" ], "UInt64"), _ -> TCppScalar "::cpp::UInt64"
+  | ([ "cpp" ], "VarArg"), _ -> TCppVarArg
+  | ([ "cpp" ], "AutoCast"), _ -> TCppAutoCast
+  | ([], "String"), [] -> TCppString
+  (* Things with type parameters hxcpp knows about ... *)
+  | ([ "cpp" ], "FastIterator"), [ p ] -> TCppFastIterator (cpp_type_of stack p)
+  | ([ "cpp" ], "Pointer"), [ p ] -> TCppPointer ("Pointer", cpp_type_of stack p)
+  | ([ "cpp" ], "ConstPointer"), [ p ] ->
+      TCppPointer ("ConstPointer", cpp_type_of stack p)
+  | ([ "cpp" ], "RawPointer"), [ p ] -> TCppRawPointer ("", cpp_type_of stack p)
+  | ([ "cpp" ], "RawConstPointer"), [ p ] ->
+      TCppRawPointer ("const ", cpp_type_of stack p)
+  | ([ "cpp" ], "Function"), [ function_type; abi ] ->
+      cpp_function_type_of stack function_type abi
+  | ([ "cpp" ], "Callable"), [ function_type ]
+  | ([ "cpp" ], "CallableData"), [ function_type ] ->
+      cpp_function_type_of_string stack function_type ""
+  | ("cpp" :: [ "objc" ], "ObjcBlock"), [ function_type ] ->
+      let args, ret = cpp_function_type_of_args_ret stack function_type in
+      TCppObjCBlock (args, ret)
+  | ([ "cpp" ], "Rest"), [ rest ] -> TCppRest (cpp_type_of stack rest)
+  | ("cpp" :: [ "objc" ], "Protocol"), [ interface_type ] -> (
+      match follow interface_type with
+      | TInst (klass, []) when has_class_flag klass CInterface ->
+          TCppProtocol klass
+      (* TODO - get the line number here *)
+      | _ ->
+          print_endline "cpp.objc.Protocol must refer to an interface";
+          die "" __LOC__)
+  | ([ "cpp" ], "Reference"), [ param ] ->
+      TCppReference (cpp_type_of stack param)
+  | ([ "cpp" ], "Struct"), [ param ] -> TCppStruct (cpp_type_of stack param)
+  | ([ "cpp" ], "Star"), [ param ] ->
+      TCppStar (cpp_type_of_pointer stack param, false)
+  | ([ "cpp" ], "ConstStar"), [ param ] ->
+      TCppStar (cpp_type_of_pointer stack param, true)
+  | ([], "Array"), [ p ] -> (
+      let arrayOf = cpp_type_of stack p in
+      match arrayOf with
+      | TCppVoid (* ? *) | TCppDynamic -> TCppDynamicArray
+      | TCppObject | TCppObjectPtr | TCppReference _ | TCppStruct _ | TCppStar _
+      | TCppEnum _ | TCppInst _ | TCppInterface _ | TCppProtocol _ | TCppClass
+      | TCppDynamicArray | TCppObjectArray _ | TCppScalarArray _ ->
+          TCppObjectArray arrayOf
+      | _ -> TCppScalarArray arrayOf)
+  | ([], "Null"), [ p ] -> cpp_type_of_null stack p
+  | _ -> default ()
+
+and cpp_type_of_null stack p =
+  let baseType = cpp_type_of stack p in
+  if type_has_meta_key Meta.NotNull p || is_cpp_scalar baseType then TCppObject
+  else baseType
+
+and cpp_type_of_pointer stack p =
+  match p with
+  | TAbstract ({ a_path = [], "Null" }, [ t ]) -> cpp_type_of stack t
+  | x -> cpp_type_of stack x
+
+(* Optional types are Dynamic if they norally could not be null *)
+and cpp_fun_arg_type_of stack tvar opt =
+  match opt with
+  | Some _ -> cpp_type_of_null stack tvar.t_type
+  | _ -> cpp_type_of stack tvar.t_type
+
+and cpp_tfun_arg_type_of stack opt t =
+  if opt then cpp_type_of_null stack t else cpp_type_of stack t
+
+and cpp_function_type_of stack function_type abi =
+  let abi =
+    match follow abi with
+    | TInst (klass1, _) ->
+        get_meta_string klass1.cl_meta Meta.Abi |> Option.default ""
+    | _ -> die "" __LOC__
+  in
+  cpp_function_type_of_string stack function_type abi
+
+and cpp_function_type_of_string stack function_type abi_string =
+  let args, ret = cpp_function_type_of_args_ret stack function_type in
+  TCppFunction (args, ret, abi_string)
+
+and cpp_function_type_of_args_ret stack function_type =
+  match follow function_type with
+  | TFun (args, ret) ->
+      (* Optional types are Dynamic if they norally could not be null *)
+      let cpp_arg_type_of (_, optional, haxe_type) =
+        if optional then cpp_type_of_null stack haxe_type
+        else cpp_type_of stack haxe_type
+      in
+      (List.map cpp_arg_type_of args, cpp_type_of stack ret)
+  | _ ->
+      (* ? *)
+      ([ TCppVoid ], TCppVoid)
+
+and cpp_instance_type stack klass params =
+  cpp_type_from_path stack klass.cl_path params (fun () ->
+      if is_objc_class klass then TCppObjC klass
+      else if has_class_flag klass CInterface && is_native_gen_class klass then
+        TCppNativePointer klass
+      else if has_class_flag klass CInterface then TCppInterface klass
+      else if
+        has_class_flag klass CExtern && not (is_internal_class klass.cl_path)
+      then
+        let tcpp_params = List.map (cpp_type_of stack) params in
+        TCppInst (klass, tcpp_params)
+      else
+        let tcpp_params = List.map (cpp_type_of stack) params in
+        TCppInst (klass, tcpp_params))
+
+let cpp_type_of = cpp_type_of []
+let cpp_type_from_path = cpp_type_from_path []
+let cpp_type_of_null = cpp_type_of_null []
+let cpp_type_of_pointer = cpp_type_of_pointer []
+let cpp_tfun_arg_type_of = cpp_tfun_arg_type_of []
+let cpp_function_type_of = cpp_function_type_of []
+let cpp_function_type_of_string = cpp_function_type_of_string []
+let cpp_function_type_of_args_ret = cpp_function_type_of_args_ret []
+let cpp_instance_type = cpp_instance_type []
+
+let expression ctx request_type function_args function_type expression_tree forInjection =
+  let rev_closures = ref [] in
+  let closureId = ref 0 in
+  let declarations = ref (Hashtbl.create 0) in
+  let undeclared = ref (Hashtbl.create 0) in
+  let uses_this = ref None in
+  let gc_stack = ref false in
+  let injection = ref forInjection in
+  let this_real = ref (if ctx.ctx_real_this_ptr then ThisReal else ThisDynamic) in
+  let file_id = ctx.ctx_file_id in
+  let function_return_type = ref (cpp_type_of function_type) in
+  let loop_stack = ref [] in
+  let forCppia = Gctx.defined ctx.ctx_common Define.Cppia in
+  let alloc_file_id () =
+    incr file_id;
+    !file_id
+  in
+  let begin_loop () =
+    loop_stack := (alloc_file_id (), ref false) :: !loop_stack;
+    fun () ->
+      match !loop_stack with
+      | (label_id, used) :: tl ->
+          loop_stack := tl;
+          if !used then label_id else -1
+      | [] -> abort "Invalid inernal loop handling" expression_tree.epos
+  in
+
+  (* '__trace' is at the top-level *)
+  Hashtbl.add !declarations "__trace" ();
+  List.iter (fun arg -> Hashtbl.add !declarations arg.v_name ()) function_args;
+
+  (* Helper functions *)
+
+  let cpp_const_type cval =
+    match cval with
+    | TInt i -> (CppInt i, TCppScalar "int")
+    | TBool b -> (CppBool b, TCppScalar "bool")
+    | TFloat f -> (CppFloat (Texpr.replace_separators f ""), TCppScalar "Float")
+    | TString s -> (CppString s, TCppString)
+    | _ ->
+        (* TNull, TThis & TSuper should already be handled *)
+        (CppNull, TCppNull)
+  in
+
+  let cpp_return_type haxe_type =
+    match haxe_type with TFun (_, ret) -> cpp_type_of ret | _ -> TCppDynamic
+  in
+
+  let cpp_member_return_type member = cpp_return_type member.cf_type in
+
+  let is_cpp_objc_type cpptype =
+    match cpptype with TCppObjC _ -> true | _ -> false
+  in
+
+  let cpp_is_real_array obj =
+    match obj.cpptype with
+    | TCppScalarArray _ | TCppObjectArray _ -> true
+    | _ -> false
+  in
+
+  let rec to_lvalue value =
+    match value.cppexpr with
+    | CppVar (VarClosure var as varloc)
+      when is_gc_element ctx (cpp_type_of var.v_type) ->
+        (CppVarRef varloc, true)
+    | CppVar (VarThis (member, _) as varloc)
+      when is_gc_element ctx (cpp_type_of member.cf_type) ->
+        (CppVarRef varloc, true)
+    | CppVar (VarInstance (obj, member, _, "->") as varloc)
+      when is_gc_element ctx (cpp_type_of member.cf_type) ->
+        (CppVarRef varloc, true)
+    | CppVar varloc -> (CppVarRef varloc, false)
+    | CppArray arrayloc ->
+        ( CppArrayRef arrayloc,
+          match arrayloc with
+          | ArrayObject (arrayObj, index, _) when is_gc_element ctx TCppDynamic
+            ->
+              true
+          | ArrayTyped (arrayObj, index, t) when is_gc_element ctx t -> true
+          | _ -> false )
+    | CppDynamicField (expr, name) -> (CppDynamicRef (expr, name), false)
+    | CppTCast (cppExpr, _)
+    | CppCast (cppExpr, _)
+    | CppCastStatic (cppExpr, _)
+    | CppCastObjC (cppExpr, _)
+    | CppCastObjCBlock (cppExpr, _, _)
+    | CppCastScalar (cppExpr, _) ->
+        to_lvalue cppExpr
+    | CppCastVariant cppExpr -> to_lvalue cppExpr
+    | CppExtern (name, isGlobal) -> (CppExternRef (name, isGlobal), false)
+    | _ ->
+        abort
+          ("Could not convert expression to l-value (" ^ s_tcpp value.cppexpr
+         ^ ")")
+          value.cpppos
+  in
+
+  let is_array_splice_call obj member =
+    match (obj.cpptype, member.cf_name) with
+    | TCppScalarArray _, "splice" | TCppObjectArray _, "splice" -> true
+    | _, _ -> false
+  in
+
+  let is_map_get_call obj member =
+    member.cf_name = "get"
+    &&
+    match obj.cpptype with
+    | TCppInst ({ cl_path = [ "cpp" ], "Int64Map" }, _) -> true
+    | TCppInst ({ cl_path = [ "haxe"; "ds" ], "IntMap" }, _) -> true
+    | TCppInst ({ cl_path = [ "haxe"; "ds" ], "StringMap" }, _) -> true
+    | TCppInst ({ cl_path = [ "haxe"; "ds" ], "ObjectMap" }, _) -> true
+    | _ -> false
+  in
+
+  let is_map_set_call obj member =
+    member.cf_name = "set"
+    &&
+    match obj.cpptype with
+    | TCppInst ({ cl_path = [ "cpp" ], "Int64Map" }, _) -> true
+    | TCppInst ({ cl_path = [ "haxe"; "ds" ], "IntMap" }, _) -> true
+    | TCppInst ({ cl_path = [ "haxe"; "ds" ], "StringMap" }, _) -> true
+    | TCppInst ({ cl_path = [ "haxe"; "ds" ], "ObjectMap" }, _) -> true
+    | _ -> false
+  in
+
+  let is_array_concat_call obj member =
+    match (obj.cpptype, member.cf_name) with
+    | TCppScalarArray _, "concat" | TCppObjectArray _, "concat" -> true
+    | _, _ -> false
+  in
+
+  let cpp_can_static_cast funcType inferredType =
+    match funcType with
+    | TCppReference _ | TCppStar _ | TCppStruct _ -> false
+    | _ -> (
+        match inferredType with
+        | TCppInst (cls, _) when is_extern_class cls -> false
+        | TCppEnum e when is_extern_enum e -> false
+        | TCppInst _ | TCppClass | TCppEnum _ ->
+            tcpp_to_string funcType <> tcpp_to_string inferredType
+        | _ -> false)
+  in
+
+  let cpp_is_templated_call ctx member =
+    Meta.has Meta.TemplatedCall member.cf_meta
+  in
+
+  let is_complex_compare = function
+    | TCppScalar _ -> false
+    | TCppString -> false
+    | _ -> true
+  in
+
+  let is_pointer_compare = function
+    | TCppObjectArray _ | TCppScalarArray _ | TCppDynamicArray | TCppClass
+    | TCppEnum _ ->
+        true
+    | _ -> false
+  in
+
+  let is_instance_compare = function
+    | TCppInterface _ | TCppInst _ -> true
+    | _ -> false
+  in
+
+  let cpp_append_block block expr =
+    match block.cppexpr with
+    | CppBlock (expr_list, closures, gc_stack) ->
+        {
+          block with
+          cppexpr = CppBlock (expr_list @ [ expr ], closures, gc_stack);
+        }
+    | _ -> abort "Internal error appending expression" block.cpppos
+  in
+
+  let rec const_int_of expr =
+    match expr.eexpr with
+    | TConst TInt x -> x
+    | TConst TBool x -> Int32.of_int (if x then 1 else 0)
+    | TParenthesis e -> const_int_of e
+    | _ -> raise Not_found
+  in
+
+  (* Core Retyping *)
+  let rec retype return_type expr =
+    let cpp_type_of t = cpp_type_of t in
+    let mk_cppexpr newExpr newType =
+      { cppexpr = newExpr; cpptype = newType; cpppos = expr.epos }
+    in
+    let retype_function_args args arg_types =
+      let rec map_pair args types result =
+        match (args, types) with
+        | args, [ TCppRest rest ] ->
+            List.rev (List.map (retype rest) args) @ result
+        | [], [] -> result
+        | a :: arest, t :: trest -> map_pair arest trest (retype t a :: result)
+        | _, [] -> abort "Too many args" expr.epos
+        | [], _ -> abort "Too many types" expr.epos
+      in
+      List.rev (map_pair args arg_types [])
+    in
+
+    let retypedExpr, retypedType =
+      match expr.eexpr with
+      | TEnumParameter (enumObj, enumField, enumIndex) ->
+          let retypedObj = retype TCppDynamic enumObj in
+          ( CppEnumParameter (retypedObj, enumField, enumIndex),
+            cpp_cast_variant_type_of
+              (cpp_type_of (get_nth_type enumField enumIndex)) )
+      | TEnumIndex enumObj ->
+          let retypedObj = retype TCppDynamic enumObj in
+          (CppEnumIndex retypedObj, TCppScalar "int")
+      | TConst TThis ->
+          uses_this := Some !this_real;
+          ( CppThis !this_real,
+            if !this_real = ThisDynamic then TCppDynamic
+            else cpp_type_of expr.etype )
+      | TConst TSuper ->
+          uses_this := Some !this_real;
+          ( CppSuper !this_real,
+            if !this_real = ThisDynamic then TCppDynamic
+            else cpp_type_of expr.etype )
+      | TConst TNull when is_objc_type expr.etype -> (CppNil, TCppNull)
+      | TConst x -> cpp_const_type x
+      | TIdent "__global__" ->
+          (* functions/vars will appear to be members of the virtual global object *)
+          (CppClassOf (([], ""), false), TCppGlobal)
+      | TLocal tvar ->
+          let name = tvar.v_name in
+          if Hashtbl.mem !declarations name then
+            (*print_endline ("Using existing tvar " ^ tvar.v_name);*)
+            (CppVar (VarLocal tvar), cpp_type_of tvar.v_type)
+          else (
+            (*print_endline ("Missing tvar " ^ tvar.v_name);*)
+            Hashtbl.replace !undeclared name tvar;
+            if has_var_flag tvar VCaptured then
+              (CppVar (VarClosure tvar), cpp_type_of tvar.v_type)
+            else (CppExtern (name, false), cpp_type_of tvar.v_type))
+      | TIdent name -> (CppExtern (name, false), return_type)
+      | TBreak -> (
+          if forCppia then (CppBreak, TCppVoid)
+          else
+            match !loop_stack with
+            | [] -> (CppBreak, TCppVoid)
+            | (label_id, used) :: _ ->
+                used := true;
+                (CppGoto label_id, TCppVoid))
+      | TContinue -> (CppContinue, TCppVoid)
+      | TThrow e1 -> (CppThrow (retype TCppDynamic e1), TCppVoid)
+      | TMeta ((Meta.Fixed, _, _), e) -> (
+          let cppType = retype return_type e in
+          match cppType.cppexpr with
+          | CppObjectDecl (def, false) ->
+              (CppObjectDecl (def, true), cppType.cpptype)
+          | _ -> (cppType.cppexpr, cppType.cpptype))
+      | TMeta (_, e) | TParenthesis e ->
+          let cppType = retype return_type e in
+          (cppType.cppexpr, cppType.cpptype)
+      | TField (obj, field) -> (
+          match field with
+          | FInstance (clazz, params, member)
+          | FClosure (Some (clazz, params), member) -> (
+              let funcReturn = cpp_member_return_type member in
+              let clazzType = cpp_instance_type clazz params in
+              let retypedObj = retype clazzType obj in
+              let exprType = cpp_type_of member.cf_type in
+              let is_objc = is_cpp_objc_type retypedObj.cpptype in
+
+              if retypedObj.cpptype = TCppNull then (CppNullAccess, TCppDynamic)
+              else if
+                retypedObj.cpptype = TCppDynamic
+                && not (has_class_flag clazz CInterface)
+              then
+                if is_internal_member member.cf_name then
+                  ( CppFunction
+                      (FuncInstance (retypedObj, InstPtr, member), funcReturn),
+                    exprType )
+                else (CppDynamicField (retypedObj, member.cf_name), TCppVariant)
+              else if cpp_is_struct_access retypedObj.cpptype then
+                match retypedObj.cppexpr with
+                | CppThis ThisReal ->
+                    (CppVar (VarThis (member, retypedObj.cpptype)), exprType)
+                | CppSuper this ->
+                    ( CppFunction
+                        ( FuncSuper (this, retypedObj.cpptype, member),
+                          funcReturn ),
+                      exprType )
+                | _ ->
+                    if is_var_field member then
+                      ( CppVar
+                          (VarInstance
+                             (retypedObj, member, tcpp_to_string clazzType, ".")),
+                        exprType )
+                    else
+                      ( CppFunction
+                          ( FuncInstance (retypedObj, InstStruct, member),
+                            funcReturn ),
+                        exprType )
+              else if is_var_field member then
+                let exprType =
+                  match (retypedObj.cpptype, exprType) with
+                  | TCppPointer (_, t), TCppDynamic
+                  | ( TCppRawPointer (_, t),
+                      TCppDynamic
+                      (* the 'type parameter' will show up as Dynamic *) ) ->
+                      t
+                  | _ -> exprType
+                in
+
+                match retypedObj.cppexpr with
+                | CppThis ThisReal ->
+                    (CppVar (VarThis (member, retypedObj.cpptype)), exprType)
+                | _ -> (
+                    match (retypedObj.cpptype, member.cf_name) with
+                    (* Special variable remapping ... *)
+                    | TCppDynamicArray, "length" when not forCppia ->
+                        ( CppCall
+                            (FuncInternal (retypedObj, "get_length", "->"), []),
+                          exprType )
+                    | TCppInterface _, _ | TCppDynamic, _ ->
+                        ( CppDynamicField (retypedObj, member.cf_name),
+                          TCppVariant )
+                    | TCppObjC _, _ ->
+                        ( CppVar
+                            (VarInstance
+                               ( retypedObj,
+                                 member,
+                                 tcpp_to_string clazzType,
+                                 "." )),
+                          exprType )
+                    | _ ->
+                        let operator =
+                          if
+                            cpp_is_struct_access retypedObj.cpptype
+                            || retypedObj.cpptype = TCppString
+                          then "."
+                          else "->"
+                        in
+                        ( CppVar
+                            (VarInstance
+                               ( retypedObj,
+                                 member,
+                                 tcpp_to_string clazzType,
+                                 operator )),
+                          exprType ))
+              else if
+                has_class_flag clazz CInterface
+                && not is_objc (* Use instance call for objc interfaces *)
+              then
+                ( CppFunction
+                    (FuncInterface (retypedObj, clazz, member), funcReturn),
+                  exprType )
+              else
+                let isArrayObj =
+                  match retypedObj.cpptype with
+                  | TCppDynamicArray | TCppObjectArray _ | TCppScalarArray _ ->
+                      true
+                  | _ -> false
+                in
+                (* Special array return values *)
+                let funcReturn =
+                  if isArrayObj then
+                    match member.cf_name with
+                    | "map" -> TCppDynamicArray
+                    | "splice" | "slice" | "concat" | "copy" | "filter" ->
+                        retypedObj.cpptype
+                    | _ -> funcReturn
+                  else
+                    match (retypedObj.cpptype, funcReturn) with
+                    | TCppPointer (_, t), TCppDynamic
+                    | ( TCppRawPointer (_, t),
+                        TCppDynamic
+                        (* the 'type parameter' will show up as Dynamic *) ) ->
+                        t
+                    | _ -> funcReturn
+                in
+                match retypedObj.cppexpr with
+                | CppThis ThisReal ->
+                    ( CppFunction
+                        (FuncThis (member, retypedObj.cpptype), funcReturn),
+                      exprType )
+                | CppSuper this ->
+                    ( CppFunction
+                        ( FuncSuper (this, retypedObj.cpptype, member),
+                          funcReturn ),
+                      exprType )
+                | _ ->
+                    ( CppFunction
+                        ( FuncInstance
+                            ( retypedObj,
+                              (if is_objc then InstObjC else InstPtr),
+                              member ),
+                          funcReturn ),
+                      exprType ))
+          | FStatic (_, ({ cf_name = "nativeFromStaticFunction" } as member)) ->
+              let funcReturn = cpp_member_return_type member in
+              let exprType = cpp_type_of member.cf_type in
+              (CppFunction (FuncFromStaticFunction, funcReturn), exprType)
+          | FStatic (clazz, member) ->
+              let funcReturn = cpp_member_return_type member in
+              let exprType = cpp_type_of member.cf_type in
+              let objC = is_objc_class clazz in
+              if is_var_field member then
+                (CppVar (VarStatic (clazz, objC, member)), exprType)
+              else
+                ( CppFunction (FuncStatic (clazz, objC, member), funcReturn),
+                  exprType )
+          | FClosure (None, field) | FAnon field ->
+              let obj = retype TCppDynamic obj in
+              let fieldName = field.cf_name in
+              if obj.cpptype = TCppGlobal then
+                (CppExtern (fieldName, true), cpp_type_of expr.etype)
+              else if obj.cpptype = TCppNull then (CppNullAccess, TCppDynamic)
+              else if is_internal_member fieldName then
+                let cppType = cpp_return_type expr.etype in
+                if obj.cpptype = TCppString then
+                  ( CppFunction (FuncInternal (obj, fieldName, "."), cppType),
+                    cppType )
+                else
+                  ( CppFunction (FuncInternal (obj, fieldName, "->"), cppType),
+                    cppType )
+              else (CppDynamicField (obj, field.cf_name), TCppVariant)
+          | FDynamic fieldName ->
+              let obj = retype TCppDynamic obj in
+              if obj.cpptype = TCppNull then (CppNullAccess, TCppDynamic)
+              else if fieldName = "cca" && obj.cpptype = TCppString then
+                ( CppFunction (FuncInternal (obj, "cca", "."), TCppScalar "int"),
+                  TCppDynamic )
+              else if fieldName = "__s" && obj.cpptype = TCppString then
+                ( CppVar (VarInternal (obj, ".", "utf8_str()")),
+                  TCppRawPointer ("const ", TCppScalar "char") )
+              else if fieldName = "__Index" then
+                (CppEnumIndex obj, TCppScalar "int")
+              else if is_internal_member fieldName || cpp_is_real_array obj then
+                let cppType = cpp_return_type expr.etype in
+                if obj.cpptype = TCppString then
+                  ( CppFunction (FuncInternal (obj, fieldName, "."), cppType),
+                    cppType )
+                else
+                  ( CppFunction (FuncInternal (obj, fieldName, "->"), cppType),
+                    cppType )
+              else if obj.cpptype = TCppGlobal then
+                (CppExtern (fieldName, true), cpp_type_of expr.etype)
+              else if obj.cpptype = TCppClass then
+                match obj.cppexpr with
+                | CppClassOf (path, _) ->
+                    ( CppExtern
+                        ( join_class_path_remap path "::" ^ "_obj::" ^ fieldName,
+                          true ),
+                      cpp_type_of expr.etype )
+                | _ ->
+                    ( CppVar (VarInternal (obj, "->", fieldName)),
+                      cpp_type_of expr.etype )
+              else (CppDynamicField (obj, fieldName), TCppVariant)
+          | FEnum (enum, enum_field) ->
+              (CppEnumField (enum, enum_field), TCppEnum enum))
+      | TCall ({ eexpr = TIdent "__cpp__" }, arg_list) ->
+          let cppExpr =
+            match arg_list with
+            | [ { eexpr = TConst (TString code) } ] -> CppCode (code, [])
+            | { eexpr = TConst (TString code) } :: remaining ->
+                let retypedArgs =
+                  List.map
+                    (fun arg -> retype (TCppCode (cpp_type_of arg.etype)) arg)
+                    remaining
+                in
+                CppCode (code, retypedArgs)
+            | _ -> abort "__cpp__'s first argument must be a string" expr.epos
+          in
+          (cppExpr, TCppCode (cpp_type_of expr.etype))
+      | TCall (func, args) -> (
+          let retypedFunc = retype TCppUnchanged func in
+          match retypedFunc.cpptype with
+          | TCppNull -> (CppNullAccess, TCppDynamic)
+          | TCppFunction (argTypes, retType, _) ->
+              let retypedArgs = retype_function_args args argTypes in
+              (CppCall (FuncExpression retypedFunc, retypedArgs), retType)
+          | TCppObjCBlock (argTypes, retType) ->
+              let retypedArgs = retype_function_args args argTypes in
+              (CppCall (FuncExpression retypedFunc, retypedArgs), retType)
+          | _ -> (
+              let cppType = cpp_type_of expr.etype in
+              match retypedFunc.cppexpr with
+              | CppFunction (FuncFromStaticFunction, returnType) -> (
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  match retypedArgs with
+                  | [
+                   {
+                     cppexpr =
+                       CppFunction
+                         (FuncStatic (clazz, false, member), funcReturn);
+                   };
+                  ] ->
+                      (CppFunctionAddress (clazz, member), funcReturn)
+                  | _ ->
+                      abort
+                        "cpp.Function.fromStaticFunction must be called on \
+                         static function"
+                        expr.epos)
+              | CppEnumIndex _ ->
+                  (* Not actually a TCall...*)
+                  (retypedFunc.cppexpr, retypedFunc.cpptype)
+              | CppFunction (FuncInstance (obj, InstPtr, member), _)
+                when (not forCppia) && return_type = TCppVoid
+                     && is_array_splice_call obj member ->
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  ( CppCall
+                      ( FuncInstance
+                          (obj, InstPtr, { member with cf_name = "removeRange" }),
+                        retypedArgs ),
+                    TCppVoid )
+              | CppFunction (FuncInstance (obj, InstPtr, member), _)
+                when is_array_concat_call obj member ->
+                  let retypedArgs = List.map (retype obj.cpptype) args in
+                  ( CppCall (FuncInstance (obj, InstPtr, member), retypedArgs),
+                    return_type )
+              | CppFunction (FuncStatic (obj, false, member), _)
+                when member.cf_name = "::hx::AddressOf" ->
+                  let arg = retype TCppUnchanged (List.hd args) in
+                  let rawType =
+                    match arg.cpptype with TCppReference x -> x | x -> x
+                  in
+                  (CppAddressOf arg, TCppRawPointer ("", rawType))
+              | CppFunction (FuncStatic (obj, false, member), _)
+                when member.cf_name = "::hx::StarOf" ->
+                  let arg = retype TCppUnchanged (List.hd args) in
+                  let rawType =
+                    match arg.cpptype with TCppReference x -> x | x -> x
+                  in
+                  (CppAddressOf arg, TCppStar (rawType, false))
+              | CppFunction (FuncStatic (obj, false, member), _)
+                when member.cf_name = "::hx::Dereference" ->
+                  let arg = retype TCppUnchanged (List.hd args) in
+                  let rawType =
+                    match arg.cpptype with TCppStar (x, _) -> x | x -> x
+                  in
+                  (CppDereference arg, TCppReference rawType)
+              | CppFunction (FuncStatic (obj, false, member), _)
+                when member.cf_name = "_hx_create_array_length" -> (
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  (* gc_stack - not needed yet *)
+                  match return_type with
+                  | TCppObjectArray _ | TCppScalarArray _ ->
+                      (CppCall (FuncNew return_type, retypedArgs), return_type)
+                  | _ ->
+                      ( CppCall (FuncNew TCppDynamicArray, retypedArgs),
+                        return_type ))
+              | CppFunction (FuncStatic (obj, false, member), returnType)
+                when cpp_is_templated_call ctx member -> (
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  match retypedArgs with
+                  | { cppexpr = CppClassOf (path, native) } :: rest ->
+                      ( CppCall (FuncTemplate (obj, member, path, native), rest),
+                        returnType )
+                  | _ ->
+                      abort
+                        "First parameter of template function must be a Class"
+                        retypedFunc.cpppos)
+              | CppFunction (FuncInstance (obj, InstPtr, member), _)
+                when is_map_get_call obj member ->
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  let fname, cppType =
+                    match return_type with
+                    | TCppVoid | TCppScalar "bool" ->
+                        ( (if forCppia then "getBool" else "get_bool"),
+                          return_type )
+                    | TCppScalar "int" ->
+                        ((if forCppia then "getInt" else "get_int"), return_type)
+                    | TCppScalar "::cpp::Int64" ->
+                        ( (if forCppia then "getInt64" else "get_int64"),
+                          return_type )
+                    | TCppScalar "Float" ->
+                        ( (if forCppia then "getFloat" else "get_float"),
+                          return_type )
+                    | TCppString ->
+                        ( (if forCppia then "getString" else "get_string"),
+                          return_type )
+                    | _ -> ("get", TCppDynamic)
+                  in
+                  let func =
+                    FuncInstance (obj, InstPtr, { member with cf_name = fname })
+                  in
+                  (*
+                   if  cpp_can_static_cast cppType return_type then begin
+                      let call = mk_cppexpr (CppCall(func,retypedArgs)) cppType in
+                      CppCastStatic(call, cppType), cppType
+                   end else
+                   *)
+                  (CppCall (func, retypedArgs), cppType)
+              | CppFunction (FuncInstance (obj, InstPtr, member), _)
+                when forCppia && is_map_set_call obj member ->
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  let fname =
+                    match retypedArgs with
+                    | [ _; { cpptype = TCppScalar "bool" } ] -> "setBool"
+                    | [ _; { cpptype = TCppScalar "int" } ] -> "setInt"
+                    | [ _; { cpptype = TCppScalar "::cpp::Int64" } ] ->
+                        "setInt64"
+                    | [ _; { cpptype = TCppScalar "Float" } ] -> "setFloat"
+                    | [ _; { cpptype = TCppString } ] -> "setString"
+                    | _ -> "set"
+                  in
+                  let func =
+                    FuncInstance (obj, InstPtr, { member with cf_name = fname })
+                  in
+                  (CppCall (func, retypedArgs), cppType)
+              | CppFunction
+                  ((FuncInstance (obj, InstPtr, member) as func), returnType)
+                when cpp_can_static_cast returnType cppType ->
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  let call =
+                    mk_cppexpr (CppCall (func, retypedArgs)) returnType
+                  in
+                  (CppCastStatic (call, cppType), cppType)
+              (*
+                let error_printer file line = Printf.sprintf "%s:%d:" file line in
+                let epos = Lexer.get_error_pos error_printer expr.epos in
+                print_endline ( "fixed override " ^ member.cf_name ^ " @ " ^  epos ^ " " ^ (tcpp_to_string returnType) ^ "->" ^ (ctx_type_string ctx expr.etype) );
+                CppCall(func,retypedArgs), returnType
+              *)
+              (* Other functions ... *)
+              | CppFunction
+                  ( (FuncInstance
+                       (_, InstStruct, { cf_type = TFun (arg_types, _) }) as
+                     func),
+                    return_type ) ->
+                  (* For struct access classes use the types of the arguments instead of the function argument types *)
+                  (* In the case of generic extern classes a TFun arg type could be `MyClass.T` instead of the real type *)
+                  let map_args func_arg passed_arg =
+                    let name, opt, _ = func_arg in
+                    (name, opt, passed_arg.etype)
+                  in
+                  let real_types = List.map2 map_args arg_types args in
+                  let arg_types =
+                    List.map
+                      (fun (_, opt, t) -> cpp_tfun_arg_type_of opt t)
+                      real_types
+                  in
+                  let retypedArgs = retype_function_args args arg_types in
+                  (CppCall (func, retypedArgs), return_type)
+              | CppFunction
+                  ( (FuncInstance (_, _, { cf_type = TFun (arg_types, _) }) as
+                     func),
+                    returnType )
+              | CppFunction
+                  ( (FuncStatic (_, _, { cf_type = TFun (arg_types, _) }) as func),
+                    returnType )
+              | CppFunction
+                  ( (FuncThis ({ cf_type = TFun (arg_types, _) }, _) as func),
+                    returnType ) ->
+                  let arg_types =
+                    List.map
+                      (fun (_, opt, t) -> cpp_tfun_arg_type_of opt t)
+                      arg_types
+                  in
+                  (* retype args specifically (not just CppDynamic) *)
+                  let retypedArgs = retype_function_args args arg_types in
+                  (CppCall (func, retypedArgs), returnType)
+              | CppFunction (func, returnType) ->
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  (CppCall (func, retypedArgs), returnType)
+              | CppEnumField (enum, field) ->
+                  (* TODO - proper re-typing *)
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  ( CppCall (FuncEnumConstruct (enum, field), retypedArgs),
+                    cppType )
+              | CppSuper _ ->
+                  (* TODO - proper re-typing *)
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  ( CppCall (FuncSuperConstruct retypedFunc.cpptype, retypedArgs),
+                    TCppVoid )
+              | CppDynamicField (expr, name) -> (
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  (* Special function calls *)
+                  match (expr.cpptype, name) with
+                  | TCppGlobal, _ ->
+                      let retypedArgs = List.map (retype TCppUnchanged) args in
+                      (CppCall (FuncExtern (name, true), retypedArgs), cppType)
+                  | TCppString, _ ->
+                      ( CppCall (FuncInternal (expr, name, "."), retypedArgs),
+                        cppType )
+                  | _, "__Tag" ->
+                      ( CppCall
+                          (FuncInternal (expr, "_hx_getTag", "->"), retypedArgs),
+                        cppType )
+                  | _, name when is_internal_member name ->
+                      ( CppCall (FuncInternal (expr, name, "->"), retypedArgs),
+                        cppType )
+                  | _ ->
+                      (* not special *)
+                      ( CppCall (FuncExpression retypedFunc, retypedArgs),
+                        TCppDynamic ))
+              | CppExtern (name, isGlobal) ->
+                  let retypedArgs = List.map (retype TCppUnchanged) args in
+                  (CppCall (FuncExtern (name, isGlobal), retypedArgs), cppType)
+              | _ ->
+                  let retypedArgs = List.map (retype TCppDynamic) args in
+                  ( CppCall (FuncExpression retypedFunc, retypedArgs),
+                    TCppDynamic )))
+      | TNew (class_def, params, args) ->
+          let constructor_type =
+            match
+              OverloadResolution.maybe_resolve_constructor_overload class_def
+                params args
+            with
+            | None -> abort "Could not find overload" expr.epos
+            | Some (_, constructor, _) -> constructor.cf_type
+          in
+          let arg_types, _ = cpp_function_type_of_args_ret constructor_type in
+          let retypedArgs = retype_function_args args arg_types in
+          let created_type = cpp_type_of expr.etype in
+          (gc_stack :=
+             !gc_stack
+             ||
+             match created_type with
+             | TCppInst (t, _) -> not (is_native_class t)
+             | _ -> false);
+          (CppCall (FuncNew created_type, retypedArgs), created_type)
+      | TFunction func ->
+          let old_this_real = !this_real in
+          this_real := ThisFake;
+          (* TODO - this_dynamic ? *)
+          let old_undeclared = Hashtbl.copy !undeclared in
+          let old_declarations = Hashtbl.copy !declarations in
+          let old_uses_this = !uses_this in
+          let old_gc_stack = !gc_stack in
+          let old_return_type = !function_return_type in
+          let ret = cpp_type_of func.tf_type in
+          function_return_type := ret;
+          uses_this := None;
+          undeclared := Hashtbl.create 0;
+          declarations := Hashtbl.create 0;
+          List.iter
+            (fun (tvar, _) -> Hashtbl.add !declarations tvar.v_name ())
+            func.tf_args;
+          let cppExpr = retype TCppVoid (mk_block func.tf_expr) in
+          let result =
+            {
+              close_expr = cppExpr;
+              close_id = !closureId;
+              close_undeclared = !undeclared;
+              close_type = ret;
+              close_args = func.tf_args;
+              close_this = !uses_this;
+            }
+          in
+          incr closureId;
+          declarations := old_declarations;
+          undeclared := old_undeclared;
+          Hashtbl.iter
+            (fun name tvar ->
+              if not (Hashtbl.mem !declarations name) then
+                Hashtbl.replace !undeclared name tvar)
+            result.close_undeclared;
+          function_return_type := old_return_type;
+          this_real := old_this_real;
+          uses_this :=
+            if !uses_this != None then Some old_this_real else old_uses_this;
+          gc_stack := old_gc_stack;
+          rev_closures := result :: !rev_closures;
+          (CppClosure result, TCppDynamic)
+      | TArray (e1, e2) ->
+          let arrayExpr, elemType =
+            match cpp_is_native_array_access (cpp_type_of e1.etype) with
+            | true ->
+                let retypedObj = retype TCppUnchanged e1 in
+                let retypedIdx = retype (TCppScalar "int") e2 in
+                ( CppArray (ArrayRawPointer (retypedObj, retypedIdx)),
+                  cpp_type_of expr.etype )
+            | false -> (
+                let retypedObj = retype TCppDynamic e1 in
+                let retypedIdx = retype (TCppScalar "int") e2 in
+                match retypedObj.cpptype with
+                | TCppScalarArray scalar ->
+                    ( CppArray (ArrayTyped (retypedObj, retypedIdx, scalar)),
+                      scalar )
+                | TCppPointer (_, elem) ->
+                    (CppArray (ArrayPointer (retypedObj, retypedIdx)), elem)
+                | TCppRawPointer (_, elem) ->
+                    (CppArray (ArrayRawPointer (retypedObj, retypedIdx)), elem)
+                | TCppObjectArray TCppDynamic ->
+                    ( CppArray
+                        (ArrayObject (retypedObj, retypedIdx, TCppDynamic)),
+                      TCppDynamic )
+                | TCppObjectArray elem ->
+                    (CppArray (ArrayObject (retypedObj, retypedIdx, elem)), elem)
+                | TCppInst (({ cl_array_access = Some _ } as klass), _) ->
+                    ( CppArray (ArrayImplements (klass, retypedObj, retypedIdx)),
+                      cpp_type_of expr.etype )
+                | TCppDynamicArray ->
+                    ( CppArray (ArrayVirtual (retypedObj, retypedIdx)),
+                      TCppDynamic )
+                | _ ->
+                    ( CppArray (ArrayDynamic (retypedObj, retypedIdx)),
+                      TCppDynamic ))
+          in
+          let returnType = cpp_type_of expr.etype in
+          if cpp_can_static_cast elemType returnType then
+            ( CppCastStatic (mk_cppexpr arrayExpr returnType, returnType),
+              returnType )
+          else (arrayExpr, elemType)
+      | TTypeExpr module_type ->
+          (* If we try and use the coreType / runtimeValue cpp.Int64 abstract with Class<T> then we get a class decl of the abstract *)
+          (* as that abstract has functions in its declaration *)
+          (* Intercept it and replace it with the path of the actual int64 type so the generated cpp is correct *)
+          let path =
+            match module_type with
+            | TClassDecl { cl_path = [ "cpp"; "_Int64" ], "Int64_Impl_" } ->
+                ([ "cpp" ], "Int64")
+            | _ -> t_path module_type
+          in
+          (CppClassOf (path, is_native_gen_module module_type), TCppClass)
+      | TBinop (op, left, right) -> (
+          let binOpType =
+            match op with
+            | OpDiv -> TCppScalar "Float"
+            | OpBoolAnd | OpBoolOr -> TCppScalar "bool"
+            | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr -> TCppScalar "int"
+            | OpAssign -> (retype TCppUnchanged left).cpptype
+            | OpMult | OpSub -> cpp_type_of expr.etype
+            | _ -> TCppUnchanged
+          in
+          let e1 = retype binOpType left in
+          let e2 = retype binOpType right in
+
+          let complex =
+            is_complex_compare e1.cpptype || is_complex_compare e2.cpptype
+          in
+          let pointer =
+            is_pointer_compare e1.cpptype || is_pointer_compare e2.cpptype
+          in
+          let instance =
+            is_instance_compare e1.cpptype || is_instance_compare e2.cpptype
+          in
+          let e1_null = e1.cpptype = TCppNull in
+          let e2_null = e2.cpptype = TCppNull in
+          let reference =
+            match op with
+            | OpAssign ->
+                let lvalue, gc = to_lvalue e1 in
+                if gc then gc_stack := true;
+                CppSet (lvalue, e2)
+            | OpAssignOp op ->
+                let lvalue, gc = to_lvalue e1 in
+                if gc then gc_stack := true;
+                CppModify (op, lvalue, e2)
+            | OpEq when e1_null && e2_null -> CppBool true
+            | OpGte when e1_null && e2_null -> CppBool true
+            | OpLte when e1_null && e2_null -> CppBool true
+            | OpNotEq when e1_null && e2_null -> CppBool false
+            | _ when e1_null && e2_null -> CppBool false
+            | OpEq when e1_null -> CppNullCompare ("IsNull", e2)
+            | OpGte when e1_null -> CppNullCompare ("IsNull", e2)
+            | OpLte when e1_null -> CppNullCompare ("IsNull", e2)
+            | OpNotEq when e1_null -> CppNullCompare ("IsNotNull", e2)
+            | OpEq when e2_null -> CppNullCompare ("IsNull", e1)
+            | OpGte when e2_null -> CppNullCompare ("IsNull", e1)
+            | OpLte when e2_null -> CppNullCompare ("IsNull", e1)
+            | OpNotEq when e2_null -> CppNullCompare ("IsNotNull", e1)
+            | OpEq when instance -> CppCompare ("IsInstanceEq", e1, e2, op)
+            | OpNotEq when instance -> CppCompare ("IsInstanceNotEq", e1, e2, op)
+            | OpEq when pointer -> CppCompare ("IsPointerEq", e1, e2, op)
+            | OpNotEq when pointer -> CppCompare ("IsPointerNotEq", e1, e2, op)
+            | OpEq when complex -> CppCompare ("IsEq", e1, e2, op)
+            | OpNotEq when complex -> CppCompare ("IsNotEq", e1, e2, op)
+            | OpGte when complex -> CppCompare ("IsGreaterEq", e1, e2, op)
+            | OpLte when complex -> CppCompare ("IsLessEq", e1, e2, op)
+            | OpGt when complex -> CppCompare ("IsGreater", e1, e2, op)
+            | OpLt when complex -> CppCompare ("IsLess", e1, e2, op)
+            | _ -> CppBinop (op, e1, e2)
+          in
+          match (op, e1.cpptype, e2.cpptype) with
+          (* Variant + Variant = Variant *)
+          | OpAdd, _, TCppVariant | OpAdd, TCppVariant, _ ->
+              (reference, TCppVariant)
+          | _, _, _ -> (reference, cpp_type_of expr.etype))
+      | TUnop (op, pre, e1) ->
+          let targetType =
+            match op with
+            | Not -> TCppScalar "bool"
+            | NegBits -> TCppScalar "int"
+            | _ -> cpp_type_of e1.etype
+          in
+
+          let e1 = retype targetType e1 in
+          let reference =
+            match op with
+            | Increment ->
+                let lvalue, gc = to_lvalue e1 in
+                if gc then gc_stack := true;
+                CppCrement (CppIncrement, pre, lvalue)
+            | Decrement ->
+                let lvalue, gc = to_lvalue e1 in
+                if gc then gc_stack := true;
+                CppCrement (CppDecrement, pre, lvalue)
+            | Neg -> CppUnop (CppNeg, e1)
+            | Not -> CppUnop (CppNot, e1)
+            | NegBits -> CppUnop (CppNegBits, e1)
+            | Spread -> die ~p:expr.epos "Unexpected spread operator" __LOC__
+          in
+          (reference, cpp_type_of expr.etype)
+      | TFor (v, init, block) ->
+          let old_declarations = Hashtbl.copy !declarations in
+          Hashtbl.add !declarations v.v_name ();
+          let init = retype (cpp_type_of v.v_type) init in
+          let block = retype TCppVoid (mk_block block) in
+          declarations := old_declarations;
+          (CppFor (v, init, block), TCppVoid)
+      | TWhile (e1, e2, flag) ->
+          let condition = retype (TCppScalar "bool") e1 in
+          let close = begin_loop () in
+          let block = retype TCppVoid (mk_block e2) in
+          (CppWhile (condition, block, flag, close ()), TCppVoid)
+      | TArrayDecl el ->
+          let retypedEls = List.map (retype TCppDynamic) el in
+          (CppArrayDecl retypedEls, cpp_type_of expr.etype)
+      | TBlock expr_list ->
+          let inject = !injection in
+          injection := false;
+          if return_type <> TCppVoid && not forCppia then
+            print_endline
+              ("Value from a block not handled " ^ expr.epos.pfile ^ " "
+              ^ string_of_int (Lexer.get_error_line expr.epos));
+
+          let old_declarations = Hashtbl.copy !declarations in
+          let old_closures = !rev_closures in
+          rev_closures := [];
+          let local_closures = ref [] in
+          let remaining = ref (List.length expr_list) in
+          let cppExprs =
+            List.map
+              (fun expr ->
+                let targetType =
+                  if inject && !remaining = 1 then cpp_type_of expr.etype
+                  else TCppVoid
+                in
+                decr remaining;
+                let result = retype targetType expr in
+                local_closures := !rev_closures @ !local_closures;
+                rev_closures := [];
+                result)
+              expr_list
+          in
+          declarations := old_declarations;
+          rev_closures := old_closures;
+
+          (CppBlock (cppExprs, List.rev !local_closures, !gc_stack), TCppVoid)
+      | TObjectDecl
+          [
+            (("fileName", _, _), { eexpr = TConst (TString file) });
+            (("lineNumber", _, _), { eexpr = TConst (TInt line) });
+            (("className", _, _), { eexpr = TConst (TString class_name) });
+            (("methodName", _, _), { eexpr = TConst (TString meth) });
+          ] ->
+          (CppPosition (file, line, class_name, meth), TCppDynamic)
+      | TObjectDecl el -> (
+          let retypedEls =
+            List.map (fun ((v, _, _), e) -> (v, retype TCppDynamic e)) el
+          in
+          match return_type with
+          | TCppVoid -> (CppObjectDecl (retypedEls, false), TCppVoid)
+          | _ -> (CppObjectDecl (retypedEls, false), TCppDynamic))
+      | TVar (v, eo) ->
+          let varType = cpp_type_of v.v_type in
+          let init =
+            match eo with None -> None | Some e -> Some (retype varType e)
+          in
+          Hashtbl.add !declarations v.v_name ();
+          (CppVarDecl (v, init), varType)
+      | TIf (ec, e1, e2) ->
+          let ec = retype (TCppScalar "bool") ec in
+          let blockify =
+            if return_type != TCppVoid then fun e -> e else mk_block
+          in
+          let e1 = retype return_type (blockify e1) in
+          let e2 =
+            match e2 with
+            | None -> None
+            | Some e -> Some (retype return_type (blockify e))
+          in
+          ( CppIf (ec, e1, e2),
+            if return_type = TCppVoid then TCppVoid else cpp_type_of expr.etype
+          )
+      (* Switch internal return - wrap whole thing in block  *)
+      | TSwitch
+          {
+            switch_subject = condition;
+            switch_cases = cases;
+            switch_default = def;
+          } -> (
+          if return_type <> TCppVoid then
+            abort "Value from a switch not handled" expr.epos;
+
+          let conditionType = cpp_type_of condition.etype in
+          let condition = retype conditionType condition in
+          let cppDef =
+            match def with
+            | None -> None
+            | Some e -> Some (retype TCppVoid (mk_block e))
+          in
+          if forCppia then
+            let cases =
+              List.map
+                (fun { case_patterns = el; case_expr = e2 } ->
+                  let cppBlock = retype TCppVoid (mk_block e2) in
+                  (List.map (retype conditionType) el, cppBlock))
+                cases
+            in
+            (CppSwitch (condition, conditionType, cases, cppDef, -1), TCppVoid)
+          else
+            try
+              (match conditionType with
+              | TCppScalar "int" | TCppScalar "bool" -> ()
+              | _ -> raise Not_found);
+              let cases =
+                List.map
+                  (fun { case_patterns = el; case_expr = e2 } ->
+                    (List.map const_int_of el, retype TCppVoid (mk_block e2)))
+                  cases
+              in
+              (CppIntSwitch (condition, cases, cppDef), TCppVoid)
+            with Not_found ->
+              let label = alloc_file_id () in
+              (* do something better maybe ... *)
+              let cases =
+                List.map
+                  (fun { case_patterns = el; case_expr = e2 } ->
+                    let cppBlock = retype TCppVoid (mk_block e2) in
+                    let gotoExpr =
+                      {
+                        cppexpr = CppGoto label;
+                        cpptype = TCppVoid;
+                        cpppos = e2.epos;
+                      }
+                    in
+                    let cppBlock = cpp_append_block cppBlock gotoExpr in
+                    (List.map (retype conditionType) el, cppBlock))
+                  cases
+              in
+              ( CppSwitch (condition, conditionType, cases, cppDef, label),
+                TCppVoid ))
+      | TTry (try_block, catches) ->
+          (* TTry internal return - wrap whole thing in block ? *)
+          if return_type <> TCppVoid then
+            abort "Value from a try-block not handled" expr.epos;
+          let cppBlock = retype TCppVoid try_block in
+          let cppCatches =
+            List.map
+              (fun (tvar, catch_block) ->
+                let old_declarations = Hashtbl.copy !declarations in
+                Hashtbl.add !declarations tvar.v_name ();
+                let cppCatchBlock = retype TCppVoid catch_block in
+                declarations := old_declarations;
+                (tvar, cppCatchBlock))
+              catches
+          in
+          (CppTry (cppBlock, cppCatches), TCppVoid)
+      | TReturn eo ->
+          ( CppReturn
+              (match eo with
+              | None -> None
+              | Some e -> Some (retype !function_return_type e)),
+            TCppVoid )
+      | TCast (base, None) -> (
+          (* Use auto-cast rules *)
+          let return_type = cpp_type_of expr.etype in
+          let baseCpp = retype return_type base in
+          let baseStr = tcpp_to_string baseCpp.cpptype in
+          let returnStr = tcpp_to_string return_type in
+          if baseStr = returnStr then
+            (baseCpp.cppexpr, baseCpp.cpptype (* nothing to do *))
+          else
+            match return_type with
+            | TCppObjC k -> (CppCastObjC (baseCpp, k), return_type)
+            | TCppPointer (_, _)
+            | TCppRawPointer (_, _)
+            | TCppStar _ | TCppInst _ ->
+                (CppCast (baseCpp, return_type), return_type)
+            | TCppString -> (CppCastScalar (baseCpp, "::String"), return_type)
+            | TCppCode t when baseStr <> tcpp_to_string t ->
+                (CppCast (baseCpp, t), t)
+            | TCppNativePointer klass -> (CppCastNative baseCpp, return_type)
+            | TCppObjCBlock (args, ret) ->
+                (CppCastObjCBlock (baseCpp, args, ret), return_type)
+            | TCppProtocol p -> (CppCastProtocol (baseCpp, p), return_type)
+            | TCppDynamic when baseCpp.cpptype = TCppClass ->
+                (CppCast (baseCpp, TCppDynamic), TCppDynamic)
+            | _ -> (baseCpp.cppexpr, baseCpp.cpptype (* use autocasting rules *))
+          )
+      | TCast (base, Some t) -> (
+          let baseCpp = retype (cpp_type_of base.etype) base in
+          let baseStr = tcpp_to_string baseCpp.cpptype in
+          let default_return_type =
+            if return_type = TCppUnchanged then cpp_type_of expr.etype
+            else return_type
+          in
+          let return_type =
+            cpp_type_from_path (t_path t) [] (fun () -> default_return_type)
+          in
+          let returnStr = tcpp_to_string return_type in
+
+          if baseStr = returnStr then
+            (baseCpp.cppexpr, baseCpp.cpptype (* nothing to do *))
+          else
+            match return_type with
+            | TCppNativePointer klass -> (CppCastNative baseCpp, return_type)
+            | TCppVoid ->
+                (CppTCast (baseCpp, cpp_type_of expr.etype), return_type)
+            | TCppDynamic -> (baseCpp.cppexpr, baseCpp.cpptype)
+            | _ -> (CppTCast (baseCpp, return_type), return_type))
+    in
+    let cppExpr = mk_cppexpr retypedExpr retypedType in
+
+    (* Autocast rules... *)
+    if return_type = TCppVoid then mk_cppexpr retypedExpr TCppVoid
+    else if return_type = TCppVarArg then
+      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 toDynamic =
+            mk_cppexpr (CppCast (cppExpr, TCppDynamic)) TCppDynamic
+          in
+          mk_cppexpr (CppCastNative toDynamic) TCppVoidStar
+    else if
+      cppExpr.cpptype = TCppVariant
+      || cppExpr.cpptype = TCppDynamic
+      || cppExpr.cpptype == TCppObject
+    then
+      match return_type with
+      | TCppUnchanged -> cppExpr
+      | TCppInst (t, _) when Meta.has Meta.StructAccess t.cl_meta ->
+          let structType = TCppStruct (TCppInst (t, [])) in
+          let structCast =
+            mk_cppexpr (CppCast (cppExpr, structType)) structType
+          in
+          mk_cppexpr (CppCast (structCast, TCppInst (t, []))) (TCppInst (t, []))
+      | TCppObjectArray _ | TCppScalarArray _ | TCppNativePointer _
+      | TCppDynamicArray | TCppObjectPtr | TCppVarArg | 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) ->
+          let ptrType =
+            TCppPointer ((if const then "ConstPointer" else "Pointer"), t)
+          in
+          let ptrCast = mk_cppexpr (CppCast (cppExpr, ptrType)) ptrType in
+          mk_cppexpr
+            (CppCast (ptrCast, TCppStar (t, const)))
+            (TCppStar (t, const))
+      | _ -> cppExpr
+    else
+      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 retypedExpr (TCppReference t)
+      | TCppStar (TCppDynamic, _), TCppStar (_, _) -> cppExpr
+      | TCppStar (TCppDynamic, const), t ->
+          mk_cppexpr retypedExpr (TCppStar (t, const))
+      | TCppStar (t, const), TCppDynamic ->
+          let ptrType =
+            TCppPointer ((if const then "ConstPointer" else "Pointer"), t)
+          in
+          let ptrCast = mk_cppexpr (CppCast (cppExpr, ptrType)) ptrType in
+          mk_cppexpr (CppCast (ptrCast, TCppDynamic)) TCppDynamic
+      | TCppStar (t, const), TCppReference _
+      | TCppStar (t, const), TCppInst _
+      | 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) | 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, _), TCppDynamic when Meta.has Meta.StructAccess t.cl_meta
+        ->
+          let structType = TCppStruct (TCppInst (t, [])) in
+          let structCast =
+            mk_cppexpr (CppCast (cppExpr, structType)) structType
+          in
+          mk_cppexpr (CppCast (structCast, TCppDynamic)) TCppDynamic
+      | _, TCppObjectPtr ->
+          mk_cppexpr (CppCast (cppExpr, TCppObjectPtr)) TCppObjectPtr
+      | TCppDynamicArray, TCppScalarArray _
+      | TCppDynamicArray, TCppObjectArray _
+      | TCppScalarArray _, TCppDynamicArray
+      | TCppObjectArray _, TCppDynamicArray
+        when forCppia ->
+          mk_cppexpr (CppCast (cppExpr, return_type)) return_type
+      | TCppScalar from, TCppScalar too when from <> too ->
+          mk_cppexpr (CppCastScalar (cppExpr, too)) return_type
+      | _ -> cppExpr
+  in
+  retype request_type expression_tree

+ 183 - 0
src/generators/cpp/cppSourceWriter.ml

@@ -0,0 +1,183 @@
+open Gctx
+open CppStrings
+open CppAstTools
+open CppTypeUtils
+
+(*
+  Code for generating source files.
+  It manages creating diretories, indents, blocks and only modifying files
+  when the content changes.
+*)
+
+let get_include_prefix common_ctx with_slash =
+  try
+    Gctx.defined_value common_ctx Define.IncludePrefix ^ if with_slash then "/" else ""
+  with Not_found -> ""
+
+let should_prefix_include = function
+  | x when is_internal_class x -> false
+  | [], "hxMath" -> true
+  | _ -> false
+
+let verbatim_include file =
+  match String.sub file 0 1 with
+  | "@" -> "@import " ^ String.sub file 1 (String.length file - 1) ^ ";\n"
+  | _ -> "#include \"" ^ file ^ "\"\n"
+
+let guarded_include file =
+  let guard_name = "INCLUDED_" ^ hash64 file in
+  "#ifndef " ^ guard_name ^ "\n" ^ "#define " ^ guard_name ^ "\n" ^ verbatim_include file ^ "#endif\n"
+
+let source_file_extension common_ctx =
+  (* no need to -D file_extension if -D objc is defined *)
+  if Gctx.defined common_ctx Define.Objc then ".mm"
+  else
+    try
+      "." ^ Gctx.defined_value common_ctx Define.FileExtension
+    with Not_found -> ".cpp"
+
+class source_writer common_ctx write_header_func write_func close_func =
+  object (this)
+    val indent_str = "\t"
+    val mutable indent = ""
+    val mutable indents = []
+    val mutable just_finished_block = false
+    val mutable headerLines = Hashtbl.create 0
+
+    method close =
+      close_func ();
+      ()
+
+    method write x =
+      write_func x;
+      just_finished_block <- false
+
+    method write_h x =
+      write_header_func x;
+      ()
+
+    method write_h_unique x =
+      if not (Hashtbl.mem headerLines x) then (
+        Hashtbl.add headerLines x ();
+        this#write_h x)
+
+    method indent_one = this#write indent_str
+
+    method push_indent =
+      indents <- indent_str :: indents;
+      indent <- String.concat "" indents
+
+    method pop_indent =
+      match indents with
+      | h :: tail ->
+          indents <- tail;
+          indent <- String.concat "" indents
+      | [] -> indent <- "/*?*/"
+
+    method write_i x = this#write (indent ^ x)
+    method get_indent = indent
+
+    method begin_block =
+      this#write "{\n";
+      this#push_indent
+
+    method end_block =
+      this#pop_indent;
+      this#write_i "}\n";
+      just_finished_block <- true
+
+    method end_block_line =
+      this#pop_indent;
+      this#write_i "}";
+      just_finished_block <- true
+
+    method terminate_line =
+      this#write (if just_finished_block then "" else ";\n")
+
+    method add_big_closures =
+      this#write_h_unique "#include <hx/MacrosJumbo.h>\n"
+
+    method add_include class_path =
+      match class_path with
+      | [ "@verbatim" ], file -> this#write_h_unique (guarded_include file)
+      | _ ->
+          let prefix =
+            if should_prefix_include class_path then ""
+            else get_include_prefix common_ctx true
+          in
+          this#write_h
+            ("#ifndef INCLUDED_" ^ join_class_path class_path "_" ^ "\n");
+          this#write_h
+            ("#include <" ^ prefix ^ join_class_path class_path "/" ^ ".h>\n");
+          this#write_h "#endif\n"
+  end
+
+let read_whole_file chan = Std.input_all chan
+
+(*
+  The cached_source_writer will not write to the file if it has not changed,
+  thus allowing the makefile dependencies to work correctly
+*)
+let cached_source_writer common_ctx filename =
+  let header = Buffer.create 0 in
+  let add_header str = Buffer.add_string header str in
+  let buffer = Buffer.create 0 in
+  let add_buf str = Buffer.add_string buffer str in
+  let close () =
+    Buffer.add_buffer header buffer;
+    let contents = Buffer.contents header in
+    let same =
+      try
+        let in_file = open_in filename in
+        let old_contents = read_whole_file in_file in
+        close_in in_file;
+        contents = old_contents
+      with _ -> false
+    in
+    if not same then (
+      let out_file = open_out filename in
+      output_string out_file contents;
+      close_out out_file)
+  in
+  new source_writer common_ctx add_header add_buf close
+
+let new_source_file common_ctx base_dir sub_dir extension class_path =
+  let include_prefix = get_include_prefix common_ctx true in
+  let full_dir =
+    if sub_dir = "include" && include_prefix <> "" then (
+      let dir =
+        match fst class_path with
+        | [] -> base_dir ^ "/include/" ^ get_include_prefix common_ctx false
+        | path ->
+            base_dir ^ "/include/" ^ include_prefix ^ String.concat "/" path
+      in
+      Path.mkdir_recursive base_dir
+        ([ "include"; include_prefix ] @ fst class_path);
+      dir)
+    else (
+      Path.mkdir_recursive base_dir (sub_dir :: fst class_path);
+      base_dir ^ "/" ^ sub_dir ^ "/" ^ String.concat "/" (fst class_path))
+  in
+  let file =
+    cached_source_writer common_ctx (full_dir ^ "/" ^ snd class_path ^ extension)
+  in
+  Gctx.map_source_header common_ctx.defines (fun s ->
+      file#write_h (Printf.sprintf "// %s\n" s));
+  file
+
+let new_cpp_file common_ctx base_dir =
+  new_source_file common_ctx base_dir "src" (source_file_extension common_ctx)
+
+let new_header_file common_ctx base_dir =
+  new_source_file common_ctx base_dir "include" ".h"
+
+let new_placed_cpp_file common_ctx class_path =
+  let base_dir = common_ctx.file in
+
+  if (Gctx.defined common_ctx Define.Vcproj ) then begin
+    Path.mkdir_recursive base_dir ("src"::[]);
+    cached_source_writer common_ctx
+      ( base_dir ^ "/src/" ^ ( String.concat "-" (fst class_path) ) ^ "-" ^
+      (snd class_path) ^ (source_file_extension common_ctx) )
+  end else
+    new_cpp_file common_ctx common_ctx.file class_path

+ 131 - 0
src/generators/cpp/cppStrings.ml

@@ -0,0 +1,131 @@
+open Extlib_leftovers
+open Globals
+
+let gen_hash32 seed str =
+  let h = ref (Int32.of_int seed) in
+  let cycle = Int32.of_int 223 in
+  for i = 0 to String.length str - 1 do
+    h :=
+      Int32.add (Int32.mul !h cycle)
+        (Int32.of_int (int_of_char (String.unsafe_get str i)))
+  done;
+  !h
+
+let hash64 s = String.sub (Digest.to_hex (Digest.string s)) 0 16
+let gen_hash seed str = Printf.sprintf "0x%08lx" (gen_hash32 seed str)
+let gen_hash_small seed str = Printf.sprintf "%08lx" (gen_hash32 seed str)
+
+let gen_qstring_hash str =
+  let h = gen_hash32 0 str in
+  Printf.sprintf "%02lx,%02lx,%02lx,%02lx"
+    (Int32.shift_right_logical (Int32.shift_left h 24) 24)
+    (Int32.shift_right_logical (Int32.shift_left h 16) 24)
+    (Int32.shift_right_logical (Int32.shift_left h 8) 24)
+    (Int32.shift_right_logical h 24)
+
+let gen_wqstring_hash str =
+  let h = gen_hash32 0 str in
+  Printf.sprintf "%04lx,%04lx"
+    (Int32.shift_right_logical (Int32.shift_left h 16) 16)
+    (Int32.shift_right_logical h 16)
+
+let special_to_hex s =
+  let l = String.length s in
+  let b = Buffer.create 0 in
+  for i = 0 to l - 1 do
+    match Char.code (String.unsafe_get s i) with
+    | c when c > 127 || c < 32 ->
+        Buffer.add_string b (Printf.sprintf "\\x%02x\"\"" c)
+    | c -> Buffer.add_char b (Char.chr c)
+  done;
+  Buffer.contents b
+
+let strq ctx s =
+  let has_utf8_chars s =
+    let result = ref false in
+    for i = 0 to String.length s - 1 do
+      result := !result || Char.code (String.unsafe_get s i) > 127
+    done;
+    !result
+  in
+
+  let gen_str macro gen s =
+    let rec split s plus =
+      let escaped = StringHelper.s_escape ~hex:false s in
+      let hexed = special_to_hex escaped in
+      if String.length hexed <= 16000 then
+        plus ^ " HX_CSTRING(\"" ^ hexed ^ "\")"
+      else
+        let len = String.length s in
+        let half = len lsr 1 in
+        split (String.sub s 0 half) plus
+        ^ split (String.sub s half (len - half)) "+"
+    in
+    let escaped = StringHelper.s_escape ~hex:false s in
+    let hexed = special_to_hex escaped in
+    if String.length hexed <= 16000 then
+      macro ^ "(\"" ^ hexed ^ "\"," ^ gen s ^ ")"
+    else "(" ^ split s "" ^ ")"
+  in
+
+  if Gctx.defined ctx Define.HxcppSmartStings && has_utf8_chars s then (
+    let b = Buffer.create 0 in
+
+    let add ichar =
+      match ichar with
+      | 92 (* \ *) -> Buffer.add_string b "\\\\"
+      | 39 (* ' *) -> Buffer.add_string b "\\\'"
+      | 34 -> Buffer.add_string b "\\\""
+      | 13 (* \r *) -> Buffer.add_string b "\\r"
+      | 10 (* \n *) -> Buffer.add_string b "\\n"
+      | 9 (* \t *) -> Buffer.add_string b "\\t"
+      | c when c < 32 || (c >= 127 && c <= 0xFFFF) ->
+          Buffer.add_string b (Printf.sprintf "\\u%04x" c)
+      | c when c > 0xFFFF -> Buffer.add_string b (Printf.sprintf "\\U%08x" c)
+      | c -> Buffer.add_char b (Char.chr c)
+    in
+    UTF8.iter (fun c -> add (UCharExt.code c)) s;
+    "HX_W(u\"" ^ Buffer.contents b ^ "\"," ^ gen_wqstring_hash s ^ ")")
+  else gen_str "HX_" gen_qstring_hash s
+
+let escape_command s =
+  let b = Buffer.create 0 in
+  String.iter
+    (fun ch ->
+      if ch == '"' || ch == '\\' then Buffer.add_string b "\\";
+      Buffer.add_char b ch)
+    s;
+  Buffer.contents b
+
+let const_char_star s =
+  let escaped = StringHelper.s_escape ~hex:false s in
+  "\"" ^ special_to_hex escaped ^ "\""
+
+let make_path_absolute path pos =
+   try
+      if (String.sub path 0 2) = "./" then begin
+         let base = if (Filename.is_relative pos.pfile) then
+            Filename.concat (Sys.getcwd()) pos.pfile
+         else
+            pos.pfile
+         in
+         Path.normalize_path (Filename.concat (Filename.dirname base) (String.sub path 2 ((String.length path) -2)))
+      end else
+         path
+   with Invalid_argument _ -> path
+
+let path_of_string path =
+  ["@verbatim"], path
+
+let get_all_meta_string_path meta_list key =
+  let extract_path pos expr =
+    match expr with
+    | Ast.EConst (Ast.String (name, _)), _ -> make_path_absolute name pos
+    | _ -> ""
+  in
+  let extract_meta meta =
+    match meta with
+    | k, exprs, pos when k = key -> Some (extract_path pos (List.hd exprs))
+    | _ -> None
+  in
+  ExtList.List.filter_map extract_meta meta_list

+ 353 - 0
src/generators/cpp/cppTypeUtils.ml

@@ -0,0 +1,353 @@
+(* Various helper functions to run checks on haxe classes and various other ast types *)
+(* functions in here operate on standard haxe ast types, not gencpp ast types *)
+
+open Type
+
+let follow = Abstract.follow_with_abstracts
+
+let is_native_gen_class class_def =
+   Meta.has Meta.NativeGen class_def.cl_meta ||
+   match class_def.cl_kind with
+   | KAbstractImpl abstract_def -> Meta.has Meta.NativeGen abstract_def.a_meta
+   | _ -> false
+
+let is_native_gen_module = function
+   | TClassDecl class_def -> is_native_gen_class class_def
+   | _ -> false
+
+let is_extern_class class_def =
+   has_class_flag class_def CExtern ||
+   Meta.has Meta.Extern class_def.cl_meta ||
+   match class_def.cl_kind with
+   | KAbstractImpl abstract_def -> Meta.has Meta.Extern abstract_def.a_meta
+   | _ -> false
+
+let is_extern_enum enum_def =
+   has_enum_flag enum_def EnExtern || Meta.has Meta.Extern enum_def.e_meta
+
+(* The internal classes are implemented by the core hxcpp system, so the cpp classes should not be generated *)
+let is_internal_class = function
+   | [], "Int"
+   | [], "Void"
+   | [], "String"
+   | [], "Null"
+   | [], "Float"
+   | [], "Array"
+   | [], "Class"
+   | [], "Enum"
+   | [], "Bool"
+   | [], "Dynamic"
+   | [], "ArrayAccess"
+   | [], "Math"
+   | [], "Single"
+   | [ "cpp" ], "FastIterator"
+   | [ "cpp" ], "Pointer"
+   | [ "cpp" ], "ConstPointer"
+   | [ "cpp" ], "RawPointer"
+   | [ "cpp" ], "RawConstPointer"
+   | [ "cpp" ], "Function"
+   | [ "cpp" ], "VirtualArray"
+   | [ "cpp" ], "Int8"
+   | [ "cpp" ], "UInt8"
+   | [ "cpp" ], "Char"
+   | [ "cpp" ], "Int16"
+   | [ "cpp" ], "UInt16"
+   | [ "cpp" ], "Int32"
+   | [ "cpp" ], "UInt32"
+   | [ "cpp" ], "Int64"
+   | [ "cpp" ], "UInt64"
+   | [ "cpp" ], "Float32"
+   | [ "cpp" ], "Float64" ->
+      true
+   | _ ->
+      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)
+
+let is_interface_type t =
+   match follow t with
+   | TInst (klass,params) -> (has_class_flag klass CInterface)
+   | _ -> false
+
+let rec is_objc_type t =
+   match t with
+   | TInst(cl,_) -> (has_class_flag cl CExtern) && Meta.has Meta.Objc cl.cl_meta
+   | TType(td,_) -> (Meta.has Meta.Objc td.t_meta)
+   | TAbstract (a,_) -> (Meta.has Meta.Objc a.a_meta)
+   | TMono r -> (match r.tm_type with | Some t -> is_objc_type t | _ -> false)
+   | TLazy f -> is_objc_type (lazy_type f)
+   | _ -> false
+
+let is_objc_type t =
+   match t with
+   | TInst(cl,_) -> (has_class_flag cl CExtern) && Meta.has Meta.Objc cl.cl_meta
+   | TType(td,_) -> (Meta.has Meta.Objc td.t_meta)
+   | TAbstract (a,_) -> (Meta.has Meta.Objc a.a_meta)
+   | TMono r -> (match r.tm_type with | Some t -> is_objc_type t | _ -> false)
+   | TLazy f -> is_objc_type (lazy_type f)
+   | _ -> false
+
+let is_dynamic_type_param class_kind =
+   match class_kind with
+   | KTypeParameter _ -> true
+   | _ -> false
+
+let is_dynamic_array_param t =
+   match follow t with
+   | TAbstract ({ a_path = ([],"Dynamic") },[]) -> true
+   | TInst (klass, params) ->
+      (match klass with
+      | { cl_path = ([], "Array") }
+      | { cl_path = ([], "Class") }
+      | { cl_path = (["cpp"], "FastIterator") }
+      | { cl_path = (["cpp"], "RawPointer") }
+      | { cl_path = (["cpp"], "ConstRawPointer") }
+      | { cl_path = (["cpp"], "Pointer") }
+      | { cl_path = (["cpp"], "ConstPointer") }
+      | { cl_path = (["cpp"], "Function") } -> false
+      | { cl_kind = KTypeParameter _ } -> true
+      | _ -> false)
+   | _ -> false
+
+let is_numeric t =
+   match follow t with
+   | TAbstract({ a_path = ([], "Int") }, [])
+   | TAbstract({ a_path = ([], "Float") }, [])
+   | TAbstract({ a_path = ([], "Single") }, [])
+   | TAbstract({ a_path = (["cpp"], "Char") }, [])
+   | TAbstract({ a_path = (["cpp"], "Float32") }, [])
+   | TAbstract({ a_path = (["cpp"], "Float64") }, [])
+   | TAbstract({ a_path = (["cpp"], "Int8") }, [])
+   | TAbstract({ a_path = (["cpp"], "Int16") }, [])
+   | TAbstract({ a_path = (["cpp"], "Int32") }, [])
+   | TAbstract({ a_path = (["cpp"], "Int64") }, [])
+   | TAbstract({ a_path = (["cpp"], "UInt8") }, [])
+   | TAbstract({ a_path = (["cpp"], "UInt16") }, [])
+   | TAbstract({ a_path = (["cpp"], "UInt32") }, [])
+   | TAbstract({ a_path = (["cpp"], "UInt64") }, [])
+      -> true
+   | _
+      -> false
+
+let is_cpp_function_instance t =
+   match follow t with
+   | TInst ({ cl_path = (["cpp"], "Function") }, _) -> true
+   | _ -> false
+
+let is_objc_class klass =
+   has_class_flag klass CExtern && Meta.has Meta.Objc klass.cl_meta
+
+let is_var_field field =
+   match field.cf_kind with
+   | Var _
+   | Method MethDynamic -> true
+   | _ -> false
+
+let is_pointer haxe_type includeRaw =
+   match follow haxe_type with
+   | TInst (klass,params) ->
+      (match klass.cl_path with
+      | ["cpp"] , "Pointer"
+      | ["cpp"] , "ConstPointer"
+      | ["cpp"] , "Function" -> true
+      | ["cpp"] , "RawPointer" when includeRaw -> true
+      | ["cpp"] , "RawConstPointer" when includeRaw -> true
+      | _ -> false )
+   | TType (type_def,params) ->
+      (match type_def.t_path with
+      | ["cpp"] , "Pointer"
+      | ["cpp"] , "ConstPointer"
+      | ["cpp"] , "Function" -> true
+      | ["cpp"] , "RawPointer" when includeRaw -> true
+      | ["cpp"] , "RawConstPointer" when includeRaw -> true
+      | _ -> false )
+   | _ -> false
+   ;;
+
+let is_array haxe_type =
+   match follow haxe_type with
+   | TInst ({ cl_path = ([], "Array") }, params)
+   | TType ({ t_path = ([], "Array") }, params) ->
+      not (is_dynamic_array_param (List.hd params))
+   | _ -> false
+
+let is_array_or_dyn_array haxe_type =
+   match follow haxe_type with
+   | TInst ({ cl_path = ([], "Array") }, _)
+   | TType ({ t_path = ([], "Array")}, _) -> true
+   | _ -> false
+
+let is_array_implementer haxe_type =
+   match follow haxe_type with
+   | TInst ({ cl_array_access = Some _ }, _) -> true
+   | _ -> false
+
+let rec has_rtti_interface c interface =
+   List.exists (function (t,pl) ->
+      (snd t.cl_path) = interface && (match fst t.cl_path with | ["cpp";"rtti"] -> true | _ -> false )
+   ) c.cl_implements ||
+      (match c.cl_super with None -> false | Some (c,_) -> has_rtti_interface c interface)
+
+let has_field_integer_lookup class_def =
+   has_rtti_interface class_def "FieldIntegerLookup"
+
+let has_field_integer_numeric_lookup class_def =
+   has_rtti_interface class_def "FieldNumericIntegerLookup"
+
+let should_implement_field x = is_physical_field x
+
+let is_scalar_abstract abstract_def =
+   Meta.has Meta.Scalar abstract_def.a_meta && Meta.has Meta.CoreType abstract_def.a_meta
+
+let is_real_function field =
+   match field.cf_kind with
+   | Method MethNormal | Method MethInline-> true
+   | _ -> false
+
+let get_nth_type field index =
+   match follow field.ef_type with
+   | TFun (args,_) ->
+      let rec nth l index = match l with
+      | [] -> raise Not_found
+      | (_,_,t)::rest ->
+            if index = 0 then t
+            else nth rest (index-1)
+      in
+      nth args index
+   | _ -> raise Not_found
+
+let is_dynamic_haxe_method f =
+   match f.cf_expr, f.cf_kind with
+   | Some { eexpr = TFunction _ }, (Var _ | Method MethDynamic) -> true
+   | _ -> false
+
+let has_dynamic_member_functions class_def =
+   List.fold_left (fun result field ->
+      match field.cf_expr with
+      | Some { eexpr = TFunction function_def } when is_dynamic_haxe_method field -> true
+      | _ -> result ) false class_def.cl_ordered_fields
+
+let has_field_init field =
+   match field.cf_expr with
+   (* Function field *)
+   | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field
+   (* Data field *)
+   | Some _ -> true
+   | _ -> false
+
+let is_data_member field =
+   match field.cf_kind with
+   | Var _ | Method MethDynamic -> true
+   | _ -> false
+
+let is_override field =
+   has_class_field_flag field CfOverride
+
+let rec unreflective_type t =
+   match follow t with
+   | TInst (klass,_) ->  Meta.has Meta.Unreflective klass.cl_meta
+   | TFun (args,ret) ->
+      List.fold_left (fun result (_,_,t) -> result || (unreflective_type t)) (unreflective_type ret) args;
+   | _ -> false
+
+let reflective class_def field = not (
+   (Meta.has Meta.NativeGen class_def.cl_meta) ||
+   (Meta.has Meta.Unreflective class_def.cl_meta) ||
+   (Meta.has Meta.Unreflective field.cf_meta) ||
+   unreflective_type field.cf_type)
+
+let has_init_field class_def =
+   match TClass.get_cl_init class_def with
+   | Some _ -> true
+   | _ -> false
+
+let is_abstract_impl class_def = match class_def.cl_kind with
+   | KAbstractImpl _ -> true
+   | _ -> false
+
+let variable_field field =
+   match field.cf_expr with
+   | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field
+   | None when has_class_field_flag field CfAbstract -> false
+   | _ -> true
+
+let is_readable class_def field =
+   match field.cf_kind with
+   | Var { v_read = AccNever } when not (is_physical_field field) -> false
+   | Var { v_read = AccInline } -> false
+   | Var _ when is_abstract_impl class_def -> false
+   | _ -> true
+
+let is_writable class_def field =
+   match field.cf_kind with
+   | Var { v_write = AccNever } when not (is_physical_field field) -> false
+   | Var { v_read = AccInline } -> false
+   | Var _ when is_abstract_impl class_def -> false
+   | _ -> true
+
+let statics_except_meta class_def = (List.filter (fun static -> static.cf_name <> "__meta__" && static.cf_name <> "__rtti") class_def.cl_ordered_statics);;
+
+let has_set_member_field class_def =
+   let reflect_fields = List.filter (reflective class_def) (class_def.cl_ordered_fields) in
+   let reflect_writable = List.filter (is_writable class_def) reflect_fields in
+   List.exists variable_field reflect_writable
+
+let has_set_static_field class_def =
+   let reflect_fields = List.filter (reflective class_def) (statics_except_meta class_def) in
+   let reflect_writable = List.filter (is_writable class_def) reflect_fields in
+   List.exists variable_field reflect_writable
+
+let has_get_fields class_def =
+   let is_data_field field = (match follow field.cf_type with | TFun _ -> false | _ -> true) in
+   List.exists is_data_field class_def.cl_ordered_fields
+
+let has_get_member_field class_def =
+   let reflect_fields = List.filter (reflective class_def) (class_def.cl_ordered_fields) in
+   List.exists (is_readable class_def) reflect_fields
+
+let has_get_static_field class_def =
+   let reflect_fields = List.filter (reflective class_def) (statics_except_meta class_def) in
+   List.exists (is_readable class_def) reflect_fields
+
+let has_compare_field class_def =
+   List.exists (fun f -> f.cf_name="__compare") class_def.cl_ordered_fields
+
+let has_boot_field class_def =
+   match TClass.get_cl_init class_def with
+   | None -> List.exists has_field_init (List.filter should_implement_field class_def.cl_ordered_statics)
+   | _ -> true
+
+(*
+   Functions are added in reverse order (oldest on right), then list is reversed because this is easier in ocaml
+   The order is important because cppia looks up functions by index
+*)
+let current_virtual_functions_rev clazz base_functions =
+   List.fold_left (fun result elem -> match follow elem.cf_type, elem.cf_kind  with
+      | _, Method MethDynamic -> result
+      | TFun (args,return_type), Method _  ->
+          if (is_override elem ) then
+            if List.exists (fun (e,a,r) -> e.cf_name=elem.cf_name ) result then
+               result
+            else
+               (elem,args,return_type) :: result
+          else
+             (elem,args,return_type) :: result
+      | _,_ -> result
+    ) base_functions clazz.cl_ordered_fields
+
+let all_virtual_functions clazz =
+  let rec all_virtual_functions_rec clazz =
+   current_virtual_functions_rev clazz (match clazz.cl_super with
+       | Some def -> all_virtual_functions_rec (fst def)
+       | _ -> []
+     )
+   in
+   List.rev (all_virtual_functions_rec clazz)
+
+let class_name class_def =
+  let (_, class_path) = class_def.cl_path in
+  let nativeGen       = Meta.has Meta.NativeGen class_def.cl_meta in
+  class_path ^ if nativeGen then "" else "_obj"
+
+let class_pointer class_def = "::hx::ObjectPtr< " ^ class_name class_def ^ " >"

+ 1928 - 0
src/generators/cpp/gen/cppCppia.ml

@@ -0,0 +1,1928 @@
+open Ast
+open Type
+open Error
+open Globals
+open CppExprUtils
+open CppTypeUtils
+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
+
+let rec script_type_string haxe_type =
+  match haxe_type with
+  | TAbstract ({ a_path = [], "Null" }, [ t ]) -> (
+      match follow t with
+      | TAbstract ({ a_path = [], "Int" }, _)
+      | TAbstract ({ a_path = [], "Float" }, _)
+      | TAbstract ({ a_path = [], "Bool" }, _) ->
+          "Dynamic"
+      | _ -> script_type_string t)
+  | TInst ({ cl_path = [], "Null" }, [ t ]) -> (
+      match follow t with
+      | TAbstract ({ a_path = [], "Int" }, _)
+      | TAbstract ({ a_path = [], "Float" }, _)
+      | TAbstract ({ a_path = [], "Bool" }, _) ->
+          "Dynamic"
+      | _ -> script_type_string t)
+  | _ -> (
+      match follow haxe_type with
+      | TType ({ t_path = [], "Array" }, params) -> "Array"
+      | TInst ({ cl_path = [], "Array" }, params) -> (
+          match params with
+          | [ t ] -> (
+              match type_string_suff "" t false with
+              | "int" -> "Array.int"
+              | "Float" -> "Array.Float"
+              | "bool" -> "Array.bool"
+              | "::String" -> "Array.String"
+              | "unsigned char" -> "Array.unsigned char"
+              | "::cpp::UInt8" -> "Array.unsigned char"
+              | "Dynamic" -> "Array.Any"
+              | _ -> "Array.Object")
+          | _ -> "Array.Object")
+      | TAbstract (abs, pl) when abs.a_impl <> None ->
+          script_type_string (Abstract.get_underlying_type abs pl)
+      | _ -> type_string_suff "" haxe_type false)
+
+let rec script_cpptype_string cppType =
+  match cppType with
+  | TCppDynamic | TCppUnchanged | TCppWrapped _ | TCppObject -> "Dynamic"
+  | TCppObjectPtr -> ".*.hx.Object*"
+  | TCppReference t -> ".ref." ^ script_cpptype_string t
+  | TCppStruct t -> ".struct." ^ script_cpptype_string t
+  | TCppStar (t, _) -> "*." ^ script_cpptype_string t
+  | TCppVoid -> "void"
+  | TCppVoidStar -> "*.void"
+  | TCppRest _ -> "vaarg_list"
+  | TCppVarArg -> "vararg"
+  | TCppAutoCast -> ".cpp.AutoCast"
+  | TCppVariant -> ".cpp.Variant"
+  | TCppEnum enum -> join_class_path enum.e_path "."
+  | TCppScalar scalar -> scalar
+  | TCppString -> "String"
+  | TCppFastIterator it -> "cpp.FastIterator." ^ script_cpptype_string it
+  | TCppPointer (_, valueType) ->
+      "cpp.Pointer." ^ script_cpptype_string valueType
+  | TCppRawPointer (_, valueType) ->
+      "cpp.RawPointer." ^ script_cpptype_string valueType
+  | TCppFunction _ -> "cpp.Function"
+  | TCppObjCBlock _ -> "cpp.ObjCBlock"
+  | TCppDynamicArray -> "Array.Any"
+  | TCppObjectArray _ -> "Array.Object"
+  | TCppScalarArray value -> "Array." ^ script_cpptype_string value
+  | TCppObjC _ -> "cpp.ObjC"
+  | TCppProtocol _ -> "cpp.ObjC.Protocol"
+  | TCppNativePointer klass ->
+      "cpp.Pointer." ^ join_class_path klass.cl_path "."
+  | TCppInterface klass -> join_class_path klass.cl_path "."
+  | TCppInst (klass, _) -> join_class_path klass.cl_path "."
+  | TCppClass -> "Class"
+  | TCppGlobal -> "?global"
+  | TCppNull -> "null"
+  | TCppCode _ -> "Dynamic"
+
+type array_of =
+  | ArrayInterface of int
+  | ArrayData of string
+  | ArrayObject
+  | ArrayAny
+  | ArrayNone
+
+let is_template_type t = false
+
+type cppia_op =
+  | IaFunction
+  | IaVar
+  | IaToInterface
+  | IaToDynArray
+  | IaToDataArray
+  | IaToInterfaceArray
+  | IaFun
+  | IaCast
+  | IaTCast
+  | IaBlock
+  | IaBreak
+  | IaContinue
+  | IaIsNull
+  | IaNotNull
+  | IaSet
+  | IaCall
+  | IaCallGlobal
+  | IaCallStatic
+  | IaCallMember
+  | IaCallSuper
+  | IaCallThis
+  | IaCallSuperNew
+  | IaCreateEnum
+  | IaADef
+  | IaIf
+  | IaIfElse
+  | IaFStatic
+  | IaFName
+  | IaFThisInst
+  | IaFLink
+  | IaFThisName
+  | IaFEnum
+  | IaThrow
+  | IaArrayI
+  | IaPlusPlus
+  | IaPlusPlusPost
+  | IaMinusMinus
+  | IaMinusMinusPost
+  | IaNeg
+  | IaBitNot
+  | IaLogicNot
+  | IaTVars
+  | IaVarDecl
+  | IaVarDeclI
+  | IaNew
+  | IaReturn
+  | IaRetVal
+  | IaPosInfo
+  | IaObjDef
+  | IaClassOf
+  | IaWhile
+  | IaFor
+  | IaEnumI
+  | IaSwitch
+  | IaTry
+  | IaImplDynamic
+  | IaConstInt
+  | IaConstFloat
+  | IaConstString
+  | IaConstFalse
+  | IaConstTrue
+  | IaConstNull
+  | IaConsThis
+  | IaConstSuper
+  | IaCastInt
+  | IaCastBool
+  | IaInterface
+  | IaClass
+  | IaAccessNormal
+  | IaAccessNot
+  | IaAccessResolve
+  | IaAccessCall
+  | IaEnum
+  | IaInline
+  | IaMain
+  | IaNoMain
+  | IaResources
+  | IaReso
+  | IaNoCast
+  | IaAccessCallNative
+  | IaBinOp of Ast.binop
+
+let cppia_op_info = function
+  | IaFunction -> ("FUNCTION", 1)
+  | IaVar -> ("VAR", 2)
+  | IaToInterface -> ("TOINTERFACE", 3)
+  | IaToDynArray -> ("TODYNARRAY", 4)
+  | IaToDataArray -> ("TODATAARRAY", 5)
+  | IaToInterfaceArray -> ("TOINTERFACEARRAY", 6)
+  | IaFun -> ("FUN", 7)
+  | IaCast -> ("CAST", 8)
+  | IaBlock -> ("BLOCK", 9)
+  | IaBreak -> ("BREAK", 10)
+  | IaContinue -> ("CONTINUE", 11)
+  | IaIsNull -> ("ISNULL", 12)
+  | IaNotNull -> ("NOTNULL", 13)
+  | IaSet -> ("SET", 14)
+  | IaCall -> ("CALL", 15)
+  | IaCallGlobal -> ("CALLGLOBAL", 16)
+  | IaCallStatic -> ("CALLSTATIC", 17)
+  | IaCallMember -> ("CALLMEMBER", 18)
+  | IaCallSuper -> ("CALLSUPER", 19)
+  | IaCallThis -> ("CALLTHIS", 20)
+  | IaCallSuperNew -> ("CALLSUPERNEW", 21)
+  | IaCreateEnum -> ("CREATEENUM", 22)
+  | IaADef -> ("ADEF", 23)
+  | IaIf -> ("IF", 24)
+  | IaIfElse -> ("IFELSE", 25)
+  | IaFName -> ("FNAME", 27)
+  | IaFStatic -> ("FSTATIC", 28)
+  | IaFThisInst -> ("FTHISINST", 29)
+  | IaFLink -> ("FLINK", 30)
+  | IaFThisName -> ("FTHISNAME", 31)
+  | IaFEnum -> ("FENUM", 32)
+  | IaThrow -> ("THROW", 33)
+  | IaArrayI -> ("ARRAYI", 34)
+  | IaPlusPlus -> ("++", 35)
+  | IaPlusPlusPost -> ("+++", 36)
+  | IaMinusMinus -> ("--", 37)
+  | IaMinusMinusPost -> ("---", 38)
+  | IaNeg -> ("NEG", 39)
+  | IaBitNot -> ("~", 40)
+  | IaLogicNot -> ("!", 41)
+  | IaTVars -> ("TVARS", 42)
+  | IaVarDecl -> ("VARDECL", 43)
+  | IaVarDeclI -> ("VARDECLI", 44)
+  | IaNew -> ("NEW", 45)
+  | IaReturn -> ("RETURN", 46)
+  | IaRetVal -> ("RETVAL", 47)
+  | IaPosInfo -> ("POSINFO", 48)
+  | IaObjDef -> ("OBJDEF", 49)
+  | IaClassOf -> ("CLASSOF", 50)
+  | IaWhile -> ("WHILE", 51)
+  | IaFor -> ("FOR", 52)
+  | IaEnumI -> ("ENUMI", 53)
+  | IaSwitch -> ("SWITCH", 54)
+  | IaTry -> ("TRY", 55)
+  | IaImplDynamic -> ("IMPLDYNAMIC", 56)
+  | IaConstInt -> ("i", 57)
+  | IaConstFloat -> ("f", 58)
+  | IaConstString -> ("s", 59)
+  | IaConstFalse -> ("false", 60)
+  | IaConstTrue -> ("true", 61)
+  | IaConstNull -> ("NULL", 62)
+  | IaConsThis -> ("THIS", 63)
+  | IaConstSuper -> ("SUPER", 64)
+  | IaCastInt -> ("CASTINT", 65)
+  | IaCastBool -> ("CASTBOOL", 66)
+  | IaInterface -> ("INTERFACE", 67)
+  | IaClass -> ("CLASS", 68)
+  | IaAccessNormal -> ("N", 69)
+  | IaAccessNot -> ("n", 70)
+  | IaAccessResolve -> ("R", 71)
+  | IaAccessCall -> ("C", 72)
+  | IaEnum -> ("ENUM", 73)
+  | IaInline -> ("INLINE", 74)
+  | IaMain -> ("MAIN", 75)
+  | IaNoMain -> ("NOMAIN", 76)
+  | IaResources -> ("RESOURCES", 77)
+  | IaReso -> ("RESO", 78)
+  | IaNoCast -> ("NOCAST", 79)
+  | IaAccessCallNative -> ("V", 80)
+  | IaBinOp OpAdd -> ("+", 101)
+  | IaBinOp OpMult -> ("*", 102)
+  | IaBinOp OpDiv -> ("/", 103)
+  | IaBinOp OpSub -> ("-", 104)
+  | IaBinOp OpAssign -> ("=", 105)
+  | IaBinOp OpEq -> ("==", 106)
+  | IaBinOp OpNotEq -> ("!=", 107)
+  | IaBinOp OpGte -> (">=", 108)
+  | IaBinOp OpLte -> ("<=", 109)
+  | IaBinOp OpGt -> (">", 110)
+  | IaBinOp OpLt -> ("<", 111)
+  | IaBinOp OpAnd -> ("&", 112)
+  | IaBinOp OpOr -> ("|", 113)
+  | IaBinOp OpXor -> ("^", 114)
+  | IaBinOp OpBoolAnd -> ("&&", 115)
+  | IaBinOp OpBoolOr -> ("||", 116)
+  | IaBinOp OpShr -> (">>", 117)
+  | IaBinOp OpUShr -> (">>>", 118)
+  | IaBinOp OpShl -> ("<<", 119)
+  | IaBinOp OpMod -> ("%", 120)
+  | IaBinOp OpInterval -> ("...", 121)
+  | IaBinOp OpArrow -> ("=>", 122)
+  | IaBinOp OpIn -> (" in ", 123)
+  | IaBinOp OpNullCoal -> ("??", 124)
+  | IaBinOp (OpAssignOp OpAdd) -> ("+=", 201)
+  | IaBinOp (OpAssignOp OpMult) -> ("*=", 202)
+  | IaBinOp (OpAssignOp OpDiv) -> ("/=", 203)
+  | IaBinOp (OpAssignOp OpSub) -> ("-=", 204)
+  | IaBinOp (OpAssignOp OpAnd) -> ("&=", 212)
+  | IaBinOp (OpAssignOp OpOr) -> ("|=", 213)
+  | IaBinOp (OpAssignOp OpXor) -> ("^=", 214)
+  | IaBinOp (OpAssignOp OpBoolAnd) -> ("&&=", 215)
+  | IaBinOp (OpAssignOp OpBoolOr) -> ("||=", 216)
+  | IaBinOp (OpAssignOp OpShr) -> (">>=", 217)
+  | IaBinOp (OpAssignOp OpUShr) -> (">>>=", 218)
+  | IaBinOp (OpAssignOp OpShl) -> ("<<=", 219)
+  | IaBinOp (OpAssignOp OpMod) -> ("%=", 220)
+  | IaBinOp (OpAssignOp OpIn)
+  | IaBinOp (OpAssignOp OpNullCoal)
+  | IaBinOp (OpAssignOp OpInterval)
+  | IaBinOp (OpAssignOp OpAssign)
+  | IaBinOp (OpAssignOp OpEq)
+  | IaBinOp (OpAssignOp OpNotEq)
+  | IaBinOp (OpAssignOp OpGte)
+  | IaBinOp (OpAssignOp OpLte)
+  | IaBinOp (OpAssignOp OpGt)
+  | IaBinOp (OpAssignOp OpLt)
+  | IaBinOp (OpAssignOp (OpAssignOp _))
+  | IaBinOp (OpAssignOp OpArrow) ->
+      die "" __LOC__
+  | IaTCast -> ("TCAST", 221)
+
+let follow = Abstract.follow_with_abstracts
+
+let is_matching_interface_type t0 t1 =
+  match (follow t0, follow t1) with
+  | TInst (k0, _), TInst (k1, _) -> k0 == k1
+  | _ -> false
+
+let rec is_null expr =
+  match expr.eexpr with
+  | TConst TNull -> true
+  | TParenthesis expr | TMeta (_, expr) -> is_null expr
+  | TCast (e, None) -> is_null e
+  | _ -> false
+
+let is_virtual_array expr = type_string expr.etype = "cpp::VirtualArray"
+
+let is_this expression =
+  match (remove_parens expression).eexpr with
+  | TConst TThis -> true
+  | _ -> false
+
+let is_super expression =
+  match (remove_parens expression).eexpr with
+  | TConst TSuper -> true
+  | _ -> false
+
+let is_native_pointer expr =
+  let t = type_string expr.etype in
+  let l = String.length t in
+  l > 1 && String.sub t (l - 1) 1 = "*"
+
+let is_extern_class_instance obj =
+  match follow obj.etype with
+  | TInst (klass, params) -> has_class_flag klass CExtern
+  | _ -> false
+
+let rec is_dynamic_in_cpp ctx expr =
+  let expr_type =
+    type_string
+      (match follow expr.etype with TFun (args, ret) -> ret | _ -> expr.etype)
+  in
+  if expr_type = "Dynamic" || expr_type = "cpp::ArrayBase" then true
+  else
+    let result =
+      match expr.eexpr with
+      | TEnumParameter (obj, _, index) -> true (* TODO? *)
+      | TField (obj, field) ->
+          is_dynamic_member_lookup_in_cpp ctx obj field
+          || is_dynamic_member_return_in_cpp ctx obj field
+      | TArray (obj, index) -> is_dynamic_in_cpp ctx obj || is_virtual_array obj
+      | TTypeExpr _ -> false
+      | TCall (func, args) -> (
+          let is_IaCall =
+            match (remove_parens_cast func).eexpr with
+            | TField ({ eexpr = TIdent "__global__" }, field) -> false
+            | TField (obj, FStatic (class_def, field))
+              when is_real_function field ->
+                false
+            | TField (obj, FInstance (_, _, field))
+              when is_this obj && is_real_function field ->
+                false
+            | TField (obj, FInstance (_, _, field)) when is_super obj -> false
+            | TField (obj, FInstance (_, _, field))
+              when field.cf_name = "_hx_getIndex" ->
+                false
+            | TField (obj, FInstance (_, _, field))
+              when field.cf_name = "__Index"
+                   || (not (is_dynamic_in_cppia ctx obj))
+                      && is_real_function field ->
+                false
+            | TField (obj, FDynamic name)
+              when is_internal_member name
+                   || (type_string obj.etype = "::String" && name = "cca") ->
+                false
+            | TConst TSuper -> false
+            | TField (_, FEnum (enum, field)) -> false
+            | _ -> true
+          in
+          if is_IaCall then true
+          else
+            match follow func.etype with
+            | TFun (args, ret) -> is_dynamic_in_cpp ctx func
+            | _ -> true)
+      | TParenthesis expr | TMeta (_, expr) -> is_dynamic_in_cpp ctx expr
+      | TCast (e, None) -> type_string expr.etype = "Dynamic"
+      | TIdent "__global__" -> false
+      | TConst TNull -> true
+      | _ -> false (* others ? *)
+    in
+    result
+
+and is_dynamic_member_lookup_in_cpp (ctx : context) field_object field =
+  let member = field_name field in
+  if is_internal_member member then false
+  else if is_native_pointer field_object then false
+  else if is_pointer field_object.etype true then false
+  else if match field_object.eexpr with TTypeExpr _ -> true | _ -> false then
+    false
+  else if is_dynamic_in_cpp ctx field_object then true
+  else if is_array field_object.etype then false
+  else
+    let tstr = type_string field_object.etype in
+    match tstr with
+    (* Internal classes have no dynamic members *)
+    | "::String" | "Null" | "::hx::Class" | "::Enum" | "::Math"
+    | "::ArrayAccess" ->
+        false
+    | "Dynamic" -> true
+    | name ->
+        let full_name = name ^ "." ^ member in
+        if Hashtbl.mem ctx.ctx_class_member_types full_name then false
+        else not (is_extern_class_instance field_object)
+
+and is_dynamic_member_return_in_cpp ctx field_object field =
+  let member = field_name field in
+  if is_array field_object.etype then false
+  else if is_pointer field_object.etype true then false
+  else if is_internal_member member then false
+  else
+    match field_object.eexpr with
+    | TTypeExpr t -> (
+        let full_name =
+          "::" ^ join_class_path_remap (t_path t) "::" ^ "." ^ member
+        in
+        try
+          let mem_type = Hashtbl.find ctx.ctx_class_member_types full_name in
+          mem_type = "Dynamic"
+          || mem_type = "cpp::ArrayBase"
+          || mem_type = "cpp::VirtualArray"
+        with Not_found -> true)
+    | _ -> (
+        let tstr = type_string field_object.etype in
+        match tstr with
+        (* Internal classes have no dynamic members *)
+        | "::String" | "Null" | "::hx::Class" | "::Enum" | "::Math"
+        | "::ArrayAccess" ->
+            false
+        | "Dynamic" | "cpp::ArrayBase" | "cpp::VirtualArray" -> true
+        | name -> (
+            let full_name = name ^ "." ^ member in
+            try
+              let mem_type =
+                Hashtbl.find ctx.ctx_class_member_types full_name
+              in
+              mem_type = "Dynamic"
+              || mem_type = "cpp::ArrayBase"
+              || mem_type = "cpp::VirtualArray"
+            with Not_found -> true))
+
+and is_dynamic_in_cppia ctx expr =
+  match expr.eexpr with
+  | TCast (_, None) -> true
+  | _ -> is_dynamic_in_cpp ctx expr
+
+class script_writer ctx filename asciiOut =
+  object (this)
+    val debug = asciiOut
+
+    val doComment =
+      asciiOut && Gctx.defined ctx.ctx_common Define.AnnotateSource
+
+    val indent_str = if asciiOut then "\t" else ""
+    val mutable indent = ""
+    val mutable indents = []
+    val mutable just_finished_block = false
+    val mutable classCount = 0
+    val mutable return_type = TMono (Monomorph.create ())
+    val buffer = Buffer.create 0
+    val identTable = Hashtbl.create 0
+    val fileTable = Hashtbl.create 0
+    val identBuffer = Buffer.create 0
+    val cppiaAst = not (Gctx.defined ctx.ctx_common Define.NoCppiaAst)
+
+    method stringId name =
+      try Hashtbl.find identTable name
+      with Not_found ->
+        let size = Hashtbl.length identTable in
+        Hashtbl.add identTable name size;
+        Buffer.add_string identBuffer
+          (string_of_int (String.length name) ^ " " ^ name ^ "\n");
+        size
+
+    method incClasses = classCount <- classCount + 1
+    method stringText name = string_of_int (this#stringId name) ^ " "
+    val typeTable = Hashtbl.create 0
+    val typeBuffer = Buffer.create 0
+
+    method typeId name =
+      let name = if name = "::hx::Class" then "::Class" else name in
+      try Hashtbl.find typeTable name
+      with Not_found ->
+        let size = Hashtbl.length typeTable in
+        Hashtbl.add typeTable name size;
+        Buffer.add_string typeBuffer
+          (string_of_int (String.length name) ^ " " ^ name ^ "\n");
+        size
+
+    method write str =
+      (if asciiOut then Buffer.add_string buffer str
+       else
+         let push i = Buffer.add_char buffer (Char.chr i) in
+         let pushI32 i =
+           push (Int32.to_int (Int32.logand i (Int32.of_int 255)))
+         in
+         List.iter
+           (fun i ->
+             if
+               Int32.compare i Int32.zero >= 0
+               && Int32.compare i (Int32.of_int 254) < 0
+             then pushI32 i
+             else if
+               Int32.compare i Int32.zero >= 0
+               && Int32.compare i (Int32.of_int 65536) < 0
+             then (
+               push 254;
+               pushI32 i;
+               pushI32 (Int32.shift_right i 8))
+             else (
+               push 255;
+               pushI32 i;
+               pushI32 (Int32.shift_right i 8);
+               pushI32 (Int32.shift_right i 16);
+               pushI32 (Int32.shift_right i 24)))
+           (List.map Int32.of_string (Str.split (Str.regexp "[\n\t ]+") str)));
+      just_finished_block <- false
+
+    method comment text = if doComment then this#write ("# " ^ text ^ "\n")
+    method commentOf text = if doComment then " # " ^ text else ""
+    method typeTextString typeName = string_of_int (this#typeId typeName) ^ " "
+
+    method typeText typeT =
+      let tname =
+        if cppiaAst then script_cpptype_string (cpp_type_of typeT)
+        else script_type_string typeT
+      in
+      string_of_int (this#typeId tname) ^ " "
+
+    method astType cppType =
+      string_of_int (this#typeId (script_cpptype_string cppType)) ^ " "
+
+    method writeType typeT = this#write (this#typeText typeT)
+
+    method toCppType etype =
+      string_of_int (this#typeId (script_cpptype_string (cpp_type_of etype)))
+      ^ " "
+
+    method boolText value = if value then "1" else "0"
+    method writeBool value = this#write (if value then "1 " else "0 ")
+    method staticText value = if value then "1" else "0"
+    method writeData str = Buffer.add_string buffer str
+    method wint ival = this#write (string_of_int ival ^ " ")
+    method ident name = this#wint (this#stringId name)
+
+    method cppInstText clazz =
+      match clazz.cl_path with
+      | [], "Array" -> this#typeTextString "Array"
+      | x -> this#typeTextString (join_class_path x ".")
+
+    method instText clazz =
+      match clazz.cl_path with
+      | [], "Array" -> string_of_int (this#typeId "Array< ::Dynamic >") ^ " "
+      | _ -> this#typeText (TInst (clazz, []))
+
+    method instName clazz =
+      this#write
+        (if cppiaAst then this#cppInstText clazz else this#instText clazz)
+
+    method enumText e = this#typeText (TEnum (e, []))
+
+    method close =
+      let out_file = open_out_bin filename in
+      output_string out_file (if asciiOut then "CPPIA\n" else "CPPIB\n");
+      let idents = Buffer.contents identBuffer in
+      output_string out_file (string_of_int (Hashtbl.length identTable) ^ "\n");
+      output_string out_file idents;
+      let types = Buffer.contents typeBuffer in
+      output_string out_file (string_of_int (Hashtbl.length typeTable) ^ "\n");
+      output_string out_file types;
+      output_string out_file (string_of_int classCount ^ "\n");
+      let contents = Buffer.contents buffer in
+      output_string out_file contents;
+      close_out out_file
+
+    method fileId file =
+      try Hashtbl.find fileTable file
+      with Not_found ->
+        let stripped_file = strip_file ctx.ctx_common file in
+        let result = this#stringId stripped_file in
+        Hashtbl.add fileTable file result;
+        result
+
+    method constText c =
+      match c with
+      | TInt i -> this#op IaConstInt ^ Printf.sprintf "%ld " i
+      | TFloat f ->
+          this#op IaConstFloat ^ this#stringText (Texpr.replace_separators f "")
+      | TString s -> this#op IaConstString ^ this#stringText s
+      | TBool true -> this#op IaConstTrue
+      | TBool false -> this#op IaConstFalse
+      | TNull -> this#op IaConstNull
+      | TThis -> this#op IaConsThis
+      | TSuper -> this#op IaConstSuper
+
+    method get_array_type t =
+      match follow t with
+      | TInst ({ cl_path = [], "Array" }, [ param ]) -> (
+          let typeName = type_string_suff "" param false in
+          match typeName with
+          | "::String" -> ArrayData "String"
+          | "int" | "Float" | "bool" | "String" | "unsigned char"
+          | "::cpp::UInt8" ->
+              ArrayData typeName
+          | "cpp::ArrayBase" | "cpp::VirtualArray" | "Dynamic" -> ArrayAny
+          | _ when is_interface_type param ->
+              ArrayInterface (this#typeId (script_type_string param))
+          | _ -> ArrayObject)
+      | TAbstract (abs, pl) when abs.a_impl <> None ->
+          this#get_array_type (Abstract.get_underlying_type abs pl)
+      | _ -> ArrayNone
+
+    method pushReturn inType =
+      let oldReturnType = return_type in
+      return_type <- inType;
+      fun () -> return_type <- oldReturnType
+
+    method fileText file = string_of_int (this#fileId file)
+    method indent_one = this#write indent_str
+
+    method push_indent =
+      indents <- indent_str :: indents;
+      indent <- String.concat "" indents
+
+    method pop_indent =
+      match indents with
+      | h :: tail ->
+          indents <- tail;
+          indent <- String.concat "" indents
+      | [] -> indent <- "/*?*/"
+
+    method write_i x = this#write (indent ^ x)
+    method get_indent = indent
+    method begin_expr = this#push_indent
+
+    method end_expr =
+      if not just_finished_block then this#write "\n";
+      this#pop_indent;
+      just_finished_block <- true
+
+    method op x =
+      match cppia_op_info x with
+      | name, index -> (if debug then name else string_of_int index) ^ " "
+
+    method writeOp o = this#write (this#op o)
+    method writeOpLine o = this#write (this#op o ^ "\n")
+
+    method voidFunc isStatic isDynamic funcName fieldExpression =
+      this#comment funcName;
+      this#write
+        (this#op IaFunction ^ this#staticText isStatic ^ " "
+       ^ this#boolText isDynamic ^ " " ^ this#stringText funcName ^ " ");
+      this#write (this#typeTextString "Void" ^ "0\n");
+      this#gen_expression fieldExpression
+
+    method func isStatic isDynamic funcName ret args isInterface fieldExpression
+        abstractPos =
+      this#comment funcName;
+      this#write
+        (this#op IaFunction ^ this#staticText isStatic ^ " "
+       ^ this#boolText isDynamic ^ " " ^ this#stringText funcName ^ " ");
+      this#write (this#typeText ret ^ string_of_int (List.length args) ^ " ");
+      List.iter
+        (fun (name, opt, typ) ->
+          this#write
+            (this#stringText name ^ this#boolText opt ^ " " ^ this#typeText typ
+           ^ " "))
+        args;
+      this#write "\n";
+      if not isInterface then
+        match fieldExpression with
+        | Some ({ eexpr = TFunction function_def } as e) ->
+            if cppiaAst then (
+              let args = List.map fst function_def.tf_args in
+              let cppExpr =
+                CppRetyper.expression ctx TCppVoid args function_def.tf_type
+                  function_def.tf_expr false
+              in
+              this#begin_expr;
+              this#writePos function_def.tf_expr;
+              this#write
+                (this#op IaFun
+                ^ this#typeText function_def.tf_type
+                ^ string_of_int (List.length args)
+                ^ "\n");
+              let close = this#gen_func_args function_def.tf_args in
+              this#gen_expression_tree cppExpr;
+              this#end_expr;
+              close ())
+            else this#gen_expression e
+        | _ ->
+            (* Abstract function - dummp implementation that (should) not get called *)
+            this#begin_expr;
+            this#wpos abstractPos;
+            this#writeOpLine IaReturn;
+            this#end_expr
+
+    method var readAcc writeAcc isExtern isStatic name varType varExpr =
+      this#write
+        (this#op IaVar ^ this#staticText isStatic ^ " " ^ this#op readAcc
+       ^ this#op writeAcc ^ this#boolText isExtern ^ " " ^ this#stringText name
+       ^ this#typeText varType
+        ^ (match varExpr with Some _ -> "1" | _ -> "0")
+        ^ if doComment then " # " ^ name ^ "\n" else "\n");
+      match varExpr with
+      | Some expression ->
+          if cppiaAst then
+            let varType = cpp_type_of expression.etype in
+            let cppExpr =
+              CppRetyper.expression ctx varType [] t_dynamic expression false
+            in
+            this#gen_expression_tree cppExpr
+          else this#gen_expression expression
+      | _ -> ()
+
+    method implDynamic = this#writeOpLine IaImplDynamic
+
+    method writeVar v =
+      this#ident v.v_name;
+      this#wint v.v_id;
+      this#writeBool (has_var_flag v VCaptured);
+      this#writeType v.v_type
+
+    method writeList prefix len =
+      this#write (prefix ^ " " ^ string_of_int len ^ "\n")
+
+    method wpos p =
+      if debug then
+        this#write
+          (this#fileText p.pfile ^ "\t"
+          ^ string_of_int (Lexer.get_error_line p)
+          ^ indent)
+
+    method writePos expr = this#wpos expr.epos
+    method writeCppPos expr = this#wpos expr.cpppos
+
+    method checkCast toType expr forceCast fromGenExpression =
+      let write_cast text =
+        if not fromGenExpression then this#writePos expr;
+        this#write (text ^ "\n");
+        this#begin_expr;
+        this#gen_expression expr;
+        this#end_expr;
+        true
+      in
+      let was_cast =
+        if is_interface_type toType then
+          if is_dynamic_in_cppia ctx expr then
+            write_cast
+              (this#op IaToInterface ^ this#typeText toType ^ " "
+              ^ this#typeTextString "Dynamic")
+          else if not (is_matching_interface_type toType expr.etype) then
+            write_cast
+              (this#op IaToInterface ^ this#typeText toType ^ " "
+             ^ this#typeText expr.etype)
+          else false
+        else
+          let get_array_expr_type expr =
+            if is_dynamic_in_cppia ctx expr then ArrayNone
+            else this#get_array_type expr.etype
+          in
+          match (this#get_array_type toType, get_array_expr_type expr) with
+          | ArrayAny, _ -> false
+          | ArrayObject, ArrayData _ -> write_cast (this#op IaToDynArray)
+          | ArrayObject, ArrayObject -> false
+          | ArrayObject, ArrayNone | ArrayObject, ArrayAny ->
+              write_cast
+                (this#op IaToDataArray ^ this#typeTextString "Array.Object")
+          | ArrayData t, ArrayNone
+          | ArrayData t, ArrayObject
+          | ArrayData t, ArrayAny ->
+              write_cast
+                (this#op IaToDataArray ^ this#typeTextString ("Array." ^ t))
+          | ArrayInterface t, ArrayNone | ArrayInterface t, ArrayAny ->
+              write_cast (this#op IaToInterfaceArray ^ string_of_int t)
+          | _, _ ->
+              (* a0,a1 ->
+                    let arrayString a =
+                       match a with
+                       | ArrayNone -> "ArrayNone"
+                       | ArrayAny -> "ArrayAny"
+                       | ArrayObject -> "ArrayObject"
+                       | ArrayData _ -> "ArrayData"
+                       | ArrayInterface _ -> "ArrayInterface"
+                 in
+                 this#write ("NOCAST " ^ (arrayString a0) ^ "=" ^ (arrayString a1)); *)
+              false
+      in
+
+      if not was_cast then (
+        (if forceCast then
+           let op =
+             match type_string expr.etype with
+             | "int" -> IaCastInt
+             | "bool" -> IaCastBool
+             | _ when is_interface_type toType -> IaNoCast
+             | _ -> IaCast
+           in
+           this#writeOpLine op);
+        this#gen_expression expr)
+
+    method gen_func_args args =
+      let gen_inits = ref [] in
+      List.iter
+        (fun (arg, init) ->
+          this#write (indent ^ indent_str);
+          this#writeVar arg;
+          match init with
+          | Some { eexpr = TConst TNull } -> this#write "0\n"
+          | Some const ->
+              let argType = cpp_type_of const.etype in
+              if is_cpp_scalar argType || argType == TCppString then (
+                this#write "1 ";
+                this#gen_expression_only const;
+                this#write "\n")
+              else (
+                gen_inits := (arg, const) :: !gen_inits;
+                this#write "0\n")
+          | _ -> this#write "0\n")
+        args;
+
+      if List.length !gen_inits == 0 then fun () -> ()
+      else (
+        this#begin_expr;
+        this#writePos (snd (List.hd !gen_inits));
+        this#writeList (this#op IaBlock) (List.length !gen_inits + 1);
+        List.iter
+          (fun (arg, const) ->
+            let start_expr () =
+              this#begin_expr;
+              this#writePos const
+            in
+            let local_var () =
+              this#begin_expr;
+              this#writePos const;
+              this#write
+                (this#op IaVar ^ string_of_int arg.v_id
+               ^ this#commentOf arg.v_name);
+              this#end_expr
+            in
+
+            start_expr ();
+            this#writeOpLine IaIf;
+            start_expr ();
+            this#writeOpLine IaIsNull;
+            local_var ();
+            this#end_expr;
+            start_expr ();
+            this#writeOpLine IaSet;
+            local_var ();
+            this#gen_expression const;
+            this#end_expr;
+            this#begin_expr)
+          !gen_inits;
+        fun () -> this#end_expr)
+
+    method gen_expression expr =
+      this#begin_expr;
+      this#writePos expr;
+      this#gen_expression_only expr;
+      this#end_expr
+
+    method gen_expression_only expr =
+      (* { *)
+      let expression = remove_parens expr in
+      match expression.eexpr with
+      | TFunction function_def ->
+          this#write
+            (this#op IaFun
+            ^ 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 pop = this#pushReturn function_def.tf_type in
+          this#gen_expression function_def.tf_expr;
+          pop ();
+          close ()
+      | TBlock expr_list ->
+          this#writeList (this#op IaBlock) (List.length expr_list);
+          List.iter this#gen_expression expr_list
+      | TConst const -> this#write (this#constText const)
+      | TBreak -> this#writeOp IaBreak
+      | TContinue -> this#writeOp IaContinue
+      | TBinop (op, e1, e2) when op = OpAssign ->
+          this#writeOpLine IaSet;
+          this#gen_expression e1;
+          this#checkCast e1.etype e2 false false
+      | TBinop (OpEq, e1, { eexpr = TConst TNull }) ->
+          this#writeOpLine IaIsNull;
+          this#gen_expression e1
+      | TBinop (OpNotEq, e1, { eexpr = TConst TNull }) ->
+          this#writeOpLine IaNotNull;
+          this#gen_expression e1
+      | TBinop (OpEq, { eexpr = TConst TNull }, e1) ->
+          this#writeOpLine IaIsNull;
+          this#gen_expression e1
+      | TBinop (OpNotEq, { eexpr = TConst TNull }, e1) ->
+          this#writeOpLine IaNotNull;
+          this#gen_expression e1
+      | TBinop (op, e1, e2) ->
+          this#writeOpLine (IaBinOp op);
+          this#gen_expression e1;
+          this#gen_expression e2
+      | TThrow e ->
+          this#writeOpLine IaThrow;
+          this#gen_expression e
+      | TArrayDecl expr_list ->
+          this#write
+            (this#op IaADef
+            ^ this#typeText expression.etype
+            ^ " "
+            ^ string_of_int (List.length expr_list)
+            ^ "\n");
+          List.iter this#gen_expression expr_list
+      | TIf (e, e1, e2) -> (
+          match e2 with
+          | None ->
+              this#writeOpLine IaIf;
+              this#gen_expression e;
+              this#gen_expression e1
+          | Some elze ->
+              this#writeOpLine IaIfElse;
+              this#gen_expression e;
+              this#gen_expression e1;
+              this#gen_expression elze)
+      | TCall (func, arg_list) -> (
+          let argN = string_of_int (List.length arg_list) ^ " " in
+          let gen_call () =
+            (match (remove_parens_cast func).eexpr with
+            | TField ({ eexpr = TIdent "__global__" }, field) ->
+                this#write
+                  (this#op IaCallGlobal
+                  ^ this#stringText (field_name field)
+                  ^ argN
+                  ^ this#commentOf (field_name field)
+                  ^ "\n")
+            | TField (obj, FStatic (class_def, field))
+              when is_real_function field ->
+                this#write
+                  (this#op IaCallStatic ^ this#instText class_def ^ " "
+                  ^ this#stringText field.cf_name
+                  ^ argN
+                  ^ this#commentOf
+                      (join_class_path class_def.cl_path "."
+                      ^ "." ^ field.cf_name)
+                  ^ "\n")
+            | TField (obj, FInstance (_, _, field))
+              when is_this obj && is_real_function field ->
+                this#write
+                  (this#op IaCallThis ^ this#typeText obj.etype ^ " "
+                  ^ this#stringText field.cf_name
+                  ^ argN
+                  ^ this#commentOf field.cf_name
+                  ^ "\n")
+            | TField (obj, FInstance (_, _, field)) when is_super obj ->
+                this#write
+                  (this#op IaCallSuper ^ this#typeText obj.etype ^ " "
+                  ^ this#stringText field.cf_name
+                  ^ argN
+                  ^ this#commentOf field.cf_name
+                  ^ "\n")
+            (* Cppia does not have a "GetEnumIndex" op code - must use IaCallMember ::hx::EnumBase.__Index *)
+            | TField (obj, FInstance (_, _, field))
+              when field.cf_name = "_hx_getIndex"
+                   && script_type_string obj.etype = "::hx::EnumBase" ->
+                this#write
+                  (this#op IaCallMember
+                  ^ this#typeTextString "::hx::EnumBase"
+                  ^ " " ^ this#stringText "__Index" ^ argN
+                  ^ this#commentOf "Enum index"
+                  ^ "\n");
+                this#gen_expression obj
+            | TField (obj, FInstance (_, _, field))
+              when field.cf_name = "__Index"
+                   || (not (is_dynamic_in_cppia ctx obj))
+                      && is_real_function field ->
+                this#write
+                  (this#op IaCallMember ^ this#typeText obj.etype ^ " "
+                  ^ this#stringText field.cf_name
+                  ^ argN
+                  ^ this#commentOf field.cf_name
+                  ^ "\n");
+                this#gen_expression obj
+            | TField (obj, FDynamic name)
+              when is_internal_member name
+                   || (type_string obj.etype = "::String" && name = "cca") ->
+                this#write
+                  (this#op IaCallMember ^ this#typeText obj.etype ^ " "
+                 ^ this#stringText name ^ argN ^ this#commentOf name ^ "\n");
+                this#gen_expression obj
+            | TConst TSuper ->
+                this#write
+                  (this#op IaCallSuperNew ^ this#typeText func.etype ^ " "
+                 ^ argN ^ "\n")
+            | TField (_, FEnum (enum, field)) ->
+                this#write
+                  (this#op IaCreateEnum ^ this#enumText enum ^ " "
+                  ^ this#stringText field.ef_name
+                  ^ argN
+                  ^ this#commentOf field.ef_name
+                  ^ "\n")
+            | _ ->
+                this#write (this#op IaCall ^ argN ^ "\n");
+                this#gen_expression func);
+            let matched_args =
+              match func.etype with
+              | TFun (args, _) -> (
+                  try
+                    List.iter2
+                      (fun (_, _, protoT) arg ->
+                        this#checkCast protoT arg false false)
+                      args arg_list;
+                    true
+                  with Invalid_argument _ ->
+                    (*print_endline "Bad count?";*) false)
+              | _ -> false
+            in
+            if not matched_args then List.iter this#gen_expression arg_list
+          in
+          match (remove_parens_cast func).eexpr with
+          | TField (obj, field)
+            when is_array_or_dyn_array obj.etype && field_name field = "map"
+            -> (
+              match this#get_array_type expression.etype with
+              | ArrayData t ->
+                  this#write
+                    (this#op IaToDataArray
+                    ^ this#typeTextString ("Array." ^ t)
+                    ^ "\n");
+                  this#begin_expr;
+                  this#writePos func;
+                  gen_call ();
+                  this#end_expr
+              | ArrayInterface t ->
+                  this#write
+                    (this#op IaToInterfaceArray ^ string_of_int t ^ "\n");
+                  this#begin_expr;
+                  this#writePos func;
+                  gen_call ();
+                  this#end_expr
+              | _ -> gen_call ())
+          | _ -> gen_call ())
+      | TField (obj, acc) -> (
+          let objType =
+            if is_dynamic_in_cppia ctx obj then "Dynamic"
+            else script_type_string obj.etype
+          in
+          let typeText =
+            if is_dynamic_in_cppia ctx obj then this#typeTextString "Dynamic"
+            else this#typeText obj.etype
+          in
+          match acc with
+          | FDynamic name ->
+              this#write
+                (this#op IaFName ^ typeText ^ " " ^ this#stringText name
+               ^ this#commentOf name ^ "\n");
+              this#gen_expression obj
+          | FStatic (class_def, field) ->
+              this#write
+                (this#op IaFStatic ^ this#instText class_def ^ " "
+                ^ this#stringText field.cf_name
+                ^ this#commentOf field.cf_name)
+          | FInstance (_, _, field) when is_this obj ->
+              this#write
+                (this#op IaFThisInst ^ typeText ^ " "
+                ^ this#stringText field.cf_name
+                ^ this#commentOf field.cf_name)
+          | FInstance (_, _, field) ->
+              this#write
+                (this#op IaFLink ^ typeText ^ " "
+                ^ this#stringText field.cf_name
+                ^ this#commentOf (objType ^ "." ^ field.cf_name)
+                ^ "\n");
+              this#gen_expression obj
+          | FClosure (_, field) when is_this obj ->
+              this#write
+                (this#op IaFThisName ^ typeText ^ " "
+                ^ this#stringText field.cf_name
+                ^ "\n")
+          | FAnon field when is_this obj ->
+              this#write
+                (this#op IaFThisName ^ typeText ^ " "
+                ^ this#stringText field.cf_name
+                ^ this#commentOf field.cf_name
+                ^ "\n")
+          | FClosure (_, field) | FAnon field ->
+              this#write
+                (this#op IaFName ^ typeText ^ " "
+                ^ this#stringText field.cf_name
+                ^ this#commentOf field.cf_name
+                ^ "\n");
+              this#gen_expression obj
+          | FEnum (enum, field) ->
+              this#write
+                (this#op IaFEnum ^ this#enumText enum ^ " "
+                ^ this#stringText field.ef_name
+                ^ this#commentOf field.ef_name))
+      | TArray (e1, e2) ->
+          this#write (this#op IaArrayI ^ this#typeText e1.etype ^ "\n");
+          this#gen_expression e1;
+          this#gen_expression e2
+      | TUnop (op, flag, e) ->
+          this#writeOpLine
+            (match (op, flag) with
+            | Increment, Prefix -> IaPlusPlus
+            | Increment, _ -> IaPlusPlusPost
+            | Decrement, Prefix -> IaMinusMinus
+            | Decrement, _ -> IaMinusMinusPost
+            | Not, _ -> IaLogicNot
+            | Neg, _ -> IaNeg
+            | Spread, _ -> die ~p:e.epos "Unexpected spread operator" __LOC__
+            | NegBits, _ -> IaBitNot);
+          this#gen_expression e
+      (* TODO - lval op-assign local/member/array *)
+      | TLocal var ->
+          this#write
+            (this#op IaVar ^ string_of_int var.v_id ^ this#commentOf var.v_name)
+      | TVar (tvar, optional_init) -> (
+          this#write
+            (this#op IaTVars ^ string_of_int 1
+            ^ this#commentOf (tvar.v_name ^ ":" ^ script_type_string tvar.v_type)
+            ^ "\n");
+          this#write ("\t\t" ^ indent);
+          match optional_init with
+          | None ->
+              this#writeOp IaVarDecl;
+              this#writeVar tvar
+          | Some init ->
+              this#writeOp IaVarDeclI;
+              let init = remove_parens init in
+              this#writeVar tvar;
+              this#write (" " ^ this#typeText init.etype);
+              this#write "\n";
+              this#checkCast tvar.v_type init false false)
+      | TNew (clazz, params, arg_list) -> (
+          this#write
+            (this#op IaNew
+            ^ this#typeText (TInst (clazz, params))
+            ^ string_of_int (List.length arg_list)
+            ^ "\n");
+          try
+            match
+              OverloadResolution.maybe_resolve_constructor_overload clazz params
+                arg_list
+            with
+            | Some (_, { cf_type = TFun (args, _) }, _) ->
+                List.iter2
+                  (fun (_, _, protoT) arg ->
+                    this#checkCast protoT arg false false)
+                  args arg_list
+            | _ -> raise (Invalid_argument "")
+          with Invalid_argument _ -> List.iter this#gen_expression arg_list)
+      | TReturn optval -> (
+          match optval with
+          | None -> this#writeOpLine IaReturn
+          | Some value ->
+              this#write (this#op IaRetVal ^ this#typeText value.etype ^ "\n");
+              this#checkCast return_type value false false)
+      | TObjectDecl
+          [
+            (("fileName", _, _), { eexpr = TConst (TString file) });
+            (("lineNumber", _, _), { eexpr = TConst (TInt line) });
+            (("className", _, _), { eexpr = TConst (TString class_name) });
+            (("methodName", _, _), { eexpr = TConst (TString meth) });
+          ] ->
+          this#write
+            (this#op IaPosInfo ^ this#stringText file
+           ^ Printf.sprintf "%ld" line ^ " " ^ this#stringText class_name ^ " "
+           ^ this#stringText meth)
+      | TObjectDecl values ->
+          this#write (this#op IaObjDef ^ string_of_int (List.length values));
+          this#write " ";
+          List.iter
+            (fun ((name, _, _), _) -> this#write (this#stringText name))
+            values;
+          this#write "\n";
+          List.iter (fun (_, e) -> this#gen_expression e) values
+      | TTypeExpr type_expr ->
+          let klass = "::" ^ join_class_path (t_path type_expr) "::" in
+          this#write (this#op IaClassOf ^ string_of_int (this#typeId klass))
+      | TWhile (e1, e2, flag) ->
+          this#write
+            (this#op IaWhile ^ (if flag = NormalWhile then "1" else "0") ^ "\n");
+          this#gen_expression e1;
+          this#gen_expression e2
+      | TFor (tvar, init, loop) ->
+          this#writeOp IaFor;
+          this#writeVar tvar;
+          this#write "\n";
+          this#gen_expression init;
+          this#gen_expression loop
+      | TEnumParameter (expr, ef, i) ->
+          let enum =
+            match follow ef.ef_type with
+            | TEnum (en, _) | TFun (_, TEnum (en, _)) -> en
+            | _ -> die "" __LOC__
+          in
+          this#write
+            (this#op IaEnumI
+            ^ this#typeText (TEnum (enum, []))
+            ^ string_of_int i ^ "\n");
+          this#gen_expression expr
+      | TEnumIndex expr ->
+          this#write
+            (this#op IaCallMember
+            ^ this#typeTextString "::hx::EnumBase"
+            ^ " " ^ this#stringText "__Index" ^ "0"
+            ^ this#commentOf "Enum index"
+            ^ "\n");
+          this#gen_expression expr
+      | TSwitch
+          {
+            switch_subject = condition;
+            switch_cases = cases;
+            switch_default = optional_default;
+          } -> (
+          this#write
+            (this#op IaSwitch
+            ^ string_of_int (List.length cases)
+            ^ " "
+            ^ (match optional_default with None -> "0" | Some _ -> "1")
+            ^ "\n");
+          this#gen_expression condition;
+          List.iter
+            (fun { case_patterns = cases_list; case_expr = expression } ->
+              this#writeList ("\t\t\t" ^ indent) (List.length cases_list);
+              List.iter (fun value -> this#gen_expression value) cases_list;
+              this#gen_expression expression)
+            cases;
+          match optional_default with
+          | None -> ()
+          | Some expr -> this#gen_expression expr)
+      | TTry (e, catches) ->
+          this#writeList (this#op IaTry) (List.length catches);
+          this#gen_expression e;
+          List.iter
+            (fun (tvar, catch_expr) ->
+              this#write ("\t\t\t" ^ indent);
+              this#writeVar tvar;
+              this#write "\n";
+              this#gen_expression catch_expr)
+            catches
+      | TCast (cast, Some (TClassDecl t)) ->
+          this#write (this#op IaTCast ^ this#typeText (TInst (t, [])) ^ "\n");
+          this#gen_expression cast
+      | TCast (cast, _) -> this#checkCast expression.etype cast true true
+      | TParenthesis _ -> abort "Unexpected parens" expression.epos
+      | TMeta (_, _) -> abort "Unexpected meta" expression.epos
+      | TIdent _ -> abort "Unexpected ident" expression.epos
+
+    (* } *)
+    method gen_expression_tree expression_tree =
+      (* { *)
+      let rec gen_expression expression =
+        this#begin_expr;
+        this#writeCppPos expression;
+        let rec match_expr expression =
+          match expression.cppexpr with
+          | CppBlock (exprs, closures, _) ->
+              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)
+                ^ "\n");
+              this#write ("\t\t" ^ indent);
+              match init with
+              | None ->
+                  this#writeOp IaVarDecl;
+                  this#writeVar var
+              | Some init ->
+                  this#writeOp IaVarDeclI;
+                  this#writeVar var;
+                  this#write (" " ^ this#astType init.cpptype);
+                  this#write "\n";
+                  gen_expression init)
+          | CppInt i -> this#write (this#op IaConstInt ^ Printf.sprintf "%ld " i)
+          | CppFloat float_as_string ->
+              this#write (this#op IaConstFloat ^ this#stringText float_as_string)
+          | CppString s -> this#write (this#op IaConstString ^ this#stringText s)
+          | CppBool false -> this#writeOp IaConstFalse
+          | CppBool true -> this#writeOp IaConstTrue
+          | CppNull -> this#writeOp IaConstNull
+          | CppNil -> abort "Nil not supported in cppia" expression.cpppos
+          | CppThis _ -> this#writeOp IaConsThis
+          | CppSuper _ -> this#writeOp IaConstSuper
+          | CppBreak -> this#writeOp IaBreak
+          | CppContinue -> this#writeOp IaContinue
+          | CppGoto label ->
+              abort "Goto not supported in cppia" expression.cpppos
+          | CppReturn None -> this#writeOpLine IaReturn
+          | CppReturn (Some value) ->
+              this#write (this#op IaRetVal ^ this#astType value.cpptype ^ "\n");
+              gen_expression value
+          | CppWhile (condition, block, while_flag, _) ->
+              this#write
+                (this#op IaWhile
+                ^ (if while_flag = NormalWhile then "1" else "0")
+                ^ "\n");
+              gen_expression condition;
+              gen_expression block
+          | CppIf (condition, block, None) ->
+              this#writeOpLine IaIf;
+              gen_expression condition;
+              gen_expression block
+          | CppIf (condition, block, Some elze) ->
+              this#writeOpLine IaIfElse;
+              gen_expression condition;
+              gen_expression block;
+              gen_expression elze
+          | CppBinop (op, left, right) ->
+              this#writeOpLine (IaBinOp op);
+              gen_expression left;
+              gen_expression right
+          | CppVar var -> gen_var_loc var
+          | CppExtern (name, _) ->
+              abort
+                ("Unexpected global '" ^ name ^ "' in cppia")
+                expression.cpppos
+          | CppSet (lvalue, rvalue) ->
+              this#writeOpLine IaSet;
+              gen_lvalue lvalue expression.cpppos;
+              gen_expression rvalue
+          | CppCall (func, args) ->
+              let argN = string_of_int (List.length args) ^ " " in
+              (match func with
+              | FuncThis (field, inst) ->
+                  let name = field.cf_name in
+                  this#write
+                    (this#op IaCallThis ^ this#astType inst ^ " "
+                   ^ this#stringText name ^ argN ^ this#commentOf name ^ "\n")
+              | FuncInstance (expr, _, field) | FuncInterface (expr, _, field)
+                ->
+                  this#write
+                    (this#op IaCallMember ^ this#astType expr.cpptype ^ " "
+                    ^ this#stringText field.cf_name
+                    ^ argN
+                    ^ this#commentOf field.cf_name
+                    ^ "\n");
+                  gen_expression expr
+              | FuncStatic (class_def, _, field) ->
+                  this#write
+                    (this#op IaCallStatic ^ this#cppInstText class_def ^ " "
+                    ^ this#stringText field.cf_name
+                    ^ argN
+                    ^ this#commentOf
+                        (join_class_path class_def.cl_path "."
+                        ^ "." ^ field.cf_name)
+                    ^ "\n")
+              | FuncTemplate _ ->
+                  abort "Templated function call not supported in cppia"
+                    expression.cpppos
+              | FuncFromStaticFunction ->
+                  abort "Unexpected FuncFromStaticFunction" expression.cpppos
+              | FuncEnumConstruct (enum, field) ->
+                  this#write
+                    (this#op IaCreateEnum ^ this#enumText enum ^ " "
+                    ^ this#stringText field.ef_name
+                    ^ argN
+                    ^ this#commentOf field.ef_name
+                    ^ "\n")
+              | FuncSuperConstruct (TCppInst (klass, _))
+                when is_native_gen_class klass && is_native_class klass ->
+                  abort "Unsupported super for native class constructor"
+                    expression.cpppos
+              | FuncSuperConstruct childType ->
+                  this#write
+                    (this#op IaCallSuperNew ^ this#astType childType ^ " "
+                   ^ argN ^ "\n")
+              | FuncSuper (_, TCppInst (klass, _), _)
+                when is_native_gen_class klass && is_native_class klass ->
+                  abort "Unsupported super for native class method"
+                    expression.cpppos
+              | FuncSuper (_, objType, field) ->
+                  this#write
+                    (this#op IaCallSuper ^ this#astType objType ^ " "
+                    ^ this#stringText field.cf_name
+                    ^ argN
+                    ^ this#commentOf field.cf_name
+                    ^ "\n")
+              | FuncExtern (name, _) ->
+                  this#write
+                    (this#op IaCallGlobal ^ this#stringText name ^ argN
+                   ^ this#commentOf name ^ "\n")
+              | FuncNew newType ->
+                  this#write (this#op IaNew ^ this#astType newType ^ argN ^ "\n")
+              | FuncInternal (obj, "cca", ".") when obj.cpptype = TCppString ->
+                  this#write
+                    (this#op IaCallMember ^ this#astType obj.cpptype ^ " "
+                   ^ this#stringText "cca" ^ argN ^ this#commentOf "cca" ^ "\n"
+                    );
+                  gen_expression obj
+              | FuncInternal (obj, name, join) ->
+                  (* abort ("Internal function call '" ^ name ^ "' not supported in cppia") expression.cpppos; *)
+                  this#write
+                    (this#op IaCallMember ^ this#astType obj.cpptype ^ " "
+                   ^ this#stringText name ^ argN ^ this#commentOf name ^ "\n");
+                  gen_expression obj
+              | FuncExpression expr ->
+                  this#write (this#op IaCall ^ argN ^ "\n");
+                  gen_expression expr);
+              List.iter gen_expression args
+          | CppFunction (func, _) -> (
+              match func with
+              | FuncThis (field, inst) ->
+                  this#write
+                    (this#op IaFThisName ^ this#astType inst ^ " "
+                    ^ this#stringText field.cf_name
+                    ^ this#commentOf
+                        (script_cpptype_string inst ^ "." ^ field.cf_name))
+              | FuncInternal (expr, name, _) ->
+                  this#write
+                    (this#op IaFLink ^ this#astType expr.cpptype ^ " "
+                   ^ this#stringText name
+                    ^ this#commentOf
+                        ("Internal "
+                        ^ script_cpptype_string expr.cpptype
+                        ^ "." ^ name)
+                    ^ "\n");
+                  gen_expression expr
+              | FuncInstance (expr, _, field) | FuncInterface (expr, _, field)
+                ->
+                  this#write
+                    (this#op IaFName ^ this#astType expr.cpptype ^ " "
+                    ^ this#stringText field.cf_name
+                    ^ this#commentOf
+                        (script_cpptype_string expr.cpptype
+                        ^ "." ^ field.cf_name)
+                    ^ "\n");
+                  gen_expression expr
+              | FuncStatic (class_def, _, field) ->
+                  this#write
+                    (this#op IaFStatic ^ this#cppInstText class_def ^ " "
+                    ^ this#stringText field.cf_name
+                    ^ this#commentOf field.cf_name)
+              | FuncExpression expr -> match_expr expr
+              | FuncExtern (name, _) ->
+                  abort
+                    ("Can't create extern " ^ name ^ " closure")
+                    expression.cpppos
+              | FuncSuper _ | FuncSuperConstruct _ ->
+                  abort "Can't create super closure" expression.cpppos
+              | FuncNew _ -> abort "Can't create new closure" expression.cpppos
+              | FuncEnumConstruct _ ->
+                  abort "Enum constructor outside of CppCall" expression.cpppos
+              | FuncFromStaticFunction ->
+                  abort "Can't create cpp.Function.fromStaticFunction closure"
+                    expression.cpppos
+              | FuncTemplate _ ->
+                  abort "Can't create template function closure"
+                    expression.cpppos)
+          | CppPosition (file, line, class_name, meth) ->
+              this#write
+                (this#op IaPosInfo ^ this#stringText file
+               ^ Printf.sprintf "%ld" line ^ " " ^ this#stringText class_name
+               ^ " " ^ this#stringText meth)
+          | CppNullCompare ("IsNull", e) ->
+              this#writeOpLine IaIsNull;
+              gen_expression e
+          | CppNullCompare (_, e) ->
+              this#writeOpLine IaNotNull;
+              gen_expression e
+          | CppCompare (_, left, right, op) ->
+              this#writeOpLine (IaBinOp op);
+              gen_expression left;
+              gen_expression right
+          | CppArray arrayLoc -> gen_array arrayLoc expression.cpppos
+          | CppArrayDecl exprList ->
+              this#write
+                (this#op IaADef
+                ^ this#astType expression.cpptype
+                ^ " "
+                ^ string_of_int (List.length exprList)
+                ^ "\n");
+              List.iter gen_expression exprList
+          | CppEnumField (enum, field) ->
+              this#write
+                (this#op IaFEnum ^ this#enumText enum ^ " "
+                ^ this#stringText field.ef_name
+                ^ this#commentOf field.ef_name)
+          | CppEnumIndex obj ->
+              (* Cppia does not have a "GetEnumIndex" op code - must use IaCallMember ::hx::EnumBase.__Index *)
+              this#write
+                (this#op IaCallMember
+                ^ this#typeTextString "::hx::EnumBase"
+                ^ " " ^ this#stringText "__Index" ^ "0"
+                ^ this#commentOf "Enum index"
+                ^ "\n");
+              gen_expression obj
+          | CppDynamicField (obj, name) ->
+              this#write
+                (this#op IaFName
+                ^ this#typeTextString "Dynamic"
+                ^ " " ^ this#stringText name ^ this#commentOf name ^ "\n");
+              gen_expression obj
+          | CppClassOf (path, native) ->
+              let klass = join_class_path path "." in
+              this#write
+                (this#op IaClassOf ^ this#typeTextString klass
+               ^ this#commentOf klass)
+          | CppEnumParameter (obj, field, index) ->
+              this#write
+                (this#op IaEnumI
+                ^ this#typeTextString "Dynamic"
+                ^ string_of_int index ^ "\n");
+              gen_expression obj
+          | CppClosure closure ->
+              this#write
+                (this#op IaFun
+                ^ this#astType closure.close_type
+                ^ string_of_int (List.length closure.close_args)
+                ^ "\n");
+              let close = this#gen_func_args closure.close_args in
+              gen_expression closure.close_expr;
+              close ()
+          | CppObjectDecl (values, isStruct) ->
+              this#write (this#op IaObjDef ^ string_of_int (List.length values));
+              this#write " ";
+              List.iter
+                (fun (name, _) -> this#write (this#stringText name))
+                values;
+              this#write "\n";
+              List.iter (fun (_, e) -> gen_expression e) values
+          | CppCrement (incFlag, preFlag, lvalue) ->
+              let op =
+                match (incFlag, preFlag) with
+                | CppIncrement, Prefix -> IaPlusPlus
+                | CppIncrement, Postfix -> IaPlusPlusPost
+                | CppDecrement, Prefix -> IaMinusMinus
+                | CppDecrement, Postfix -> IaMinusMinusPost
+              in
+              this#writeOpLine op;
+              gen_lvalue lvalue expression.cpppos
+          | CppModify (op, lvalue, rvalue) ->
+              this#writeOpLine (IaBinOp (OpAssignOp op));
+              gen_lvalue lvalue expression.cpppos;
+              gen_expression rvalue
+          | CppUnop (op, expr) ->
+              let op =
+                match op with
+                | CppNot -> IaLogicNot
+                | CppNeg -> IaNeg
+                | CppNegBits -> IaBitNot
+              in
+              this#writeOpLine op;
+              gen_expression expr
+          | CppThrow value ->
+              this#writeOpLine IaThrow;
+              gen_expression value
+          | CppTry (block, catches) ->
+              this#writeList (this#op IaTry) (List.length catches);
+              gen_expression block;
+              List.iter
+                (fun (tvar, catch_expr) ->
+                  this#write ("\t\t\t" ^ indent);
+                  this#writeVar tvar;
+                  this#write "\n";
+                  gen_expression catch_expr)
+                catches
+          | CppIntSwitch _ ->
+              abort "CppIntSwitch not supported in cppia" expression.cpppos
+          | CppSwitch (condition, _, cases, optional_default, _) -> (
+              this#write
+                (this#op IaSwitch
+                ^ string_of_int (List.length cases)
+                ^ " "
+                ^ (match optional_default with None -> "0" | Some _ -> "1")
+                ^ "\n");
+              gen_expression condition;
+              List.iter
+                (fun (cases_list, expression) ->
+                  this#writeList ("\t\t\t" ^ indent) (List.length cases_list);
+                  List.iter (fun value -> gen_expression value) cases_list;
+                  gen_expression expression)
+                cases;
+              match optional_default with
+              | None -> ()
+              | Some expr -> gen_expression expr)
+          | CppTCast (expr, toType) ->
+              this#write (this#op IaTCast ^ this#astType toType ^ "\n");
+              gen_expression expr
+          | CppCast (expr, toType) -> (
+              match toType with
+              | TCppDynamicArray ->
+                  this#write (this#op IaToDynArray ^ "\n");
+                  gen_expression expr
+              | TCppObjectArray _ ->
+                  this#write
+                    (this#op IaToDataArray
+                    ^ this#typeTextString "Array.Object"
+                    ^ "\n");
+                  gen_expression expr
+              | TCppScalarArray t ->
+                  this#write
+                    (this#op IaToDataArray
+                    ^ this#typeTextString ("Array." ^ script_cpptype_string t)
+                    ^ "\n");
+                  gen_expression expr
+              | _ -> match_expr expr)
+          | CppCastScalar (expr, "bool") ->
+              this#writeOpLine IaCastBool;
+              gen_expression expr
+          | CppCastScalar (expr, "int") ->
+              this#writeOpLine IaCastInt;
+              gen_expression expr
+          | CppCastScalar (expr, "Float") ->
+              this#write
+                (this#op IaTCast ^ this#astType (TCppScalar "Float") ^ "\n");
+              gen_expression expr
+          | CppCastScalar (expr, _) -> match_expr expr
+          | CppCastVariant expr -> match_expr expr
+          | CppCastStatic (expr, _) -> match_expr expr
+          | CppNullAccess ->
+              this#writeOpLine IaThrow;
+              this#begin_expr;
+              this#writeCppPos expression;
+              this#write (this#op IaConstString ^ this#stringText "Null access");
+              this#end_expr
+          | CppCode _ | CppFunctionAddress _ | CppNewNative _ | CppDereference _
+          | CppAddressOf _ | CppFor _ | CppCastObjC _ | CppCastObjCBlock _
+          | CppCastProtocol _ | CppCastNative _ ->
+              abort
+                ("Unsupported operation in cppia :" ^ s_tcpp expression.cppexpr)
+                expression.cpppos
+          (*| x -> print_endline ("Unknown cppexpr " ^ (s_tcpp x) );*)
+        in
+
+        match_expr expression;
+        this#end_expr
+      and gen_array arrayLoc pos =
+        match arrayLoc with
+        | ArrayObject (arrayObj, index, _) | ArrayTyped (arrayObj, index, _) ->
+            this#write (this#op IaArrayI ^ this#astType arrayObj.cpptype ^ "\n");
+            gen_expression arrayObj;
+            gen_expression index
+        | ArrayPointer (_, _) | ArrayRawPointer (_, _) ->
+            abort "Unvalid array access in cppia" pos
+        | ArrayVirtual (arrayObj, index)
+        | ArrayImplements (_, arrayObj, index)
+        | ArrayDynamic (arrayObj, index) ->
+            this#write (this#op IaArrayI ^ this#astType arrayObj.cpptype ^ "\n");
+            gen_expression arrayObj;
+            gen_expression index
+      and gen_lvalue lvalue pos =
+        this#begin_expr;
+        this#wpos pos;
+        (match lvalue with
+        | CppVarRef varLoc -> gen_var_loc varLoc
+        | CppArrayRef arrayLoc -> gen_array arrayLoc pos
+        | CppExternRef (name, _) ->
+            abort ("Unsupported extern '" ^ name ^ "' in cppia") pos
+        | CppDynamicRef (expr, name) ->
+            let typeText = this#typeTextString "Dynamic" in
+            this#write
+              (this#op IaFName ^ typeText ^ " " ^ this#stringText name
+             ^ this#commentOf name ^ "\n");
+            gen_expression expr);
+        this#end_expr
+      and gen_var_loc loc =
+        match loc with
+        | VarClosure var | VarLocal var ->
+            this#write
+              (this#op IaVar ^ string_of_int var.v_id
+             ^ this#commentOf var.v_name)
+        | VarStatic (class_def, _, field) ->
+            this#write
+              (this#op IaFStatic ^ this#cppInstText class_def ^ " "
+              ^ this#stringText field.cf_name
+              ^ this#commentOf field.cf_name)
+        | VarThis (field, thisType) ->
+            this#write
+              (this#op IaFThisInst ^ this#astType thisType ^ " "
+              ^ this#stringText field.cf_name
+              ^ this#commentOf field.cf_name)
+        | VarInstance (obj, field, _, _) | VarInterface (obj, field) ->
+            let objType = script_cpptype_string obj.cpptype in
+            this#write
+              (this#op IaFLink ^ this#astType obj.cpptype ^ " "
+              ^ this#stringText field.cf_name
+              ^ this#commentOf (objType ^ "." ^ field.cf_name)
+              ^ "\n");
+            gen_expression obj
+        | VarInternal (obj, _, name) ->
+            let objType = script_cpptype_string obj.cpptype in
+            this#write
+              (this#op IaFLink ^ this#astType obj.cpptype ^ " "
+             ^ this#stringText name
+              ^ this#commentOf (objType ^ "." ^ name)
+              ^ "\n");
+            gen_expression obj
+        (*
+      and get_array_type elem =
+         this#stringText (script_cpptype_string elem.cpptype);
+      *)
+      in
+      gen_expression expression_tree
+  end
+
+let generate_script_class common_ctx script class_def =
+  script#incClasses;
+  let classText = join_class_path class_def.cl_path "." in
+  script#comment ("Class " ^ classText);
+  script#writeOp
+    (if has_class_flag class_def CInterface then IaInterface else IaClass);
+  script#instName class_def;
+  (match class_def.cl_super with
+  | None -> script#ident ""
+  | Some (c, _) -> script#instName c);
+  script#wint (List.length class_def.cl_implements);
+  List.iter (fun (c, _) -> script#instName c) class_def.cl_implements;
+  script#write "\n";
+  (* Looks like some map impl classes have their bodies discarded - not sure best way to filter *)
+  let non_dodgy_function allow_empty field =
+    has_class_flag class_def CInterface
+    ||
+    match (field.cf_kind, field.cf_expr) with
+    | Var _, _ -> true
+    | Method MethDynamic, _ -> true
+    | Method MethNormal, None when allow_empty -> true
+    | Method _, Some _ -> true
+    | _ -> false
+  in
+  let ordered_statics =
+    List.filter (non_dodgy_function false) class_def.cl_ordered_statics
+  in
+  let ordered_fields =
+    List.filter (non_dodgy_function true) class_def.cl_ordered_fields
+  in
+  script#write
+    (string_of_int
+       (List.length ordered_fields
+       + List.length ordered_statics
+       + (match class_def.cl_constructor with Some _ -> 1 | _ -> 0)
+       + match TClass.get_cl_init class_def with Some _ -> 1 | _ -> 0)
+    ^ "\n");
+
+  let generate_field isStatic field =
+    match (field.cf_kind, follow field.cf_type) with
+    | Var { v_read = AccInline; v_write = AccNever }, _ ->
+        script#writeOpLine IaInline
+    | Var v, _ ->
+        let mode_code mode =
+          match mode with
+          | AccNormal | AccCtor -> IaAccessNormal
+          | AccNo -> IaAccessNot
+          | AccNever -> IaAccessNot
+          | AccCall ->
+              if
+                Meta.has Meta.NativeProperty class_def.cl_meta
+                || Meta.has Meta.NativeProperty field.cf_meta
+                || Gctx.defined common_ctx Define.ForceNativeProperty
+              then IaAccessCallNative
+              else IaAccessCall
+          | AccInline -> IaAccessNormal
+          | AccRequire (_, _) -> IaAccessNormal
+        in
+        let isExtern = not (is_physical_field field) in
+        script#var (mode_code v.v_read) (mode_code v.v_write) isExtern isStatic
+          field.cf_name field.cf_type field.cf_expr
+    | Method MethDynamic, TFun (args, ret) ->
+        script#func isStatic true field.cf_name ret args
+          (has_class_flag class_def CInterface)
+          field.cf_expr field.cf_pos
+    | Method _, TFun (args, ret) when field.cf_name = "new" ->
+        script#func true false "new"
+          (TInst (class_def, []))
+          args false field.cf_expr field.cf_pos
+    | Method _, TFun (args, ret) ->
+        script#func isStatic false field.cf_name ret args
+          (has_class_flag class_def CInterface)
+          field.cf_expr field.cf_pos
+    | Method _, _ ->
+        print_endline
+          ("Unknown method type "
+          ^ join_class_path class_def.cl_path "."
+          ^ "." ^ field.cf_name)
+  in
+  (match class_def.cl_constructor with
+  | Some field -> generate_field true field
+  | _ -> ());
+  (match TClass.get_cl_init class_def with
+  | Some expression -> script#voidFunc true false "__init__" expression
+  | _ -> ());
+
+  List.iter (generate_field false) ordered_fields;
+  List.iter (generate_field true) ordered_statics;
+  script#write "\n"
+
+let generate_script_enum script enum_def meta =
+  script#incClasses;
+  let sorted_items =
+    List.sort
+      (fun f1 f2 -> f1.ef_index - f2.ef_index)
+      (pmap_values enum_def.e_constrs)
+  in
+  script#writeList
+    (script#op IaEnum ^ script#enumText enum_def)
+    (List.length sorted_items);
+
+  List.iter
+    (fun constructor ->
+      let name = script#stringText constructor.ef_name in
+      match constructor.ef_type with
+      | TFun (args, _) ->
+          script#write (name ^ " " ^ string_of_int (List.length args));
+          List.iter
+            (fun (arg, _, t) ->
+              script#write
+                (" " ^ script#stringText arg ^ " " ^ script#typeText t))
+            args;
+          script#write "\n"
+      | _ -> script#write (name ^ " 0\n"))
+    sorted_items;
+
+  match meta with
+  | Some expr ->
+      script#write "1\n";
+      script#gen_expression expr
+  | _ ->
+      script#write "0\n";
+      script#write "\n"
+
+let generate_cppia ctx =
+  let common_ctx = ctx.ctx_common in
+  let debug = ctx.ctx_debug_level in
+  Path.mkdir_from_path common_ctx.file;
+  let script = new script_writer ctx common_ctx.file common_ctx.debug in
+  ignore (script#stringId "");
+  ignore (script#typeId "");
+
+  List.iter
+    (fun object_def ->
+      match object_def with
+      | TClassDecl class_def when has_class_flag class_def CExtern ->
+          () (*if (gen_externs) then gen_extern_class common_ctx class_def;*)
+      | TClassDecl class_def ->
+          let is_internal = is_internal_class class_def.cl_path in
+          if is_internal || Meta.has Meta.Macro class_def.cl_meta then (
+            if debug >= 4 then
+              print_endline
+                (" internal class " ^ join_class_path class_def.cl_path "."))
+          else generate_script_class common_ctx script class_def
+      | TEnumDecl enum_def when has_enum_flag enum_def EnExtern -> ()
+      | TEnumDecl enum_def ->
+          let is_internal = is_internal_class enum_def.e_path in
+          if is_internal then (
+            if debug >= 4 then
+              print_endline
+                (" internal enum " ^ join_class_path enum_def.e_path "."))
+          else
+            let meta = Texpr.build_metadata common_ctx.basic object_def in
+            if has_enum_flag enum_def EnExtern then
+              if debug >= 4 then
+                print_endline
+                  ("external enum " ^ join_class_path enum_def.e_path ".");
+            generate_script_enum script enum_def meta
+      | TTypeDecl _ | TAbstractDecl _ -> (* already done *) ())
+    common_ctx.types;
+
+  (match common_ctx.main.main_expr with
+  | None -> script#writeOpLine IaNoMain
+  | Some e ->
+      script#writeOpLine IaMain;
+      script#gen_expression e);
+
+  script#write
+    (script#op IaResources
+    ^ string_of_int (Hashtbl.length common_ctx.resources)
+    ^ "\n");
+  Hashtbl.iter
+    (fun name data ->
+      script#write
+        (script#op IaReso ^ script#stringText name
+        ^ string_of_int (String.length data)
+        ^ "\n"))
+    common_ctx.resources;
+  Hashtbl.iter (fun _ data -> script#writeData data) common_ctx.resources;
+
+  script#close

+ 2047 - 0
src/generators/cpp/gen/cppGen.ml

@@ -0,0 +1,2047 @@
+open Ast
+open Gctx
+open Type
+open Error
+open Globals
+open CppStrings
+open CppTypeUtils
+open CppAst
+open CppAstTools
+open CppSourceWriter
+open CppContext
+
+type tinject = {
+  inj_prologue : bool -> unit;
+  inj_setvar : string;
+  inj_tail : string;
+}
+
+let cpp_type_of = CppRetyper.cpp_type_of
+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_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 ->
+      ("::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
+  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_list arg_list prefix =
+  String.concat ","
+    (List.map (fun (v, o) -> print_arg v.v_name o v.v_type 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)
+       arg_list)
+
+let print_arg_names args =
+  String.concat "," (List.map (fun (name, _, _) -> keyword_remap name) args)
+
+let rec print_tfun_arg_list include_names arg_list =
+  let oType o arg_type =
+    let type_str = type_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 ^ " > "
+    else type_str
+  in
+  match arg_list with
+  | [] -> ""
+  | [ (name, o, arg_type) ] ->
+      oType o arg_type ^ if include_names then " " ^ keyword_remap name else ""
+  | (name, o, arg_type) :: remaining ->
+      oType o arg_type
+      ^ (if include_names then " " ^ keyword_remap name else "")
+      ^ ","
+      ^ print_tfun_arg_list include_names remaining
+
+let has_new_gc_references class_def =
+  let is_gc_reference field =
+    should_implement_field field
+    && is_data_member field
+    && not (type_cant_be_null field.cf_type)
+  in
+  List.exists is_gc_reference class_def.cl_ordered_fields
+
+let rec has_gc_references class_def =
+  (match class_def.cl_super with
+  | Some def when has_gc_references (fst def) -> true
+  | _ -> false)
+  || has_new_gc_references class_def
+
+let rec find_next_super_iteration class_def =
+  match class_def.cl_super with
+  | Some (klass, params) when has_new_gc_references klass ->
+      tcpp_to_string_suffix "_obj" (cpp_instance_type klass params)
+  | Some (klass, _) -> find_next_super_iteration klass
+  | _ -> ""
+
+let cpp_member_name_of member =
+  match get_meta_string member.cf_meta Meta.Native with
+  | Some n -> n
+  | None -> keyword_remap member.cf_name
+
+let function_signature include_names tfun abi =
+  match follow tfun with
+  | TFun (args, ret) ->
+      type_to_string ret ^ " " ^ abi ^ "("
+      ^ print_tfun_arg_list include_names args
+      ^ ")"
+  | _ -> "void *"
+
+let cpp_no_debug_synbol ctx var =
+  ctx.ctx_debug_level <= 1
+  || (match var.v_kind with VUser _ -> false | _ -> true)
+  ||
+  match cpp_type_of var.v_type with
+  | TCppStar _ | TCppReference _ -> 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
+      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 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
+  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 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
+
+let can_quick_alloc klass =
+  (not (is_native_class klass)) && not (implements_native_interface klass)
+
+let only_stack_access haxe_type =
+  match cpp_type_of haxe_type with
+  | TCppInst (klass, _) -> Meta.has Meta.StackOnly klass.cl_meta
+  | _ -> false
+
+let cpp_is_static_extension member =
+  Meta.has Meta.NativeStaticExtension member.cf_meta
+
+let cpp_enum_name_of field =
+  match get_meta_string field.ef_meta Meta.Native with
+  | Some n -> n
+  | None -> keyword_remap field.ef_name
+
+let string_of_path path = "::" ^ join_class_path_remap path "::" ^ "_obj"
+
+let default_value_string ctx value =
+  match value.eexpr with
+  | TConst (TInt i) -> Printf.sprintf "%ld" i
+  | TConst (TFloat float_as_string) ->
+      "((Float)" ^ Texpr.replace_separators float_as_string "" ^ ")"
+  | TConst (TString s) -> strq ctx s
+  | TConst (TBool b) -> if b then "true" else "false"
+  | TConst TNull -> "null()"
+  | TField (_, FEnum (enum, field)) ->
+      string_of_path enum.e_path ^ "::" ^ cpp_enum_name_of field ^ "_dyn()"
+  | _ -> "/* Hmmm " ^ s_expr_kind value ^ " */"
+
+let cpp_gen_default_values ctx args prefix =
+  List.iter
+    (fun (tvar, o) ->
+      let vtype = cpp_type_of tvar.v_type in
+      let not_null =
+        type_has_meta_key Meta.NotNull tvar.v_type || is_cpp_scalar vtype
+      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
+          ctx.ctx_output
+            (spacer ^ "\t" ^ tcpp_to_string vtype ^ " " ^ 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
+               ^ " = "
+               ^ 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 "::")
+
+let cpp_template_param path native =
+  let path = "::" ^ join_class_path_remap path "::" in
+  if native then path
+  else
+    match path with
+    | "::Array" -> "::hx::ArrayBase"
+    | "::Int" -> "int"
+    | "::Bool" -> "bool"
+    | x -> x
+
+let rec is_constant_zero expr =
+  match expr.cppexpr with
+  | CppFloat x when float_of_string x = 0.0 -> true
+  | CppInt i when i = Int32.zero -> true
+  | CppCastScalar (expr, _) -> is_constant_zero expr
+  | _ -> false
+
+let cpp_is_const_scalar_array arrayType expressions =
+  List.length expressions > 0
+  &&
+  match arrayType with
+  | TCppScalarArray _ ->
+      List.for_all
+        (fun expr ->
+          match expr.cppexpr with
+          | CppInt _ | CppFloat _ | CppString _ | CppBool _ -> true
+          | _ -> false)
+        expressions
+  | _ -> false
+
+let list_num l = string_of_int (List.length l)
+
+(* This gets the class include order correct.  In the header files, we forward declare
+   the class types so the header file does not have any undefined variables.
+   In the cpp files, we include all the required header files, providing the actual
+   types for everything.  This way there is no problem with circular class references.
+*)
+let gen_forward_decl writer class_path isNative =
+  let output = writer#write in
+  match class_path with
+  | [ "@verbatim" ], file -> writer#write (guarded_include file)
+  | _ ->
+      let name = fst (remap_class_path class_path) in
+      output
+        ((if isNative then "HX_DECLARE_NATIVE" else "HX_DECLARE_CLASS")
+        ^ list_num name ^ "(");
+      List.iter (fun package_part -> output (package_part ^ ",")) name;
+      output (snd class_path ^ ")\n")
+
+let format_code code = String.concat "\n" (ExtString.String.nsplit code "\r\n")
+
+let get_meta_string_full_filename meta key =
+  let rec loop = function
+    | [] -> ""
+    | (k, _, pos) :: _ when k = key ->
+        if Filename.is_relative pos.pfile then
+          Path.normalize_path (Filename.concat (Sys.getcwd ()) pos.pfile)
+        else pos.pfile
+    | _ :: l -> loop l
+  in
+  loop meta
+
+let get_meta_string_full_dirname meta key =
+  let name = get_meta_string_full_filename meta key in
+  try Path.normalize_path (Filename.dirname name)
+  with Invalid_argument _ -> ""
+
+let get_code meta key =
+  let code = get_meta_string meta key |> Option.default "" in
+  let magic_var = "${GENCPP_SOURCE_DIRECTORY}" in
+  let code =
+    if ExtString.String.exists code magic_var then
+      let source_directory = get_meta_string_full_dirname meta key in
+      let _, code = ExtString.String.replace code magic_var source_directory in
+      code
+    else code
+  in
+  if code <> "" then format_code code ^ "\n" else code
+
+let get_class_code class_def key =
+  match class_def.cl_kind with
+  | KAbstractImpl abstract_def ->
+      let value = get_code abstract_def.a_meta key in
+      value
+  | _ -> get_code class_def.cl_meta key
+
+let with_debug ctx metadata run =
+  let old_debug = ctx.ctx_debug_level in
+  let no_debug = Meta.has Meta.NoDebug metadata in
+  if no_debug then ctx.ctx_debug_level <- 0;
+  run no_debug;
+  ctx.ctx_debug_level <- old_debug
+
+let hx_stack_push ctx output clazz func_name pos gc_stack =
+  if ctx.ctx_debug_level > 0 then (
+    let stripped_file = strip_file ctx.ctx_common pos.pfile in
+    let esc_file = StringHelper.s_escape stripped_file in
+    ctx.ctx_file_info := PMap.add stripped_file pos.pfile !(ctx.ctx_file_info);
+    let full_name =
+      clazz ^ "." ^ func_name
+      ^
+      if clazz = "*" then
+        " (" ^ esc_file ^ ":" ^ string_of_int (Lexer.get_error_line pos) ^ ")"
+      else ""
+    in
+
+    let hash_class_func = gen_hash 0 (clazz ^ "." ^ func_name) in
+    let hash_file = gen_hash 0 stripped_file in
+
+    let lineName = string_of_int (Lexer.get_error_line pos) in
+    incr ctx.ctx_file_id;
+    let classId = hash64 (clazz ^ "." ^ stripped_file) in
+    let varName = "_hx_pos_" ^ classId ^ "_" ^ lineName ^ "_" ^ func_name in
+    let decl =
+      varName ^ ",\"" ^ clazz ^ "\",\"" ^ func_name ^ "\"," ^ hash_class_func
+      ^ ",\"" ^ full_name ^ "\",\"" ^ esc_file ^ "\"," ^ lineName ^ ","
+      ^ hash_file
+    in
+    if ctx.ctx_is_header then
+      ctx.ctx_writer#write_h_unique
+        ("HX_DECLARE_STACK_FRAME" ^ "(" ^ varName ^ ")\n")
+    else
+      ctx.ctx_writer#write_h_unique
+        ((if func_name = "new" then "HX_DEFINE_STACK_FRAME"
+          else "HX_LOCAL_STACK_FRAME")
+        ^ "(" ^ decl ^ ")\n");
+    output
+      ((if gc_stack then "HX_GC_STACKFRAME" else "HX_STACKFRAME")
+      ^ "(&" ^ varName ^ ")\n"))
+  else if gc_stack then output "HX_JUST_GC_STACKFRAME\n"
+
+(* Add include to source code *)
+let add_include writer class_path = writer#add_include class_path
+
+let real_interfaces =
+  List.filter (function t, pl ->
+      (match (t, pl) with
+      | { cl_path = [ "cpp"; "rtti" ], _ }, [] -> false
+      | _ -> true))
+
+let native_field_name_remap is_static field =
+  let remap_name = keyword_remap field.cf_name in
+  if not is_static then remap_name
+  else
+    match get_meta_string field.cf_meta Meta.Native with
+    | Some nativeImpl ->
+        let r = Str.regexp "^[a-zA-Z_0-9]+$" in
+        if Str.string_match r remap_name 0 then "_hx_" ^ remap_name
+        else "_hx_f" ^ gen_hash 0 remap_name
+    | None -> remap_name
+
+let rec is_dynamic_accessor name acc field class_def =
+  acc ^ "_" ^ field.cf_name = name
+  && (not (List.exists (fun f -> f.cf_name = name) class_def.cl_ordered_fields))
+  &&
+  match class_def.cl_super with
+  | None -> true
+  | Some (parent, _) -> is_dynamic_accessor name acc field parent
+
+(* Builds inheritance tree, so header files can include parents defs.  *)
+let create_super_dependencies common_ctx =
+  let result = Hashtbl.create 0 in
+  let real_non_native_interfaces =
+    List.filter (function t, pl ->
+        (match (t, pl) with
+        | { cl_path = [ "cpp"; "rtti" ], _ }, [] -> false
+        | _ -> not (is_native_gen_class t)))
+  in
+  let iterator object_def =
+    match object_def with
+    | TClassDecl class_def when not (has_class_flag class_def CExtern) ->
+        let deps = ref [] in
+        (match class_def.cl_super with
+        | Some super ->
+            if not (has_class_flag (fst super) CExtern) then
+              deps := (fst super).cl_path :: !deps
+        | _ -> ());
+        List.iter
+          (fun imp ->
+            if not (has_class_flag (fst imp) CExtern) then
+              deps := (fst imp).cl_path :: !deps)
+          (real_non_native_interfaces class_def.cl_implements);
+        Hashtbl.add result class_def.cl_path !deps
+    | TEnumDecl enum_def when not (has_enum_flag enum_def EnExtern) ->
+        Hashtbl.add result enum_def.e_path []
+    | _ -> ()
+  in
+  List.iter iterator common_ctx.types;
+  result
+
+let can_inline_constructor baseCtx class_def super_deps constructor_deps =
+  match class_def.cl_constructor with
+  | Some { cf_expr = Some super_func } ->
+      let is_simple = ref true in
+      let rec check_simple e =
+        (match e.eexpr with
+        | TReturn _ -> is_simple := false
+        | TArrayDecl e when List.length e > 0 -> is_simple := false
+        | _ -> ());
+        if !is_simple then Type.iter check_simple e
+      in
+      check_simple super_func;
+      !is_simple
+      &&
+      let rec known_classes class_def so_far =
+        match class_def.cl_super with
+        | Some super -> known_classes (fst super) ((fst super).cl_path :: so_far)
+        | _ -> so_far
+      in
+      let allowed = known_classes class_def [ class_def.cl_path ] in
+      (* Check to see if all the types required by the constructor are already in the header *)
+      (* This is quite restrictive, since most classes are forward-declared *)
+      let deps, _ =
+        CppReferences.find_referenced_types_flags baseCtx (TClassDecl class_def)
+          "new" super_deps constructor_deps false false true
+      in
+      List.for_all (fun dep -> List.mem dep allowed) deps
+  | _ -> true
+
+let create_constructor_dependencies common_ctx =
+  let result = Hashtbl.create 0 in
+  List.iter
+    (fun object_def ->
+      match object_def with
+      | TClassDecl class_def when not (has_class_flag class_def CExtern) -> (
+          match class_def.cl_constructor with
+          | Some func_def -> Hashtbl.add result class_def.cl_path func_def
+          | _ -> ())
+      | _ -> ())
+    common_ctx.types;
+  result
+
+let begin_namespace output class_path =
+  List.iter
+    (fun namespace -> output ("namespace " ^ namespace ^ "{\n"))
+    (List.map keyword_remap (fst class_path))
+
+let end_namespace output class_path =
+  List.iter
+    (fun namespace -> output ("}" ^ " // end namespace " ^ namespace ^ "\n"))
+    (fst class_path)
+
+let begin_header_file output_h def_string nativeGen =
+  output_h ("#ifndef INCLUDED_" ^ def_string ^ "\n");
+  output_h ("#define INCLUDED_" ^ def_string ^ "\n\n");
+  output_h "#ifndef HXCPP_H\n";
+  if nativeGen then (
+    output_h "#ifdef HXCPP_API_LEVEL\n";
+    output_h "#include <hxcpp.h>\n";
+    output_h "#else\n";
+    output_h "#include <hx/Native.h>\n";
+    output_h "#endif\n")
+  else output_h "#include <hxcpp.h>\n";
+  output_h "#endif\n\n"
+
+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
+  "( " ^ returnType ^ " (::hx::Object::*)(" ^ argList ^ "))"
+
+exception FieldFound of tclass_field
+
+let find_class_implementation class_def name interface =
+  let rec find def =
+    List.iter
+      (fun f -> if f.cf_name = name then raise (FieldFound f))
+      def.cl_ordered_fields;
+    match def.cl_super with Some (def, _) -> find def | _ -> ()
+  in
+  try
+    find class_def;
+    abort
+      ("Could not find implementation of " ^ name ^ " in "
+      ^ join_class_path class_def.cl_path "."
+      ^ " required by "
+      ^ join_class_path interface.cl_path ".")
+      class_def.cl_pos
+  with FieldFound field -> (
+    match (follow field.cf_type, field.cf_kind) with
+    | _, Method MethDynamic -> ""
+    | TFun (args, return_type), Method _ ->
+        cpp_tfun_signature false args return_type
+    | _, _ -> "")
+
+let gen_gc_name class_path =
+  let class_name_text = join_class_path class_path "." in
+  const_char_star class_name_text
+
+(* All interfaces (and sub-interfaces) implemented *)
+let implementations class_def =
+  let implemented_hash = Hashtbl.create 0 in
+  let native_implemented = Hashtbl.create 0 in
+
+  let cpp_interface_impl_name interface =
+    "_hx_" ^ join_class_path interface.cl_path "_"
+  in
+  let iterator impl =
+    let rec descend_interface interface =
+      let intf_def = fst interface in
+      let interface_name = cpp_interface_impl_name intf_def in
+      let hash =
+        if is_native_gen_class intf_def then native_implemented
+        else implemented_hash
+      in
+      if not (Hashtbl.mem hash interface_name) then (
+        Hashtbl.replace hash interface_name intf_def;
+        List.iter descend_interface intf_def.cl_implements);
+      match intf_def.cl_super with
+      | Some (interface, params) -> descend_interface (interface, params)
+      | _ -> ()
+    in
+    descend_interface impl
+  in
+
+  List.iter iterator (real_interfaces class_def.cl_implements);
+  (implemented_hash, native_implemented)
+
+let needed_interface_functions implemented_instance_fields
+    native_implementations =
+  let have =
+    List.map (fun field -> (field.cf_name, ())) implemented_instance_fields
+    |> List.to_seq |> Hashtbl.of_seq
+  in
+  let want = ref [] in
+  Hashtbl.iter
+    (fun _ intf_def ->
+      List.iter
+        (fun field ->
+          if not (Hashtbl.mem have field.cf_name) then (
+            Hashtbl.replace have field.cf_name ();
+            want := field :: !want))
+        intf_def.cl_ordered_fields)
+    native_implementations;
+  !want
+
+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
+  let tempId = ref 0 in
+  let strq = strq ctx.ctx_common in
+
+  let spacer = if ctx.ctx_debug_level > 0 then "            \t" else "" in
+  let output_i value =
+    out spacer;
+    writer#write_i value
+  in
+
+  let output_p expr value =
+    if ctx.ctx_debug_level > 0 then (
+      let line = Lexer.get_error_line expr.cpppos in
+      let lineName = Printf.sprintf "%4d" line in
+      let macro = if line != !lastLine then "HXLINE" else "HXDLIN" in
+      out (macro ^ "(" ^ lineName ^ ")\t");
+      lastLine := line);
+    writer#write_i value
+  in
+
+  let forInjection =
+    match injection with Some inject -> inject.inj_setvar <> "" | _ -> false
+  in
+
+  let cppTree =
+    CppRetyper.expression ctx TCppVoid function_args function_type tree
+      forInjection
+  in
+  let label_name i = Printf.sprintf "_hx_goto_%i" i in
+  let class_hash = gen_hash_small 0 class_name in
+
+  let rec gen_with_injection injection expr new_line =
+    (match expr.cppexpr with
+    | CppBlock (exprs, closures, gc_stack) ->
+        writer#begin_block;
+        List.iter gen_closure closures;
+        (match injection with
+        | Some inject -> inject.inj_prologue gc_stack
+        | _ -> ());
+        let remaining = ref (List.length exprs) in
+        lastLine := Lexer.get_error_line tree.epos;
+        List.iter
+          (fun e ->
+            output_p e "";
+            (if !remaining = 1 then
+               match injection with
+               | Some inject -> out inject.inj_setvar
+               | _ -> ());
+            gen e;
+            decr remaining;
+            writer#terminate_line)
+          exprs;
+        (match injection with Some inject -> out inject.inj_tail | _ -> ());
+        out spacer;
+        if new_line then writer#end_block else writer#end_block_line
+    | CppInt i ->
+        out
+          (Printf.sprintf
+             (if i > Int32.of_int (-1000000000) && i < Int32.of_int 1000000000
+              then "%ld"
+              else "(int)%ld")
+             i)
+    | CppFloat float_as_string -> out ("((Float)" ^ float_as_string ^ ")")
+    | CppString s -> out (strq s)
+    | CppBool b -> out (if b then "true" else "false")
+    | CppNull -> out "null()"
+    | CppNil -> out "nil"
+    | CppThis ThisReal -> out "::hx::ObjectPtr<OBJ_>(this)"
+    | CppThis _ -> out "__this"
+    | CppSuper thiscall ->
+        out
+          ("::hx::ObjectPtr<super>("
+          ^ (if thiscall = ThisReal then "this" else "__this.mPtr")
+          ^ ")")
+    | 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
+        | _ -> ())
+    | CppEnumIndex obj ->
+        gen obj;
+        if cpp_is_dynamic_type obj.cpptype then
+          out ".StaticCast< ::hx::EnumBase >()";
+        out "->_hx_getIndex()"
+    | CppNullAccess -> out ("::hx::Throw(" ^ strq "Null access" ^ ")")
+    | CppFunction (func, _) -> (
+        match func with
+        | FuncThis (field, _) ->
+            out ("this->" ^ cpp_member_name_of field ^ "_dyn()")
+        | FuncInstance (expr, inst, field) ->
+            gen expr;
+            out
+              ((if expr.cpptype = TCppString || inst = InstStruct then "."
+                else "->")
+              ^ cpp_member_name_of field ^ "_dyn()")
+        | FuncInterface (expr, _, field) ->
+            gen expr;
+            out ("->__Field(" ^ strq field.cf_name ^ ", ::hx::paccDynamic)")
+        | FuncStatic (clazz, _, field) -> (
+            match get_meta_string field.cf_meta Meta.Native with
+            | Some n -> out n
+            | None ->
+                out (cpp_class_name clazz);
+                out ("::" ^ cpp_member_name_of field ^ "_dyn()"))
+        | FuncExpression expr -> gen expr
+        | FuncExtern (name, isGlobal) ->
+            if isGlobal then out " ::";
+            out name
+        | FuncInternal (expr, name, _) ->
+            gen expr;
+            out ("->__Field(" ^ strq name ^ ",::hx::paccDynamic)")
+        | FuncSuper _ | FuncSuperConstruct _ ->
+            abort "Can't create super closure" expr.cpppos
+        | FuncNew _ -> abort "Can't create new closure" expr.cpppos
+        | FuncEnumConstruct _ ->
+            abort "Enum constructor outside of CppCall" expr.cpppos
+        | FuncFromStaticFunction ->
+            abort "Can't create cpp.Function.fromStaticFunction closure"
+              expr.cpppos
+        | FuncTemplate _ ->
+            abort "Can't create template function closure" expr.cpppos)
+    | CppCall (FuncInterface (expr, clazz, field), args)
+      when not (is_native_gen_class clazz) ->
+        out (cpp_class_name clazz ^ "::" ^ cpp_member_name_of field ^ "(");
+        gen expr;
+        List.iter
+          (fun arg ->
+            out ",";
+            gen arg)
+          args;
+        out ")"
+    | 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
+        | _ -> ());
+
+        let names = ExtString.String.nsplit field.cf_name ":" in
+        let field_name, arg_names =
+          match names with
+          | name :: args -> (name, args)
+          | _ -> die "" __LOC__ (* per nsplit specs, this should never happen *)
+        in
+        out (" " ^ field_name);
+        (try
+           match (arg_list, arg_names) with
+           | [], _ -> ()
+           | [ single_arg ], _ ->
+               out ": ";
+               gen single_arg
+           | first_arg :: args, arg_names ->
+               out ": ";
+               gen first_arg;
+               List.iter2
+                 (fun arg arg_name ->
+                   out (" " ^ arg_name ^ ": ");
+                   gen arg)
+                 args arg_names
+         with Invalid_argument _ ->
+           (* not all arguments names are known *)
+           abort
+             ("The function called here with name " ^ String.concat ":" names
+            ^ " does not contain the right amount of arguments' names as \
+               required" ^ " by the objective-c calling / naming convention:"
+            ^ " expected "
+             ^ string_of_int (List.length arg_list)
+             ^ " and found "
+             ^ string_of_int (List.length arg_names))
+             expr.cpppos);
+        out " ]"
+    | CppCall (FuncNew (TCppInst (klass, p)), args) when can_quick_alloc klass
+      ->
+        out (cpp_class_path_of klass p ^ "_obj::__alloc( HX_CTX ");
+        List.iter
+          (fun arg ->
+            out ",";
+            gen arg)
+          args;
+        out ")"
+    | CppCall (func, args) ->
+        let doCall = ref true in
+        let closeCall = ref "" in
+        let argsRef = ref args in
+        (match func with
+        | FuncThis (field, _) -> out ("this->" ^ cpp_member_name_of field)
+        | FuncInstance (expr, inst, field) ->
+            let operator =
+              if expr.cpptype = TCppString || inst = InstStruct then "."
+              else "->"
+            in
+            gen expr;
+            out (operator ^ cpp_member_name_of field)
+        | FuncInterface (expr, _, field) ->
+            gen expr;
+            out ("->" ^ cpp_member_name_of field)
+        | FuncStatic (clazz, false, field) when cpp_is_static_extension field
+          -> (
+            match args with
+            | fst :: remaining ->
+                argsRef := remaining;
+                gen fst;
+                out ("->" ^ cpp_member_name_of field)
+            | _ ->
+                abort "Native static extensions must have at least 1 argument"
+                  expr.cpppos)
+        | 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 *)
+                if String.contains rename ' ' then (
+                  out "(";
+                  closeCall := ")");
+                out rename
+            | None ->
+                out (cpp_class_name clazz);
+                out ("::" ^ cpp_member_name_of field))
+        | FuncTemplate (clazz, field, tpath, native) ->
+            (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 *)
+                if String.contains rename ' ' then (
+                  out "(";
+                  closeCall := ")");
+                out rename
+            | None ->
+                out (cpp_class_name clazz);
+                out ("::" ^ cpp_member_name_of field));
+            out ("< " ^ cpp_template_param tpath native ^ "  >")
+        | FuncFromStaticFunction ->
+            abort "Unexpected FuncFromStaticFunction" expr.cpppos
+        | FuncEnumConstruct (enum, field) ->
+            out (string_of_path enum.e_path ^ "::" ^ cpp_enum_name_of field)
+        | FuncSuperConstruct (TCppInst (klass, _)) when is_native_class klass ->
+            doCall := false
+        | FuncSuperConstruct _ ->
+            out
+              ((if not ctx.ctx_real_this_ptr then "__this->" else "")
+              ^ "super::__construct")
+        | FuncSuper (_, TCppInst (klass, p), field) when is_native_class klass
+          ->
+            out (cpp_class_path_of klass p ^ "::" ^ cpp_member_name_of field)
+        | FuncSuper (this, _, field) ->
+            out
+              ((if this == ThisReal then "this->" else "__->")
+              ^ "super::" ^ cpp_member_name_of field)
+        | FuncNew newType ->
+            let objName =
+              match newType with
+              | TCppString -> "::String"
+              | TCppDynamicArray -> "::cpp::VirtualArray_obj::__new"
+              | TCppObjectArray _ -> "::Array_obj< ::Dynamic>::__new"
+              | TCppScalarArray value ->
+                  "::Array_obj< " ^ tcpp_to_string value ^ " >::__new"
+              | TCppObjC klass -> cpp_class_path_of klass [] ^ "_obj::__new"
+              | TCppNativePointer klass -> "new " ^ cpp_class_path_of klass []
+              | 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
+            in
+            out objName
+        | FuncInternal (func, name, join) ->
+            gen func;
+            out (join ^ name)
+        | FuncExtern (name, isGlobal) ->
+            if isGlobal then out " ::";
+            out name
+        | FuncExpression expr -> gen expr);
+        if !doCall then (
+          let sep = ref "" in
+          out "(";
+          List.iter
+            (fun arg ->
+              out !sep;
+              sep := ",";
+              gen arg)
+            !argsRef;
+          out (")" ^ !closeCall))
+    | CppNewNative e ->
+        out "new ";
+        gen e
+    | CppAddressOf e ->
+        out "&(";
+        gen e;
+        out ")"
+    | CppDereference e ->
+        out "(*(";
+        gen e;
+        out "))"
+    | CppFunctionAddress (klass, member) ->
+        let signature = function_signature false member.cf_type "" in
+        let name = cpp_member_name_of member in
+        (*let void_cast = has_meta_key field.cf_meta Meta.Void in*)
+        out ("::cpp::Function< " ^ signature ^ ">(::hx::AnyCast(");
+        out ("&::" ^ join_class_path_remap klass.cl_path "::" ^ "_obj::" ^ name);
+        out " ))"
+    | CppExtern (name, isGlobal) ->
+        if isGlobal then out " ::";
+        out name
+    | CppDynamicField (obj, name) ->
+        gen obj;
+        out ("->__Field(" ^ strq name ^ ",::hx::paccDynamic)")
+    | CppArray arrayLoc -> (
+        match arrayLoc with
+        | ArrayTyped (arrayObj, index, _) ->
+            gen arrayObj;
+            out "->__get(";
+            gen index;
+            out ")"
+        | ArrayPointer (arrayObj, index) ->
+            gen arrayObj;
+            out ".ptr[";
+            gen index;
+            out "]"
+        | ArrayRawPointer (arrayObj, index) ->
+            gen arrayObj;
+            out "[";
+            gen index;
+            out "]"
+        | ArrayObject (arrayObj, index, elem) ->
+            let close =
+              if cpp_is_dynamic_type elem then ""
+              else if elem = TCppDynamicArray then (
+                out (tcpp_to_string elem ^ "( ");
+                ")")
+              else ".StaticCast< " ^ tcpp_to_string elem ^ " >()"
+            in
+            gen arrayObj;
+            out "->__get(";
+            gen index;
+            out (")" ^ close)
+        | ArrayVirtual (arrayObj, index) ->
+            gen arrayObj;
+            out "->__get(";
+            gen index;
+            out ")"
+        | ArrayDynamic (arrayObj, index) ->
+            gen arrayObj;
+            out "->__GetItem(";
+            gen index;
+            out ")"
+        | ArrayImplements (_, arrayObj, index) ->
+            gen arrayObj;
+            out "->__get(";
+            gen index;
+            out ")")
+    | CppSet (lvalue, rvalue) ->
+        let close =
+          if expr.cpptype = TCppVoid then ""
+          else (
+            out "(";
+            ")")
+        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, ");
+            gen rvalue;
+            out ")"
+        | CppVarRef (VarThis (member, _))
+          when is_gc_element ctx (cpp_type_of member.cf_type) ->
+            out ("this->_hx_set_" ^ cpp_member_name_of member ^ "(HX_CTX, ");
+            gen rvalue;
+            out ")"
+        | CppVarRef (VarInstance (obj, member, _, "->"))
+          when is_gc_element ctx (cpp_type_of member.cf_type) ->
+            gen obj;
+            out ("->_hx_set_" ^ cpp_member_name_of member ^ "(HX_CTX, ");
+            gen rvalue;
+            out ")"
+        | CppVarRef (VarInternal (obj, operator, member)) ->
+            gen obj;
+            out (operator ^ member)
+        | CppVarRef varLoc ->
+            gen_val_loc varLoc true;
+            out " = ";
+            gen rvalue
+        | CppArrayRef arrayLoc -> (
+            match arrayLoc with
+            | ArrayObject (arrayObj, index, _)
+              when is_gc_element ctx TCppDynamic ->
+                gen arrayObj;
+                out "->setCtx( HX_CTX, ";
+                gen index;
+                out ",";
+                gen rvalue;
+                out ")"
+            | ArrayTyped (arrayObj, index, t) when is_gc_element ctx t ->
+                gen arrayObj;
+                out "->setCtx( HX_CTX, ";
+                gen index;
+                out ",";
+                gen rvalue;
+                out ")"
+            | ArrayObject (arrayObj, index, _)
+            | ArrayTyped (arrayObj, index, _)
+            | ArrayRawPointer (arrayObj, index) ->
+                gen arrayObj;
+                out "[";
+                gen index;
+                out "] = ";
+                gen rvalue
+            | ArrayPointer (arrayObj, index) ->
+                gen arrayObj;
+                out ".ptr[";
+                gen index;
+                out "] = ";
+                gen rvalue
+            | ArrayVirtual (arrayObj, index) ->
+                gen arrayObj;
+                out "->set(";
+                gen index;
+                out ",";
+                gen rvalue;
+                out ")"
+            | ArrayDynamic (arrayObj, index) ->
+                gen arrayObj;
+                out "->__SetItem(";
+                gen index;
+                out ",";
+                gen rvalue;
+                out ")"
+            | ArrayImplements (_, arrayObj, index) ->
+                gen arrayObj;
+                out "->__set(";
+                gen index;
+                out ",";
+                gen rvalue;
+                out ")")
+        | CppDynamicRef (expr, name) ->
+            gen expr;
+            out ("->__SetField(" ^ strq name ^ ",");
+            gen rvalue;
+            out ",::hx::paccDynamic)"
+        | CppExternRef (name, isGlobal) ->
+            if isGlobal then out " ::";
+            out (name ^ " = "));
+        out close
+    | CppCrement (incFlag, preFlag, lvalue) ->
+        let op = if incFlag == CppIncrement then "++" else "--" in
+        if preFlag == Prefix then out op;
+        gen_lvalue lvalue;
+        if preFlag == Postfix then out op
+    | CppModify (op, lvalue, rvalue) ->
+        out (string_of_op_eq op expr.cpppos);
+        out "(";
+        gen_lvalue lvalue;
+        out ",";
+        gen rvalue;
+        out ")"
+    | CppPosition (name, line, clazz, func) ->
+        out
+          ("::hx::SourceInfo(" ^ strq name ^ ","
+          ^ string_of_int (Int32.to_int line)
+          ^ "," ^ strq clazz ^ "," ^ strq func ^ ")")
+    | CppClassOf (path, native) ->
+        let path = "::" ^ join_class_path_remap path "::" in
+        let path =
+          match path with "::Int" -> "int" | "::Bool" -> "bool" | x -> x
+        in
+        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
+    | CppClosure closure ->
+        out
+          (" ::Dynamic(new _hx_Closure_" ^ string_of_int closure.close_id ^ "(");
+        let separator = ref "" in
+        (match closure.close_this with
+        | Some this ->
+            out (if this = ThisReal then "this" else "__this");
+            separator := ","
+        | _ -> ());
+
+        Hashtbl.iter
+          (fun name value ->
+            out !separator;
+            separator := ",";
+            out (keyword_remap name))
+          closure.close_undeclared;
+        out "))"
+    | CppObjectDecl (values, isStruct) ->
+        let length = List.length values in
+        let lengthStr = string_of_int length in
+        if expr.cpptype != TCppVoid then out " ::Dynamic(";
+        if isStruct && length > 0 && length <= 5 then (
+          out
+            ("::hx::AnonStruct" ^ lengthStr ^ "_obj< "
+            ^ String.concat ","
+                (List.map
+                   (fun (_, value) -> tcpp_to_string value.cpptype)
+                   values)
+            ^ " >::Create(");
+          let sep = ref "" in
+          List.iter
+            (fun (name, value) ->
+              out (!sep ^ strq name ^ ",");
+              sep := ",";
+              gen value)
+            values;
+          out ")")
+        else (
+          out ("::hx::Anon_obj::Create(" ^ lengthStr ^ ")");
+          let sorted =
+            List.sort
+              (fun (_, _, h0) (_, _, h1) -> Int32.compare h0 h1)
+              (List.map
+                 (fun (name, value) -> (name, value, gen_hash32 0 name))
+                 values)
+          in
+          writer#push_indent;
+          ExtList.List.iteri
+            (fun idx (name, value, _) ->
+              out ("\n" ^ spacer);
+              writer#write_i
+                ("->setFixed(" ^ string_of_int idx ^ "," ^ strq name ^ ",");
+              gen value;
+              out ")")
+            sorted);
+        if expr.cpptype != TCppVoid then out ")";
+        writer#pop_indent
+    | CppArrayDecl exprList when cpp_is_const_scalar_array expr.cpptype exprList
+      ->
+        let arrayType =
+          match expr.cpptype with
+          | TCppScalarArray value -> value
+          | _ -> assert false
+        in
+        let typeName = tcpp_to_string arrayType in
+        incr ctx.ctx_file_id;
+
+        let id =
+          "_hx_array_data_" ^ class_hash ^ "_"
+          ^ string_of_int !(ctx.ctx_file_id)
+        in
+
+        let out_top = ctx.ctx_writer#write_h in
+        out_top ("static const " ^ typeName ^ " " ^ id ^ "[] = {\n\t");
+        List.iter
+          (fun expr ->
+            match expr.cppexpr with
+            | CppInt i -> out_top (Printf.sprintf "(%s)%ld," typeName i)
+            | CppFloat f -> out_top (f ^ ",")
+            | CppString s -> out_top (strq s ^ ",")
+            | CppBool b -> out_top (if b then "1," else "0,")
+            | _ -> die "" __LOC__)
+          exprList;
+        out_top "\n};\n";
+        out
+          ("::Array_obj< " ^ typeName ^ " >::fromData( " ^ id ^ ","
+         ^ list_num exprList ^ ")")
+    | CppArrayDecl exprList ->
+        let count = List.length exprList in
+        let countStr = string_of_int count in
+        let arrayType, close =
+          match expr.cpptype with
+          | TCppObjectArray _ -> ("::Array_obj< ::Dynamic>", "")
+          | TCppScalarArray value ->
+              ("::Array_obj< " ^ tcpp_to_string value ^ " >", "")
+          | TCppDynamicArray -> ("::cpp::VirtualArray_obj", "")
+          | _ -> (" ::Dynamic( ::cpp::VirtualArray_obj", ")")
+        in
+        out (arrayType ^ "::__new(" ^ countStr ^ ")");
+        ExtList.List.iteri
+          (fun idx elem ->
+            out ("->init(" ^ string_of_int idx ^ ",");
+            gen elem;
+            out ")")
+          exprList;
+        out close
+    | CppBinop (Ast.OpUShr, left, right) ->
+        out "::hx::UShr(";
+        gen left;
+        out ",";
+        gen right;
+        out ")"
+    | CppBinop (Ast.OpMod, left, right) ->
+        if is_constant_zero right then (
+          out "::hx::Mod(";
+          gen left;
+          out ",(double)( ";
+          gen right;
+          out " ))")
+        else (
+          out "::hx::Mod(";
+          gen left;
+          out ",";
+          gen right;
+          out ")")
+    | CppBinop (Ast.OpDiv, left, right) when is_constant_zero right ->
+        out "::hx::DivByZero(";
+        gen left;
+        out ")"
+    | CppBinop (op, left, right) ->
+        let op = string_of_op op expr.cpppos in
+        out "(";
+        gen left;
+        out (" " ^ op ^ " ");
+        gen right;
+        out ")"
+    | CppCompare (opName, left, right, _) ->
+        out ("::hx::" ^ opName ^ "( ");
+        gen left;
+        out ",";
+        gen right;
+        out " )"
+    | CppNullCompare (op, left) ->
+        out ("::hx::" ^ op ^ "( ");
+        gen left;
+        out " )"
+    | CppThrow value ->
+        out "HX_STACK_DO_THROW(";
+        gen value;
+        out ")"
+    | CppReturn None -> out "return"
+    | CppReturn (Some value) ->
+        out "return ";
+        gen value
+    | CppEnumField (enum, field) ->
+        out
+          (string_of_path enum.e_path ^ "::" ^ cpp_enum_name_of field ^ "_dyn()")
+    | CppEnumParameter (obj, field, index) -> (
+        let valueType = cpp_type_of (get_nth_type field index) in
+        let baseType = enum_getter_type valueType in
+        gen obj;
+        if cpp_is_dynamic_type obj.cpptype then
+          out ".StaticCast< ::hx::EnumBase >()";
+        out ("->_hx_get" ^ baseType ^ "(" ^ string_of_int index ^ ")");
+        match valueType with
+        | TCppObjectArray _ | TCppScalarArray _ | TCppDynamicArray | TCppClass
+        | TCppEnum _ | TCppInst _ ->
+            out (".StaticCast< " ^ tcpp_to_string valueType ^ " >()")
+        | _ -> ())
+    | CppIntSwitch (condition, cases, defVal) ->
+        out "switch((int)(";
+        gen condition;
+        out "))";
+        writer#begin_block;
+        List.iter
+          (fun (values, expr) ->
+            out spacer;
+            writer#write_i "";
+            List.iter
+              (fun value ->
+                out ("case (int)" ^ Printf.sprintf "%ld" value ^ ": "))
+              values;
+            gen expr;
+            out spacer;
+            writer#write_i "break;\n")
+          cases;
+        (match defVal with
+        | Some expr ->
+            output_i "default:";
+            gen expr
+        | _ -> ());
+        out spacer;
+        writer#end_block
+    | CppSwitch (condition, conditionType, cases, optional_default, label) ->
+        let tmp_name = "_hx_switch_" ^ string_of_int !tempId in
+        incr tempId;
+        out (tcpp_to_string conditionType ^ " " ^ tmp_name ^ " = ");
+        gen condition;
+        out ";\n";
+        List.iter
+          (fun (cases, expression) ->
+            output_i "if ( ";
+            let or_str = ref "" in
+            List.iter
+              (fun value ->
+                out (!or_str ^ " (" ^ tmp_name ^ "==");
+                gen value;
+                out ")";
+                or_str := " || ")
+              cases;
+            out " )";
+            gen expression)
+          cases;
+        (match optional_default with
+        | None -> ()
+        | Some default ->
+            output_i "/* default */";
+            gen default);
+        output_i (label_name label ^ ":")
+    | CppUnop (unop, value) ->
+        out
+          (match unop with CppNot -> "!" | CppNeg -> "-" | CppNegBits -> "~");
+        out "(";
+        gen value;
+        out ")"
+    | CppWhile (condition, block, while_flag, loop_id) ->
+        (match while_flag with
+        | NormalWhile ->
+            out "while(";
+            gen condition;
+            out ")";
+            lastLine := -1;
+            gen block
+        | DoWhile ->
+            out "do ";
+            lastLine := -1;
+            gen_with_injection None block false;
+            out " while(";
+            gen condition;
+            out ");\n");
+        if loop_id > -1 then output_i (label_name loop_id ^ ":")
+    | CppIf (condition, block, None) ->
+        out "if (";
+        gen condition;
+        out ") ";
+        gen block
+    | CppIf (condition, block, Some elze) when expr.cpptype = TCppVoid ->
+        out "if (";
+        gen condition;
+        out ") ";
+        gen block;
+        output_i "else ";
+        gen elze
+    | CppIf (condition, block, Some elze) ->
+        gen condition;
+        out " ? ";
+        gen block;
+        out " : ";
+        gen elze
+    | CppFor (tvar, init, loop) ->
+        let varType = cpp_var_type_of tvar 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")
+        in
+        gen_with_injection (mk_injection prologue "" "") loop true
+    | CppTry (block, catches) ->
+        let prologue = function
+          | _ ->
+              ExtList.List.iteri
+                (fun idx (v, _) ->
+                  output_i
+                    ("HX_STACK_CATCHABLE(" ^ cpp_macro_var_type_of v ^ ", "
+                   ^ string_of_int idx ^ ");\n"))
+                catches
+        in
+        out "try ";
+        gen_with_injection
+          (mk_injection prologue "" "")
+          block
+          (List.length catches < 0);
+        if List.length catches > 0 then (
+          out " catch( ::Dynamic _hx_e) ";
+          writer#begin_block;
+
+          let seen_dynamic = ref false in
+          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
+              | TCppInterface klass ->
+                  let hash = cpp_class_hash klass in
+                  output_i
+                    (!else_str ^ "if (::hx::TIsInterface< (int)" ^ hash
+                   ^ " >(_hx_e.mPtr))")
+              | TCppString ->
+                  output_i
+                    (!else_str
+                   ^ "if (_hx_e.IsClass< ::String >() && \
+                      _hx_e->toString()!=null() )")
+              | _ ->
+                  if type_name = "Dynamic" then (
+                    seen_dynamic := true;
+                    output_i !else_str)
+                  else
+                    output_i
+                      (!else_str ^ "if (_hx_e.IsClass< " ^ type_name ^ " >() )"));
+
+              let prologue = function
+                | _ ->
+                    output_i "HX_STACK_BEGIN_CATCH\n";
+                    output_i
+                      (type_name ^ " " ^ cpp_var_name_of v ^ " = _hx_e;\n")
+              in
+              gen_with_injection (mk_injection prologue "" "") catch true;
+              else_str := "else ")
+            catches;
+
+          if not !seen_dynamic then (
+            output_i "else {\n";
+            output_i "\tHX_STACK_DO_THROW(_hx_e);\n";
+            output_i "}\n");
+          out spacer;
+          writer#end_block)
+    | CppCode (value, exprs) ->
+        Codegen.interpolate_code ctx.ctx_common.error (format_code value) exprs out
+          (fun e -> gen e)
+          expr.cpppos
+    | CppTCast (expr, cppType) -> (
+        match cppType with
+        | TCppInterface i ->
+            out " ::hx::interface_check(";
+            gen expr;
+            out ("," ^ cpp_class_hash i ^ ")")
+        | _ ->
+            let toType = tcpp_to_string cppType in
+            if toType = "Dynamic" then (
+              out " ::Dynamic(";
+              gen expr;
+              out ")")
+            else (
+              out ("::hx::TCast< " ^ toType ^ " >::cast(");
+              gen expr;
+              out ")"))
+    | CppCastStatic (expr, toType) ->
+        let close =
+          match expr.cpptype with
+          | TCppDynamic -> ""
+          | _ ->
+              out "Dynamic( ";
+              ")"
+        in
+        gen expr;
+        out (close ^ ".StaticCast< " ^ tcpp_to_string toType ^ " >()")
+    | CppCast (expr, toType) -> (
+        match (expr.cppexpr, expr.cpptype, toType) with
+        | CppCall (FuncInternal _, _), _, _ ->
+            gen expr;
+            out (".StaticCast< " ^ tcpp_to_string toType ^ " >()")
+        | _, TCppObjC _, _ | _, TCppObjCBlock _, _ ->
+            out ("( (" ^ tcpp_to_string toType ^ ")((id) ( ");
+            gen expr;
+            out ") ))"
+        | _, _, TCppObjectPtr ->
+            out "::hx::DynamicPtr(";
+            gen expr;
+            out ")"
+        | _, TCppPointer (_, _), TCppStar (_, _)
+        | _, TCppPointer (_, _), TCppRawPointer (_, _) ->
+            out ("( (" ^ tcpp_to_string toType ^ ")( (");
+            gen expr;
+            out ").get_raw()) )"
+        | _ ->
+            out ("( (" ^ tcpp_to_string toType ^ ")(");
+            gen expr;
+            out ") )")
+    | CppCastScalar (expr, scalar) ->
+        out ("( (" ^ scalar ^ ")(");
+        gen expr;
+        out ") )"
+    | CppCastVariant expr ->
+        out " ::Dynamic(";
+        gen expr;
+        out ")"
+    | CppCastObjC (expr, klass) ->
+        let path = join_class_path_remap klass.cl_path "::" in
+        let toType =
+          if has_class_flag klass CInterface then "id < " ^ path ^ ">"
+          else path ^ " *"
+        in
+        out ("( (" ^ toType ^ ") (id) (");
+        gen expr;
+        out ") )"
+    | CppCastObjCBlock (expr, args, ret) ->
+        out (tcpp_objc_block_struct args ret ^ "::create( ");
+        gen expr;
+        out ")"
+    | CppCastProtocol (expr, klass) ->
+        out (join_class_path_remap klass.cl_path "::" ^ "_obj::_hx_toProtocol( ");
+        gen expr;
+        out ")"
+    | CppCastNative expr ->
+        out "(";
+        gen expr;
+        out ").mPtr");
+    if ctx.ctx_debug_level >= 3 then
+      out
+        ("/* " ^ s_tcpp expr.cppexpr ^ ":" ^ tcpp_to_string expr.cpptype ^ " */")
+  and gen expr = gen_with_injection None expr true
+  and gen_lvalue lvalue =
+    match lvalue with
+    | CppVarRef varLoc -> gen_val_loc varLoc true
+    | CppArrayRef arrayLoc -> (
+        match arrayLoc with
+        | ArrayObject (arrayObj, index, _) ->
+            out "::hx::IndexRef(";
+            gen arrayObj;
+            out ".mPtr,";
+            gen index;
+            out ")"
+        | ArrayTyped (arrayObj, index, _) ->
+            gen arrayObj;
+            out "[";
+            gen index;
+            out "]"
+        | ArrayPointer (arrayObj, index) ->
+            gen arrayObj;
+            out ".ptr[";
+            gen index;
+            out "]"
+        | ArrayRawPointer (arrayObj, index) ->
+            gen arrayObj;
+            out "[";
+            gen index;
+            out "]"
+        | ArrayVirtual (arrayObj, index) | ArrayDynamic (arrayObj, index) ->
+            out "::hx::IndexRef(";
+            gen arrayObj;
+            out ".mPtr,";
+            gen index;
+            out ")"
+        | ArrayImplements (_, arrayObj, index) ->
+            out "::hx::__ArrayImplRef(";
+            gen arrayObj;
+            out ",";
+            gen index;
+            out ")")
+    | CppExternRef (name, isGlobal) ->
+        if isGlobal then out " ::";
+        out name
+    | CppDynamicRef (expr, name) ->
+        let objPtr =
+          match expr.cpptype with TCppVariant -> "getObject()" | _ -> ".mPtr"
+        in
+        out "::hx::FieldRef((";
+        gen expr;
+        out (")" ^ objPtr ^ "," ^ strq name ^ ")")
+  and gen_val_loc loc lvalue =
+    match loc with
+    | VarClosure var -> out (cpp_var_name_of var)
+    | VarLocal local -> out (cpp_var_name_of local)
+    | VarStatic (clazz, objc, member) -> (
+        match get_meta_string member.cf_meta Meta.Native with
+        | Some n -> out n
+        | None ->
+            if objc then (
+              out (join_class_path_remap clazz.cl_path "::");
+              out ("." ^ cpp_member_name_of member))
+            else (
+              out (cpp_class_name clazz);
+              out ("::" ^ cpp_member_name_of member)))
+    | VarThis (member, _) -> out ("this->" ^ cpp_member_name_of member)
+    | VarInstance (obj, member, _, operator) ->
+        gen obj;
+        out (operator ^ cpp_member_name_of member)
+    | VarInternal (obj, operator, member) ->
+        gen obj;
+        out (operator ^ member)
+    | VarInterface (obj, member) ->
+        gen obj;
+        out ("->" ^ cpp_member_name_of member ^ "_get()")
+  and string_of_op_eq op pos =
+    match op with
+    | OpAdd -> "::hx::AddEq"
+    | OpMult -> "::hx::MultEq"
+    | OpDiv -> "::hx::DivEq"
+    | OpSub -> "::hx::SubEq"
+    | OpAnd -> "::hx::AndEq"
+    | OpOr -> "::hx::OrEq"
+    | OpXor -> "::hx::XorEq"
+    | OpShl -> "::hx::ShlEq"
+    | OpShr -> "::hx::ShrEq"
+    | OpUShr -> "::hx::UShrEq"
+    | OpMod -> "::hx::ModEq"
+    | _ -> abort "Bad assign op" pos
+  and string_of_op op pos =
+    match op with
+    | OpAdd -> "+"
+    | OpMult -> "*"
+    | OpDiv -> "/"
+    | OpSub -> "-"
+    | OpEq -> "=="
+    | OpNotEq -> "!="
+    | OpGt -> ">"
+    | OpGte -> ">="
+    | OpLt -> "<"
+    | OpLte -> "<="
+    | OpAnd -> "&"
+    | OpOr -> "|"
+    | OpXor -> "^"
+    | OpBoolAnd -> "&&"
+    | OpBoolOr -> "||"
+    | OpShl -> "<<"
+    | OpShr -> ">>"
+    | OpUShr -> ">>>"
+    | OpMod -> "%"
+    | OpInterval -> "..."
+    | OpArrow -> "->"
+    | OpIn -> " in "
+    | OpNullCoal -> "??"
+    | OpAssign | OpAssignOp _ -> abort "Unprocessed OpAssign" pos
+  and gen_closure closure =
+    let argc = Hashtbl.length closure.close_undeclared in
+    let size = string_of_int argc in
+    if argc >= 62 then
+      (* Limited by c++ macro size of 128 args *)
+      abort "Too many capture variables" closure.close_expr.cpppos;
+    if argc >= 20 || List.length closure.close_args >= 20 then
+      writer#add_big_closures;
+    let argsCount = list_num closure.close_args in
+    output_i ("HX_BEGIN_LOCAL_FUNC_S" ^ size ^ "(");
+    out
+      (if closure.close_this != None then "::hx::LocalThisFunc,"
+       else "::hx::LocalFunc,");
+    out ("_hx_Closure_" ^ string_of_int closure.close_id);
+    Hashtbl.iter
+      (fun name var ->
+        out ("," ^ cpp_macro_var_type_of var ^ "," ^ keyword_remap 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_" ^ ")");
+
+    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 (
+            if closure.close_this != None then
+              output_i "HX_STACK_THIS(__this.mPtr)\n";
+            List.iter
+              (fun (v, _) ->
+                output_i
+                  ("HX_STACK_ARG(" ^ cpp_var_name_of v ^ ",\""
+                 ^ cpp_debug_name_of v ^ "\")\n"))
+              (List.filter (cpp_debug_var_visible ctx) closure.close_args);
+
+            let line = Lexer.get_error_line closure.close_expr.cpppos in
+            let lineName = Printf.sprintf "%4d" line in
+            out ("HXLINE(" ^ lineName ^ ")\n"))
+    in
+    gen_with_injection (mk_injection prologue "" "") closure.close_expr true;
+
+    let return =
+      match closure.close_type with TCppVoid -> "(void)" | _ -> "return"
+    in
+
+    output_i ("HX_END_LOCAL_FUNC" ^ argsCount ^ "(" ^ return ^ ")\n\n")
+  in
+
+  gen_with_injection injection cppTree true
+
+let gen_cpp_init ctx dot_name func_name var_name expr =
+  let output = ctx.ctx_output in
+  let prologue = function
+    | gc_stack ->
+        let spacer =
+          if ctx.ctx_debug_level > 0 then "            \t" else "\t"
+        in
+        let output_i s = output (spacer ^ s) in
+        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)
+
+let generate_main_header output_main =
+  output_main "#include <hxcpp.h>\n\n";
+  output_main "#include <stdio.h>\n\n";
+  output_main "extern \"C\" void __hxcpp_main();\n\n";
+  output_main "extern \"C\" void __hxcpp_lib_main();\n\n"
+
+let generate_main_footer1 output_main = output_main "void __hxcpp_main() {\n"
+
+let generate_main_footer2 output_main =
+  output_main "\t}\n\n";
+  output_main "void __hxcpp_lib_main() {\n";
+  output_main "\tHX_TOP_OF_STACK\n";
+  output_main "\t::hx::Boot();\n";
+  output_main "\t__boot_all();\n";
+  output_main "\t__hxcpp_main();\n";
+  output_main "\t}\n"
+
+let generate_main ctx super_deps class_def =
+  let common_ctx = ctx.ctx_common in
+  (* main routine should be a single static function *)
+  let main_expression =
+    match class_def.cl_ordered_statics with
+    | [ { cf_expr = Some expression } ] -> expression
+    | _ -> die "" __LOC__
+  in
+  CppReferences.find_referenced_types ctx (TClassDecl class_def) super_deps
+    (Hashtbl.create 0) false false false
+  |> ignore;
+  let depend_referenced =
+    CppReferences.find_referenced_types ctx (TClassDecl class_def) super_deps
+      (Hashtbl.create 0) false true false
+  in
+  let generate_startup filename is_main =
+    (*make_class_directories base_dir ( "src" :: []);*)
+    let cpp_file = new_cpp_file common_ctx common_ctx.file ([], filename) in
+    let output_main = cpp_file#write in
+
+    generate_main_header cpp_file#write_h;
+
+    List.iter (add_include cpp_file) depend_referenced;
+    output_main "\n\n";
+
+    if is_main then output_main "\n#include <hx/HxcppMain.h>\n\n";
+
+    generate_main_footer1 output_main;
+
+    let ctx = file_context ctx cpp_file 1 false in
+    gen_cpp_init ctx "hxcpp" "__hxcpp_main" "" main_expression;
+
+    generate_main_footer2 output_main;
+    cpp_file#close
+  in
+  generate_startup "__main__" true;
+  generate_startup "__lib__" false
+
+let generate_dummy_main common_ctx =
+  let generate_startup filename is_main =
+    let main_file = new_cpp_file common_ctx common_ctx.file ([], filename) in
+    let output_main = main_file#write in
+    generate_main_header main_file#write_h;
+    if is_main then output_main "\n#include <hx/HxcppMain.h>\n\n";
+    generate_main_footer1 output_main;
+    generate_main_footer2 output_main;
+    main_file#close
+  in
+  generate_startup "__main__" true;
+  generate_startup "__lib__" false
+
+let generate_boot ctx boot_enums boot_classes nonboot_classes init_classes =
+  let common_ctx = ctx.ctx_common in
+  (* Write boot class too ... *)
+  let base_dir = common_ctx.file in
+  let boot_file = new_cpp_file common_ctx base_dir ([], "__boot__") in
+  let output_boot = boot_file#write in
+  boot_file#write_h "#include <hxcpp.h>\n\n";
+
+  List.iter
+    (fun class_path -> boot_file#add_include class_path)
+    (boot_enums @ boot_classes @ nonboot_classes);
+
+  let newScriptable = Gctx.defined common_ctx Define.Scriptable in
+  if newScriptable then (
+    output_boot "#include <hx/Scriptable.h>\n";
+    let funcs =
+      hash_iterate !(ctx.ctx_interface_slot) (fun name id -> (name, id))
+    in
+    let sorted = List.sort (fun (_, id1) (_, id2) -> id1 - id2) funcs in
+    output_boot
+      "static const char *scriptableInterfaceFuncs[] = {\n\t0,\n\t0,\n";
+    List.iter
+      (fun (name, id) ->
+        output_boot ("\t\"" ^ name ^ "\", //" ^ string_of_int (-id) ^ "\n"))
+      sorted;
+    output_boot "};\n");
+
+  output_boot "\nvoid __files__boot();\n";
+  output_boot "\nvoid __boot_all()\n{\n";
+  output_boot "__files__boot();\n";
+  output_boot "::hx::RegisterResources( ::hx::GetResources() );\n";
+  if newScriptable then
+    output_boot
+      ("::hx::ScriptableRegisterNameSlots(scriptableInterfaceFuncs,"
+      ^ string_of_int !(ctx.ctx_interface_slot_count)
+      ^ ");\n");
+
+  List.iter
+    (fun class_path ->
+      output_boot
+        ("::" ^ join_class_path_remap class_path "::" ^ "_obj::__register();\n"))
+    (boot_enums @ boot_classes @ nonboot_classes);
+
+  let dump_boot =
+    List.iter (fun class_path ->
+        output_boot
+          ("::" ^ join_class_path_remap class_path "::" ^ "_obj::__boot();\n"))
+  in
+
+  dump_boot boot_enums;
+
+  List.iter
+    (fun class_path ->
+      output_boot
+        ("::" ^ join_class_path_remap class_path "::" ^ "_obj::__init__();\n"))
+    (List.rev init_classes);
+
+  let is_cpp_class = function
+    | "cpp" :: _, _ -> true
+    | [], "EReg" -> true
+    | [ "haxe" ], "Log" -> true
+    | _ -> false
+  in
+
+  dump_boot
+    (List.filter (fun path -> is_cpp_class path) (List.rev boot_classes));
+  dump_boot
+    (List.filter (fun path -> not (is_cpp_class path)) (List.rev boot_classes));
+
+  output_boot "}\n\n";
+  boot_file#close
+
+let generate_files common_ctx file_info =
+  (* Write __files__ class too ... *)
+  let base_dir = common_ctx.file in
+  let files_file = new_cpp_file common_ctx base_dir ([], "__files__") in
+  let output_files = files_file#write in
+  let types = common_ctx.types in
+  files_file#write_h "#include <hxcpp.h>\n\n";
+  output_files "namespace hx {\n";
+  output_files "const char *__hxcpp_all_files[] = {\n";
+  output_files "#ifdef HXCPP_DEBUGGER\n";
+  List.iter
+    (fun file -> output_files (const_char_star file ^ ",\n"))
+    (List.sort String.compare (pmap_keys !file_info));
+  output_files "#endif\n";
+  output_files " 0 };\n";
+  output_files "\n";
+
+  output_files "const char *__hxcpp_all_files_fullpath[] = {\n";
+  output_files "#ifdef HXCPP_DEBUGGER\n";
+  List.iter
+    (fun file ->
+      output_files
+        (const_char_star
+           (Path.get_full_path
+              (try Gctx.find_file common_ctx file with Not_found -> file))
+        ^ ",\n"))
+    (List.sort String.compare (pmap_keys !file_info));
+  output_files "#endif\n";
+  output_files " 0 };\n";
+  output_files "\n";
+
+  output_files "const char *__hxcpp_all_classes[] = {\n";
+  output_files "#ifdef HXCPP_DEBUGGER\n";
+  List.iter
+    (fun object_def ->
+      match object_def with
+      | TClassDecl class_def when is_extern_class class_def -> ()
+      | TClassDecl class_def when has_class_flag class_def CInterface -> ()
+      | TClassDecl class_def ->
+          output_files
+            (const_char_star (join_class_path class_def.cl_path ".") ^ ",\n")
+      | _ -> ())
+    types;
+  output_files "#endif\n";
+  output_files " 0 };\n";
+
+  output_files "} // namespace hx\n";
+  output_files
+    "void __files__boot() { \
+     __hxcpp_set_debugger_info(::hx::__hxcpp_all_classes, \
+     ::hx::__hxcpp_all_files_fullpath); }\n";
+
+  files_file#close
+
+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;
+  let prologue = function
+    | 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
+          gc_stack;
+        if ctx.ctx_debug_level >= 2 then (
+          if not is_static then
+            output_i
+              ("HX_STACK_THIS("
+              ^ (if ctx.ctx_real_this_ptr then "this" else "__this")
+              ^ ")\n");
+          List.iter
+            (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;
+
+          let line = Lexer.get_error_line function_def.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)
+
+let constructor_arg_var_list class_def =
+  match class_def.cl_constructor with
+  | Some definition -> (
+      match definition.cf_expr with
+      | Some { eexpr = TFunction function_def } ->
+          List.map
+            (fun (v, o) ->
+              (v.v_name, type_arg_to_string v.v_name o v.v_type "__o_"))
+            function_def.tf_args
+      | _ -> (
+          match follow definition.cf_type with
+          | TFun (args, _) ->
+              List.map (fun (a, _, t) -> (a, (type_to_string t, a))) args
+          | _ -> []))
+  | _ -> []
+
+let generate_constructor ctx out class_def isHeader =
+  let class_name = class_name class_def in
+  let ptr_name = class_pointer class_def in
+  let can_quick_alloc = can_quick_alloc class_def in
+  let gcName = gen_gc_name class_def.cl_path in
+  let isContainer = if has_gc_references class_def then "true" else "false" in
+  let cargs = constructor_arg_var_list class_def in
+  let constructor_type_var_list = List.map snd cargs in
+  let constructor_type_args =
+    String.concat ","
+      (List.map (fun (t, a) -> t ^ " " ^ a) constructor_type_var_list)
+  in
+  let constructor_var_list = List.map snd constructor_type_var_list in
+  let constructor_args = String.concat "," constructor_var_list in
+
+  let classScope = if isHeader then "" else class_name ^ "::" in
+  let staticHead = if isHeader then "inline static " else "" in
+  out
+    (staticHead ^ ptr_name ^ " " ^ classScope ^ "__new(" ^ constructor_type_args
+   ^ ") {\n");
+  out ("\t" ^ ptr_name ^ " __this = new " ^ class_name ^ "();\n");
+  out ("\t__this->__construct(" ^ constructor_args ^ ");\n");
+  out "\treturn __this;\n";
+  out "}\n\n";
+
+  if can_quick_alloc then (
+    out
+      (staticHead ^ ptr_name ^ " " ^ classScope ^ "__alloc(::hx::Ctx *_hx_ctx"
+      ^ (if constructor_type_args = "" then "" else "," ^ constructor_type_args)
+      ^ ") {\n");
+    out
+      ("\t" ^ class_name ^ " *__this = (" ^ class_name
+     ^ "*)(::hx::Ctx::alloc(_hx_ctx, sizeof(" ^ class_name ^ "), " ^ isContainer
+     ^ ", " ^ gcName ^ "));\n");
+    out ("\t*(void **)__this = " ^ class_name ^ "::_hx_vtable;\n");
+    let rec dump_dynamic class_def =
+      if has_dynamic_member_functions class_def then
+        out
+          ("\t"
+          ^ join_class_path_remap class_def.cl_path "::"
+          ^ "_obj::__alloc_dynamic_functions(_hx_ctx,__this);\n")
+      else
+        match class_def.cl_super with
+        | Some super -> dump_dynamic (fst super)
+        | _ -> ()
+    in
+    dump_dynamic class_def;
+
+    if isHeader then
+      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 ->
+              ctx.ctx_real_this_ptr <- false;
+              gen_cpp_function_body ctx class_def false "new" function_def "" ""
+                no_debug;
+              out "\n")
+      | _ -> ()
+    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 cargs = constructor_arg_var_list class_def in
+  let constructor_type_var_list = List.map snd cargs in
+  let constructor_type_args =
+    String.concat ","
+      (List.map (fun (t, a) -> t ^ " " ^ a) constructor_type_var_list)
+  in
+  let class_name = class_name class_def in
+
+  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 dynamic_functions class_def =
+  List.fold_left
+    (fun result field ->
+      match field.cf_expr with
+      | Some { eexpr = TFunction function_def }
+        when is_dynamic_haxe_method field ->
+          keyword_remap field.cf_name :: result
+      | _ -> result)
+    [] class_def.cl_ordered_fields

+ 551 - 0
src/generators/cpp/gen/cppGenClassHeader.ml

@@ -0,0 +1,551 @@
+open Ast
+open Type
+open Error
+open Globals
+open CppStrings
+open CppTypeUtils
+open CppAst
+open CppAstTools
+open CppSourceWriter
+open CppContext
+open CppGen
+
+let gen_member_def ctx class_def is_static is_interface field =
+  let output = ctx.ctx_output in
+  let remap_name = keyword_remap field.cf_name in
+  let nativeGen = Meta.has Meta.NativeGen class_def.cl_meta in
+
+  if is_interface then
+    match (follow field.cf_type, field.cf_kind) with
+    | _, Method MethDynamic -> ()
+    | TFun (args, return_type), Method _ ->
+        let gen_args = print_tfun_arg_list true in
+        if is_static || nativeGen then (
+          output
+            ((if not is_static then "\t\tvirtual " else "\t\t")
+            ^ type_to_string return_type);
+          output (" " ^ remap_name ^ "( ");
+          output (gen_args args);
+          output (if not is_static then ")=0;\n" else ");\n");
+          if reflective class_def field then
+            if Gctx.defined ctx.ctx_common Define.DynamicInterfaceClosures
+            then
+              output
+                ("\t\tinline ::Dynamic " ^ remap_name
+               ^ "_dyn() { return __Field( "
+                ^ strq ctx.ctx_common field.cf_name
+                ^ ", ::hx::paccDynamic); }\n")
+            else output ("\t\tvirtual ::Dynamic " ^ remap_name ^ "_dyn()=0;\n"))
+        else
+          let argList = gen_args args in
+          let returnType = type_to_string return_type in
+          let returnStr = if returnType = "void" then "" else "return " in
+          let commaArgList = if argList = "" then argList else "," ^ argList in
+          let cast =
+            "::hx::interface_cast< ::"
+            ^ join_class_path_remap class_def.cl_path "::"
+            ^ "_obj *>"
+          in
+          output
+            ("\t\t" ^ returnType ^ " (::hx::Object :: *_hx_" ^ remap_name ^ ")("
+           ^ argList ^ "); \n");
+          output
+            ("\t\tstatic inline " ^ returnType ^ " " ^ remap_name
+           ^ "( ::Dynamic _hx_" ^ commaArgList ^ ") {\n");
+          output "\t\t\t#ifdef HXCPP_CHECK_POINTER\n";
+          output
+            "\t\t\tif (::hx::IsNull(_hx_)) ::hx::NullReference(\"Object\", \
+             false);\n";
+          output "\t\t\t#ifdef HXCPP_GC_CHECK_POINTER\n";
+          output "\t\t\t\tGCCheckPointer(_hx_.mPtr);\n";
+          output "\t\t\t#endif\n";
+          output "\t\t\t#endif\n";
+          output
+            ("\t\t\t" ^ returnStr ^ "(_hx_.mPtr->*( " ^ cast
+           ^ "(_hx_.mPtr->_hx_getInterface(" ^ cpp_class_hash class_def
+           ^ ")))->_hx_" ^ remap_name ^ ")(" ^ print_arg_names args
+           ^ ");\n\t\t}\n")
+    | _ -> ()
+  else
+    let nonVirtual = Meta.has Meta.NonVirtual field.cf_meta in
+    let doDynamic =
+      (nonVirtual || not (is_override field)) && reflective class_def field
+    in
+    let decl = get_meta_string field.cf_meta Meta.Decl in
+    let has_decl = match decl with Some _ -> true | None -> false in
+    if has_decl then output ("      typedef " ^ (decl |> Option.get) ^ ";\n");
+    output (if is_static then "\t\tstatic " else "\t\t");
+    match field.cf_expr with
+    | Some { eexpr = TFunction function_def } ->
+        (if is_dynamic_haxe_method field then (
+           if doDynamic then (
+             output ("::Dynamic " ^ remap_name ^ ";\n");
+             if (not is_static) && is_gc_element ctx TCppDynamic then
+               output
+                 ("\t\tinline ::Dynamic _hx_set_" ^ remap_name
+                ^ "(::hx::StackContext *_hx_ctx,::Dynamic _hx_v) { \
+                   HX_OBJ_WB(this,_hx_v.mPtr) return " ^ remap_name
+                ^ "=_hx_v; }\n");
+             output (if is_static then "\t\tstatic " else "\t\t");
+             output
+               ("inline ::Dynamic &" ^ remap_name ^ "_dyn() " ^ "{return "
+              ^ remap_name ^ "; }\n")))
+         else
+           let return_type = type_to_string function_def.tf_type in
+           (if (not is_static) && not nonVirtual then
+              let scriptable =
+                Gctx.defined ctx.ctx_common Define.Scriptable
+              in
+              if (not (is_internal_member field.cf_name)) && not scriptable then
+                let key =
+                  join_class_path class_def.cl_path "." ^ "." ^ field.cf_name
+                in
+                try output (Hashtbl.find ctx.ctx_class_member_types key)
+                with Not_found -> ()
+              else output "virtual ");
+           output (if return_type = "Void" then "void" else return_type);
+
+           let remap_name = native_field_name_remap is_static field in
+           output (" " ^ remap_name ^ "(");
+           output (print_arg_list function_def.tf_args "");
+           output ");\n";
+           if doDynamic then (
+             output (if is_static then "\t\tstatic " else "\t\t");
+             output ("::Dynamic " ^ remap_name ^ "_dyn();\n")));
+        output "\n"
+    | _ when has_class_field_flag field CfAbstract ->
+        let ctx_arg_list ctx arg_list prefix =
+          let get_default_value name =
+            try
+              match Meta.get Meta.Value field.cf_meta with
+              | _, [ (EObjectDecl decls, _) ], _ ->
+                  Some
+                    (List.find (fun ((n, _, _), _) -> n = name) decls
+                    |> snd
+                    |> type_constant_value ctx.ctx_common.basic)
+              | _ -> None
+            with Not_found -> None
+          in
+
+          String.concat ","
+            (List.map
+               (fun (n, o, t) -> print_arg n (get_default_value n) t prefix)
+               arg_list)
+        in
+        let tl, tr =
+          match follow field.cf_type with
+          | TFun (tl, tr) -> (tl, tr)
+          | _ -> die "" __LOC__
+        in
+        let return_type = type_to_string tr in
+        let remap_name = native_field_name_remap is_static field in
+        output "virtual ";
+        output (if return_type = "Void" then "void" else return_type);
+        output (" " ^ remap_name ^ "(");
+        output (ctx_arg_list ctx tl "");
+        output
+          (") "
+          ^ (if return_type = "void" then "{}" else "{ return 0; }")
+          ^ "\n");
+        if doDynamic then output ("\t\t::Dynamic " ^ remap_name ^ "_dyn();\n")
+    | _ when has_decl -> output (remap_name ^ "_decl " ^ remap_name ^ ";\n")
+    (* Variable access *)
+    | _ -> (
+        (* Variable access *)
+        let tcpp = cpp_type_of field.cf_type in
+        let tcppStr = tcpp_to_string tcpp in
+        if (not is_static) && only_stack_access field.cf_type then
+          abort
+            ("Variables of type " ^ tcppStr ^ " may not be used as members")
+            field.cf_pos;
+
+        output (tcppStr ^ " " ^ remap_name ^ ";\n");
+        (if (not is_static) && is_gc_element ctx tcpp then
+           let getPtr =
+             match tcpp with TCppString -> ".raw_ref()" | _ -> ".mPtr"
+           in
+           output
+             ("\t\tinline " ^ tcppStr ^ " _hx_set_" ^ remap_name
+            ^ "(::hx::StackContext *_hx_ctx," ^ tcppStr
+            ^ " _hx_v) { HX_OBJ_WB(this,_hx_v" ^ getPtr ^ ") return "
+            ^ remap_name ^ "=_hx_v; }\n"));
+
+        (* Add a "dyn" function for variable to unify variable/function access *)
+        match follow field.cf_type with
+        | _ when nativeGen -> ()
+        | TFun (_, _) ->
+            output (if is_static then "\t\tstatic " else "\t\t");
+            output
+              ("Dynamic " ^ remap_name ^ "_dyn() { return " ^ remap_name
+             ^ ";}\n")
+        | _ -> (
+            (match field.cf_kind with
+            | Var { v_read = AccCall }
+              when (not is_static)
+                   && is_dynamic_accessor ("get_" ^ field.cf_name) "get" field
+                        class_def ->
+                output ("\t\tDynamic get_" ^ field.cf_name ^ ";\n")
+            | _ -> ());
+            match field.cf_kind with
+            | Var { v_write = AccCall }
+              when (not is_static)
+                   && is_dynamic_accessor ("set_" ^ field.cf_name) "set" field
+                        class_def ->
+                output ("\t\tDynamic set_" ^ field.cf_name ^ ";\n")
+            | _ -> ()))
+
+let generate baseCtx class_def =
+  let common_ctx = baseCtx.ctx_common in
+  let class_path = class_def.cl_path in
+  let nativeGen = Meta.has Meta.NativeGen class_def.cl_meta in
+  let smart_class_name = snd class_path in
+  let scriptable =
+    Gctx.defined common_ctx Define.Scriptable && not class_def.cl_private
+  in
+  let class_name = class_name class_def in
+  let ptr_name = class_pointer class_def in
+  let can_quick_alloc = can_quick_alloc class_def in
+  let gcName = gen_gc_name class_def.cl_path in
+  let isContainer = if has_gc_references class_def then "true" else "false" in
+  let cargs = constructor_arg_var_list class_def in
+  let constructor_type_var_list = List.map snd cargs in
+  let constructor_type_args =
+    String.concat ","
+      (List.map (fun (t, a) -> t ^ " " ^ a) constructor_type_var_list)
+  in
+
+  (*let cpp_file = new_cpp_file common_ctx.file class_path in*)
+  let debug =
+    if
+      Meta.has Meta.NoDebug class_def.cl_meta
+      || Gctx.defined baseCtx.ctx_common Define.NoDebug
+    then 0
+    else 1
+  in
+
+  let h_file = new_header_file common_ctx common_ctx.file class_path in
+  let ctx = file_context baseCtx h_file debug true in
+  let strq = strq ctx.ctx_common in
+
+  let parent, super =
+    match class_def.cl_super with
+    | Some (klass, params) ->
+        let name =
+          tcpp_to_string_suffix "_obj" (cpp_instance_type klass params)
+        in
+        ( (if has_class_flag class_def CInterface && nativeGen then "virtual "
+           else "")
+          ^ name,
+          name )
+    | None when nativeGen && has_class_flag class_def CInterface ->
+        ("virtual ::hx::NativeInterface", "::hx::NativeInterface")
+    | None when has_class_flag class_def CInterface -> ("", "::hx::Object")
+    | None when nativeGen -> ("", "")
+    | None -> ("::hx::Object", "::hx::Object")
+  in
+  let output_h = h_file#write in
+  let def_string = join_class_path class_path "_" in
+
+  begin_header_file h_file#write_h def_string nativeGen;
+
+  (* Include the real header file for the super class *)
+  (match class_def.cl_super with
+  | Some super ->
+      let klass = fst super in
+      let include_files = get_all_meta_string_path klass.cl_meta Meta.Include in
+      if List.length include_files > 0 then
+        List.iter
+          (fun inc -> h_file#add_include (path_of_string inc))
+          include_files
+      else h_file#add_include klass.cl_path
+  | _ -> ());
+
+  (* And any interfaces ... *)
+  List.iter
+    (fun imp ->
+      let interface = fst imp in
+      let include_files =
+        get_all_meta_string_path interface.cl_meta Meta.Include
+      in
+      if List.length include_files > 0 then
+        List.iter
+          (fun inc -> h_file#add_include (path_of_string inc))
+          include_files
+      else h_file#add_include interface.cl_path)
+    (real_interfaces class_def.cl_implements);
+
+  (* Only need to forward-declare classes that are mentioned in the header file
+     (ie, not the implementation) *)
+  let super_deps = create_super_dependencies common_ctx in
+  let header_referenced, header_flags =
+    CppReferences.find_referenced_types_flags ctx (TClassDecl class_def) "*"
+      super_deps (Hashtbl.create 0) true false scriptable
+  in
+  List.iter2
+    (fun r f -> gen_forward_decl h_file r f)
+    header_referenced header_flags;
+  output_h "\n";
+
+  output_h (get_class_code class_def Meta.HeaderCode);
+  let includes =
+    get_all_meta_string_path class_def.cl_meta Meta.HeaderInclude
+  in
+  let printer inc = output_h ("#include \"" ^ inc ^ "\"\n") in
+  List.iter printer includes;
+
+  begin_namespace output_h class_path;
+  output_h "\n\n";
+  output_h (get_class_code class_def Meta.HeaderNamespaceCode);
+
+  let extern_class = Gctx.defined common_ctx Define.DllExport in
+  let attribs =
+    "HXCPP_" ^ (if extern_class then "EXTERN_" else "") ^ "CLASS_ATTRIBUTES"
+  in
+
+  let dump_native_interfaces () =
+    List.iter
+      (fun (c, params) ->
+        output_h (" , public virtual " ^ join_class_path c.cl_path "::"))
+      (List.filter
+         (fun (t, _) -> is_native_gen_class t)
+         class_def.cl_implements)
+  in
+
+  if has_class_flag class_def CInterface && not nativeGen then (
+    output_h ("class " ^ attribs ^ " " ^ class_name ^ " {\n");
+    output_h "\tpublic:\n";
+    output_h ("\t\ttypedef " ^ super ^ " super;\n"))
+  else if super = "" then (
+    output_h ("class " ^ attribs ^ " " ^ class_name);
+    dump_native_interfaces ();
+    output_h "\n{\n\tpublic:\n")
+  else (
+    output_h ("class " ^ attribs ^ " " ^ class_name ^ " : public " ^ parent);
+    dump_native_interfaces ();
+    output_h "\n{\n\tpublic:\n";
+    if not nativeGen then (
+      output_h ("\t\ttypedef " ^ super ^ " super;\n");
+      output_h ("\t\ttypedef " ^ class_name ^ " OBJ_;\n")));
+
+  let classId =
+    try Hashtbl.find baseCtx.ctx_type_ids (class_text class_def.cl_path)
+    with Not_found -> Int32.zero
+  in
+  let classIdTxt = Printf.sprintf "0x%08lx" classId in
+
+  if (not (has_class_flag class_def CInterface)) && not nativeGen then (
+    output_h ("\t\t" ^ class_name ^ "();\n");
+    output_h "\n\tpublic:\n";
+    output_h ("\t\tenum { _hx_ClassId = " ^ classIdTxt ^ " };\n\n");
+    output_h ("\t\tvoid __construct(" ^ constructor_type_args ^ ");\n");
+    output_h
+      ("\t\tinline void *operator new(size_t inSize, bool inContainer="
+     ^ isContainer ^ ",const char *inName=" ^ gcName ^ ")\n");
+    output_h
+      "\t\t\t{ return ::hx::Object::operator new(inSize,inContainer,inName); }\n";
+    output_h "\t\tinline void *operator new(size_t inSize, int extra)\n";
+    output_h
+      ("\t\t\t{ return ::hx::Object::operator new(inSize+extra," ^ isContainer
+     ^ "," ^ gcName ^ "); }\n");
+    if has_class_flag class_def CAbstract then output_h "\n"
+    else if
+      can_inline_constructor baseCtx class_def super_deps
+        (create_constructor_dependencies common_ctx)
+    then (
+      output_h "\n";
+      CppGen.generate_constructor ctx
+        (fun str -> output_h ("\t\t" ^ str))
+        class_def true)
+    else (
+      output_h
+        ("\t\tstatic " ^ ptr_name ^ " __new(" ^ constructor_type_args ^ ");\n");
+      if can_quick_alloc then
+        output_h
+          ("\t\tstatic " ^ ptr_name ^ " __alloc(::hx::Ctx *_hx_ctx"
+          ^ (if constructor_type_args = "" then ""
+             else "," ^ constructor_type_args)
+          ^ ");\n"));
+    if not (has_class_flag class_def CAbstract) then (
+      output_h "\t\tstatic void * _hx_vtable;\n";
+      output_h "\t\tstatic Dynamic __CreateEmpty();\n";
+      output_h "\t\tstatic Dynamic __Create(::hx::DynamicArray inArgs);\n");
+    if List.length (CppGen.dynamic_functions class_def) > 0 then
+      output_h
+        ("\t\tstatic void __alloc_dynamic_functions(::hx::Ctx *_hx_alloc,"
+       ^ class_name ^ " *_hx_obj);\n");
+    if scriptable then
+      output_h "\t\tstatic ::hx::ScriptFunction __script_construct;\n";
+    output_h ("\t\t//~" ^ class_name ^ "();\n\n");
+    output_h "\t\tHX_DO_RTTI_ALL;\n";
+    if has_get_member_field class_def then
+      output_h
+        "\t\t::hx::Val __Field(const ::String &inString, ::hx::PropertyAccess \
+         inCallProp);\n";
+    if has_get_static_field class_def then
+      output_h
+        "\t\tstatic bool __GetStatic(const ::String &inString, Dynamic \
+         &outValue, ::hx::PropertyAccess inCallProp);\n";
+    if has_set_member_field class_def then
+      output_h
+        "\t\t::hx::Val __SetField(const ::String &inString,const ::hx::Val \
+         &inValue, ::hx::PropertyAccess inCallProp);\n";
+    if has_set_static_field class_def then
+      output_h
+        "\t\tstatic bool __SetStatic(const ::String &inString, Dynamic \
+         &ioValue, ::hx::PropertyAccess inCallProp);\n";
+    if has_get_fields class_def then
+      output_h "\t\tvoid __GetFields(Array< ::String> &outFields);\n";
+
+    if has_compare_field class_def then
+      output_h
+        ("\t\tint __Compare(const ::hx::Object *inRHS) const { "
+       ^ "return const_cast<" ^ class_name
+       ^ " *>(this)->__compare(Dynamic((::hx::Object *)inRHS)); }\n");
+
+    output_h "\t\tstatic void __register();\n";
+    let native_gen = Meta.has Meta.NativeGen class_def.cl_meta in
+    let needs_gc_funcs = (not native_gen) && has_new_gc_references class_def in
+    if needs_gc_funcs then (
+      output_h "\t\tvoid __Mark(HX_MARK_PARAMS);\n";
+      output_h "\t\tvoid __Visit(HX_VISIT_PARAMS);\n");
+
+    let haxe_implementations, native_implementations =
+      CppGen.implementations class_def
+    in
+    let implements_haxe = Hashtbl.length haxe_implementations > 0 in
+    let implements_native = Hashtbl.length native_implementations > 0 in
+
+    if implements_native then (
+      let implemented_instance_fields =
+        List.filter should_implement_field class_def.cl_ordered_fields
+      in
+      let neededInterfaceFunctions =
+        match implements_native with
+        | true ->
+            CppGen.needed_interface_functions implemented_instance_fields
+              native_implementations
+        | false -> []
+      in
+
+      output_h "\n\t\tHX_NATIVE_IMPLEMENTATION\n";
+      List.iter
+        (fun field ->
+          match (follow field.cf_type, field.cf_kind) with
+          | _, Method MethDynamic -> ()
+          | TFun (args, return_type), _ ->
+              let retVal = type_to_string return_type in
+              let ret = if retVal = "void" then "" else "return " in
+              let name = keyword_remap field.cf_name in
+              let argNames =
+                List.map (fun (name, _, _) -> keyword_remap name) args
+              in
+              output_h
+                ("\t\t" ^ retVal ^ " " ^ name ^ "( "
+                ^ print_tfun_arg_list true args
+                ^ ") {\n");
+              output_h
+                ("\t\t\t" ^ ret ^ "super::" ^ name ^ "( "
+               ^ String.concat "," argNames ^ ");\n\t\t}\n")
+          | _ -> ())
+        neededInterfaceFunctions;
+      output_h "\n");
+
+    output_h "\t\tbool _hx_isInstanceOf(int inClassId);\n";
+    if implements_haxe then (
+      output_h "\t\tvoid *_hx_getInterface(int inHash);\n";
+      (* generate header glue *)
+      let alreadyGlued = Hashtbl.create 0 in
+      Hashtbl.iter
+        (fun interface_name src ->
+          let rec check_interface interface =
+            let check_field field =
+              match (follow field.cf_type, field.cf_kind) with
+              | _, Method MethDynamic -> ()
+              | TFun (args, return_type), Method _ ->
+                  let cast = cpp_tfun_signature false args return_type in
+                  let class_implementation =
+                    find_class_implementation class_def field.cf_name interface
+                  in
+                  let realName = cpp_member_name_of field in
+                  let castKey = realName ^ "::" ^ cast in
+                  let castKey =
+                    if interface_name = "_hx_haxe_IMap" && realName = "set" then
+                      castKey ^ "*"
+                    else castKey
+                  in
+                  let implementationKey =
+                    realName ^ "::" ^ class_implementation
+                  in
+                  if castKey <> implementationKey then
+                    let glue =
+                      Printf.sprintf "%s_%08lx" 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 args in
+                      let returnType = type_to_string return_type in
+                      let headerCode =
+                        "\t\t" ^ returnType ^ " " ^ glue ^ "(" ^ argList
+                        ^ ");\n"
+                      in
+                      output_h headerCode;
+                      output_h "\n")
+              | _ -> ()
+            in
+            (match interface.cl_super with
+            | Some (super, _) -> check_interface super
+            | _ -> ());
+            List.iter check_field interface.cl_ordered_fields
+          in
+          check_interface src)
+        haxe_implementations);
+
+    if has_init_field class_def then output_h "\t\tstatic void __init__();\n\n";
+    output_h
+      ("\t\t::String __ToString() const { return " ^ strq smart_class_name
+     ^ "; }\n\n"))
+  else if not nativeGen then output_h "\t\tHX_DO_INTERFACE_RTTI;\n\n"
+  else (
+    CppGen.generate_native_constructor ctx output_h class_def true;
+    (* native interface *) ());
+
+  if has_boot_field class_def then output_h "\t\tstatic void __boot();\n";
+
+  (match class_def.cl_array_access with
+  | Some t -> output_h ("\t\ttypedef " ^ type_string t ^ " __array_access;\n")
+  | _ -> ());
+
+  List.iter
+    (gen_member_def ctx class_def true (has_class_flag class_def CInterface))
+    (List.filter should_implement_field class_def.cl_ordered_statics);
+
+  let not_toString (field, args, _) =
+    field.cf_name <> "toString" || has_class_flag class_def CInterface
+  in
+  let functions = List.filter not_toString (all_virtual_functions class_def) in
+  if has_class_flag class_def CInterface then
+    List.iter
+      (fun (field, _, _) -> gen_member_def ctx class_def false true field)
+      functions
+  else
+    List.iter
+      (gen_member_def ctx class_def false false)
+      (List.filter should_implement_field class_def.cl_ordered_fields);
+
+  (if has_class_flag class_def CInterface then
+     match get_meta_string class_def.cl_meta Meta.ObjcProtocol with
+     | Some protocol ->
+         output_h
+           ("\t\tstatic id<" ^ protocol
+          ^ "> _hx_toProtocol(Dynamic inImplementation);\n")
+     | None -> ());
+
+  output_h (get_class_code class_def Meta.HeaderClassCode);
+  output_h "};\n\n";
+
+  end_namespace output_h class_path;
+
+  end_header_file output_h def_string;
+
+  h_file#close

+ 1391 - 0
src/generators/cpp/gen/cppGenClassImplementation.ml

@@ -0,0 +1,1391 @@
+open Ast
+open Type
+open Error
+open Globals
+open CppStrings
+open CppTypeUtils
+open CppAst
+open CppAstTools
+open CppSourceWriter
+open CppContext
+open CppGen
+
+let gen_field ctx class_def class_name is_static field =
+  ctx.ctx_real_this_ptr <- not is_static;
+
+  let output = ctx.ctx_output in
+  let remap_name = keyword_remap field.cf_name in
+  let decl = get_meta_string field.cf_meta Meta.Decl in
+  let has_decl = match decl with Some _ -> true | None -> false in
+  match field.cf_expr with
+  (* Function field *)
+  | Some { eexpr = TFunction function_def } ->
+      let return_type_str = type_to_string function_def.tf_type in
+      let nargs = string_of_int (List.length function_def.tf_args) in
+      let return_type = cpp_type_of function_def.tf_type in
+      let is_void = return_type = TCppVoid in
+      let ret = if is_void then "(void)" else "return " in
+
+      let needsWrapper t =
+        match t with
+        | TCppStar _ -> true
+        | TCppInst (t, _) -> Meta.has Meta.StructAccess t.cl_meta
+        | _ -> false
+      in
+      let orig_debug = ctx.ctx_debug_level in
+      let no_debug = Meta.has Meta.NoDebug field.cf_meta in
+
+      if not (is_dynamic_haxe_method field) then (
+        (* The actual function definition *)
+        let remap_name = native_field_name_remap is_static field in
+        output (if is_void then "void" else return_type_str);
+        output (" " ^ class_name ^ "::" ^ remap_name ^ "(");
+        output (print_arg_list function_def.tf_args "__o_");
+        output ")";
+        ctx.ctx_real_this_ptr <- true;
+        let code = get_code field.cf_meta Meta.FunctionCode in
+        let tail_code = get_code field.cf_meta Meta.FunctionTailCode in
+
+        match get_meta_string field.cf_meta Meta.Native with
+        | Some nativeImpl when is_static ->
+            output " {\n";
+            output
+              ("\t" ^ ret ^ "::" ^ nativeImpl ^ "("
+              ^ print_arg_list_name function_def.tf_args "__o_"
+              ^ ");\n");
+            output "}\n\n"
+        | _ ->
+            gen_cpp_function_body ctx class_def is_static field.cf_name
+              function_def code tail_code no_debug;
+
+            output "\n\n";
+            let nonVirtual = Meta.has Meta.NonVirtual field.cf_meta in
+            let doDynamic =
+              (nonVirtual || not (is_override field))
+              && reflective class_def field
+            in
+            (* generate dynamic version too ... *)
+            if doDynamic then
+              let tcpp_args =
+                List.map
+                  (fun (v, _) -> cpp_type_of v.v_type)
+                  function_def.tf_args
+              in
+              let wrap =
+                needsWrapper return_type || List.exists needsWrapper tcpp_args
+              in
+              if wrap then (
+                let wrapName = "_hx_wrap" ^ class_name ^ "_" ^ remap_name in
+                output ("static ::Dynamic " ^ wrapName ^ "( ");
+                let sep = ref " " in
+                if not is_static then (
+                  output "::hx::Object *obj";
+                  sep := ",");
+                ExtList.List.iteri
+                  (fun i _ ->
+                    output (!sep ^ "const Dynamic &a" ^ string_of_int i);
+                    sep := ",")
+                  tcpp_args;
+                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 ");
+
+                if is_static then output (class_name ^ "::" ^ remap_name ^ "(")
+                else
+                  output
+                    ("reinterpret_cast< " ^ class_name ^ " *>(obj)->"
+                   ^ remap_name ^ "(");
+
+                sep := "";
+                ExtList.List.iteri
+                  (fun i arg ->
+                    output !sep;
+                    sep := ",";
+                    (match arg with
+                    | TCppStar (t, const) ->
+                        output
+                          ("(cpp::"
+                          ^ (if const then "Const" else "")
+                          ^ "Pointer<" ^ tcpp_to_string t ^ " >) ")
+                    | TCppInst (t, _) when Meta.has Meta.StructAccess t.cl_meta
+                      ->
+                        output ("(cpp::Struct< " ^ tcpp_to_string arg ^ " >) ")
+                    | _ -> ());
+                    output ("a" ^ string_of_int i))
+                  tcpp_args;
+
+                output ");\n";
+
+                if is_void then output "\treturn null();\n";
+                output "}\n";
+                let nName = string_of_int (List.length tcpp_args) in
+                output
+                  ("::Dynamic " ^ class_name ^ "::" ^ remap_name
+                 ^ "_dyn() {\n\treturn ");
+                if is_static then
+                  output
+                    ("::hx::CreateStaticFunction" ^ nName ^ "(\"" ^ remap_name
+                   ^ "\"," ^ wrapName ^ ");")
+                else
+                  output
+                    ("::hx::CreateMemberFunction" ^ nName ^ "(\"" ^ remap_name
+                   ^ "\",this," ^ wrapName ^ ");");
+                output "}\n")
+              else (
+                if is_static then output "STATIC_";
+                output
+                  ("HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ ","
+                 ^ remap_name ^ "," ^ ret ^ ")\n\n")))
+      else (
+        ctx.ctx_real_this_ptr <- false;
+        let func_name = "__default_" ^ remap_name in
+        output ("HX_BEGIN_DEFAULT_FUNC(" ^ func_name ^ "," ^ class_name ^ ")\n");
+        output return_type_str;
+        output
+          (" _hx_run(" ^ print_arg_list function_def.tf_args "__o_" ^ ")");
+        gen_cpp_function_body ctx class_def is_static func_name function_def ""
+          "" no_debug;
+
+        output ("HX_END_LOCAL_FUNC" ^ nargs ^ "(" ^ ret ^ ")\n");
+        output "HX_END_DEFAULT_FUNC\n\n";
+
+        if is_static then
+          output ("::Dynamic " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"));
+      ctx.ctx_debug_level <- orig_debug
+  (* Data field *)
+  | _ when has_decl ->
+      if is_static then (
+        output (class_name ^ "::" ^ remap_name ^ "_decl ");
+        output (" " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"))
+  | _ ->
+      if is_static && is_physical_field field then (
+        gen_type ctx field.cf_type;
+        output (" " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"))
+      else if has_class_field_flag field CfAbstract then
+        let tl, tr =
+          match follow field.cf_type with
+          | TFun (tl, tr) -> (tl, tr)
+          | _ -> die "" __LOC__
+        in
+        let nargs = string_of_int (List.length tl) in
+        let return_type = cpp_type_of tr in
+        let is_void = return_type = TCppVoid in
+        let ret = if is_void then "(void)" else "return " in
+        output
+          ("HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ ","
+         ^ remap_name ^ "," ^ ret ^ ")\n\n")
+
+let gen_field_init ctx class_def field =
+  let dot_name = join_class_path class_def.cl_path "." in
+  let output = ctx.ctx_output in
+  let remap_name = keyword_remap field.cf_name in
+
+  match field.cf_expr with
+  (* Function field *)
+  | Some { eexpr = TFunction function_def } ->
+      if is_dynamic_haxe_method field then
+        let func_name = "__default_" ^ remap_name in
+        output ("\t" ^ remap_name ^ " = new " ^ func_name ^ ";\n\n")
+  (* Data field *)
+  | Some expr ->
+      let var_name =
+        match remap_name with
+        | "__meta__" -> "__mClass->__meta__"
+        | "__rtti" -> "__mClass->__rtti__"
+        | _ -> remap_name
+      in
+
+      gen_cpp_init ctx dot_name "boot" (var_name ^ " = ") expr
+  | _ -> ()
+
+let cpp_get_interface_slot ctx name =
+  try Hashtbl.find !(ctx.ctx_interface_slot) name
+  with Not_found ->
+    let result = !(ctx.ctx_interface_slot_count) in
+    Hashtbl.replace !(ctx.ctx_interface_slot) name result;
+    ctx.ctx_interface_slot_count := !(ctx.ctx_interface_slot_count) + 1;
+    result
+
+let generate_protocol_delegate ctx class_def output =
+  let protocol =
+    get_meta_string class_def.cl_meta Meta.ObjcProtocol |> Option.default ""
+  in
+  let full_class_name =
+    ("::" ^ join_class_path_remap class_def.cl_path "::") ^ "_obj"
+  in
+  let name = "_hx_" ^ protocol ^ "_delegate" in
+  output ("@interface " ^ name ^ " : NSObject<" ^ protocol ^ "> {\n");
+  output "\t::hx::Object *haxeObj;\n";
+  output "}\n";
+  output "@end\n\n";
+  output ("@implementation " ^ name ^ "\n");
+  output "- (id)initWithImplementation:( ::hx::Object *)inInplemnetation {\n";
+  output "  if (self = [super init]) {\n";
+  output "     self->haxeObj = inInplemnetation;\n";
+  output "     GCAddRoot(&self->haxeObj);\n";
+  output "  }\n";
+  output "  return self;\n";
+  output "}\n";
+  output "- (void)dealloc {\n";
+  output "   GCRemoveRoot(&self->haxeObj);\n";
+  output "   #ifndef OBJC_ARC\n";
+  output "   [super dealloc];\n";
+  output "   #endif\n";
+  output "}\n\n";
+
+  let dump_delegate field =
+    match field.cf_type with
+    | TFun (args, ret) ->
+        let retStr = type_to_string ret in
+        let fieldName, argNames =
+          match get_meta_string field.cf_meta Meta.ObjcProtocol with
+          | Some nativeName ->
+              let parts = ExtString.String.nsplit nativeName ":" in
+              (List.hd parts, parts)
+          | None -> (field.cf_name, List.map (fun (n, _, _) -> n) args)
+        in
+        output ("- (" ^ retStr ^ ") " ^ fieldName);
+
+        let first = ref true in
+        (try
+           List.iter2
+             (fun (name, _, argType) signature_name ->
+               if !first then
+                 output (" :(" ^ type_to_string argType ^ ")" ^ name)
+               else
+                 output
+                   (" " ^ signature_name ^ ":(" ^ type_to_string argType ^ ")"
+                  ^ name);
+               first := false)
+             args argNames
+         with Invalid_argument _ ->
+           abort
+             (let argString =
+                String.concat "," (List.map (fun (name, _, _) -> name) args)
+              in
+              "Invalid arg count in delegate in " ^ field.cf_name ^ " '"
+              ^ field.cf_name ^ "," ^ argString ^ "' != '"
+              ^ String.concat "," argNames ^ "'")
+             field.cf_pos);
+        output " {\n";
+        output "\t::hx::NativeAttach _hx_attach;\n";
+        output
+          ((if retStr = "void" then "\t" else "\treturn ")
+          ^ full_class_name ^ "::"
+          ^ keyword_remap field.cf_name
+          ^ "(haxeObj");
+        List.iter (fun (name, _, _) -> output ("," ^ name)) args;
+        output ");\n}\n\n"
+    | _ -> ()
+  in
+  List.iter dump_delegate class_def.cl_ordered_fields;
+
+  output "@end\n\n"
+
+let generate baseCtx class_def =
+  let common_ctx = baseCtx.ctx_common in
+  let class_path = class_def.cl_path in
+  let debug = baseCtx.ctx_debug_level in
+  let cpp_file = new_placed_cpp_file baseCtx.ctx_common class_path in
+  let cpp_ctx = file_context baseCtx cpp_file debug false in
+  let ctx = cpp_ctx in
+  let output_cpp = cpp_file#write in
+  let strq = strq ctx.ctx_common in
+  let scriptable =
+    Gctx.defined common_ctx Define.Scriptable && not class_def.cl_private
+  in
+
+  let class_super_name =
+    match class_def.cl_super with
+    | Some (klass, params) ->
+        tcpp_to_string_suffix "_obj" (cpp_instance_type klass params)
+    | _ -> ""
+  in
+  if debug > 1 then
+    print_endline
+      ("Found class definition:" ^ join_class_path class_def.cl_path "::");
+
+  cpp_file#write_h "#include <hxcpp.h>\n\n";
+
+  let constructor_deps = create_constructor_dependencies common_ctx in
+  let super_deps = create_super_dependencies common_ctx in
+  let all_referenced =
+    CppReferences.find_referenced_types ctx (TClassDecl class_def) super_deps
+      constructor_deps false false scriptable
+  in
+  List.iter (add_include cpp_file) all_referenced;
+
+  if scriptable then cpp_file#write_h "#include <hx/Scriptable.h>\n";
+
+  cpp_file#write_h "\n";
+
+  output_cpp (get_class_code class_def Meta.CppFileCode);
+  let includes = get_all_meta_string_path class_def.cl_meta Meta.CppInclude in
+  let printer inc = output_cpp ("#include \"" ^ inc ^ "\"\n") in
+  List.iter printer includes;
+
+  begin_namespace output_cpp class_path;
+  output_cpp "\n";
+
+  output_cpp (get_class_code class_def Meta.CppNamespaceCode);
+
+  let nativeGen = Meta.has Meta.NativeGen class_def.cl_meta in
+  let class_name = class_name class_def in
+  let cargs = constructor_arg_var_list class_def in
+  let constructor_type_var_list = List.map snd cargs in
+  let constructor_var_list = List.map snd constructor_type_var_list in
+  let constructor_type_args =
+    String.concat ","
+      (List.map (fun (t, a) -> t ^ " " ^ a) constructor_type_var_list)
+  in
+  let haxe_implementations, native_implementations =
+    implementations class_def
+  in
+
+  if (not (has_class_flag class_def CInterface)) && not nativeGen then (
+    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")
+    | _ -> output_cpp " { }\n\n");
+
+    (* Destructor goes in the cpp file so we can "see" the full definition of the member vars *)
+    if not (has_class_flag class_def CAbstract) then (
+      let ptr_name = class_pointer class_def in
+      let array_arg_list inList =
+        (* Convert an array to a comma separated list of values *)
+        let i = ref (0 - 1) in
+        String.concat ","
+          (List.map
+             (fun _ ->
+               incr i;
+               "inArgs[" ^ string_of_int !i ^ "]")
+             inList)
+      in
+
+      output_cpp
+        ("Dynamic " ^ class_name ^ "::__CreateEmpty() { return new "
+       ^ class_name ^ "; }\n\n");
+      output_cpp ("void *" ^ class_name ^ "::_hx_vtable = 0;\n\n");
+
+      output_cpp
+        ("Dynamic " ^ class_name ^ "::__Create(::hx::DynamicArray inArgs)\n");
+      output_cpp
+        ("{\n\t" ^ ptr_name ^ " _hx_result = new " ^ class_name ^ "();\n");
+      output_cpp
+        ("\t_hx_result->__construct("
+        ^ array_arg_list constructor_var_list
+        ^ ");\n");
+      output_cpp "\treturn _hx_result;\n}\n\n");
+    let rec addParent cls others =
+      match cls.cl_super with
+      | Some (super, _) -> (
+          try
+            let parentId =
+              Hashtbl.find ctx.ctx_type_ids (class_text super.cl_path)
+            in
+            addParent super (parentId :: others)
+          with Not_found -> others)
+      | _ -> others
+    in
+    let classId =
+      try Hashtbl.find baseCtx.ctx_type_ids (class_text class_def.cl_path)
+      with Not_found -> Int32.zero
+    in
+    let implemented_classes = addParent class_def [ classId; Int32.of_int 1 ] in
+    let implemented_classes = List.sort compare implemented_classes in
+
+    output_cpp ("bool " ^ class_name ^ "::_hx_isInstanceOf(int inClassId) {\n");
+    let txt cId = Printf.sprintf "0x%08lx" cId in
+    let rec dump_classes indent classes =
+      match classes with
+      | [] -> ()
+      | [ c ] -> output_cpp (indent ^ "return inClassId==(int)" ^ txt c ^ ";\n")
+      | [ c; c1 ] ->
+          output_cpp
+            (indent ^ "return inClassId==(int)" ^ txt c ^ " || inClassId==(int)"
+           ^ txt c1 ^ ";\n")
+      | _ ->
+          let len = List.length classes in
+          let mid = List.nth classes (len / 2) in
+          let low, high = List.partition (fun e -> e <= mid) classes in
+          output_cpp (indent ^ "if (inClassId<=(int)" ^ txt mid ^ ") {\n");
+          dump_classes (indent ^ "\t") low;
+          output_cpp (indent ^ "} else {\n");
+          dump_classes (indent ^ "\t") high;
+          output_cpp (indent ^ "}\n")
+    in
+    dump_classes "\t" implemented_classes;
+    output_cpp "}\n\n";
+
+    let implements_haxe_keys = hash_keys haxe_implementations in
+    let implements_haxe = Hashtbl.length haxe_implementations > 0 in
+
+    if implements_haxe then (
+      let alreadyGlued = Hashtbl.create 0 in
+      let cname = "_hx_" ^ join_class_path class_def.cl_path "_" in
+      let implname = cpp_class_name class_def in
+      let cpp_glue = ref [] in
+      List.iter
+        (fun interface_name ->
+          try
+            let interface = Hashtbl.find haxe_implementations interface_name in
+            output_cpp
+              ("static " ^ cpp_class_name interface ^ " " ^ cname ^ "_"
+             ^ interface_name ^ "= {\n");
+            let rec gen_interface_funcs interface =
+              let gen_field field =
+                match (follow field.cf_type, field.cf_kind) with
+                | _, Method MethDynamic -> ()
+                | TFun (args, return_type), Method _ ->
+                    let cast = cpp_tfun_signature false args return_type in
+                    let class_implementation =
+                      find_class_implementation class_def field.cf_name
+                        interface
+                    in
+                    let realName = cpp_member_name_of field in
+                    let castKey = realName ^ "::" ^ cast in
+                    (* C++ can't work out which function it needs to take the addrss of
+                       when the implementation is overloaded - currently the map-set functions.
+                       Change the castKey to force a glue function in this case (could double-cast the pointer, but it is ugly)
+                    *)
+                    let castKey =
+                      if interface_name = "_hx_haxe_IMap" && realName = "set"
+                      then castKey ^ "*"
+                      else castKey
+                    in
+                    let implementationKey =
+                      realName ^ "::" ^ class_implementation
+                    in
+                    if castKey <> implementationKey then (
+                      let glue =
+                        Printf.sprintf "%s_%08lx" 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 args in
+                        let returnType = type_to_string return_type in
+                        let returnStr =
+                          if returnType = "void" then "" else "return "
+                        in
+                        let cppCode =
+                          returnType ^ " " ^ class_name ^ "::" ^ glue ^ "("
+                          ^ argList ^ ") {\n" ^ "\t\t\t" ^ returnStr ^ realName
+                          ^ "(" ^ print_arg_names args ^ ");\n}\n"
+                        in
+                        (* let headerCode = "\t\t" ^ returnType ^ " " ^ glue ^ "(" ^ argList ^ ");\n" in *)
+                        (* header_glue := headerCode :: !header_glue; *)
+                        cpp_glue := cppCode :: !cpp_glue);
+                      output_cpp
+                        ("\t" ^ cast ^ "&" ^ implname ^ "::" ^ glue ^ ",\n"))
+                    else
+                      output_cpp
+                        ("\t" ^ cast ^ "&" ^ implname ^ "::" ^ realName ^ ",\n")
+                | _ -> ()
+              in
+              (match interface.cl_super with
+              | Some super -> gen_interface_funcs (fst super)
+              | _ -> ());
+              List.iter gen_field interface.cl_ordered_fields
+            in
+            gen_interface_funcs interface;
+            output_cpp "};\n\n"
+          with Not_found -> ())
+        implements_haxe_keys;
+
+      output_cpp (String.concat "\n" !cpp_glue);
+
+      output_cpp ("void *" ^ class_name ^ "::_hx_getInterface(int inHash) {\n");
+      output_cpp "\tswitch(inHash) {\n";
+      List.iter
+        (fun interface_name ->
+          try
+            let interface = Hashtbl.find haxe_implementations interface_name in
+            output_cpp
+              ("\t\tcase (int)" ^ cpp_class_hash interface ^ ": return &"
+             ^ cname ^ "_" ^ interface_name ^ ";\n")
+          with Not_found -> ())
+        implements_haxe_keys;
+
+      output_cpp "\t}\n";
+
+      if class_super_name = "" then (
+        output_cpp "\t#ifdef HXCPP_SCRIPTABLE\n";
+        output_cpp "\treturn super::_hx_getInterface(inHash);\n";
+        output_cpp "\t#else\n";
+        output_cpp "\treturn 0;\n";
+        output_cpp "\t#endif\n")
+      else output_cpp "\treturn super::_hx_getInterface(inHash);\n";
+      output_cpp "}\n\n"));
+
+  (match TClass.get_cl_init class_def with
+  | Some expression ->
+      let ctx = file_context baseCtx cpp_file debug false in
+      output_cpp ("void " ^ class_name ^ "::__init__()");
+      gen_cpp_init ctx (cpp_class_name class_def) "__init__" ""
+        (mk_block expression);
+      output_cpp "\n\n"
+  | _ -> ());
+
+  let dump_field_name field = output_cpp ("\t" ^ strq field.cf_name ^ ",\n") in
+  let statics_except_meta = statics_except_meta class_def in
+  let implemented_fields =
+    List.filter should_implement_field statics_except_meta
+  in
+
+  List.iter
+    (gen_field ctx class_def class_name false)
+    class_def.cl_ordered_fields;
+  List.iter (gen_field ctx class_def class_name true) statics_except_meta;
+  output_cpp "\n";
+
+  let dynamic_functions = dynamic_functions class_def in
+  if List.length dynamic_functions > 0 then (
+    output_cpp
+      ("void " ^ class_name ^ "::__alloc_dynamic_functions(::hx::Ctx *_hx_ctx,"
+     ^ class_name ^ " *_hx_obj) {\n");
+    List.iter
+      (fun name ->
+        output_cpp
+          ("\tif (!_hx_obj->" ^ name ^ ".mPtr) _hx_obj->" ^ name
+         ^ " = new __default_" ^ name ^ "(_hx_obj);\n"))
+      dynamic_functions;
+    (match class_def.cl_super with
+    | Some super ->
+        let rec find_super class_def =
+          if has_dynamic_member_functions class_def then
+            let super_name =
+              join_class_path_remap class_def.cl_path "::" ^ "_obj"
+            in
+            output_cpp
+              ("\t" ^ super_name
+             ^ "::__alloc_dynamic_functions(_hx_ctx,_hx_obj);\n")
+          else
+            match class_def.cl_super with
+            | Some super -> find_super (fst super)
+            | _ -> ()
+        in
+        find_super (fst super)
+    | _ -> ());
+    output_cpp "}\n");
+
+  let inline_constructor =
+    can_inline_constructor baseCtx class_def super_deps
+      (create_constructor_dependencies common_ctx)
+  in
+  if
+    (not (has_class_flag class_def CInterface))
+    && (not nativeGen) && (not inline_constructor)
+    && not (has_class_flag class_def CAbstract)
+  then generate_constructor ctx output_cpp class_def false
+  else if nativeGen then
+    generate_native_constructor ctx output_cpp class_def false;
+
+  let reflect_member_fields =
+    List.filter (reflective class_def) class_def.cl_ordered_fields
+  in
+  let reflect_static_fields =
+    List.filter (reflective class_def) statics_except_meta
+  in
+
+  (* Initialise non-static variables *)
+  if (not (has_class_flag class_def CInterface)) && not nativeGen then (
+    output_cpp (class_name ^ "::" ^ class_name ^ "()\n{\n");
+    List.iter
+      (fun name ->
+        output_cpp ("\t" ^ name ^ " = new __default_" ^ name ^ "(this);\n"))
+      dynamic_functions;
+    output_cpp "}\n\n";
+
+    let dump_field_iterator macro field =
+      if is_data_member field then (
+        let remap_name = keyword_remap field.cf_name in
+        output_cpp
+          ("\t" ^ macro ^ "(" ^ remap_name ^ ",\"" ^ field.cf_name ^ "\");\n");
+
+        (match field.cf_kind with
+        | Var { v_read = AccCall }
+          when is_dynamic_accessor ("get_" ^ field.cf_name) "get" field
+                 class_def ->
+            let name = "get_" ^ field.cf_name in
+            output_cpp ("\t" ^ macro ^ "(" ^ name ^ "," ^ "\"" ^ name ^ "\");\n")
+        | _ -> ());
+        match field.cf_kind with
+        | Var { v_write = AccCall }
+          when is_dynamic_accessor ("set_" ^ field.cf_name) "set" field
+                 class_def ->
+            let name = "set_" ^ field.cf_name in
+            output_cpp ("\t" ^ macro ^ "(" ^ name ^ "," ^ "\"" ^ name ^ "\");\n")
+        | _ -> ())
+    in
+
+    let implemented_instance_fields =
+      List.filter should_implement_field class_def.cl_ordered_fields
+    in
+
+    let override_iteration =
+      (not nativeGen) && has_new_gc_references class_def
+    in
+    if override_iteration then (
+      let super_needs_iteration = find_next_super_iteration class_def in
+      let smart_class_name = snd class_path in
+      (* MARK function - explicitly mark all child pointers *)
+      output_cpp ("void " ^ class_name ^ "::__Mark(HX_MARK_PARAMS)\n{\n");
+      output_cpp ("\tHX_MARK_BEGIN_CLASS(" ^ smart_class_name ^ ");\n");
+      List.iter
+        (dump_field_iterator "HX_MARK_MEMBER_NAME")
+        implemented_instance_fields;
+      (match super_needs_iteration with
+      | "" -> ()
+      | super -> output_cpp ("\t" ^ super ^ "::__Mark(HX_MARK_ARG);\n"));
+      output_cpp "\tHX_MARK_END_CLASS();\n";
+      output_cpp "}\n\n";
+
+      (* Visit function - explicitly visit all child pointers *)
+      output_cpp ("void " ^ class_name ^ "::__Visit(HX_VISIT_PARAMS)\n{\n");
+      List.iter
+        (dump_field_iterator "HX_VISIT_MEMBER_NAME")
+        implemented_instance_fields;
+      (match super_needs_iteration with
+      | "" -> ()
+      | super -> output_cpp ("\t" ^ super ^ "::__Visit(HX_VISIT_ARG);\n"));
+      output_cpp "}\n\n");
+
+    let dump_quick_field_test fields =
+      if List.length fields > 0 then (
+        let len = function _, l, _ -> l in
+        let sfields = List.sort (fun f1 f2 -> len f1 - len f2) fields in
+        let len_case = ref (-1) in
+        output_cpp "\tswitch(inName.length) {\n";
+        List.iter
+          (fun (field, l, result) ->
+            if l <> !len_case then (
+              if !len_case >= 0 then output_cpp "\t\tbreak;\n";
+              output_cpp ("\tcase " ^ string_of_int l ^ ":\n");
+              len_case := l);
+            output_cpp
+              ("\t\tif (HX_FIELD_EQ(inName,\""
+              ^ StringHelper.s_escape field
+              ^ "\") ) { " ^ result ^ " }\n"))
+          sfields;
+        output_cpp "\t}\n")
+    in
+
+    let checkPropCall field =
+      if
+        Meta.has Meta.NativeProperty class_def.cl_meta
+        || Meta.has Meta.NativeProperty field.cf_meta
+        || Gctx.defined common_ctx Define.ForceNativeProperty
+      then "inCallProp != ::hx::paccNever"
+      else "inCallProp == ::hx::paccAlways"
+    in
+
+    let toCommon t f value =
+      t ^ "( "
+      ^ (match cpp_type_of f.cf_type with
+        | TCppInst (t, _) as inst when Meta.has Meta.StructAccess t.cl_meta ->
+            "cpp::Struct< " ^ tcpp_to_string inst ^ " >( " ^ value ^ " )"
+        | TCppStar (t, _) -> "cpp::Pointer<void *>( " ^ value ^ " )"
+        | _ -> value)
+      ^ " )"
+    in
+    let toVal f value = toCommon "::hx::Val" f value in
+    let toDynamic f value = toCommon "" f value in
+
+    if has_get_member_field class_def then (
+      (* Dynamic "Get" Field function - string version *)
+      output_cpp
+        ("::hx::Val " ^ class_name
+       ^ "::__Field(const ::String &inName,::hx::PropertyAccess inCallProp)\n\
+          {\n");
+      let get_field_dat =
+        List.map (fun f ->
+            ( f.cf_name,
+              String.length f.cf_name,
+              match f.cf_kind with
+              | Var { v_read = AccCall } when not (is_physical_field f) ->
+                  "if (" ^ checkPropCall f ^ ") return "
+                  ^ toVal f (keyword_remap ("get_" ^ f.cf_name) ^ "()")
+                  ^ ";"
+              | Var { v_read = AccCall } ->
+                  "return "
+                  ^ toVal f
+                      (checkPropCall f ^ " ? "
+                      ^ keyword_remap ("get_" ^ f.cf_name)
+                      ^ "() : " ^ keyword_remap f.cf_name
+                      ^ if variable_field f then "" else "_dyn()")
+                  ^ ";"
+              | _ ->
+                  "return "
+                  ^ toVal f
+                      (keyword_remap f.cf_name
+                      ^ if variable_field f then "" else "_dyn()")
+                  ^ ";" ))
+      in
+      let reflect_member_readable =
+        List.filter (is_readable class_def) reflect_member_fields
+      in
+      dump_quick_field_test (get_field_dat reflect_member_readable);
+      output_cpp "\treturn super::__Field(inName,inCallProp);\n}\n\n");
+
+    if has_get_static_field class_def then (
+      output_cpp
+        ("bool " ^ class_name
+       ^ "::__GetStatic(const ::String &inName, Dynamic &outValue, \
+          ::hx::PropertyAccess inCallProp)\n\
+          {\n");
+      let get_field_dat =
+        List.map (fun f ->
+            ( f.cf_name,
+              String.length f.cf_name,
+              match f.cf_kind with
+              | Var { v_read = AccCall } when not (is_physical_field f) ->
+                  "if (" ^ checkPropCall f ^ ") { outValue = "
+                  ^ toDynamic f (keyword_remap ("get_" ^ f.cf_name) ^ "()")
+                  ^ "; return true; }"
+              | Var { v_read = AccCall } ->
+                  "outValue = "
+                  ^ toDynamic f
+                      (checkPropCall f ^ " ? "
+                      ^ keyword_remap ("get_" ^ f.cf_name)
+                      ^ "() : " ^ keyword_remap f.cf_name
+                      ^ if variable_field f then "" else "_dyn()")
+                  ^ "; return true;"
+              | _ when variable_field f ->
+                  "outValue = "
+                  ^ toDynamic f (keyword_remap f.cf_name)
+                  ^ "; return true;"
+              | _ ->
+                  "outValue = "
+                  ^ native_field_name_remap true f
+                  ^ "_dyn(); return true;" ))
+      in
+      let reflect_static_readable =
+        List.filter (is_readable class_def) reflect_static_fields
+      in
+      dump_quick_field_test (get_field_dat reflect_static_readable);
+      output_cpp "\treturn false;\n}\n\n");
+
+    let castable f =
+      match cpp_type_of 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
+    in
+
+    (* Dynamic "Set" Field function *)
+    if has_set_member_field class_def then (
+      output_cpp
+        ("::hx::Val " ^ class_name
+       ^ "::__SetField(const ::String &inName,const ::hx::Val \
+          &inValue,::hx::PropertyAccess inCallProp)\n\
+          {\n");
+
+      let set_field_dat =
+        List.map (fun f ->
+            let default_action =
+              if is_gc_element ctx (cpp_type_of f.cf_type) then
+                "_hx_set_" ^ keyword_remap f.cf_name
+                ^ "(HX_CTX_GET,inValue.Cast< " ^ castable f ^ " >());"
+                ^ " return inValue;"
+              else
+                keyword_remap f.cf_name ^ "=inValue.Cast< " ^ castable f
+                ^ " >();" ^ " return inValue;"
+            in
+            ( f.cf_name,
+              String.length f.cf_name,
+              match f.cf_kind with
+              | Var { v_write = AccCall } ->
+                  let inVal = "(inValue.Cast< " ^ castable f ^ " >())" in
+                  let setter = keyword_remap ("set_" ^ f.cf_name) in
+                  "if (" ^ checkPropCall f ^ ") return "
+                  ^ toVal f (setter ^ inVal)
+                  ^ ";"
+                  ^ if not (is_physical_field f) then "" else default_action
+              | _ -> default_action ))
+      in
+
+      let reflect_member_writable =
+        List.filter (is_writable class_def) reflect_member_fields
+      in
+      let reflect_write_member_variables =
+        List.filter variable_field reflect_member_writable
+      in
+      dump_quick_field_test (set_field_dat reflect_write_member_variables);
+      output_cpp "\treturn super::__SetField(inName,inValue,inCallProp);\n}\n\n");
+
+    if has_set_static_field class_def then (
+      output_cpp
+        ("bool " ^ class_name
+       ^ "::__SetStatic(const ::String &inName,Dynamic \
+          &ioValue,::hx::PropertyAccess inCallProp)\n\
+          {\n");
+
+      let set_field_dat =
+        List.map (fun f ->
+            let default_action =
+              keyword_remap f.cf_name ^ "=ioValue.Cast< " ^ castable f
+              ^ " >(); return true;"
+            in
+            ( f.cf_name,
+              String.length f.cf_name,
+              match f.cf_kind with
+              | Var { v_write = AccCall } ->
+                  let inVal = "(ioValue.Cast< " ^ castable f ^ " >())" in
+                  let setter = keyword_remap ("set_" ^ f.cf_name) in
+                  "if (" ^ checkPropCall f ^ ")  ioValue = "
+                  ^ toDynamic f (setter ^ inVal)
+                  ^ ";"
+                  ^
+                  if not (is_physical_field f) then ""
+                  else " else " ^ default_action
+              | _ -> default_action ))
+      in
+
+      let reflect_static_writable =
+        List.filter (is_writable class_def) reflect_static_fields
+      in
+      let reflect_write_static_variables =
+        List.filter variable_field reflect_static_writable
+      in
+      dump_quick_field_test (set_field_dat reflect_write_static_variables);
+      output_cpp "\treturn false;\n}\n\n");
+
+    (* For getting a list of data members (eg, for serialization) *)
+    if has_get_fields class_def then (
+      let append_field field =
+        output_cpp ("\toutFields->push(" ^ strq field.cf_name ^ ");\n")
+      in
+      let is_data_field field =
+        match follow field.cf_type with TFun _ -> false | _ -> true
+      in
+
+      output_cpp
+        ("void " ^ class_name
+       ^ "::__GetFields(Array< ::String> &outFields)\n{\n");
+      List.iter append_field
+        (List.filter is_data_field class_def.cl_ordered_fields);
+      output_cpp "\tsuper::__GetFields(outFields);\n";
+      output_cpp "};\n\n");
+
+    let storage field =
+      match cpp_type_of field.cf_type with
+      | TCppScalar "bool" -> "::hx::fsBool"
+      | TCppScalar "int" -> "::hx::fsInt"
+      | TCppScalar "Float" -> "::hx::fsFloat"
+      | TCppString -> "::hx::fsString"
+      | o when is_object_element o ->
+          "::hx::fsObject" ^ " /* " ^ tcpp_to_string o ^ " */ "
+      | u -> "::hx::fsUnknown" ^ " /* " ^ tcpp_to_string u ^ " */ "
+    in
+    let dump_member_storage field =
+      output_cpp
+        ("\t{" ^ storage field ^ ",(int)offsetof(" ^ class_name ^ ","
+        ^ keyword_remap field.cf_name
+        ^ ")," ^ strq field.cf_name ^ "},\n")
+    in
+    let dump_static_storage field =
+      output_cpp
+        ("\t{" ^ storage field ^ ",(void *) &" ^ class_name ^ "::"
+        ^ keyword_remap field.cf_name
+        ^ "," ^ strq field.cf_name ^ "},\n")
+    in
+
+    output_cpp "#ifdef HXCPP_SCRIPTABLE\n";
+
+    let stored_fields =
+      List.filter is_data_member implemented_instance_fields
+    in
+    if List.length stored_fields > 0 then (
+      output_cpp
+        ("static ::hx::StorageInfo " ^ class_name
+       ^ "_sMemberStorageInfo[] = {\n");
+      List.iter dump_member_storage stored_fields;
+      output_cpp "\t{ ::hx::fsUnknown, 0, null()}\n};\n")
+    else
+      output_cpp
+        ("static ::hx::StorageInfo *" ^ class_name
+       ^ "_sMemberStorageInfo = 0;\n");
+
+    let stored_statics = List.filter is_data_member implemented_fields in
+    if List.length stored_statics > 0 then (
+      output_cpp
+        ("static ::hx::StaticInfo " ^ class_name ^ "_sStaticStorageInfo[] = {\n");
+      List.iter dump_static_storage stored_statics;
+      output_cpp "\t{ ::hx::fsUnknown, 0, null()}\n};\n")
+    else
+      output_cpp
+        ("static ::hx::StaticInfo *" ^ class_name ^ "_sStaticStorageInfo = 0;\n");
+
+    output_cpp "#endif\n\n");
+
+  (* cl_interface *)
+  let implemented_instance_fields =
+    List.filter should_implement_field class_def.cl_ordered_fields
+  in
+  let reflective_members =
+    List.filter (reflective class_def) implemented_instance_fields
+  in
+  let sMemberFields =
+    match reflective_members with
+    | [] -> "0 /* sMemberFields */"
+    | _ ->
+        let memberFields = class_name ^ "_sMemberFields" in
+        output_cpp ("static ::String " ^ memberFields ^ "[] = {\n");
+        List.iter dump_field_name reflective_members;
+        output_cpp "\t::String(null()) };\n\n";
+        memberFields
+  in
+
+  let hasMarkFunc =
+    (not nativeGen) && List.exists is_data_member implemented_fields
+  in
+
+  if hasMarkFunc then (
+    (* Mark static variables as used *)
+    output_cpp
+      ("static void " ^ class_name ^ "_sMarkStatics(HX_MARK_PARAMS) {\n");
+    List.iter
+      (fun field ->
+        if is_data_member field then
+          output_cpp
+            ("\tHX_MARK_MEMBER_NAME(" ^ class_name ^ "::"
+            ^ keyword_remap field.cf_name
+            ^ ",\"" ^ field.cf_name ^ "\");\n"))
+      implemented_fields;
+    output_cpp "};\n\n";
+
+    (* Visit static variables *)
+    output_cpp "#ifdef HXCPP_VISIT_ALLOCS\n";
+    output_cpp
+      ("static void " ^ class_name ^ "_sVisitStatics(HX_VISIT_PARAMS) {\n");
+    List.iter
+      (fun field ->
+        if is_data_member field then
+          output_cpp
+            ("\tHX_VISIT_MEMBER_NAME(" ^ class_name ^ "::"
+            ^ keyword_remap field.cf_name
+            ^ ",\"" ^ field.cf_name ^ "\");\n"))
+      implemented_fields;
+    output_cpp "};\n\n";
+    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) && not (has_class_flag class_def CInterface)
+        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 dump_call cast =
+          if has_class_flag class_def CInterface then
+            output_cpp
+              (class_name ^ "::" ^ callName ^ "(ctx->getThis()"
+              ^ if List.length args > 0 then "," else "")
+          else 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 ""
+        in
+
+        if ret <> "v" then output_cpp ")";
+        output_cpp ";\n}\n";
+        signature
+    | _ -> ""
+  in
+
+  let newInteface = has_class_flag class_def CInterface in
+
+  if scriptable && not nativeGen then (
+    let delegate = "this->" in
+    let dump_script_field idx (field, f_args, return_t) =
+      let args = print_tfun_arg_list true f_args in
+      let names = List.map (fun (n, _, _) -> keyword_remap n) f_args in
+      let return_type = type_to_string return_t in
+      let ret =
+        if return_type = "Void" || return_type = "void" then " " else "return "
+      in
+      let name = keyword_remap field.cf_name in
+      let vtable = "__scriptVTable[" ^ string_of_int (idx + 1) ^ "] " in
+      let args_varray =
+        List.fold_left
+          (fun l n -> l ^ ".Add(" ^ n ^ ")")
+          "Array<Dynamic>()" names
+      in
+
+      output_cpp ("\t" ^ return_type ^ " " ^ name ^ "( " ^ args ^ " ) {\n");
+      if newInteface then (
+        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) ->
+            output_cpp
+              ("\t\t__ctx->push" ^ CppCppia.script_type t opt ^ "("
+             ^ keyword_remap name ^ ");\n"))
+          f_args;
+        let interfaceSlot = string_of_int (-cpp_get_interface_slot ctx name) in
+        output_cpp
+          ("\t\t" ^ ret ^ "__ctx->run"
+          ^ CppCppia.script_type return_t false
+          ^ "(__GetScriptVTable()[" ^ interfaceSlot ^ "]);\n");
+        output_cpp "\t}\n")
+      else (
+        output_cpp ("\tif (" ^ vtable ^ ") {\n");
+        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("
+          ^ (if has_class_flag class_def CInterface then "mDelegate.mPtr"
+             else "this")
+          ^ ");\n");
+        List.iter
+          (fun (name, opt, t) ->
+            output_cpp
+              ("\t\t__ctx->push" ^ CppCppia.script_type t opt ^ "("
+             ^ keyword_remap name ^ ");\n"))
+          f_args;
+        output_cpp
+          ("\t\t" ^ ret ^ "__ctx->run"
+          ^ CppCppia.script_type return_t false
+          ^ "(" ^ vtable ^ ");\n");
+        output_cpp ("\t}  else " ^ ret);
+
+        if has_class_flag class_def CInterface then (
+          output_cpp
+            (" " ^ delegate ^ "__Field(HX_CSTRING(\"" ^ field.cf_name
+           ^ "\"), ::hx::paccNever)");
+          if List.length names <= 5 then
+            output_cpp ("->__run(" ^ String.concat "," names ^ ");")
+          else output_cpp ("->__Run(" ^ args_varray ^ ");"))
+        else
+          output_cpp
+            (class_name ^ "::" ^ name ^ "(" ^ String.concat "," names ^ ");");
+        if return_type <> "void" then output_cpp "return null();";
+        output_cpp "}\n";
+        let dynamic_interface_closures =
+          Gctx.defined baseCtx.ctx_common Define.DynamicInterfaceClosures
+        in
+        if has_class_flag class_def CInterface && not dynamic_interface_closures
+        then
+          output_cpp
+            ("\tDynamic " ^ name
+           ^ "_dyn() { return mDelegate->__Field(HX_CSTRING(\"" ^ field.cf_name
+           ^ "\"), ::hx::paccNever); }\n\n"))
+    in
+
+    let new_sctipt_functions =
+      if newInteface then all_virtual_functions class_def
+      else List.rev (current_virtual_functions_rev class_def [])
+    in
+    let sctipt_name = class_name ^ "__scriptable" in
+
+    if newInteface then (
+      output_cpp ("class " ^ sctipt_name ^ " : public ::hx::Object {\n");
+      output_cpp "public:\n")
+    else (
+      output_cpp ("class " ^ sctipt_name ^ " : public " ^ class_name ^ " {\n");
+      output_cpp ("   typedef " ^ sctipt_name ^ " __ME;\n");
+      output_cpp ("   typedef " ^ class_name ^ " super;\n");
+      let field_arg_count field =
+        match (follow field.cf_type, field.cf_kind) with
+        | _, Method MethDynamic -> -1
+        | TFun (args, return_type), Method _ -> List.length args
+        | _, _ -> -1
+      in
+      let has_funky_toString =
+        List.exists
+          (fun f -> f.cf_name = "toString")
+          class_def.cl_ordered_statics
+        || List.exists
+             (fun f -> f.cf_name = "toString" && field_arg_count f <> 0)
+             class_def.cl_ordered_fields
+      in
+      let super_string =
+        if has_funky_toString then class_name ^ "::super" else class_name
+      in
+      output_cpp ("   typedef " ^ super_string ^ " __superString;\n");
+      if has_class_flag class_def CInterface then
+        output_cpp "   HX_DEFINE_SCRIPTABLE_INTERFACE\n"
+      else (
+        output_cpp
+          ("   HX_DEFINE_SCRIPTABLE(HX_ARR_LIST"
+          ^ string_of_int (List.length constructor_var_list)
+          ^ ")\n");
+        output_cpp "\tHX_DEFINE_SCRIPTABLE_DYNAMIC;\n"));
+
+    let list_iteri func in_list =
+      let idx = ref 0 in
+      List.iter
+        (fun elem ->
+          func !idx elem;
+          idx := !idx + 1)
+        in_list
+    in
+
+    let not_toString (field, args, _) =
+      field.cf_name <> "toString" || has_class_flag class_def CInterface
+    in
+    let functions =
+      List.filter not_toString (all_virtual_functions class_def)
+    in
+    list_iteri dump_script_field functions;
+    output_cpp "};\n\n";
+
+    let sigs = Hashtbl.create 0 in
+
+    let static_functions =
+      List.filter (fun f -> not (is_data_member f)) reflect_static_fields
+    in
+    let all_script_functions =
+      List.map (fun (f, _, _) -> f) new_sctipt_functions @ static_functions
+    in
+
+    if List.length all_script_functions > 0 then (
+      List.iter
+        (fun (f, _, _) ->
+          let s =
+            generate_script_function false f ("__s_" ^ f.cf_name)
+              (keyword_remap f.cf_name)
+          in
+          Hashtbl.add sigs f.cf_name s)
+        new_sctipt_functions;
+
+      let dump_script_static f =
+        let s =
+          generate_script_function true f ("__s_" ^ f.cf_name)
+            (keyword_remap f.cf_name)
+        in
+        Hashtbl.add sigs f.cf_name s
+      in
+      List.iter dump_script_static class_def.cl_ordered_statics;
+
+      output_cpp "#ifndef HXCPP_CPPIA_SUPER_ARG\n";
+      output_cpp "#define HXCPP_CPPIA_SUPER_ARG(x)\n";
+      output_cpp "#endif\n";
+      output_cpp
+        "static ::hx::ScriptNamedFunction __scriptableFunctions[] = {\n";
+      let dump_func f isStaticFlag =
+        let s = try Hashtbl.find sigs f.cf_name with Not_found -> "v" in
+        output_cpp
+          ("  ::hx::ScriptNamedFunction(\"" ^ f.cf_name ^ "\",__s_" ^ f.cf_name
+         ^ ",\"" ^ s ^ "\", " ^ isStaticFlag ^ " ");
+        let superCall =
+          if isStaticFlag = "true" || has_class_flag class_def CInterface then
+            "0"
+          else "__s_" ^ f.cf_name ^ "<true>"
+        in
+        output_cpp ("HXCPP_CPPIA_SUPER_ARG(" ^ superCall ^ ")");
+        output_cpp " ),\n"
+      in
+      List.iter (fun (f, _, _) -> dump_func f "false") new_sctipt_functions;
+      List.iter (fun f -> dump_func f "true") static_functions;
+      output_cpp
+        "  ::hx::ScriptNamedFunction(0,0,0 HXCPP_CPPIA_SUPER_ARG(0) ) };\n")
+    else
+      output_cpp
+        "static ::hx::ScriptNamedFunction *__scriptableFunctions = 0;\n";
+
+    if newInteface then (
+      output_cpp ("\n\n" ^ class_name ^ " " ^ class_name ^ "_scriptable = {\n");
+      List.iter
+        (fun (f, args, return_type) ->
+          let cast = cpp_tfun_signature true args return_type in
+          output_cpp
+            ("\t" ^ cast ^ "&" ^ sctipt_name ^ "::" ^ keyword_remap f.cf_name
+           ^ ",\n"))
+        new_sctipt_functions;
+      output_cpp "};\n"));
+
+  let class_name_text = join_class_path class_path "." in
+
+  (* Initialise static in boot function ... *)
+  if (not (has_class_flag class_def CInterface)) && not nativeGen then (
+    (* 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 ->
+           let signature =
+             generate_script_function false field "__script_construct_func"
+               "__construct"
+           in
+           output_cpp
+             ("::hx::ScriptFunction " ^ class_name
+            ^ "::__script_construct(__script_construct_func,\"" ^ signature
+            ^ "\");\n")
+       | _ ->
+           output_cpp
+             ("::hx::ScriptFunction " ^ class_name
+            ^ "::__script_construct(0,0);\n"));
+
+    let reflective_statics =
+      List.filter (reflective class_def) implemented_fields
+    in
+    let sStaticFields =
+      if List.length reflective_statics > 0 then (
+        output_cpp ("static ::String " ^ class_name ^ "_sStaticFields[] = {\n");
+        List.iter dump_field_name reflective_statics;
+        output_cpp "\t::String(null())\n};\n\n";
+        class_name ^ "_sStaticFields")
+      else "0 /* sStaticFields */"
+    in
+
+    output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
+    if not (has_class_flag class_def CAbstract) then (
+      output_cpp ("\t" ^ class_name ^ " _hx_dummy;\n");
+      output_cpp ("\t" ^ class_name ^ "::_hx_vtable = *(void **)&_hx_dummy;\n"));
+    output_cpp "\t::hx::Static(__mClass) = new ::hx::Class_obj();\n";
+    output_cpp ("\t__mClass->mName = " ^ strq class_name_text ^ ";\n");
+    output_cpp "\t__mClass->mSuper = &super::__SGetClass();\n";
+    if not (has_class_flag class_def CAbstract) then (
+      output_cpp "\t__mClass->mConstructEmpty = &__CreateEmpty;\n";
+      output_cpp "\t__mClass->mConstructArgs = &__Create;\n");
+    output_cpp
+      ("\t__mClass->mGetStaticField = &"
+      ^
+      if has_get_static_field class_def then class_name ^ "::__GetStatic;\n"
+      else "::hx::Class_obj::GetNoStaticField;\n");
+    output_cpp
+      ("\t__mClass->mSetStaticField = &"
+      ^
+      if has_set_static_field class_def then class_name ^ "::__SetStatic;\n"
+      else "::hx::Class_obj::SetNoStaticField;\n");
+    if hasMarkFunc then
+      output_cpp ("\t__mClass->mMarkFunc = " ^ class_name ^ "_sMarkStatics;\n");
+    output_cpp
+      ("\t__mClass->mStatics = ::hx::Class_obj::dupFunctions(" ^ sStaticFields
+     ^ ");\n");
+    output_cpp
+      ("\t__mClass->mMembers = ::hx::Class_obj::dupFunctions(" ^ sMemberFields
+     ^ ");\n");
+    output_cpp ("\t__mClass->mCanCast = ::hx::TCanCast< " ^ class_name ^ " >;\n");
+    if hasMarkFunc then
+      output_cpp
+        ("#ifdef HXCPP_VISIT_ALLOCS\n\t__mClass->mVisitFunc = " ^ class_name
+       ^ "_sVisitStatics;\n#endif\n");
+    output_cpp
+      ("#ifdef HXCPP_SCRIPTABLE\n\t__mClass->mMemberStorageInfo = " ^ class_name
+     ^ "_sMemberStorageInfo;\n#endif\n");
+    output_cpp
+      ("#ifdef HXCPP_SCRIPTABLE\n\t__mClass->mStaticStorageInfo = " ^ class_name
+     ^ "_sStaticStorageInfo;\n#endif\n");
+    output_cpp "\t::hx::_hx_RegisterClass(__mClass->mName, __mClass);\n";
+    if scriptable then
+      output_cpp
+        ("  HX_SCRIPTABLE_REGISTER_CLASS(\"" ^ class_name_text ^ "\","
+       ^ class_name ^ ");\n");
+    Hashtbl.iter
+      (fun _ intf_def ->
+        output_cpp
+          ("\tHX_REGISTER_VTABLE_OFFSET( " ^ class_name ^ ","
+          ^ join_class_path_remap intf_def.cl_path "::"
+          ^ ");\n"))
+      native_implementations;
+    output_cpp "}\n\n")
+  else if not nativeGen then (
+    output_cpp ("::hx::Class " ^ class_name ^ "::__mClass;\n\n");
+
+    output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
+
+    output_cpp "\t::hx::Static(__mClass) = new ::hx::Class_obj();\n";
+    output_cpp ("\t__mClass->mName = " ^ strq class_name_text ^ ";\n");
+    output_cpp "\t__mClass->mSuper = &super::__SGetClass();\n";
+    if hasMarkFunc then
+      output_cpp ("\t__mClass->mMarkFunc = " ^ class_name ^ "_sMarkStatics;\n");
+    output_cpp
+      ("\t__mClass->mMembers = ::hx::Class_obj::dupFunctions(" ^ sMemberFields
+     ^ ");\n");
+    output_cpp
+      ("\t__mClass->mCanCast = ::hx::TIsInterface< (int)"
+     ^ cpp_class_hash class_def ^ " >;\n");
+    if hasMarkFunc then
+      output_cpp
+        ("#ifdef HXCPP_VISIT_ALLOCS\n\t__mClass->mVisitFunc = " ^ class_name
+       ^ "_sVisitStatics;\n#endif\n");
+    output_cpp "\t::hx::_hx_RegisterClass(__mClass->mName, __mClass);\n";
+    if scriptable then
+      output_cpp
+        ("  HX_SCRIPTABLE_REGISTER_INTERFACE(\"" ^ class_name_text ^ "\","
+       ^ class_name ^ ");\n");
+    output_cpp "}\n\n");
+
+  if has_boot_field class_def then (
+    output_cpp ("void " ^ class_name ^ "::__boot()\n{\n");
+
+    List.iter
+      (gen_field_init ctx class_def)
+      (List.filter should_implement_field class_def.cl_ordered_statics);
+
+    output_cpp "}\n\n");
+
+  end_namespace output_cpp class_path;
+
+  if
+    has_class_flag class_def CInterface
+    && Meta.has Meta.ObjcProtocol class_def.cl_meta
+  then (
+    let full_class_name =
+      ("::" ^ join_class_path_remap class_path "::") ^ "_obj"
+    in
+    let protocol =
+      get_meta_string class_def.cl_meta Meta.ObjcProtocol |> Option.default ""
+    in
+    generate_protocol_delegate ctx class_def output_cpp;
+    output_cpp
+      ("id<" ^ protocol ^ "> " ^ full_class_name
+     ^ "::_hx_toProtocol(Dynamic inImplementation) {\n");
+    output_cpp
+      ("\treturn [ [_hx_" ^ protocol
+     ^ "_delegate alloc] initWithImplementation:inImplementation.mPtr];\n");
+    output_cpp "}\n\n");
+
+  cpp_file#close

+ 205 - 0
src/generators/cpp/gen/cppGenEnum.ml

@@ -0,0 +1,205 @@
+open Type
+open CppStrings
+open CppAstTools
+open CppSourceWriter
+open CppContext
+open CppGen
+
+let generate baseCtx enum_def =
+  let common_ctx       = baseCtx.ctx_common in
+  let class_path       = enum_def.e_path in
+  let just_class_name  = (snd class_path) in
+  let class_name       = just_class_name ^ "_obj" in
+  let remap_class_name = ("::" ^ (join_class_path_remap class_path "::") )  in
+  let cpp_file         = new_placed_cpp_file common_ctx class_path in
+  let output_cpp       = (cpp_file#write) in
+  let debug            = if (Meta.has Meta.NoDebug enum_def.e_meta) || ( Gctx.defined common_ctx Define.NoDebug) then 0 else 1 in
+
+  let ctx = file_context baseCtx cpp_file debug false in
+  let strq = strq ctx.ctx_common in
+
+  let classId = try Hashtbl.find baseCtx.ctx_type_ids (class_text enum_def.e_path) with Not_found -> Int32.zero in
+  let classIdTxt = Printf.sprintf "0x%08lx" classId in
+
+  if (debug>1) then
+      print_endline ("Found enum definition:" ^ (join_class_path  class_path "::" ));
+
+  cpp_file#write_h "#include <hxcpp.h>\n\n";
+
+  let super_deps       = create_super_dependencies common_ctx in
+  let referenced,flags = CppReferences.find_referenced_types_flags ctx (TEnumDecl enum_def) "*" super_deps (Hashtbl.create 0) false false false in
+  List.iter (add_include cpp_file) referenced;
+
+  begin_namespace output_cpp class_path;
+  output_cpp "\n";
+
+  PMap.iter (fun _ constructor ->
+      let name = keyword_remap constructor.ef_name in
+      match constructor.ef_type with
+      | TFun (args,_) ->
+        output_cpp (remap_class_name ^ " " ^ class_name ^ "::" ^ name ^ "(" ^
+            (print_tfun_arg_list true args) ^")\n");
+
+        output_cpp ("{\n\treturn ::hx::CreateEnum< " ^ class_name ^ " >(" ^ (strq name) ^ "," ^
+            (string_of_int constructor.ef_index) ^ "," ^ (string_of_int (List.length args)) ^  ")" );
+          ExtList.List.iteri (fun i (arg,_,_) -> output_cpp ("->_hx_init(" ^ (string_of_int i) ^ "," ^ (keyword_remap arg) ^ ")")) args;
+        output_cpp ";\n}\n\n"
+      | _ ->
+        output_cpp ( remap_class_name ^ " " ^ class_name ^ "::" ^ name ^ ";\n\n" )
+  ) enum_def.e_constrs;
+
+
+  let constructor_arg_count constructor =
+      (match constructor.ef_type with | TFun(args,_) -> List.length args | _ -> 0 )
+  in
+
+  output_cpp ("bool " ^ class_name ^ "::__GetStatic(const ::String &inName, ::Dynamic &outValue, ::hx::PropertyAccess inCallProp)\n{\n");
+  PMap.iter (fun _ constructor ->
+      let name = constructor.ef_name in
+      let dyn = if constructor_arg_count constructor > 0 then "_dyn()" else "" in
+      output_cpp ("\tif (inName==" ^ strq name ^ ") { outValue = " ^ class_name ^ "::" ^ keyword_remap name ^ dyn ^ "; return true; }\n" );
+  ) enum_def.e_constrs;
+  output_cpp ("\treturn super::__GetStatic(inName, outValue, inCallProp);\n}\n\n");
+
+  output_cpp ("HX_DEFINE_CREATE_ENUM(" ^ class_name ^ ")\n\n");
+
+  output_cpp ("bool " ^ class_name ^ "::_hx_isInstanceOf(int inClassId) {\n");
+  output_cpp ("\treturn inClassId == (int)0x00000001 || inClassId == ::hx::EnumBase_obj::_hx_ClassId || inClassId == _hx_ClassId;\n");
+  output_cpp ("}\n");
+
+  output_cpp ("int " ^ class_name ^ "::__FindIndex(::String inName)\n{\n");
+  PMap.iter (fun _ constructor ->
+      let name = constructor.ef_name in
+      let idx = string_of_int constructor.ef_index in
+      output_cpp ("\tif (inName==" ^ (strq name) ^ ") return " ^ idx ^ ";\n") ) enum_def.e_constrs;
+  output_cpp ("\treturn super::__FindIndex(inName);\n");
+  output_cpp ("}\n\n");
+
+  (* Dynamic versions of constructors *)
+  let dump_dynamic_constructor _ constr =
+      let count = constructor_arg_count constr in
+      if (count>0) then begin
+        let nargs = string_of_int count in
+        output_cpp ("STATIC_HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^
+              (keyword_remap constr.ef_name) ^ ",return)\n\n");
+      end
+  in
+  PMap.iter dump_dynamic_constructor enum_def.e_constrs;
+
+
+  output_cpp ("int " ^ class_name ^ "::__FindArgCount(::String inName)\n{\n");
+  PMap.iter (fun _ constructor ->
+      let name = constructor.ef_name in
+      let count = string_of_int (constructor_arg_count constructor) in
+      output_cpp ("\tif (inName==" ^ (strq name) ^ ") return " ^ count ^ ";\n") ) enum_def.e_constrs;
+      output_cpp ("\treturn super::__FindArgCount(inName);\n");
+      output_cpp ("}\n\n");
+
+  (* Dynamic "Get" Field function - string version *)
+  output_cpp ("::hx::Val " ^ class_name ^ "::__Field(const ::String &inName,::hx::PropertyAccess inCallProp)\n{\n");
+  let dump_constructor_test _ constr =
+      output_cpp ("\tif (inName==" ^ (strq constr.ef_name) ^ ") return " ^
+                  (keyword_remap constr.ef_name) );
+      if ( (constructor_arg_count constr) > 0 ) then output_cpp "_dyn()";
+      output_cpp (";\n")
+  in
+  PMap.iter dump_constructor_test enum_def.e_constrs;
+  output_cpp ("\treturn super::__Field(inName,inCallProp);\n}\n\n");
+
+  output_cpp ("static ::String " ^ class_name ^ "_sStaticFields[] = {\n");
+  let sorted =
+      List.sort (fun f1 f2 -> (PMap.find f1 enum_def.e_constrs ).ef_index -
+              (PMap.find f2 enum_def.e_constrs ).ef_index )
+        (pmap_keys enum_def.e_constrs) in
+
+    List.iter (fun name -> output_cpp ("\t" ^ (strq name) ^ ",\n") ) sorted;
+
+  output_cpp "\t::String(null())\n};\n\n";
+
+  (* ENUM - Mark static as used by GC - they are const now, so no marking*)
+  (* ENUM - Visit static as used by GC - none *)
+
+  output_cpp ("::hx::Class " ^ class_name ^ "::__mClass;\n\n");
+
+  output_cpp ("Dynamic __Create_" ^ class_name ^ "() { return new " ^ class_name ^ "; }\n\n");
+
+  output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
+  let text_name = strq (join_class_path class_path ".") in
+  output_cpp ("\n::hx::Static(__mClass) = ::hx::_hx_RegisterClass(" ^ text_name ^
+              ", ::hx::TCanCast< " ^ class_name ^ " >," ^ class_name ^ "_sStaticFields,0,\n");
+  output_cpp ("\t&__Create_" ^ class_name ^ ", &__Create,\n");
+  output_cpp ("\t&super::__SGetClass(), &Create" ^ class_name ^ ", 0\n");
+  output_cpp("#ifdef HXCPP_VISIT_ALLOCS\n    , 0\n#endif\n");
+  output_cpp ("#ifdef HXCPP_SCRIPTABLE\n    , 0\n#endif\n");
+      output_cpp (");\n");
+  output_cpp ("\t__mClass->mGetStaticField = &" ^ class_name ^"::__GetStatic;\n");
+  output_cpp "}\n\n";
+
+  output_cpp ("void " ^ class_name ^ "::__boot()\n{\n");
+  (match Texpr.build_metadata common_ctx.basic (TEnumDecl enum_def) with
+      | Some expr ->
+        let ctx = file_context ctx cpp_file 1 false in
+        gen_cpp_init ctx class_name "boot" "__mClass->__meta__ = " expr
+      | _ -> () );
+  PMap.iter (fun _ constructor ->
+      let name = constructor.ef_name in
+      match constructor.ef_type with
+      | TFun (_,_) -> ()
+      | _ ->
+        output_cpp ( (keyword_remap name) ^ " = ::hx::CreateConstEnum< " ^ class_name ^ " >(" ^ (strq name) ^  "," ^
+            (string_of_int constructor.ef_index) ^ ");\n" )
+  ) enum_def.e_constrs;
+  output_cpp ("}\n\n");
+
+  output_cpp "\n";
+  end_namespace output_cpp class_path;
+  cpp_file#close;
+
+  let h_file = new_header_file common_ctx common_ctx.file class_path in
+  let super = "::hx::EnumBase_obj" in
+  let output_h = (h_file#write) in
+  let def_string = join_class_path class_path "_"  in
+
+  begin_header_file (h_file#write_h) def_string false;
+
+  List.iter2 (fun r f -> gen_forward_decl h_file r f) referenced flags;
+
+  output_h ( get_code enum_def.e_meta Meta.HeaderCode );
+
+  begin_namespace output_h class_path;
+
+  output_h "\n\n";
+  output_h ("class " ^ class_name ^ " : public " ^ super ^ "\n");
+  output_h ("{\n\ttypedef " ^ super ^ " super;\n");
+  output_h ("\t\ttypedef " ^ class_name ^ " OBJ_;\n");
+  output_h "\n\tpublic:\n";
+  output_h ("\t\tenum { _hx_ClassId = " ^ classIdTxt ^ " };\n\n");
+  output_h ("\t\t" ^ class_name ^ "() {};\n");
+  output_h ("\t\tHX_DO_ENUM_RTTI;\n");
+  output_h ("\t\tstatic void __boot();\n");
+  output_h ("\t\tstatic void __register();\n");
+  output_h ("\t\tstatic bool __GetStatic(const ::String &inName, Dynamic &outValue, ::hx::PropertyAccess inCallProp);\n");
+  output_h ("\t\t::String GetEnumName( ) const { return " ^ (strq (join_class_path class_path "."))  ^ "; }\n" );
+  output_h ("\t\t::String __ToString() const { return " ^ (strq (just_class_name ^ ".") )^ " + _hx_tag; }\n");
+  output_h ("\t\tbool _hx_isInstanceOf(int inClassId);\n\n");
+
+
+  PMap.iter (fun _ constructor ->
+      let name = keyword_remap constructor.ef_name in
+      output_h ( "\t\tstatic " ^  remap_class_name ^ " " ^ name );
+      match constructor.ef_type with
+      | TFun (args,_) ->
+        output_h ( "(" ^ (print_tfun_arg_list true args) ^");\n");
+        output_h ( "\t\tstatic ::Dynamic " ^ name ^ "_dyn();\n");
+      | _ ->
+        output_h ";\n";
+        output_h ( "\t\tstatic inline " ^  remap_class_name ^ " " ^ name ^
+                  "_dyn() { return " ^name ^ "; }\n" );
+  ) enum_def.e_constrs;
+
+  output_h "};\n\n";
+
+  end_namespace output_h class_path;
+
+  end_header_file output_h def_string;
+  h_file#close

+ 229 - 0
src/generators/cpp/gen/cppReferences.ml

@@ -0,0 +1,229 @@
+open Type
+open CppStrings
+open CppTypeUtils
+open CppAstTools
+open CppContext
+
+(*
+   Get a list of all classes referred to by the class/enum definition
+   These are used for "#include"ing the appropriate header files,
+   or for building the dependencies in the Build.xml file
+*)
+let find_referenced_types_flags ctx obj field_name super_deps constructor_deps header_only for_depends include_super_args =
+  let types = ref PMap.empty in
+  (if for_depends then
+     let include_files =
+       get_all_meta_string_path (t_infos obj).mt_meta Meta.Depend
+     in
+     let include_adder inc =
+       types := PMap.add (path_of_string inc) true !types
+     in
+     List.iter include_adder include_files);
+  let rec add_type_flag isNative in_path =
+    if not (PMap.mem in_path !types) then (
+      types := PMap.add in_path isNative !types;
+      try List.iter (add_type_flag isNative) (Hashtbl.find super_deps in_path)
+      with Not_found -> ())
+  and add_type in_path = add_type_flag false in_path in
+  let add_extern_type decl =
+    let tinfo = t_infos decl in
+    let include_files =
+      get_all_meta_string_path tinfo.mt_meta
+        (if for_depends then Meta.Depend else Meta.Include)
+    in
+    if List.length include_files > 0 then
+      List.iter (fun inc -> add_type (path_of_string inc)) include_files
+    else if (not for_depends) && Meta.has Meta.Include tinfo.mt_meta then
+      add_type tinfo.mt_path
+  in
+
+  let add_extern_class klass = add_extern_type (TClassDecl klass) in
+  let add_extern_enum enum = add_extern_type (TEnumDecl enum) in
+  let add_native_gen_class klass =
+    let include_files =
+      get_all_meta_string_path klass.cl_meta
+        (if for_depends then Meta.Depend else Meta.Include)
+    in
+    if List.length include_files > 0 then
+      List.iter (fun inc -> add_type (path_of_string inc)) include_files
+    else if for_depends then add_type klass.cl_path
+    else
+      let path = klass.cl_path in
+      if not (has_class_flag klass CInterface) then
+        (* Always include native struct headers directly ... *)
+        add_type (path_of_string (join_class_path path "/" ^ ".h"))
+      else add_type_flag true klass.cl_path
+  in
+  let visited = ref [] in
+  let rec visit_type in_type =
+    if not (List.exists (fun t2 -> Type.fast_eq in_type t2) !visited) then (
+      visited := in_type :: !visited;
+      (match follow in_type with
+      | TMono r -> ( match r.tm_type with None -> () | Some t -> visit_type t)
+      | TEnum (enum, _) -> (
+          match is_extern_enum enum with
+          | true -> add_extern_enum enum
+          | false -> add_type enum.e_path)
+      (* If a class has a template parameter, then we treat it as dynamic - except
+         for the Array, Class, FastIterator or Pointer classes, for which we do a fully typed object *)
+      | TInst (klass, params) -> (
+          match klass.cl_path with
+          | [], "Array"
+          | [], "Class"
+          | [ "cpp" ], "FastIterator"
+          | [ "cpp" ], "Pointer"
+          | [ "cpp" ], "ConstPointer"
+          | [ "cpp" ], "Function"
+          | [ "cpp" ], "RawPointer"
+          | [ "cpp" ], "RawConstPointer" ->
+              List.iter visit_type params
+          | _ when is_native_gen_class klass -> add_native_gen_class klass
+          | _ when is_extern_class klass ->
+              add_extern_class klass;
+              List.iter visit_type params
+          | _ -> (
+              match klass.cl_kind with
+              | KTypeParameter _ -> ()
+              | _ -> add_type klass.cl_path))
+      | TAbstract (a, params) when is_scalar_abstract a ->
+          add_extern_type (TAbstractDecl a)
+      | TFun (args, haxe_type) ->
+          visit_type haxe_type;
+          List.iter (fun (_, _, t) -> visit_type t) args
+      | _ -> ());
+      visited := List.tl !visited)
+  in
+  let visit_params expression =
+    let rec visit_expression expression =
+      (* Expand out TTypeExpr (ie, the name of a class, as used for static access etc ... *)
+      (match expression.eexpr with
+      | TTypeExpr type_def -> (
+          match type_def with
+          | TClassDecl class_def when is_native_gen_class class_def ->
+              add_native_gen_class class_def
+          | TClassDecl class_def when is_extern_class class_def ->
+              add_extern_class class_def
+          | TEnumDecl enum_def when is_extern_enum enum_def ->
+              add_extern_enum enum_def
+          | _ -> add_type (t_path type_def))
+      (* Must visit the types, Type.iter will visit the expressions ... *)
+      | TTry (e, catches) ->
+          List.iter (fun (v, _) -> visit_type v.v_type) catches
+      (* Must visit type too, Type.iter will visit the expressions ... *)
+      | TNew (klass, params, _) -> (
+          visit_type (TInst (klass, params));
+          try
+            let construct_type = Hashtbl.find constructor_deps klass.cl_path in
+            visit_type construct_type.cf_type
+          with Not_found -> ())
+      (* Must visit type too, Type.iter will visit the expressions ... *)
+      | TVar (v, _) -> visit_type v.v_type
+      (* Must visit enum type too, Type.iter will visit the expressions ... *)
+      | TEnumParameter (_, ef, _) -> visit_type (follow ef.ef_type)
+      (* Must visit args too, Type.iter will visit the expressions ... *)
+      | TFunction func_def ->
+          List.iter (fun (v, _) -> visit_type v.v_type) func_def.tf_args
+      | TField (obj, field) -> (
+          match field with
+          | FInstance (clazz, params, _) | FClosure (Some (clazz, params), _) ->
+              visit_type (TInst (clazz, params))
+          | _ -> ())
+      | TConst TSuper -> (
+          match follow expression.etype with
+          | TInst (klass, params) -> (
+              try
+                let construct_type =
+                  Hashtbl.find constructor_deps klass.cl_path
+                in
+                visit_type construct_type.cf_type
+              with Not_found -> ())
+          | _ ->
+              print_endline
+                ("TSuper : Odd etype ?"
+                ^ (CppRetyper.cpp_type_of expression.etype |> tcpp_to_string)))
+      | _ -> ());
+      Type.iter visit_expression expression;
+      visit_type (follow expression.etype)
+    in
+    visit_expression expression
+  in
+  let visit_field field =
+    (* Add the type of the expression ... *)
+    visit_type field.cf_type;
+    if not header_only then
+      match field.cf_expr with
+      | Some expression -> visit_params expression
+      | _ -> ()
+  in
+  let visit_class class_def =
+    let fields =
+      List.append class_def.cl_ordered_fields class_def.cl_ordered_statics
+    in
+    let fields_and_constructor =
+      List.append fields
+        (match class_def.cl_constructor with Some expr -> [ expr ] | _ -> [])
+    in
+    let fields_and_constructor =
+      if field_name = "*" then fields_and_constructor
+      else List.filter (fun f -> f.cf_name = field_name) fields_and_constructor
+    in
+    List.iter visit_field fields_and_constructor;
+    if include_super_args then
+      List.iter visit_field
+        (List.map (fun (a, _, _) -> a) (all_virtual_functions class_def));
+
+    (* Add super & interfaces *)
+    if is_native_gen_class class_def then add_native_gen_class class_def
+    else add_type class_def.cl_path
+  in
+  let visit_enum enum_def =
+    add_type enum_def.e_path;
+    PMap.iter
+      (fun _ constructor ->
+        match constructor.ef_type with
+        | TFun (args, _) -> List.iter (fun (_, _, t) -> visit_type t) args
+        | _ -> ())
+      enum_def.e_constrs;
+    if not header_only then
+      let meta =
+        Texpr.build_metadata ctx.ctx_common.basic (TEnumDecl enum_def)
+      in
+      match meta with Some expr -> visit_params expr | _ -> ()
+  in
+  let inc_cmp i1 i2 =
+    String.compare (join_class_path i1 ".") (join_class_path i2 ".")
+  in
+
+  (* Body of main function *)
+  (match obj with
+  | TClassDecl class_def -> (
+      visit_class class_def;
+      match TClass.get_cl_init class_def with
+      | Some expression -> visit_params expression
+      | _ -> ())
+  | TEnumDecl enum_def -> visit_enum enum_def
+  | TTypeDecl _ | TAbstractDecl _ -> (* These are expanded *) ());
+
+  (*
+        The internal header files are also defined in the hx/Object.h file, so you do
+        #include them separately. However, Math classes has its
+        own header file (under the hxcpp tree) so these should be included
+    *)
+  let include_class_header = function
+    | [], "@Main" -> false
+    | [], "Math" -> true
+    | path -> not (is_internal_class path)
+  in
+  let deps =
+    List.sort inc_cmp
+      (List.filter (fun path -> include_class_header path) (pmap_keys !types))
+  in
+  let flags = List.map (fun dep -> PMap.find dep !types) deps in
+  (deps, flags)
+
+let find_referenced_types ctx obj super_deps constructor_deps header_only for_depends include_super_args =
+  let deps, _ =
+    find_referenced_types_flags ctx obj "*" super_deps constructor_deps
+      header_only for_depends include_super_args
+  in
+  deps

+ 119 - 0
src/generators/gctx.ml

@@ -0,0 +1,119 @@
+open Globals
+open Type
+open Warning
+
+type context_main = {
+	mutable main_class : path option;
+	mutable main_expr : texpr option;
+}
+
+type warning_function = ?depth:int -> ?from_macro:bool -> warning -> Warning.warning_option list list -> string -> pos -> unit
+type error_function = ?depth:int -> string -> pos -> unit
+
+type t = {
+	platform : platform;
+	defines : Define.define;
+	class_paths : ClassPaths.class_paths;
+	run_command : string -> int;
+	run_command_args : string -> string list -> int;
+	warning : warning_function;
+	error : error_function;
+	print : string -> unit;
+	basic : basic_types;
+	debug : bool;
+	file : string;
+	version : int;
+	features : (string,bool) Hashtbl.t;
+	modules : Type.module_def list;
+	main : context_main;
+	types : Type.module_type list;
+	resources : (string,string) Hashtbl.t;
+	native_libs : NativeLibraries.native_library_base list;
+	include_files : (string * string) list;
+	std : tclass; (* TODO: I would prefer to not have this here, have to check default_cast *)
+}
+
+let defined com s =
+	Define.defined com.defines s
+
+let defined_value com v =
+	Define.defined_value com.defines v
+
+let define_value com k v =
+	Define.define_value com.defines k v
+
+let defined_value_safe ?default com v =
+	match default with
+		| Some s -> Define.defined_value_safe ~default:s com.defines v
+		| None -> Define.defined_value_safe com.defines v
+
+let raw_defined gctx v =
+	Define.raw_defined gctx.defines v
+
+let find_file ctx f =
+	(ctx.class_paths#find_file f).file
+
+let add_feature gctx f =
+	Hashtbl.replace gctx.features f true
+
+let has_dce gctx =
+	try
+		Define.defined_value gctx.defines Define.Dce <> "no"
+with Not_found ->
+	false
+
+let is_directly_used gctx meta =
+	not (has_dce gctx) || Meta.has Meta.DirectlyUsed meta
+
+let rec has_feature gctx f =
+	try
+		Hashtbl.find gctx.features f
+	with Not_found ->
+		if gctx.types = [] then not (has_dce gctx) else
+		match List.rev (ExtString.String.nsplit f ".") with
+		| [] -> die "" __LOC__
+		| [cl] -> has_feature gctx (cl ^ ".*")
+		| field :: cl :: pack ->
+			let r = (try
+				let path = List.rev pack, cl in
+				(match List.find (fun t -> t_path t = path && not (Meta.has Meta.RealPath (t_infos t).mt_meta)) gctx.types with
+				| t when field = "*" ->
+					not (has_dce gctx) ||
+					begin match t with
+						| TClassDecl c ->
+							has_class_flag c CUsed;
+						| TAbstractDecl a ->
+							Meta.has Meta.ValueUsed a.a_meta
+						| _ -> Meta.has Meta.Used (t_infos t).mt_meta
+					end;
+				| TClassDecl c when (has_class_flag c CExtern) && (gctx.platform <> Js || cl <> "Array" && cl <> "Math") ->
+					not (has_dce gctx) || has_class_field_flag (try PMap.find field c.cl_statics with Not_found -> PMap.find field c.cl_fields) CfUsed
+				| TClassDecl c ->
+					PMap.exists field c.cl_statics || PMap.exists field c.cl_fields
+				| _ ->
+					false)
+			with Not_found ->
+				false
+			) in
+			Hashtbl.add gctx.features f r;
+			r
+
+let get_entry_point gctx =
+	Option.map (fun path ->
+		let m = List.find (fun m -> m.m_path = path) gctx.modules in
+		let c =
+			match m.m_statics with
+			| Some c when (PMap.mem "main" c.cl_statics) -> c
+			| _ -> Option.get (ExtList.List.find_map (fun t -> match t with TClassDecl c when c.cl_path = path -> Some c | _ -> None) m.m_types)
+		in
+		let e = Option.get gctx.main.main_expr in (* must be present at this point *)
+		(snd path, c, e)
+	) gctx.main.main_class
+
+let get_es_version defines =
+	try int_of_string (Define.defined_value defines Define.JsEs) with _ -> 0
+
+let map_source_header defines f =
+	match Define.defined_value_safe defines Define.SourceHeader with
+	| "" -> ()
+	| s -> f s

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 21 - 6894
src/generators/gencpp.ml


+ 53 - 47
src/generators/genhl.ml

@@ -24,7 +24,7 @@ open Globals
 open Ast
 open Type
 open Error
-open Common
+open Gctx
 open Hlcode
 
 (* compiler *)
@@ -78,13 +78,14 @@ type array_impl = {
 	ai32 : tclass;
 	af32 : tclass;
 	af64 : tclass;
+	ai64 : tclass;
 }
 
 type constval =
 	| CString of string
 
 type context = {
-	com : Common.context;
+	com : Gctx.t;
 	cglobals : (string, ttype) lookup;
 	cstrings : (string, string) lookup;
 	cbytes : (bytes, bytes) lookup;
@@ -151,7 +152,7 @@ let is_extern_field f =
 
 let is_array_class name =
 	match name with
-	| "hl.types.ArrayDyn" | "hl.types.ArrayBytes_Int" | "hl.types.ArrayBytes_Float" | "hl.types.ArrayObj" | "hl.types.ArrayBytes_hl_F32" | "hl.types.ArrayBytes_hl_UI16" -> true
+	| "hl.types.ArrayDyn" | "hl.types.ArrayBytes_Int" | "hl.types.ArrayBytes_Float" | "hl.types.ArrayObj" | "hl.types.ArrayBytes_hl_F32" | "hl.types.ArrayBytes_hl_UI16" | "hl.types.ArrayBytes_hl_I64" -> true
 	| _ -> false
 
 let is_array_type t =
@@ -287,6 +288,8 @@ let array_class ctx t =
 		ctx.array_impl.af32
 	| HF64 ->
 		ctx.array_impl.af64
+	| HI64 ->
+		ctx.array_impl.ai64
 	| HDyn ->
 		ctx.array_impl.adyn
 	| _ ->
@@ -322,7 +325,7 @@ let set_curpos ctx p =
 
 let make_debug ctx arr =
 	let get_relative_path p =
-		match Common.defined ctx.com Common.Define.AbsolutePath with
+		match Gctx.defined ctx.com Define.AbsolutePath with
 		| true -> if (Filename.is_relative p.pfile)
 			then Filename.concat (Sys.getcwd()) p.pfile
 			else p.pfile
@@ -387,7 +390,7 @@ let rec to_type ?tref ctx t =
 	| TType (td,tl) ->
 		let t =
 			get_rec_cache ctx t
-				(fun() -> abort "Unsupported recursive type" td.t_pos)
+				(fun() -> HDyn)
 				(fun tref -> to_type ~tref ctx (apply_typedef td tl))
 		in
 		(match td.t_path with
@@ -470,7 +473,7 @@ let rec to_type ?tref ctx t =
 			| ["hl"], "UI16" -> HUI16
 			| ["hl"], "UI8" -> HUI8
 			| ["hl"], "I64" -> HI64
-			| ["hl"], "NativeArray" -> HArray
+			| ["hl"], "NativeArray" -> HArray (to_type ctx (List.hd pl))
 			| ["haxe";"macro"], "Position" -> HAbstract ("macro_pos", alloc_string ctx "macro_pos")
 			| _ -> failwith ("Unknown core type " ^ s_type_path a.a_path))
 		else
@@ -896,6 +899,15 @@ let op ctx o =
 let set_op ctx pos o =
 	DynArray.set ctx.m.mops pos o
 
+let alloc_array ctx size et =
+	let a = alloc_tmp ctx (HArray HDyn) in
+	let b = alloc_tmp ctx (HArray et) in
+	let rt = alloc_tmp ctx HType in
+	op ctx (OType (rt,et));
+	op ctx (OCall2 (a,alloc_std ctx "alloc_array" [HType;HI32] (HArray HDyn),rt,size));
+	op ctx (OUnsafeCast(b,a));
+	b
+
 let jump ctx f =
 	let pos = current_pos ctx in
 	op ctx (OJAlways (-1)); (* loop *)
@@ -1423,7 +1435,7 @@ and get_access ctx e =
 
 and array_read ctx ra (at,vt) ridx p =
 	match at with
-	| HUI8 | HUI16 | HI32 | HF32 | HF64 ->
+	| HUI8 | HUI16 | HI32 | HF32 | HF64 | HI64 ->
 		(* check bounds *)
 		hold ctx ridx;
 		let length = alloc_tmp ctx HI32 in
@@ -1432,7 +1444,7 @@ and array_read ctx ra (at,vt) ridx p =
 		let j = jump ctx (fun i -> OJULt (ridx,length,i)) in
 		let r = alloc_tmp ctx (match at with HUI8 | HUI16 -> HI32 | _ -> at) in
 		(match at with
-		| HUI8 | HUI16 | HI32 ->
+		| HUI8 | HUI16 | HI32 | HI64 ->
 			op ctx (OInt (r,alloc_i32 ctx 0l));
 		| HF32 | HF64 ->
 			op ctx (OFloat (r,alloc_float ctx 0.));
@@ -1462,7 +1474,7 @@ and array_read ctx ra (at,vt) ridx p =
 		let jend = jump ctx (fun i -> OJAlways i) in
 		j();
 		let tmp = alloc_tmp ctx HDyn in
-		let harr = alloc_tmp ctx HArray in
+		let harr = alloc_tmp ctx (HArray vt) in
 		op ctx (OField (harr,ra,1));
 		op ctx (OGetArray (tmp,harr,ridx));
 		op ctx (OMov (r,unsafe_cast_to ctx tmp vt p));
@@ -1475,7 +1487,7 @@ and jump_expr ctx e jcond =
 		jump_expr ctx e jcond
 	| TUnop (Not,_,e) ->
 		jump_expr ctx e (not jcond)
-	| TBinop (OpEq,{ eexpr = TConst(TNull) },e) | TBinop (OpEq,e,{ eexpr = TConst(TNull) }) ->
+	| TBinop ((OpEq | OpGte | OpLte),{ eexpr = TConst(TNull) },e) | TBinop ((OpEq | OpGte | OpLte),e,{ eexpr = TConst(TNull) }) ->
 		let r = eval_expr ctx e in
 		if is_nullable(rtype ctx r) then
 			jump ctx (fun i -> if jcond then OJNull (r,i) else OJNotNull (r,i))
@@ -2004,23 +2016,21 @@ and eval_expr ctx e =
 				let arr = eval_expr ctx e in
 				op ctx (ONullCheck arr);
 				op ctx (OArraySize (r, arr))
+			| TAbstract ({ a_path = ["hl"],"NativeArray" },[t]) ->
+				op ctx (OArraySize (r, eval_to ctx e (HArray (to_type ctx t))))
 			| _ ->
-				op ctx (OArraySize (r, eval_to ctx e HArray)));
+				invalid());
 			r
 		| "$aalloc", [esize] ->
 			let et = (match follow e.etype with TAbstract ({ a_path = ["hl"],"NativeArray" },[t]) -> to_type ctx t | _ -> invalid()) in
 			let size = eval_to ctx esize HI32 in
-			let a = alloc_tmp ctx HArray in
-			let rt = alloc_tmp ctx HType in
-			op ctx (OType (rt,et));
-			op ctx (OCall2 (a,alloc_std ctx "alloc_array" [HType;HI32] HArray,rt,size));
-			a
+			alloc_array ctx size et
 		| "$aget", [a; pos] ->
 			(*
 				read/write on arrays are unsafe : the type of NativeArray needs to be correcly set.
 			*)
 			let at = (match follow a.etype with TAbstract ({ a_path = ["hl"],"NativeArray" },[t]) -> to_type ctx t | _ -> invalid()) in
-			let arr = eval_to ctx a HArray in
+			let arr = eval_to ctx a (HArray at) in
 			hold ctx arr;
 			let pos = eval_to ctx pos HI32 in
 			free ctx arr;
@@ -2029,7 +2039,7 @@ and eval_expr ctx e =
 			cast_to ctx r (to_type ctx e.etype) e.epos
 		| "$aset", [a; pos; value] ->
 			let et = (match follow a.etype with TAbstract ({ a_path = ["hl"],"NativeArray" },[t]) -> to_type ctx t | _ -> invalid()) in
-			let arr = eval_to ctx a HArray in
+			let arr = eval_to ctx a (HArray et) in
 			hold ctx arr;
 			let pos = eval_to ctx pos HI32 in
 			hold ctx pos;
@@ -2106,12 +2116,9 @@ and eval_expr ctx e =
 		| "$resources", [] ->
 			let tdef = (try List.find (fun t -> (t_infos t).mt_path = (["haxe";"_Resource"],"ResourceContent")) ctx.com.types with Not_found -> die "" __LOC__) in
 			let t = class_type ctx (match tdef with TClassDecl c -> c | _ -> die "" __LOC__) [] false in
-			let arr = alloc_tmp ctx HArray in
-			let rt = alloc_tmp ctx HType in
-			op ctx (OType (rt,t));
 			let res = Hashtbl.fold (fun k v acc -> (k,v) :: acc) ctx.com.resources [] in
 			let size = reg_int ctx (List.length res) in
-			op ctx (OCall2 (arr,alloc_std ctx "alloc_array" [HType;HI32] HArray,rt,size));
+			let arr = alloc_array ctx size HBytes in
 			let ro = alloc_tmp ctx t in
 			let rb = alloc_tmp ctx HBytes in
 			let ridx = reg_int ctx 0 in
@@ -2553,12 +2560,12 @@ and eval_expr ctx e =
 					op ctx (OCall2 (alloc_tmp ctx HVoid, alloc_fun_path ctx (array_class ctx at).cl_path "__expand", ra, ridx));
 					j();
 					match at with
-					| HI32 | HF64 | HUI16 | HF32 ->
+					| HI32 | HF64 | HUI16 | HF32 | HI64 ->
 						let b = alloc_tmp ctx HBytes in
 						op ctx (OField (b,ra,1));
 						write_mem ctx b (shl ctx ridx (type_size_bits at)) at v
 					| _ ->
-						let arr = alloc_tmp ctx HArray in
+						let arr = alloc_tmp ctx (HArray vt) in
 						op ctx (OField (arr,ra,1));
 						op ctx (OSetArray (arr,ridx,cast_to ctx v (if is_dynamic at then at else HDyn) e.epos))
 				);
@@ -2829,13 +2836,12 @@ and eval_expr ctx e =
 			array_bytes 2 HF32 "F32" (fun b i r -> OSetMem (b,i,r))
 		| HF64 ->
 			array_bytes 3 HF64 "F64" (fun b i r -> OSetMem (b,i,r))
+		| HI64 ->
+			array_bytes 3 HI64 "I64" (fun b i r -> OSetMem (b,i,r))
 		| _ ->
 			let at = if is_dynamic et then et else HDyn in
-			let a = alloc_tmp ctx HArray in
-			let rt = alloc_tmp ctx HType in
-			op ctx (OType (rt,at));
 			let size = reg_int ctx (List.length el) in
-			op ctx (OCall2 (a,alloc_std ctx "alloc_array" [HType;HI32] HArray,rt,size));
+			let a = alloc_array ctx size at in
 			hold ctx a;
 			list_iteri (fun i e ->
 				let r = eval_to ctx e at in
@@ -3122,7 +3128,7 @@ and gen_assign_op ctx acc e1 f =
 		let r = f r in
 		op ctx (OSetEnumField (ctx.m.mcaptreg,idx,r));
 		r
-	| AArray (ra,(at,_),ridx) ->
+	| AArray (ra,(at,vt),ridx) ->
 		hold ctx ra;
 		hold ctx ridx;
 		let r = (match at with
@@ -3142,7 +3148,7 @@ and gen_assign_op ctx acc e1 f =
 			op ctx (OCall2 (alloc_tmp ctx HVoid, alloc_fun_path ctx (array_class ctx at).cl_path "__expand", ra, ridx));
 			j();
 			match at with
-			| HUI8 | HUI16 | HI32 | HF32 | HF64 ->
+			| HUI8 | HUI16 | HI32 | HF32 | HF64 | HI64->
 				let hbytes = alloc_tmp ctx HBytes in
 				op ctx (OField (hbytes, ra, 1));
 				let ridx = shl ctx ridx (type_size_bits at) in
@@ -3156,7 +3162,7 @@ and gen_assign_op ctx acc e1 f =
 				free ctx hbytes;
 				r
 			| _ ->
-				let arr = alloc_tmp ctx HArray in
+				let arr = alloc_tmp ctx (HArray vt) in
 				op ctx (OField (arr,ra,1));
 				let r = alloc_tmp ctx at in
 				op ctx (OGetArray (r,arr,ridx));
@@ -3460,7 +3466,7 @@ let generate_static ctx c f =
 			| (Meta.HlNative,[(EConst(String(lib,_)),_)] ,_ ) :: _ ->
 				add_native lib f.cf_name
 			| (Meta.HlNative,[(EConst(Float(ver,_)),_)] ,_ ) :: _ ->
-				let cur_ver = (try Common.defined_value ctx.com Define.HlVer with Not_found -> "") in
+				let cur_ver = (try Gctx.defined_value ctx.com Define.HlVer with Not_found -> "") in
 				if cur_ver < ver then
 					let gen_content() =
 						op ctx (OThrow (make_string ctx ("Requires compiling with -D hl-ver=" ^ ver ^ ".0 or higher") null_pos));
@@ -3658,10 +3664,9 @@ let generate_static_init ctx types main =
 				in
 				if (has_class_flag c CInterface) then begin
 					let l = gather_implements() in
-					let ra = alloc_tmp ctx HArray in
 					let rt = alloc_tmp ctx HType in
 					op ctx (OType (rt, HType));
-					op ctx (OCall2 (ra, alloc_std ctx "alloc_array" [HType;HI32] HArray, rt, reg_int ctx (List.length l)));
+					let ra = alloc_array ctx (reg_int ctx (List.length l)) HType in
 					list_iteri (fun i intf ->
 						op ctx (OType (rt, to_type ctx (TInst (intf,[]))));
 						op ctx (OSetArray (ra, reg_int ctx i, rt));
@@ -3704,7 +3709,7 @@ let generate_static_init ctx types main =
 						die "" __LOC__
 				in
 
-				let avalues = alloc_tmp ctx HArray in
+				let avalues = alloc_tmp ctx (HArray t) in
 				op ctx (OField (avalues, r, index "__evalues__"));
 
 				List.iter (fun n ->
@@ -3992,7 +3997,7 @@ let write_code ch code debug =
 			Array.iter (fun (_,n,t) -> write_index n; write_type t) p.pfields;
 			Array.iter (fun f -> write_index f.fid; write_index f.fmethod; write_index (match f.fvirtual with None -> -1 | Some i -> i)) p.pproto;
 			List.iter (fun (fid,fidx) -> write_index fid; write_index fidx) p.pbindings;
-		| HArray ->
+		| HArray _ ->
 			byte 12
 		| HType ->
 			byte 13
@@ -4124,8 +4129,8 @@ let create_context com dump =
 	in
 	let ctx = {
 		com = com;
-		optimize = not (Common.raw_defined com "hl_no_opt");
-		w_null_compare = Common.raw_defined com "hl_w_null_compare";
+		optimize = not (Gctx.raw_defined com "hl_no_opt");
+		w_null_compare = Gctx.raw_defined com "hl_w_null_compare";
 		dump_out = if dump then Some (IO.output_channel (open_out_bin "dump/hlopt.txt")) else None;
 		m = method_context 0 HVoid null_capture false;
 		cints = new_lookup();
@@ -4151,6 +4156,7 @@ let create_context com dump =
 			ai32 = get_class "ArrayBytes_Int";
 			af32 = get_class "ArrayBytes_hl_F32";
 			af64 = get_class "ArrayBytes_Float";
+			ai64 = get_class "ArrayBytes_hl_I64";
 		};
 		base_class = get_class "Class";
 		base_enum = get_class "Enum";
@@ -4244,8 +4250,8 @@ let make_context_sign com =
 let prev_sign = ref "" and prev_data = ref ""
 
 let generate com =
-	let dump = Common.defined com Define.Dump in
-	let hl_check = Common.raw_defined com "hl_check" in
+	let dump = Gctx.defined com Define.Dump in
+	let hl_check = Gctx.raw_defined com "hl_check" in
 
 	let sign = make_context_sign com in
 	if sign = !prev_sign && not dump && not hl_check then begin
@@ -4265,7 +4271,7 @@ let generate com =
 		Hlcode.dump (fun s -> output_string ch (s ^ "\n")) code;
 		close_out ch;
 	end;
-	(*if Common.raw_defined com "hl_dump_spec" then begin
+	(*if Gctx.raw_defined com "hl_dump_spec" then begin
 		let ch = open_out_bin "dump/hlspec.txt" in
 		let write s = output_string ch (s ^ "\n") in
 		Array.iter (fun f ->
@@ -4291,19 +4297,19 @@ let generate com =
 	if Path.file_extension com.file = "c" then begin
 		let gnames = Array.make (Array.length code.globals) "" in
 		PMap.iter (fun n i -> gnames.(i) <- n) ctx.cglobals.map;
-		if not (Common.defined com Define.SourceHeader) then begin
+		if not (Gctx.defined com Define.SourceHeader) then begin
 			let version_major = com.version / 1000 in
 			let version_minor = (com.version mod 1000) / 100 in
 			let version_revision = (com.version mod 100) in
-			Common.define_value com Define.SourceHeader (Printf.sprintf "Generated by HLC %d.%d.%d (HL v%d)" version_major version_minor version_revision code.version);
+			Gctx.define_value com Define.SourceHeader (Printf.sprintf "Generated by HLC %d.%d.%d (HL v%d)" version_major version_minor version_revision code.version);
 		end;
 		Hl2c.write_c com com.file code gnames;
 		let t = Timer.timer ["nativecompile";"hl"] in
-		if not (Common.defined com Define.NoCompilation) && com.run_command_args "haxelib" ["run";"hashlink";"build";escape_command com.file] <> 0 then failwith "Build failed";
+		if not (Gctx.defined com Define.NoCompilation) && com.run_command_args "haxelib" ["run";"hashlink";"build";escape_command com.file] <> 0 then failwith "Build failed";
 		t();
 	end else begin
 		let ch = IO.output_string() in
-		write_code ch code (not (Common.raw_defined com "hl_no_debug"));
+		write_code ch code (not (Gctx.raw_defined com "hl_no_debug"));
 		let str = IO.close_out ch in
 		let ch = open_out_bin com.file in
 		output_string ch str;
@@ -4313,10 +4319,10 @@ let generate com =
 	end;
 	Hlopt.clean_cache();
 	t();
-	if Common.raw_defined com "run" then begin
+	if Gctx.raw_defined com "run" then begin
 		if com.run_command_args "haxelib" ["run";"hashlink";"run";escape_command com.file] <> 0 then failwith "Failed to run HL";
 	end;
-	if Common.defined com Define.Interp then
+	if Gctx.defined com Define.Interp then
 		try
 			let t = Timer.timer ["generate";"hl";"interp"] in
 			let ctx = Hlinterp.create true in

+ 25 - 47
src/generators/genjs.ml

@@ -21,11 +21,11 @@ open Globals
 open Ast
 open Type
 open Error
-open Common
+open Gctx
 open JsSourcemap
 
 type ctx = {
-	com : Common.context;
+	com : Gctx.t;
 	buf : Rbuffer.t;
 	mutable chan : out_channel option;
 	packages : (string list,unit) Hashtbl.t;
@@ -46,7 +46,6 @@ type ctx = {
 	mutable separator : bool;
 	mutable found_expose : bool;
 	mutable catch_vars : texpr list;
-	mutable deprecation_context : DeprecationCheck.deprecation_context;
 }
 
 type object_store = {
@@ -90,7 +89,7 @@ let es5kwds = [
 
 let setup_kwds com =
 	Hashtbl.reset kwds;
-	let es_version = get_es_version com in
+	let es_version = Gctx.get_es_version com.defines in
 	let lst = if es_version >= 5 then es5kwds else es3kwds in
 	List.iter (fun s -> Hashtbl.add kwds s ()) lst
 
@@ -148,8 +147,8 @@ let module_field_expose_path mpath f =
 	with Not_found ->
 		(dot_path mpath) ^ "." ^ f.cf_name
 
-let has_feature ctx = Common.has_feature ctx.com
-let add_feature ctx = Common.add_feature ctx.com
+let has_feature ctx = Gctx.has_feature ctx.com
+let add_feature ctx = Gctx.add_feature ctx.com
 
 let unsupported p = abort "This expression cannot be compiled to Javascript" p
 
@@ -367,24 +366,6 @@ let rec gen_call ctx e el in_value =
 			| _ ->
 				abort "js.Lib.getOriginalException can only be called inside a catch block" e.epos
 		)
-	| TIdent "__new__", args ->
-		print_deprecation_message ctx.deprecation_context "__new__ is deprecated, use js.Syntax.construct instead" e.epos;
-		gen_syntax ctx "construct" args e.epos
-	| TIdent "__js__", args ->
-		print_deprecation_message ctx.deprecation_context "__js__ is deprecated, use js.Syntax.code instead" e.epos;
-		gen_syntax ctx "code" args e.epos
-	| TIdent "__instanceof__",  args ->
-		print_deprecation_message ctx.deprecation_context "__instanceof__ is deprecated, use js.Syntax.instanceof instead" e.epos;
-		gen_syntax ctx "instanceof" args e.epos
-	| TIdent "__typeof__",  args ->
-		print_deprecation_message ctx.deprecation_context "__typeof__ is deprecated, use js.Syntax.typeof instead" e.epos;
-		gen_syntax ctx "typeof" args e.epos
-	| TIdent "__strict_eq__" , args ->
-		print_deprecation_message ctx.deprecation_context "__strict_eq__ is deprecated, use js.Syntax.strictEq instead" e.epos;
-		gen_syntax ctx "strictEq" args e.epos
-	| TIdent "__strict_neq__" , args ->
-		print_deprecation_message ctx.deprecation_context "__strict_neq__ is deprecated, use js.Syntax.strictNeq instead" e.epos;
-		gen_syntax ctx "strictNeq" args e.epos
 	| TIdent "__define_feature__", [_;e] ->
 		gen_expr ctx e
 	| TIdent "__feature__", { eexpr = TConst (TString f) } :: eif :: eelse ->
@@ -550,13 +531,13 @@ and gen_expr ctx e =
 			print ctx ",$bind($_,$_%s))" (if Meta.has Meta.SelfCall f.cf_meta then "" else (field f.cf_name)))
 	| TEnumIndex x ->
 		gen_value ctx x;
-		if not (Common.defined ctx.com Define.JsEnumsAsArrays) then
+		if not (Gctx.defined ctx.com Define.JsEnumsAsArrays) then
 		print ctx "._hx_index"
 		else
 		print ctx "[1]"
 	| TEnumParameter (x,f,i) ->
 		gen_value ctx x;
-		if not (Common.defined ctx.com Define.JsEnumsAsArrays) then
+		if not (Gctx.defined ctx.com Define.JsEnumsAsArrays) then
 			let fname = (match f.ef_type with TFun((args,_)) -> let fname,_,_ = List.nth args i in  fname | _ -> die "" __LOC__ ) in
 			print ctx ".%s" (ident fname)
 		else
@@ -1031,7 +1012,7 @@ and gen_syntax ctx meth args pos =
 					)
 					args
 				in
-				Codegen.interpolate_code ctx.com code args (spr ctx) (gen_value ctx) code_pos
+				Codegen.interpolate_code ctx.com.error code args (spr ctx) (gen_value ctx) code_pos
 		end
 	| "plainCode", [code] ->
 		let code =
@@ -1147,7 +1128,6 @@ let can_gen_class_field ctx = function
 		is_physical_field f
 
 let gen_class_field ctx c f =
-	ctx.deprecation_context <- {ctx.deprecation_context with field_meta = f.cf_meta};
 	check_field_name c f;
 	match f.cf_expr with
 	| None ->
@@ -1473,7 +1453,6 @@ let generate_class_es6 ctx c =
 
 let generate_class ctx c =
 	ctx.current <- c;
-	ctx.deprecation_context <- {ctx.deprecation_context with class_meta = c.cl_meta};
 	ctx.id_counter <- 0;
 	(match c.cl_path with
 	| [],"Function" -> abort "This class redefine a native one" c.cl_pos
@@ -1496,7 +1475,7 @@ let generate_enum ctx e =
 	else
 		generate_package_create ctx e.e_path;
 	print ctx "%s = " p;
-	let as_objects = not (Common.defined ctx.com Define.JsEnumsAsArrays) in
+	let as_objects = not (Gctx.defined ctx.com Define.JsEnumsAsArrays) in
 	(if as_objects then
 		print ctx "$hxEnums[\"%s\"] = " dotp
 	else if has_feature ctx "Type.resolveEnum" then
@@ -1653,7 +1632,7 @@ let set_current_class ctx c =
 
 let alloc_ctx com es_version =
 	let smap =
-		if com.debug || Common.defined com Define.JsSourceMap || Common.defined com Define.SourceMap then
+		if com.debug || Gctx.defined com Define.JsSourceMap || Gctx.defined com Define.SourceMap then
 			Some {
 				source_last_pos = { file = 0; line = 0; col = 0};
 				print_comma = false;
@@ -1673,10 +1652,10 @@ let alloc_ctx com es_version =
 		chan = None;
 		packages = Hashtbl.create 0;
 		smap = smap;
-		js_modern = not (Common.defined com Define.JsClassic);
-		js_flatten = not (Common.defined com Define.JsUnflatten);
-		has_resolveClass = Common.has_feature com "Type.resolveClass";
-		has_interface_check = Common.has_feature com "js.Boot.__interfLoop";
+		js_modern = not (Gctx.defined com Define.JsClassic);
+		js_flatten = not (Gctx.defined com Define.JsUnflatten);
+		has_resolveClass = Gctx.has_feature com "Type.resolveClass";
+		has_interface_check = Gctx.has_feature com "js.Boot.__interfLoop";
 		es_version = es_version;
 		statics = [];
 		inits = [];
@@ -1689,7 +1668,6 @@ let alloc_ctx com es_version =
 		separator = false;
 		found_expose = false;
 		catch_vars = [];
-		deprecation_context = DeprecationCheck.create_context com;
 	} in
 
 	ctx.type_accessor <- (fun t ->
@@ -1714,22 +1692,22 @@ let gen_single_expr ctx e expr =
 	ctx.id_counter <- 0;
 	str
 
-let generate com =
-	(match com.js_gen with
+let generate js_gen com =
+	(match js_gen with
 	| Some g -> g()
 	| None ->
 
-	let es_version = get_es_version com in
+	let es_version = Gctx.get_es_version com.defines in
 
 	if es_version >= 6 then
 		ES6Ctors.rewrite_ctors com;
 
 	let ctx = alloc_ctx com es_version in
-	Codegen.map_source_header com (fun s -> print ctx "// %s\n" s);
+	Gctx.map_source_header com.defines (fun s -> print ctx "// %s\n" s);
 	if has_feature ctx "Class" || has_feature ctx "Type.getClassName" then add_feature ctx "js.Boot.isClass";
 	if has_feature ctx "Enum" || has_feature ctx "Type.getEnumName" then add_feature ctx "js.Boot.isEnum";
 
-	let nodejs = Common.raw_defined com "nodejs" in
+	let nodejs = Gctx.raw_defined com "nodejs" in
 
 	setup_kwds com;
 
@@ -1792,7 +1770,7 @@ let generate com =
 		| _ -> ()
 	) include_files;
 
-	let defined_global_value = Common.defined_value_safe com Define.JsGlobal in
+	let defined_global_value = Gctx.defined_value_safe com Define.JsGlobal in
 
 	let defined_global = defined_global_value <> "" in
 
@@ -1813,7 +1791,7 @@ let generate com =
 	) in
 
 	let closureArgs = [var_global] in
-	let closureArgs = if (anyExposed && not (Common.defined com Define.ShallowExpose)) then
+	let closureArgs = if (anyExposed && not (Gctx.defined com Define.ShallowExpose)) then
 		var_exports :: closureArgs
 	else
 		closureArgs
@@ -1829,7 +1807,7 @@ let generate com =
 		(* Add node globals to pseudo-keywords, so they are not shadowed by local vars *)
 		List.iter (fun s -> Hashtbl.replace kwds2 s ()) [ "global"; "process"; "__filename"; "__dirname"; "module" ];
 
-	if (anyExposed && ((Common.defined com Define.ShallowExpose) || not ctx.js_modern)) then (
+	if (anyExposed && ((Gctx.defined com Define.ShallowExpose) || not ctx.js_modern)) then (
 		print ctx "var %s = %s" (fst var_exports) (snd var_exports);
 		ctx.separator <- true;
 		newline ctx
@@ -1870,7 +1848,7 @@ let generate com =
 	if (not ctx.js_modern) && (ctx.es_version < 5) then
 		spr ctx "var console = $global.console || {log:function(){}};\n";
 
-	let enums_as_objects = not (Common.defined com Define.JsEnumsAsArrays) in
+	let enums_as_objects = not (Gctx.defined com Define.JsEnumsAsArrays) in
 
 	(* TODO: fix $estr *)
 	let vars = [] in
@@ -1989,7 +1967,7 @@ let generate com =
 		newline ctx;
 	end;
 
-	if (anyExposed && (Common.defined com Define.ShallowExpose)) then (
+	if (anyExposed && (Gctx.defined com Define.ShallowExpose)) then (
 		List.iter (fun f ->
 			print ctx "var %s = $hx_exports%s" f.os_name (path_to_brackets f.os_name);
 			ctx.separator <- true;
@@ -2006,7 +1984,7 @@ let generate com =
 	| Some smap ->
 		write_mappings ctx.com smap "file:///";
 		let basefile = Filename.basename com.file in
-		print ctx "\n//# sourceMappingURL=%s.map" (url_encode_s basefile);
+		print ctx "\n//# sourceMappingURL=%s.map" (StringHelper.url_encode_s basefile);
 	| None -> try Sys.remove (com.file ^ ".map") with _ -> ());
 	flush ctx;
 	Option.may (fun chan -> close_out chan) ctx.chan

+ 56 - 49
src/generators/genjvm.ml

@@ -19,7 +19,7 @@
 
 open Globals
 open Ast
-open Common
+open Gctx
 open Type
 open Path
 open JvmGlobals
@@ -53,7 +53,7 @@ let get_construction_mode c cf =
 (* Haxe *)
 
 type generation_context = {
-	com : Common.context;
+	gctx : Gctx.t;
 	out : Zip_output.any_output;
 	t_runtime_exception : Type.t;
 	entry_point : (tclass * texpr) option;
@@ -126,13 +126,13 @@ open NativeSignatures
 
 let jsignature_of_path path = match path with
 	| [],"Bool" -> TBool
-	| ["java"],"Int8" -> TByte
-	| ["java"],"Int16" -> TShort
+	| ["jvm"],"Int8" -> TByte
+	| ["jvm"],"Int16" -> TShort
 	| [],"Int" -> TInt
 	| ["haxe"],"Int32" -> TInt
 	| ["haxe"],"Int64" -> TLong
-	| ["java"],"Int64" -> TLong
-	| ["java"],"Char16" -> TChar
+	| ["jvm"],"Int64" -> TLong
+	| ["jvm"],"Char16" -> TChar
 	| [],"Single" -> TFloat
 	| [],"Float" -> TDouble
 	| [],"Dynamic" -> object_sig
@@ -183,7 +183,7 @@ let rec jsignature_of_type gctx stack t =
 	| TInst({cl_path = (["haxe";"root"],"Array")},[t]) ->
 		let t = get_boxed_type (jsignature_of_type t) in
 		TObject((["haxe";"root"],"Array"),[TType(WNone,t)])
-	| TInst({cl_path = (["java"],"NativeArray")},[t]) ->
+	| TInst({cl_path = (["jvm"],"NativeArray")},[t]) ->
 		TArray(jsignature_of_type t,None)
 	| TInst({cl_kind = KTypeParameter ttp; cl_path = (_,name)},_) ->
 		begin match get_constraints ttp with
@@ -515,7 +515,6 @@ class texpr_to_jvm
 	(jm : JvmMethod.builder)
 	(return_type : jsignature option)
 = object(self)
-	val com = gctx.com
 	val code = jm#get_code
 	val pool : JvmConstantPool.constant_pool = jc#get_pool
 
@@ -531,7 +530,7 @@ class texpr_to_jvm
 	method vtype t =
 		jsignature_of_type gctx t
 
-	method mknull t = com.basic.tnull (follow t)
+	method mknull t = gctx.gctx.basic.tnull (follow t)
 
 	(* locals *)
 
@@ -745,7 +744,7 @@ class texpr_to_jvm
 		| FInstance({cl_path = (["java";"lang"],"String")},_,{cf_name = "length"}) ->
 			self#texpr rvalue_any e1;
 			jm#invokevirtual string_path "length" (method_sig [] (Some TInt))
-		| FInstance({cl_path = (["java"],"NativeArray")},_,{cf_name = "length"}) ->
+		| FInstance({cl_path = (["jvm"],"NativeArray")},_,{cf_name = "length"}) ->
 			self#texpr rvalue_any e1;
 			let vtobj = self#vtype e1.etype in
 			code#arraylength vtobj;
@@ -858,7 +857,7 @@ class texpr_to_jvm
 					apply (fun () -> code#dup_x2;);
 					jm#expect_reference_type;
 					jm#invokevirtual c.cl_path "__set" (method_sig [TInt;object_sig] None);
-				| TInst({cl_path = (["java"],"NativeArray")},[t]) ->
+				| TInst({cl_path = (["jvm"],"NativeArray")},[t]) ->
 					let vte = self#vtype t in
 					let vta = self#vtype e1.etype in
 					self#texpr rvalue_any e1;
@@ -1000,13 +999,13 @@ class texpr_to_jvm
 			store();
 			let ev = mk (TLocal v) v.v_type null_pos in
 			let el = List.rev_map (fun case ->
-				let f e' = mk (TBinop(OpEq,ev,e')) com.basic.tbool e'.epos in
+				let f e' = mk (TBinop(OpEq,ev,e')) gctx.gctx.basic.tbool e'.epos in
 				let e_cond = match case.case_patterns with
 					| [] -> die "" __LOC__
 					| [e] -> f e
 					| e :: el ->
 						List.fold_left (fun eacc e ->
-							mk (TBinop(OpBoolOr,eacc,f e)) com.basic.tbool e.epos
+							mk (TBinop(OpBoolOr,eacc,f e)) gctx.gctx.basic.tbool e.epos
 						) (f e) el
 				in
 				(e_cond,case.case_expr)
@@ -1103,13 +1102,21 @@ class texpr_to_jvm
 	method binop_compare op e1 e2 =
 		let sig1 = jsignature_of_type gctx e1.etype in
 		let sig2 = jsignature_of_type gctx e2.etype in
+		let is_eq_op = match op with
+			| CmpEq
+			| CmpGe
+			| CmpLe ->
+				true
+			| _ ->
+				false
+		in
 		match (Texpr.skip e1),(Texpr.skip e2) with
 		| {eexpr = TConst TNull},_ when not (is_unboxed sig2) ->
 			self#texpr rvalue_any e2;
-			CmpSpecial ((if op = CmpEq then jm#get_code#if_nonnull else jm#get_code#if_null) sig2)
+			CmpSpecial ((if is_eq_op then jm#get_code#if_nonnull else jm#get_code#if_null) sig2)
 		| _,{eexpr = TConst TNull} when not (is_unboxed sig1) ->
 			self#texpr rvalue_any e1;
-			CmpSpecial ((if op = CmpEq then jm#get_code#if_nonnull else jm#get_code#if_null) sig1)
+			CmpSpecial ((if is_eq_op then jm#get_code#if_nonnull else jm#get_code#if_null) sig1)
 		| {eexpr = TConst (TInt i32);etype = t2},e1 when Int32.to_int i32 = 0 && sig2 = TInt ->
 			let op = match op with
 				| CmpGt -> CmpGe
@@ -1627,9 +1634,9 @@ class texpr_to_jvm
 			| _ ->
 				die "" __LOC__
 			end
-		| TIdent "__array__" | TField(_,FStatic({cl_path = (["java"],"NativeArray")},{cf_name = "make"})) ->
+		| TIdent "__array__" | TField(_,FStatic({cl_path = (["jvm"],"NativeArray")},{cf_name = "make"})) ->
 			begin match follow tr with
-			| TInst({cl_path = (["java"],"NativeArray")},[t]) ->
+			| TInst({cl_path = (["jvm"],"NativeArray")},[t]) ->
 				let jsig = self#vtype t in
 				self#new_native_array jsig el;
 				Some (array_sig jsig)
@@ -2039,7 +2046,7 @@ class texpr_to_jvm
 			else self#read (fun () -> self#cast_expect ret e.etype) e1 fa;
 		| TCall(e1,el) ->
 			self#call ret e.etype e1 el
-		| TNew({cl_path = (["java"],"NativeArray")},[t],[e1]) ->
+		| TNew({cl_path = (["jvm"],"NativeArray")},[t],[e1]) ->
 			self#texpr (if need_val ret then rvalue_any else RVoid) e1;
 			(* Technically this could throw... but whatever *)
 			if need_val ret then ignore(NativeArray.create jm#get_code jc#get_pool (jsignature_of_type gctx t))
@@ -2095,7 +2102,7 @@ class texpr_to_jvm
 				jm#cast TInt;
 				jm#invokevirtual c.cl_path "__get" (method_sig [TInt] (Some object_sig));
 				self#cast e.etype
-			| TInst({cl_path = (["java"],"NativeArray")},[t]) ->
+			| TInst({cl_path = (["jvm"],"NativeArray")},[t]) ->
 				self#texpr rvalue_any e1;
 				let vt = self#vtype e1.etype in
 				let vte = self#vtype t in
@@ -2135,7 +2142,7 @@ class texpr_to_jvm
 		| TParenthesis e1 | TMeta(_,e1) ->
 			self#texpr ret e1
 		| TFor(v,e1,e2) ->
-			self#texpr ret (Texpr.for_remap com.basic v e1 e2 e.epos)
+			self#texpr ret (Texpr.for_remap gctx.gctx.basic v e1 e2 e.epos)
 		| TEnumIndex e1 ->
 			self#texpr rvalue_any e1;
 			jm#invokevirtual java_enum_path "ordinal" (method_sig [] (Some TInt))
@@ -2585,9 +2592,9 @@ class tclass_to_jvm gctx c = object(self)
 			| None ->
 				if c.cl_path = (["haxe"],"Resource") && cf.cf_name = "content" then begin
 					let el = Hashtbl.fold (fun name _ acc ->
-						Texpr.Builder.make_string gctx.com.basic name null_pos :: acc
-					) gctx.com.resources [] in
-					let e = mk (TArrayDecl el) (gctx.com.basic.tarray gctx.com.basic.tstring) null_pos in
+						Texpr.Builder.make_string gctx.gctx.basic name null_pos :: acc
+					) gctx.gctx.resources [] in
+					let e = mk (TArrayDecl el) (gctx.gctx.basic.tarray gctx.gctx.basic.tstring) null_pos in
 					default e;
 				end;
 			| Some e when mtype <> MStatic ->
@@ -2598,8 +2605,8 @@ class tclass_to_jvm gctx c = object(self)
 				begin match cf.cf_kind with
 					| Method MethDynamic ->
 						let enull = Texpr.Builder.make_null efield.etype null_pos in
-						let echeck = Texpr.Builder.binop OpEq efield enull gctx.com.basic.tbool null_pos in
-						let eif = mk (TIf(echeck,eop,None)) gctx.com.basic.tvoid null_pos in
+						let echeck = Texpr.Builder.binop OpEq efield enull gctx.gctx.basic.tbool null_pos in
+						let eif = mk (TIf(echeck,eop,None)) gctx.gctx.basic.tvoid null_pos in
 						DynArray.add delayed_field_inits eif
 					| _ ->
 						DynArray.add field_inits eop
@@ -2636,11 +2643,11 @@ class tclass_to_jvm gctx c = object(self)
 		let jsig = method_sig [array_sig string_sig] None in
 		let jm = jc#spawn_method "main" jsig [MPublic;MStatic] in
 		let _,load,_ = jm#add_local "args" (TArray(string_sig,None)) VarArgument in
-		if has_feature gctx.com "haxe.root.Sys.args" then begin
+		if has_feature gctx.gctx "haxe.root.Sys.args" then begin
 			load();
 			jm#putstatic (["haxe";"root"],"Sys") "_args" (TArray(string_sig,None))
 		end;
-		jm#invokestatic (["haxe"; "java"], "Init") "init" (method_sig [] None);
+		jm#invokestatic (["haxe"; "jvm"], "Jvm") "init" (method_sig [] None);
 		self#generate_expr gctx None jc jm e SCNone MStatic;
 		if not jm#is_terminated then jm#return
 
@@ -2866,7 +2873,7 @@ let generate_enum gctx en =
 		jm_values#new_native_array (object_path_sig jc_enum#get_this_path) fl;
 		jm_values#return;
 		(* Add __meta__ TODO: do this via annotations instead? *)
-		begin match Texpr.build_metadata gctx.com.basic (TEnumDecl en) with
+		begin match Texpr.build_metadata gctx.gctx.basic (TEnumDecl en) with
 		| None ->
 			()
 		| Some e ->
@@ -3029,7 +3036,7 @@ module Preprocessor = struct
 				| _ ->
 					()
 			) m.m_types
-		) gctx.com.modules;
+		) gctx.gctx.modules;
 		(* preprocess classes *)
 		List.iter (fun mt ->
 			match mt with
@@ -3039,24 +3046,24 @@ module Preprocessor = struct
 				else if has_class_flag c CFunctionalInterface then
 					check_functional_interface gctx c
 			| _ -> ()
-		) gctx.com.types;
+		) gctx.gctx.types;
 		(* find typedef-interface implementations *)
 		List.iter (fun mt -> match mt with
 			| TClassDecl c when not (has_class_flag c CInterface) && not (has_class_flag c CExtern) ->
 				gctx.typedef_interfaces#process_class c;
 			| _ ->
 				()
-		) gctx.com.types
+		) gctx.gctx.types
 end
 
-let generate jvm_flag com =
-	let path = FilePath.parse com.file in
-	let jar_name,entry_point = match get_entry_point com with
+let generate jvm_flag gctx =
+	let path = FilePath.parse gctx.file in
+	let jar_name,entry_point = match get_entry_point gctx with
 		| Some (jarname,cl,expr) -> jarname, Some (cl,expr)
 		| None -> "jar",None
 	in
 	let compression_level = try
-		int_of_string (Define.defined_value com.defines Define.JvmCompressionLevel)
+		int_of_string (Define.defined_value gctx.defines Define.JvmCompressionLevel)
 	with _ ->
 		6
 	in
@@ -3069,10 +3076,10 @@ let generate jvm_flag com =
 		| Some _ ->
 			begin match path.directory with
 				| None ->
-					"./",create_jar ("./" ^ com.file)
+					"./",create_jar ("./" ^ gctx.file)
 				| Some dir ->
 					mkdir_from_path dir;
-					add_trailing_slash dir,create_jar com.file
+					add_trailing_slash dir,create_jar gctx.file
 			end
 		| None -> match path.directory with
 			| Some dir ->
@@ -3081,25 +3088,25 @@ let generate jvm_flag com =
 			| None ->
 				failwith "Please specify an output file name"
 	end else begin
-		let jar_name = if com.debug then jar_name ^ "-Debug" else jar_name in
-		let jar_dir = add_trailing_slash com.file in
+		let jar_name = if gctx.debug then jar_name ^ "-Debug" else jar_name in
+		let jar_dir = add_trailing_slash gctx.file in
 		let jar_path = Printf.sprintf "%s%s.jar" jar_dir jar_name in
 		jar_dir,create_jar jar_path
 	end in
 	let anon_identification = new tanon_identification in
 	let dynamic_level = try
-		int_of_string (Define.defined_value com.defines Define.JvmDynamicLevel)
+		int_of_string (Define.defined_value gctx.defines Define.JvmDynamicLevel)
 	with _ ->
 		1
 	in
 	if dynamic_level < 0 || dynamic_level > 2 then failwith "Invalid value for -D jvm.dynamic-level: Must be >=0 and <= 2";
 	let gctx = {
-		com = com;
+		gctx = gctx;
 		out = out;
-		t_runtime_exception = TInst(resolve_class com (["java";"lang"],"RuntimeException"),[]);
+		t_runtime_exception = TInst(resolve_class gctx (["java";"lang"],"RuntimeException"),[]);
 		entry_point = entry_point;
-		t_exception = TInst(resolve_class com (["java";"lang"],"Exception"),[]);
-		t_throwable = TInst(resolve_class com (["java";"lang"],"Throwable"),[]);
+		t_exception = TInst(resolve_class gctx (["java";"lang"],"Exception"),[]);
+		t_throwable = TInst(resolve_class gctx (["java";"lang"],"Throwable"),[]);
 		anon_identification = anon_identification;
 		preprocessor = Obj.magic ();
 		typedef_interfaces = Obj.magic ();
@@ -3110,14 +3117,14 @@ let generate jvm_flag com =
 		default_export_config = {
 			export_debug = true;
 		};
-		detail_times = Common.raw_defined com "jvm_times";
+		detail_times = Gctx.raw_defined gctx "jvm_times";
 		timer = new Timer.timer ["generate";"java"];
 		jar_compression_level = compression_level;
 		dynamic_level = dynamic_level;
 		functional_interfaces = [];
 	} in
 	Hashtbl.add gctx.known_typed_functions haxe_function_path ();
-	gctx.preprocessor <- new preprocessor com.basic (jsignature_of_type gctx);
+	gctx.preprocessor <- new preprocessor gctx.gctx.basic (jsignature_of_type gctx);
 	gctx.typedef_interfaces <- new typedef_interfaces gctx.preprocessor#get_infos anon_identification;
 	gctx.typedef_interfaces#add_interface_rewrite (["haxe";"root"],"Iterator") (["java";"util"],"Iterator") true;
 	let class_paths = ExtList.List.filter_map (fun java_lib ->
@@ -3134,13 +3141,13 @@ let generate jvm_flag com =
 			close_out ch_out;
 			Some (Printf.sprintf "lib/%s \n" name)
 		end
-	) com.native_libs.java_libs in
+	) gctx.gctx.native_libs in
 	Hashtbl.iter (fun name v ->
 		let filename = StringHelper.escape_res_name name ['/';'-'] in
 		gctx.out#add_entry v filename;
-	) com.resources;
+	) gctx.gctx.resources;
 	let generate_real_types () =
-		List.iter (generate_module_type gctx) com.types;
+		List.iter (generate_module_type gctx) gctx.gctx.types;
 	in
 	let generate_typed_interfaces () =
 		Hashtbl.iter (fun _ c -> generate_module_type gctx (TClassDecl c)) gctx.typedef_interfaces#get_interfaces;

+ 31 - 29
src/generators/genlua.ml

@@ -23,7 +23,7 @@
 open Extlib_leftovers
 open Ast
 open Type
-open Common
+open Gctx
 open ExtList
 open Error
 open JsSourcemap
@@ -31,7 +31,7 @@ open JsSourcemap
 type pos = Globals.pos
 
 type ctx = {
-    com : Common.context;
+    com : Gctx.t;
     buf : Buffer.t;
     packages : (string list,unit) Hashtbl.t;
     smap : sourcemap option;
@@ -137,8 +137,8 @@ let static_field c s =
     | "length" | "name" when not (has_class_flag c CExtern) || Meta.has Meta.HxGen c.cl_meta-> "._hx" ^ s
     | s -> field s
 
-let has_feature ctx = Common.has_feature ctx.com
-let add_feature ctx = Common.add_feature ctx.com
+let has_feature ctx = Gctx.has_feature ctx.com
+let add_feature ctx = Gctx.add_feature ctx.com
 
 let temp ctx =
     ctx.id_counter <- ctx.id_counter + 1;
@@ -458,7 +458,7 @@ and gen_call ctx e el =
      | TIdent "__lua__", [{ eexpr = TConst (TString code) }] ->
          spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n"))
      | TIdent "__lua__", { eexpr = TConst (TString code); epos = p } :: tl ->
-         Codegen.interpolate_code ctx.com code tl (spr ctx) (gen_expr ctx) p
+         Codegen.interpolate_code ctx.com.error code tl (spr ctx) (gen_expr ctx) p
      | TIdent "__type__",  [o] ->
          spr ctx "type";
          gen_paren ctx [o];
@@ -1886,7 +1886,7 @@ let generate_type_forward ctx = function
 
 let alloc_ctx com =
     let smap =
-		if com.debug || Common.defined com Define.SourceMap then
+		if com.debug || Gctx.defined com Define.SourceMap then
 			Some {
 				source_last_pos = { file = 0; line = 0; col = 0};
 				print_comma = false;
@@ -1919,10 +1919,10 @@ let alloc_ctx com =
         type_accessor = (fun _ -> Globals.die "" __LOC__);
         separator = false;
         found_expose = false;
-        lua_jit = Common.defined com Define.LuaJit;
-        lua_vanilla = Common.defined com Define.LuaVanilla;
+        lua_jit = Gctx.defined com Define.LuaJit;
+        lua_vanilla = Gctx.defined com Define.LuaVanilla;
         lua_ver = try
-                float_of_string (Common.defined_value com Define.LuaVer)
+                float_of_string (Gctx.defined_value com Define.LuaVer)
             with | Not_found -> 5.2;
     } in
     ctx.type_accessor <- (fun t ->
@@ -2009,7 +2009,7 @@ let transform_multireturn ctx = function
 let generate com =
     let ctx = alloc_ctx com in
 
-    Codegen.map_source_header com (fun s -> print ctx "-- %s\n" s);
+    Gctx.map_source_header com.defines (fun s -> print ctx "-- %s\n" s);
 
     if has_feature ctx "Class" || has_feature ctx "Type.getClassName" then add_feature ctx "lua.Boot.isClass";
     if has_feature ctx "Enum" || has_feature ctx "Type.getEnumName" then add_feature ctx "lua.Boot.isEnum";
@@ -2019,20 +2019,22 @@ let generate com =
         print ctx "%s\n" file_content;
     in
 
+	let find_file f = (com.class_paths#find_file f).file in
+
     (* base table-to-array helpers and metatables *)
-    print_file (Common.find_file com "lua/_lua/_hx_tab_array.lua");
+    print_file (find_file "lua/_lua/_hx_tab_array.lua");
 
     (* base lua "toString" functionality for haxe objects*)
-    print_file (Common.find_file com "lua/_lua/_hx_tostring.lua");
+    print_file (find_file "lua/_lua/_hx_tostring.lua");
 
     (* base lua metatables for prototypes, inheritance, etc. *)
-    print_file (Common.find_file com "lua/_lua/_hx_anon.lua");
+    print_file (find_file "lua/_lua/_hx_anon.lua");
 
     (* Helpers for creating metatables from prototypes *)
-    print_file (Common.find_file com "lua/_lua/_hx_objects.lua");
+    print_file (find_file "lua/_lua/_hx_objects.lua");
 
     (* base runtime class stubs for haxe value types (Int, Float, etc) *)
-    print_file (Common.find_file com "lua/_lua/_hx_classes.lua");
+    print_file (find_file "lua/_lua/_hx_classes.lua");
 
     let include_files = List.rev com.include_files in
     List.iter (fun file ->
@@ -2122,18 +2124,18 @@ let generate com =
 
     (* If bit ops are manually imported include the haxe wrapper for them *)
     if has_feature ctx "use._bitop" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_bit.lua");
+        print_file (find_file "lua/_lua/_hx_bit.lua");
     end;
 
     (* integer clamping is always required, and will use bit ops if available *)
-    print_file (Common.find_file com "lua/_lua/_hx_bit_clamp.lua");
+    print_file (find_file "lua/_lua/_hx_bit_clamp.lua");
 
     (* Array is required, always patch it *)
     println ctx "_hx_array_mt.__index = Array.prototype";
     newline ctx;
 
     (* Functions to support auto-run of libuv loop *)
-    print_file (Common.find_file com "lua/_lua/_hx_luv.lua");
+    print_file (find_file "lua/_lua/_hx_luv.lua");
 
     let b = open_block ctx in
     (* Localize init variables inside a do-block *)
@@ -2148,45 +2150,45 @@ let generate com =
     newline ctx;
 
     if has_feature ctx "use._hx_bind" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_bind.lua");
+        print_file (find_file "lua/_lua/_hx_bind.lua");
     end;
 
     if has_feature ctx "use._hx_staticToInstance" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_static_to_instance.lua");
+        print_file (find_file "lua/_lua/_hx_static_to_instance.lua");
     end;
 
     if has_feature ctx "use._hx_funcToField" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_func_to_field.lua");
+        print_file (find_file "lua/_lua/_hx_func_to_field.lua");
     end;
 
     if has_feature ctx "Math.random" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_random_init.lua");
+        print_file (find_file "lua/_lua/_hx_random_init.lua");
     end;
 
     if has_feature ctx "use._hx_print" then
-        print_file (Common.find_file com "lua/_lua/_hx_print.lua");
+        print_file (find_file "lua/_lua/_hx_print.lua");
 
     if has_feature ctx "use._hx_apply_self" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_apply_self.lua");
+        print_file (find_file "lua/_lua/_hx_apply_self.lua");
     end;
 
     if has_feature ctx "use._hx_box_mr" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_box_mr.lua");
+        print_file (find_file "lua/_lua/_hx_box_mr.lua");
     end;
 
     if has_feature ctx "use._hx_table" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_table.lua");
+        print_file (find_file "lua/_lua/_hx_table.lua");
     end;
 
     if has_feature ctx "use._hx_wrap_if_string_field" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_wrap_if_string_field.lua");
+        print_file (find_file "lua/_lua/_hx_wrap_if_string_field.lua");
     end;
 
     if has_feature ctx "use._hx_dyn_add" then begin
-        print_file (Common.find_file com "lua/_lua/_hx_dyn_add.lua");
+        print_file (find_file "lua/_lua/_hx_dyn_add.lua");
     end;
 
-    print_file (Common.find_file com "lua/_lua/_hx_handle_error.lua");
+    print_file (find_file "lua/_lua/_hx_handle_error.lua");
 
     println ctx "_hx_static_init();";
 

+ 11 - 11
src/generators/genneko.ml

@@ -21,11 +21,11 @@ open Ast
 open Globals
 open Type
 open Nast
-open Common
+open Gctx
 
 type context = {
 	version : int;
-	com : Common.context;
+	com : Gctx.t;
 	packages : (string list, unit) Hashtbl.t;
 	globals : (string list * string, string) Hashtbl.t;
 	mutable curglobal : int;
@@ -50,7 +50,7 @@ let pos ctx p =
 			try
 				Hashtbl.find files p.pfile
 			with Not_found ->
-				let path = (match Common.defined ctx.com Common.Define.AbsolutePath with
+				let path = (match Gctx.defined ctx.com Define.AbsolutePath with
 				| true -> if (Filename.is_relative p.pfile)
 					then Filename.concat (Sys.getcwd()) p.pfile
 					else p.pfile
@@ -371,7 +371,7 @@ and gen_expr ctx e =
 	| TCast (e,None) ->
 		gen_expr ctx e
 	| TCast (e1,Some t) ->
-		gen_expr ctx (Codegen.default_cast ~vtmp:"@tmp" ctx.com e1 t e.etype e.epos)
+		gen_expr ctx (Codegen.default_cast ~vtmp:"@tmp" ctx.com.basic ctx.com.std e1 t e.etype e.epos)
 	| TIdent s ->
 		ident p s
 	| TSwitch {switch_subject = e;switch_cases = cases;switch_default = eo} ->
@@ -771,19 +771,19 @@ let build ctx types =
 	let vars = List.concat (List.map (gen_static_vars ctx) types) in
 	packs @ methods @ boot :: names @ inits @ vars
 
-let generate com =
+let generate neko_lib_paths com =
 	Hashtbl.clear files;
-	let ctx = new_context com (if Common.defined com Define.NekoV1 then 1 else 2) false in
+	let ctx = new_context com (if Gctx.defined com Define.NekoV1 then 1 else 2) false in
 	let libs = (EBlock
-		(if Common.defined com Define.NekoNoHaxelibPaths then []
-		else generate_libs_init com.neko_lib_paths),
+		(if Gctx.defined com Define.NekoNoHaxelibPaths then []
+		else generate_libs_init neko_lib_paths),
 		{ psource = "<header>"; pline = 1; }
 	) in
 	let el = build ctx com.types in
 	let emain = (match com.main.main_expr with None -> [] | Some e -> [gen_expr ctx e]) in
 	let e = (EBlock ((header()) @ libs :: el @ emain), null_pos) in
-	let source = Common.defined com Define.NekoSource in
-	let use_nekoc = Common.defined com Define.UseNekoc in
+	let source = Gctx.defined com Define.NekoSource in
+	let use_nekoc = Gctx.defined com Define.UseNekoc in
 	if not use_nekoc then begin
 		try
 			Path.mkdir_from_path com.file;
@@ -791,7 +791,7 @@ let generate com =
 			Nbytecode.write ch (Ncompile.compile ctx.version e);
 			IO.close_out ch;
 		with Ncompile.Error (msg,pos) ->
-			let pfile = Common.find_file com pos.psource in
+			let pfile = Gctx.find_file com pos.psource in
 			let rec loop p =
 				let pp = { pfile = pfile; pmin = p; pmax = p; } in
 				if Lexer.get_error_line pp >= pos.pline then

+ 11 - 13
src/generators/genphp7.ml

@@ -3,8 +3,8 @@
 *)
 
 open Ast
+open Gctx
 open Type
-open Common
 open Meta
 open Globals
 open Sourcemaps
@@ -72,7 +72,7 @@ type used_type = {
 }
 
 type php_generator_context = {
-	pgc_common : Common.context;
+	pgc_common : Gctx.t;
 	(** Do not add comments with Haxe positions before each line of generated php code *)
 	pgc_skip_line_directives : bool;
 	(** The value of `-D php-prefix=value` split by dots *)
@@ -2011,8 +2011,6 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 			@see http://old.haxe.org/doc/advanced/magic#php-magic
 		*)
 		method write_expr_magic name args =
-			let msg = "untyped " ^ name ^ " is deprecated. Use php.Syntax instead." in
-			DeprecationCheck.warn_deprecation (DeprecationCheck.create_context ctx.pgc_common) msg self#pos;
 			let error = ("Invalid arguments for " ^ name ^ " magic call") in
 			match args with
 				| [] -> fail ~msg:error self#pos __LOC__
@@ -2021,7 +2019,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 						| "__php__" ->
 							(match expr.eexpr with
 								| TConst (TString php) ->
-									Codegen.interpolate_code ctx.pgc_common php args self#write self#write_expr self#pos
+									Codegen.interpolate_code ctx.pgc_common.error php args self#write self#write_expr self#pos
 								| _ -> fail self#pos __LOC__
 							)
 						| "__call__" ->
@@ -2445,7 +2443,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name =
 						)
 						args
 					in
-					Codegen.interpolate_code ctx.pgc_common php args self#write self#write_expr self#pos
+					Codegen.interpolate_code ctx.pgc_common.error php args self#write self#write_expr self#pos
 				| _ -> ctx.pgc_common.error "First argument of php.Syntax.code() must be a constant string." self#pos
 		(**
 			Writes error suppression operator (for `php.Syntax.suppress()`)
@@ -3045,7 +3043,7 @@ class virtual type_builder ctx (wrapper:type_wrapper) =
 			writer#indent 0;
 			writer#write_line "<?php";
 			writer#write_line "/**";
-			Codegen.map_source_header ctx.pgc_common (fun s -> writer#write_line (" * " ^ s));
+			Gctx.map_source_header ctx.pgc_common.defines (fun s -> writer#write_line (" * " ^ s));
 			if ctx.pgc_common.debug then writer#write_line (" * Haxe source file: " ^ self#get_source_file);
 			writer#write_line " */";
 			writer#write "\n";
@@ -3944,7 +3942,7 @@ class generator (ctx:php_generator_context) =
 			and name = builder#get_name in
 			let filename = (create_dir_recursive (build_dir :: namespace)) ^ "/" ^ name ^ ".php" in
 			let channel = open_out filename in
-			if Common.defined ctx.pgc_common Define.SourceMap then
+			if Gctx.defined ctx.pgc_common Define.SourceMap then
 				builder#set_sourcemap_generator (new sourcemap_builder filename);
 			output_string channel builder#get_contents;
 			close_out channel;
@@ -3993,7 +3991,7 @@ class generator (ctx:php_generator_context) =
 			match self#get_entry_point with
 				| None -> ()
 				| Some (uses, entry_point) ->
-					let filename = Common.defined_value_safe ~default:"index.php" ctx.pgc_common Define.PhpFront in
+					let filename = Gctx.defined_value_safe ~default:"index.php" ctx.pgc_common Define.PhpFront in
 					let front_dirs = split_file_path (Filename.dirname filename) in
 					if front_dirs <> [] then
 						ignore(create_dir_recursive (root_dir :: front_dirs));
@@ -4032,7 +4030,7 @@ class generator (ctx:php_generator_context) =
 			Returns path from `index.php` to directory which will contain all generated classes
 		*)
 		method private get_lib_path : string list =
-			let path = Common.defined_value_safe ~default:"lib" ctx.pgc_common Define.PhpLib in
+			let path = Gctx.defined_value_safe ~default:"lib" ctx.pgc_common Define.PhpLib in
 			split_file_path path
 		(**
 			Returns PHP code for entry point
@@ -4069,12 +4067,12 @@ let get_boot com : tclass =
 (**
 	Entry point to Genphp7
 *)
-let generate (com:context) =
+let generate (com:Gctx.t) =
 	let ctx =
 		{
 			pgc_common = com;
-			pgc_skip_line_directives = Common.defined com Define.RealPosition;
-			pgc_prefix = Str.split (Str.regexp "\\.") (Common.defined_value_safe com Define.PhpPrefix);
+			pgc_skip_line_directives = Gctx.defined com Define.RealPosition;
+			pgc_prefix = Str.split (Str.regexp "\\.") (Gctx.defined_value_safe com Define.PhpPrefix);
 			pgc_boot = get_boot com;
 			pgc_namespaces_types_cache = Hashtbl.create 512;
 			pgc_anons = Hashtbl.create 0;

+ 12 - 13
src/generators/genpy.ml

@@ -21,7 +21,7 @@ open Globals
 open Ast
 open Error
 open Type
-open Common
+open Gctx
 open Texpr.Builder
 
 module Utils = struct
@@ -955,7 +955,8 @@ module Transformer = struct
 			let r = { a_expr with eexpr = TArrayDecl exprs } in
 			lift_expr ae.a_next_id ~blocks:blocks r
 		| (is_value, TCast(e1,Some mt)) ->
-			let e = Codegen.default_cast ~vtmp:(ae.a_next_id()) (match !como with Some com -> com | None -> die "" __LOC__) e1 mt ae.a_expr.etype ae.a_expr.epos in
+			let com = (match !como with Some com -> com | None -> die "" __LOC__) in
+			let e = Codegen.default_cast ~vtmp:(ae.a_next_id()) com.basic com.std e1 mt ae.a_expr.etype ae.a_expr.epos in
 			transform_expr ae.a_next_id ~is_value:is_value e
 		| (is_value, TCast(e,None)) ->
 			let e = trans is_value [] e in
@@ -999,12 +1000,12 @@ module Printer = struct
 		pc_indent : string;
 		pc_next_anon_func : unit -> string;
 		pc_debug : bool;
-		pc_com : Common.context;
+		pc_com : Gctx.t;
 	}
 
-	let has_feature pctx = Common.has_feature pctx.pc_com
+	let has_feature pctx = Gctx.has_feature pctx.pc_com
 
-	let add_feature pctx = Common.add_feature pctx.pc_com
+	let add_feature pctx = Gctx.add_feature pctx.pc_com
 
 	let create_context =
 		let n = ref (-1) in
@@ -1491,11 +1492,9 @@ module Printer = struct
 			| ("python_Syntax.code"),({ eexpr = TConst (TString code) } as ecode) :: tl ->
 				let buf = Buffer.create 0 in
 				let interpolate () =
-					Codegen.interpolate_code pctx.pc_com code tl (Buffer.add_string buf) (fun e -> Buffer.add_string buf (print_expr pctx e)) ecode.epos
+					Codegen.interpolate_code pctx.pc_com.error code tl (Buffer.add_string buf) (fun e -> Buffer.add_string buf (print_expr pctx e)) ecode.epos
 				in
-				let old = pctx.pc_com.error_ext in
-				pctx.pc_com.error_ext <- (fun err -> raise (Error.Fatal_error err));
-				Std.finally (fun() -> pctx.pc_com.error_ext <- old) interpolate ();
+				interpolate ();
 				Buffer.contents buf
 			| ("python_Syntax._pythonCode"), [e] ->
 				print_expr pctx e
@@ -1673,7 +1672,7 @@ end
 
 module Generator = struct
 	type context = {
-		com : Common.context;
+		com : Gctx.t;
 		buf : Buffer.t;
 		packages : (string,int) Hashtbl.t;
 		mutable static_inits : (unit -> unit) list;
@@ -1683,8 +1682,8 @@ module Generator = struct
 		print_time : float;
 	}
 
-	let has_feature ctx = Common.has_feature ctx.com
-	let add_feature ctx = Common.add_feature ctx.com
+	let has_feature ctx = Gctx.has_feature ctx.com
+	let add_feature ctx = Gctx.add_feature ctx.com
 
 	type class_field_infos = {
 		cfd_fields : string list;
@@ -2427,7 +2426,7 @@ module Generator = struct
 	let run com =
 		Transformer.init com;
 		let ctx = mk_context com in
-		Codegen.map_source_header com (fun s -> print ctx "# %s\n# coding: utf-8\n" s);
+		Gctx.map_source_header com.defines (fun s -> print ctx "# %s\n# coding: utf-8\n" s);
 		if has_feature ctx "closure_Array" || has_feature ctx "closure_String" then
 			spr ctx "from functools import partial as _hx_partial\n";
 		spr ctx "import sys\n";

+ 52 - 32
src/generators/genswf.ml

@@ -21,10 +21,9 @@ open As3hl
 open ExtString
 open Type
 open Error
-open Common
+open Gctx
 open Ast
 open Globals
-open NativeLibraries
 
 let tag ?(ext=false) d = {
 	tid = 0;
@@ -32,14 +31,35 @@ let tag ?(ext=false) d = {
 	tdata = d;
 }
 
-let convert_header com (w,h,fps,bg) =
+let flash_version_tag = function
+	| 6. -> 6
+	| 7. -> 7
+	| 8. -> 8
+	| 9. -> 9
+	| 10. | 10.1 -> 10
+	| 10.2 -> 11
+	| 10.3 -> 12
+	| 11. -> 13
+	| 11.1 -> 14
+	| 11.2 -> 15
+	| 11.3 -> 16
+	| 11.4 -> 17
+	| 11.5 -> 18
+	| 11.6 -> 19
+	| 11.7 -> 20
+	| 11.8 -> 21
+	| 11.9 -> 22
+	| v when v >= 12.0 && float_of_int (int_of_float v) = v -> int_of_float v + 11
+	| v -> failwith ("Invalid SWF version " ^ string_of_float v)
+
+let convert_header com flash_version (w,h,fps,bg) =
 	let high = (max w h) * 20 in
 	let rec loop b =
 		if 1 lsl b > high then b else loop (b + 1)
 	in
 	let bits = loop 0 in
 	{
-		h_version = Common.flash_version_tag com.flash_version;
+		h_version = flash_version_tag flash_version;
 		h_size = {
 			rect_nbits = bits + 1;
 			left = 0;
@@ -49,11 +69,11 @@ let convert_header com (w,h,fps,bg) =
 		};
 		h_frame_count = 1;
 		h_fps = to_float16 (if fps > 127.0 then 127.0 else fps);
-		h_compressed = not (Common.defined com Define.NoSwfCompress);
+		h_compressed = not (Gctx.defined com Define.NoSwfCompress);
 	} , bg
 
-let default_header com =
-	convert_header com (400,300,30.,0xFFFFFF)
+let default_header com flash_version =
+	convert_header com flash_version (400,300,30.,0xFFFFFF)
 
 type dependency_kind =
 	| DKInherit
@@ -223,7 +243,7 @@ let detect_format data p =
 		abort "Unknown file format" p
 
 let build_swf9 com file swc =
-	let boot_name = if swc <> None || Common.defined com Define.HaxeBoot then "haxe" else "boot_" ^ (String.sub (Digest.to_hex (Digest.string (Filename.basename file))) 0 4) in
+	let boot_name = if swc <> None || Gctx.defined com Define.HaxeBoot then "haxe" else "boot_" ^ (String.sub (Digest.to_hex (Digest.string (Filename.basename file))) 0 4) in
 	let code = Genswf9.generate com boot_name in
 	let code = (match swc with
 	| Some cat ->
@@ -256,7 +276,7 @@ let build_swf9 com file swc =
 		tag (TBinaryData (!cid,data)) :: acc
 	) com.resources [] in
 	let load_file_data file p =
-		let file = try Common.find_file com file with Not_found -> file in
+		let file = try Gctx.find_file com  file with Not_found -> file in
 		if String.length file > 5 && String.sub file 0 5 = "data:" then
 			String.sub file 5 (String.length file - 5)
 		else
@@ -435,12 +455,12 @@ let build_swf9 com file swc =
 	let clips = [tag (TF9Classes (List.rev !classes))] in
 	res @ bmp @ code @ clips
 
-let merge com file priority (h1,tags1) (h2,tags2) =
+let merge com flash_version file priority (h1,tags1) (h2,tags2) =
 	(* prioritize header+bgcolor for first swf *)
-	let header = if priority then { h2 with h_version = max h2.h_version (Common.flash_version_tag com.flash_version) } else h1 in
+	let header = if priority then { h2 with h_version = max h2.h_version (flash_version_tag flash_version) } else h1 in
 	let tags1 = if priority then List.filter (function { tdata = TSetBgColor _ } -> false | _ -> true) tags1 else tags1 in
 	(* remove unused tags *)
-	let use_stage = priority && Common.defined com Define.FlashUseStage in
+	let use_stage = priority && Gctx.defined com Define.FlashUseStage in
 	let classes = ref [] in
 	let nframe = ref 0 in
 	let tags2 = List.filter (fun t ->
@@ -451,9 +471,9 @@ let merge com file priority (h1,tags1) (h2,tags2) =
 		| TRemoveObject _ -> use_stage
 		| TShowFrame -> incr nframe; use_stage
 		| TFilesAttributes _ | TEnableDebugger2 _ | TScenes _ -> false
-		| TMetaData _ -> not (Common.defined com Define.SwfMetadata)
+		| TMetaData _ -> not (Gctx.defined com Define.SwfMetadata)
 		| TSetBgColor _ -> priority
-		| TExport el when !nframe = 0 && com.flash_version >= 9. ->
+		| TExport el when !nframe = 0 && flash_version >= 9. ->
 			let el = List.filter (fun e ->
 				let path = parse_path e.exp_name in
 				let b = List.exists (fun t -> t_path t = path) com.types in
@@ -508,8 +528,8 @@ let merge com file priority (h1,tags1) (h2,tags2) =
 	let tags = loop tags1 tags2 in
 	header, tags
 
-let generate swf_header com =
-	let swc = if Common.defined com Define.Swc then Some (ref "") else None in
+let generate swf_header swf_libs flash_version com =
+	let swc = if Gctx.defined com Define.Swc then Some (ref "") else None in
 	let file , codeclip = (try let f , c = ExtString.String.split com.file "@" in f, Some c with _ -> com.file , None) in
 	(* list exports *)
 	let exports = Hashtbl.create 0 in
@@ -541,39 +561,39 @@ let generate swf_header com =
 				) el
 			| _ -> ()
 		) tags;
-	) com.native_libs.swf_libs;
+	) swf_libs;
 	(* build haxe swf *)
 	let tags = build_swf9 com file swc in
-	let header, bg = (match swf_header with None -> default_header com | Some h -> convert_header com h) in
+	let header, bg = (match swf_header with None -> default_header com flash_version | Some h -> convert_header com flash_version h) in
 	let bg = tag (TSetBgColor { cr = bg lsr 16; cg = (bg lsr 8) land 0xFF; cb = bg land 0xFF }) in
 	let scene = tag ~ext:true (TScenes ([(0,"Scene1")],[])) in
 	let swf_debug_password = try
-		Digest.to_hex(Digest.string (Common.defined_value com Define.SwfDebugPassword))
+		Digest.to_hex(Digest.string (Gctx.defined_value com Define.SwfDebugPassword))
 	with Not_found ->
 		""
 	in
-	let debug = (if Common.defined com Define.Fdb then [tag (TEnableDebugger2 (0, swf_debug_password))] else []) in
+	let debug = (if Gctx.defined com Define.Fdb then [tag (TEnableDebugger2 (0, swf_debug_password))] else []) in
 	let meta_data =
 		try
-			let file = Common.defined_value com Define.SwfMetadata in
-			let file = try Common.find_file com file with Not_found -> file in
+			let file = Gctx.defined_value com Define.SwfMetadata in
+			let file = try Gctx.find_file com file with Not_found -> file in
 			let data = try Std.input_file ~bin:true file with Sys_error _ -> failwith ("Metadata resource file not found : " ^ file) in
 			[tag(TMetaData (data))]
 		with Not_found ->
 			[]
 	in
-	let fattr = (if com.flash_version < 8. then [] else
+	let fattr = (if flash_version < 8. then [] else
 		[tag (TFilesAttributes {
-			fa_network = Common.defined com Define.NetworkSandbox;
+			fa_network = Gctx.defined com Define.NetworkSandbox;
 			fa_as3 = true;
 			fa_metadata = meta_data <> [];
-			fa_gpu = com.flash_version > 9. && Common.defined com Define.SwfGpu;
-			fa_direct_blt = com.flash_version > 9. && Common.defined com Define.SwfDirectBlit;
+			fa_gpu = flash_version > 9. && Gctx.defined com Define.SwfGpu;
+			fa_direct_blt = flash_version > 9. && Gctx.defined com Define.SwfDirectBlit;
 		})]
 	) in
-	let fattr = if Common.defined com Define.AdvancedTelemetry then fattr @ [tag (TUnknown (0x5D,"\x00\x00"))] else fattr in
+	let fattr = if Gctx.defined com Define.AdvancedTelemetry then fattr @ [tag (TUnknown (0x5D,"\x00\x00"))] else fattr in
 	let swf_script_limits = try
-		let s = Common.defined_value com Define.SwfScriptTimeout in
+		let s = Gctx.defined_value com Define.SwfScriptTimeout in
 		let i = try int_of_string s with _ -> abort "Argument to swf_script_timeout must be an integer" null_pos in
 		[tag(TScriptLimits (256, if i < 0 then 0 else if i > 65535 then 65535 else i))]
 	with Not_found ->
@@ -583,12 +603,12 @@ let generate swf_header com =
 	(* merge swf libraries *)
 	let priority = ref (swf_header = None) in
 	let swf = List.fold_left (fun swf swf_lib ->
-		let swf = merge com file !priority swf (SwfLoader.remove_classes toremove swf_lib#get_data swf_lib#list_modules) in
+		let swf = merge com flash_version file !priority swf (SwfLoader.remove_classes toremove swf_lib#get_data swf_lib#list_modules) in
 		priority := false;
 		swf
-	) swf com.native_libs.swf_libs in
+	) swf swf_libs in
 	let swf = match swf with
-	| header,tags when Common.defined com Define.SwfPreloaderFrame ->
+	| header,tags when Gctx.defined com Define.SwfPreloaderFrame ->
 		let rec loop l =
 			match l with
 			| ({tdata = TFilesAttributes _ | TUnknown (0x5D,"\x00\x00") | TMetaData _ | TSetBgColor _ | TEnableDebugger2 _ | TScriptLimits _} as t) :: l -> t :: loop l
@@ -599,7 +619,7 @@ let generate swf_header com =
 	| _ -> swf in
 	(* write swf/swc *)
 	let t = Timer.timer ["write";"swf"] in
-	let level = (try int_of_string (Common.defined_value com Define.SwfCompressLevel) with Not_found -> 9) in
+	let level = (try int_of_string (Gctx.defined_value com Define.SwfCompressLevel) with Not_found -> 9) in
 	SwfParser.init Extc.input_zip (Extc.output_zip ~level);
 	(match swc with
 	| Some cat ->

+ 10 - 10
src/generators/genswf9.ml

@@ -19,11 +19,11 @@
 open Extlib_leftovers
 open Globals
 open Ast
+open Gctx
 open Type
 open Error
 open As3
 open As3hl
-open Common
 open FlashProps
 
 type read = Read
@@ -81,7 +81,7 @@ type try_infos = {
 
 type context = {
 	(* globals *)
-	com : Common.context;
+	com : Gctx.t;
 	debugger : bool;
 	swc : bool;
 	boot : path;
@@ -351,7 +351,7 @@ let property ctx fa t =
 	| TInst ({ cl_path = [],"Array" },_) ->
 		(match p with
 		| "length" -> ident p, Some KInt, false (* UInt in the spec *)
-		| "map" | "filter" when Common.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
+		| "map" | "filter" when Gctx.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
 		| "copy" | "insert" | "contains" | "remove" | "iterator" | "keyValueIterator"
 		| "toString" | "map" | "filter" | "resize" -> ident p , None, true
 		| _ -> as3 p, None, false);
@@ -364,13 +364,13 @@ let property ctx fa t =
 	| TInst ({ cl_path = [],"String" },_) ->
 		(match p with
 		| "length" (* Int in AS3/Haxe *) -> ident p, None, false
-		| "charCodeAt" when Common.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
+		| "charCodeAt" when Gctx.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
 		| "charCodeAt" (* use Haxe version *) -> ident p, None, true
 		| "cca" -> as3 "charCodeAt", None, false
 		| _ -> as3 p, None, false);
 	| TInst ({ cl_path = [],"Date" },_) ->
 		(match p with
-		| "toString" when Common.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
+		| "toString" when Gctx.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
 		| _ -> ident p, None, false)
 	| TAnon a ->
 		(match !(a.a_status) with
@@ -2833,7 +2833,7 @@ let generate_resource ctx name =
 let generate com boot_name =
 	let ctx = {
 		com = com;
-		need_ctor_skip = Common.has_feature com "Type.createEmptyInstance";
+		need_ctor_skip = Gctx.has_feature com "Type.createEmptyInstance";
 		handle_spread_args = (fun basic args t_result args_to_expr ->
 			match List.rev args with
 			| { eexpr = TUnop (Spread,Prefix,rest) } :: args_rev ->
@@ -2869,12 +2869,12 @@ let generate com boot_name =
 			| _ ->
 				None
 		);
-		debug = com.Common.debug;
+		debug = com.Gctx.debug;
 		cur_class = null_class;
 		boot = ([],boot_name);
-		debugger = Common.defined com Define.Fdb;
-		swc = Common.defined com Define.Swc;
-		swf_protected = Common.defined com Define.SwfProtected;
+		debugger = Gctx.defined com Define.Fdb;
+		swc = Gctx.defined com Define.Swc;
+		swf_protected = Gctx.defined com Define.SwfProtected;
 		code = DynArray.create();
 		locals = PMap.empty;
 		infos = default_infos();

+ 14 - 12
src/generators/hl2c.ml

@@ -78,7 +78,7 @@ type context = {
 	mutable file_prefix : string;
 	mutable fun_index : int;
 	mutable type_module : (ttype, code_module) PMap.t;
-	gcon : Common.context;
+	gcon : Gctx.t;
 }
 
 let sprintf = Printf.sprintf
@@ -117,7 +117,7 @@ let s_comp = function
 let core_types =
 	let vp = { vfields = [||]; vindex = PMap.empty } in
 	let ep = { ename = ""; eid = 0; eglobal = None; efields = [||] } in
-	[HVoid;HUI8;HUI16;HI32;HI64;HF32;HF64;HBool;HBytes;HDyn;HFun ([],HVoid);HObj null_proto;HArray;HType;HRef HVoid;HVirtual vp;HDynObj;HAbstract ("",0);HEnum ep;HNull HVoid;HMethod ([],HVoid);HStruct null_proto]
+	[HVoid;HUI8;HUI16;HI32;HI64;HF32;HF64;HBool;HBytes;HDyn;HFun ([],HVoid);HObj null_proto;HArray HDyn;HType;HRef HVoid;HVirtual vp;HDynObj;HAbstract ("",0);HEnum ep;HNull HVoid;HMethod ([],HVoid);HStruct null_proto]
 
 let tname str =
 	let n = String.concat "__" (ExtString.String.nsplit str ".") in
@@ -125,7 +125,7 @@ let tname str =
 
 let is_gc_ptr = function
 	| HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HType | HRef _ | HMethod _ | HPacked _ -> false
-	| HBytes | HDyn | HFun _ | HObj _ | HArray | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ | HStruct _ -> true
+	| HBytes | HDyn | HFun _ | HObj _ | HArray _ | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ | HStruct _ -> true
 
 let is_ptr = function
 	| HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool -> false
@@ -144,7 +144,7 @@ let rec ctype_no_ptr = function
 	| HDyn -> "vdynamic",1
 	| HFun _ -> "vclosure",1
 	| HObj p | HStruct p -> tname p.pname,0
-	| HArray -> "varray",1
+	| HArray _ -> "varray",1
 	| HType -> "hl_type",1
 	| HRef t -> let s,i = ctype_no_ptr t in s,i + 1
 	| HVirtual _ -> "vvirtual",1
@@ -192,7 +192,7 @@ let type_id t =
 	| HDyn -> "HDYN"
 	| HFun _ -> "HFUN"
 	| HObj _ -> "HOBJ"
-	| HArray -> "HARRAY"
+	| HArray _ -> "HARRAY"
 	| HType -> "HTYPE"
 	| HRef _ -> "HREF"
 	| HVirtual _ -> "HVIRTUAL"
@@ -237,7 +237,7 @@ let define ctx s =
 
 let rec define_type ctx t =
 	match t with
-	| HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HBytes | HDyn | HArray | HType | HDynObj | HNull _ | HRef _ -> ()
+	| HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HBytes | HDyn | HArray _ | HType | HDynObj | HNull _ | HRef _ -> ()
 	| HAbstract _ ->
 		define ctx "#include <hl/natives.h>";
 	| HFun (args,ret) | HMethod (args,ret) ->
@@ -345,7 +345,7 @@ let short_digest str =
 let open_file ctx file =
 	if ctx.curfile <> "" then close_file ctx;
 	if file <> "hlc.json" then
-		Codegen.map_source_header ctx.gcon (fun s -> define ctx (sprintf "// %s" s));
+		Gctx.map_source_header ctx.gcon.defines (fun s -> define ctx (sprintf "// %s" s));
 	ctx.curfile <- file;
 	ctx.fun_index <- 0;
 	ctx.file_prefix <- (short_digest file) ^ "_"
@@ -744,7 +744,7 @@ let generate_function ctx f =
 			match rtype a, rtype b with
 			| (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64), (HUI8 | HUI16 | HI32 | HF32 | HF64 | HBool | HI64) ->
 				phys_compare()
-			| HBytes, HBytes | HArray,HArray ->
+			| HBytes, HBytes | HArray _,HArray _ ->
 				phys_compare()
 			| HType, HType ->
 				sexpr "if( hl_same_type(%s,%s) %s 0 ) {} else goto %s" (reg a) (reg b) (s_comp op) (label d)
@@ -1095,7 +1095,7 @@ let generate_function ctx f =
 			sexpr "hl_assert()"
 		| ORefData (r,d) ->
 			(match rtype d with
-			| HArray ->
+			| HArray _ ->
 				sexpr "%s = (%s)hl_aptr(%s,void*)" (reg r) (ctype (rtype r)) (reg d)
 			| _ ->
 				Globals.die "" __LOC__)
@@ -1138,7 +1138,7 @@ let make_types_idents htypes =
 	let types_descs = ref PMap.empty in
 	let rec make_desc t =
 		match t with
-		| HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HBytes | HDyn | HArray | HType | HRef _ | HDynObj | HNull _ ->
+		| HVoid | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HBytes | HDyn | HArray _ | HType | HRef _ | HDynObj | HNull _ ->
 			DSimple t
 		| HFun (tl,t) ->
 			DFun (List.map make_desc tl, make_desc t, true)
@@ -1181,6 +1181,8 @@ let make_types_idents htypes =
 			"t$nul_" ^ tstr t
 		| DSimple (HRef t) ->
 			"t$ref_" ^ (match make_desc t with DSimple _ -> tstr t | d -> desc_string d)
+		| DSimple (HArray t) ->
+			"t$array_" ^ (desc_string (make_desc t))
 		| DSimple t ->
 			"t$_" ^ tstr t
 		| DFun _ ->
@@ -1459,7 +1461,7 @@ let write_c com file (code:code) gnames =
 	let bnames = Array.map (fun b -> "bytes$" ^ short_digest (Digest.to_hex (Digest.bytes b))) code.bytes in
 
 	let ctx = {
-		version = com.Common.version;
+		version = com.Gctx.version;
 		out = Buffer.create 1024;
 		tabs = "";
 		hlcode = code;
@@ -1574,7 +1576,7 @@ let write_c com file (code:code) gnames =
 	in
 	Array.iteri (fun i str ->
 		if String.length str >= string_data_limit then begin
-			let s = Common.utf8_to_utf16 str true in
+			let s = StringHelper.utf8_to_utf16 str true in
 			sline "// %s..." (String.escaped (String.sub str 0 (string_data_limit-4)));
 			output ctx (Printf.sprintf "vbyte string$%s[] = {" (short_digest str));
 			output_bytes (output ctx) s;

+ 18 - 5
src/generators/hlcode.ml

@@ -38,7 +38,7 @@ type ttype =
 	| HDyn
 	| HFun of ttype list * ttype
 	| HObj of class_proto
-	| HArray
+	| HArray of ttype
 	| HType
 	| HRef of ttype
 	| HVirtual of virtual_proto
@@ -258,7 +258,7 @@ let list_mapi f l =
 *)
 let is_nullable t =
 	match t with
-	| HBytes | HDyn | HFun _ | HObj _ | HArray | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ | HRef _ | HType | HMethod _ | HStruct _ -> true
+	| HBytes | HDyn | HFun _ | HObj _ | HArray _ | HVirtual _ | HDynObj | HAbstract _ | HEnum _ | HNull _ | HRef _ | HType | HMethod _ | HStruct _ -> true
 	| HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 | HBool | HVoid | HPacked _ -> false
 
 let is_struct = function
@@ -288,7 +288,7 @@ let is_nullt = function
 *)
 let is_dynamic t =
 	match t with
-	| HDyn | HFun _ | HObj _ | HArray | HVirtual _ | HDynObj | HNull _ | HEnum _ -> true
+	| HDyn | HFun _ | HObj _ | HArray _ | HVirtual _ | HDynObj | HNull _ | HEnum _ -> true
 	| _ -> false
 
 let rec tsame t1 t2 =
@@ -314,6 +314,17 @@ let rec tsame t1 t2 =
 	| HRef t1, HRef t2 -> tsame t1 t2
 	| _ -> false
 
+let compatible_element_types t1 t2 =
+	if t1 == t2 then
+		true (* equal types are always compatible *)
+	else match t1,t2 with
+	| (HI32 | HF32),(HI32 | HF32)
+	| (HI64 | HF64),(HI64 | HF64) ->
+		true (* same size numbers are also compatible *)
+	| _ ->
+		(* no other number combinations are compatible, but everything else is *)
+		not (is_number t1) && not (is_number t2)
+
 (*
 	can we use a value of t1 as t2
 *)
@@ -345,6 +356,8 @@ let rec safe_cast t1 t2 =
 		safe_cast t1 t2
 	| HFun (args1,t1), HFun (args2,t2) when List.length args1 = List.length args2 ->
 		List.for_all2 (fun t1 t2 -> safe_cast t2 t1 || (t1 = HDyn && is_dynamic t2)) args1 args2 && safe_cast t1 t2
+	| HArray t1,HArray t2 ->
+		compatible_element_types t1 t2
 	| _ ->
 		tsame t1 t2
 
@@ -456,8 +469,8 @@ let rec tstr ?(stack=[]) ?(detailed=false) t =
 		let proto = "{"  ^ String.concat "," (List.map (fun p -> (match p.fvirtual with None -> "" | Some _ -> "virtual ") ^ p.fname ^ "@" ^  string_of_int p.fmethod) (Array.to_list o.pproto)) ^ "}" in
 		let str = o.pname ^ "[" ^ (match o.psuper with None -> "" | Some p -> ">" ^ p.pname ^ " ") ^ "fields=" ^ fields ^ " proto=" ^ proto ^ "]" in
 		(match t with HObj o -> str | _ -> "@" ^ str)
-	| HArray ->
-		"array"
+	| HArray t ->
+		"array(" ^ (tstr ~stack ~detailed t) ^ ")"
 	| HType ->
 		"type"
 	| HRef t ->

+ 20 - 16
src/generators/hlinterp.ml

@@ -132,7 +132,7 @@ let get_type = function
 	| VObj o -> Some (HObj o.oproto.pclass)
 	| VDynObj _ -> Some HDynObj
 	| VVirtual v -> Some (HVirtual v.vtype)
-	| VArray _ -> Some HArray
+	| VArray (_,t) -> Some (HArray t)
 	| VClosure (f,None) -> Some (match f with FFun f -> f.ftype | FNativeFun (_,_,t) -> t)
 	| VClosure (f,Some _) -> Some (match f with FFun { ftype = HFun(_::args,ret) } | FNativeFun (_,_,HFun(_::args,ret)) -> HFun (args,ret) | _ -> Globals.die "" __LOC__)
 	| VVarArgs _ -> Some (HFun ([],HDyn))
@@ -158,7 +158,7 @@ let rec is_compatible v t =
 	| v, HNull t -> is_compatible v t
 	| v, HDyn -> v_dynamic v
 	| VType _, HType -> true
-	| VArray _, HArray -> true
+	| VArray _, HArray _ -> true
 	| VDynObj _, HDynObj -> true
 	| VVirtual v, HVirtual _ -> safe_cast (HVirtual v.vtype) t
 	| VRef (_,t1), HRef t2 -> tsame t1 t2
@@ -292,7 +292,7 @@ let fstr = function
 	| FFun f -> "function@" ^ string_of_int f.findex
 	| FNativeFun (s,_,_) -> "native[" ^ s ^ "]"
 
-let caml_to_hl str = Common.utf8_to_utf16 str true
+let caml_to_hl str = StringHelper.utf8_to_utf16 str true
 
 let hash ctx str =
 	let h = hl_hash str in
@@ -317,7 +317,7 @@ let utf16_iter f s =
 	loop 0
 
 let utf16_char buf c =
-	Common.utf16_add buf (int_of_char c)
+	StringHelper.utf16_add buf (int_of_char c)
 
 let hl_to_caml str =
 	let utf16_eof s =
@@ -526,7 +526,7 @@ and dyn_call ctx v args tret =
 		null_access()
 	| VVarArgs (f,a) ->
 		let arr = VArray (Array.of_list (List.map (fun (v,t) -> make_dyn v t) args),HDyn) in
-		dyn_call ctx (VClosure (f,a)) [arr,HArray] tret
+		dyn_call ctx (VClosure (f,a)) [arr,HArray HDyn] tret
 	| _ ->
 		throw_msg ctx (vstr_d ctx v ^ " cannot be called")
 
@@ -1073,7 +1073,7 @@ let interp ctx f args =
 					| HDyn -> 9
 					| HFun _ -> 10
 					| HObj _ -> 11
-					| HArray -> 12
+					| HArray _ -> 12
 					| HType -> 13
 					| HRef _ -> 14
 					| HVirtual _ -> 15
@@ -1776,9 +1776,9 @@ let load_native ctx lib name t =
 						if c >= int_of_char 'a' && c <= int_of_char 'z' then c + int_of_char 'A' - int_of_char 'a'
 						else c
 					in
-					Common.utf16_add buf c
+					StringHelper.utf16_add buf c
 				) (String.sub s (int pos) ((int len) lsl 1));
-				Common.utf16_add buf 0;
+				StringHelper.utf16_add buf 0;
 				VBytes (Buffer.contents buf)
 			| _ -> Globals.die "" __LOC__)
 		| "ucs2_lower" ->
@@ -1790,9 +1790,9 @@ let load_native ctx lib name t =
 						if c >= int_of_char 'A' && c <= int_of_char 'Z' then c + int_of_char 'a' - int_of_char 'A'
 						else c
 					in
-					Common.utf16_add buf c
+					StringHelper.utf16_add buf c
 				) (String.sub s (int pos) ((int len) lsl 1));
-				Common.utf16_add buf 0;
+				StringHelper.utf16_add buf 0;
 				VBytes (Buffer.contents buf)
 			| _ -> Globals.die "" __LOC__)
 		| "url_encode" ->
@@ -1800,8 +1800,8 @@ let load_native ctx lib name t =
 			| [VBytes s; VRef (r, HI32)] ->
 				let s = hl_to_caml s in
 				let buf = Buffer.create 0 in
-				Common.url_encode s (utf16_char buf);
-				Common.utf16_add buf 0;
+				StringHelper.url_encode s (utf16_char buf);
+				StringHelper.utf16_add buf 0;
 				let str = Buffer.contents buf in
 				set_ref r (to_int (String.length str lsr 1 - 1));
 				VBytes str
@@ -2424,7 +2424,7 @@ let check comerror code =
 			| ORethrow r ->
 				reg r HDyn
 			| OGetArray (v,a,i) ->
-				(match rtype a with HAbstract ("hl_carray",_) -> () | _ -> reg a HArray);
+				(match rtype a with HAbstract ("hl_carray",_) | HArray _ -> () | _ -> reg a (HArray HDyn));
 				reg i HI32;
 				ignore(rtype v);
 			| OGetUI8 (r,b,p) | OGetUI16(r,b,p) ->
@@ -2444,7 +2444,7 @@ let check comerror code =
 				reg p HI32;
 				(match rtype v with HI32 | HI64 | HF32 | HF64 -> () | _ -> error (reg_inf r ^ " should be numeric"));
 			| OSetArray (a,i,v) ->
-				(match rtype a with HAbstract ("hl_carray",_) -> () | _ -> reg a HArray);
+				(match rtype a with HAbstract ("hl_carray",_) | HArray _ -> () | _ -> reg a (HArray HDyn));
 				reg i HI32;
 				ignore(rtype v);
             | OUnsafeCast (a,b) | OSafeCast (a,b) ->
@@ -2523,8 +2523,12 @@ let check comerror code =
 			| OAssert _ ->
 				()
 			| ORefData (r,d) ->
-				reg d HArray;
-				(match rtype r with HRef _ -> () | _ -> reg r (HRef HDyn))
+				(match rtype r with
+					| HRef t ->
+						reg d (HArray t);
+					| _ ->
+						reg d (HArray HDyn);
+						reg r (HRef HDyn))
 			| ORefOffset (r,r2,off) ->
 				(match rtype r2 with HRef _ -> () | _ -> reg r2 (HRef HDyn));
 				reg r (rtype r2);

+ 1 - 1
src/generators/hlopt.ml

@@ -578,7 +578,7 @@ let remap_fun ctx f dump get_str old_code =
 				if p < 0 || (match op p with ONop _ -> false | _ -> true) then [(i,p)] else
 				let reg, last_w = try Hashtbl.find ctx.r_reg_moved p with Not_found -> (-1,-1) in
 				if reg < 0 then [] (* ? *) else
-				if reg < nargs then [(i,-reg-1)] else
+				if reg < nargs then [(i,-reg-2)] else
 				let b = resolve_block p in
 				if last_w >= b.bstart && last_w < b.bend && last_w < p then loop last_w else
 				let wp = try PMap.find reg b.bwrite with Not_found -> -1 in

+ 2 - 3
src/generators/jsSourcemap.ml

@@ -19,7 +19,6 @@
 open Extlib_leftovers
 open Globals
 open Type
-open Common
 
 type sourcemap = {
 	sources : (string) DynArray.t;
@@ -131,7 +130,7 @@ let handle_newlines smap str =
 		loop 0
 	) smap
 
-let write_mappings (com : Common.context) smap source_path_prefix =
+let write_mappings (com : Gctx.t) smap source_path_prefix =
 	let basefile = Filename.basename com.file in
 	let channel = open_out_bin (com.file ^ ".map") in
 	let sources = DynArray.to_list smap.sources in
@@ -145,7 +144,7 @@ let write_mappings (com : Common.context) smap source_path_prefix =
 	output_string channel ("\"sources\":[" ^
 		(String.concat "," (List.map (fun s -> "\"" ^ source_path_prefix ^ to_url s ^ "\"") sources)) ^
 		"],\n");
-	if Common.defined com Define.SourceMapContent then begin
+	if Gctx.defined com Define.SourceMapContent then begin
 		output_string channel ("\"sourcesContent\":[" ^
 			(String.concat "," (List.map (fun s -> try "\"" ^ StringHelper.s_escape (Std.input_file ~bin:true s) ^ "\"" with _ -> "null") sources)) ^
 			"],\n");

+ 0 - 4
src/macro/eval/evalContext.ml

@@ -406,10 +406,6 @@ let exc_string_p str p = throw (vstring (EvalString.create_ascii str)) p
 
 let error_message = exc_string
 
-let flush_core_context f =
-	let ctx = get_ctx() in
-	ctx.curapi.MacroApi.flush_context f
-
 (* Environment handling *)
 
 let no_timer = fun () -> ()

+ 4 - 4
src/macro/eval/evalDebugSocket.ml

@@ -83,7 +83,7 @@ let var_to_json name value vio env =
 		| VInstance vi -> (rev_hash vi.iproto.ppath) ^ " {...}"
 		| VPrototype proto -> (s_proto_kind proto).sstring
 		| VFunction _ | VFieldClosure _ -> "<fun>"
-		| VLazy f -> level2_value_repr (!f())
+		| VLazy f -> level2_value_repr (Lazy.force f)
 		| VNativeString s -> string_repr s
 		| VHandle _ -> "<handle>"
 	in
@@ -148,7 +148,7 @@ let var_to_json name value vio env =
 			let fields = proto_fields proto in
 			jv "Anonymous" (s_proto_kind proto).sstring (List.length fields)
 		| VFunction _ | VFieldClosure _ -> jv "Function" "<fun>" 0
-		| VLazy f -> value_string (!f())
+		| VLazy f -> value_string (Lazy.force f)
 		| VNativeString s ->
 			jv "NativeString" (string_repr s) 0
 		| VHandle _ -> jv "Handle" "<handle>" 0
@@ -331,7 +331,7 @@ let output_inner_vars v env =
 				let n = rev_hash n in
 				n, v
 			) fields
-		| VLazy f -> loop (!f())
+		| VLazy f -> loop (Lazy.force f)
 	in
 	let children = loop v in
 	let vars = List.map (fun (n,v) -> var_to_json n v None env) children in
@@ -458,7 +458,7 @@ module ValueCompletion = struct
 				let fields = prototype_static_fields proto in
 				IntMap.fold (fun _ v acc -> v :: acc) fields []
 			| VLazy f ->
-				loop (!f())
+				loop (Lazy.force f)
 			| VEnumValue ve ->
 				begin match (get_static_prototype_raise (get_ctx()) ve.epath).pkind with
 					| PEnum names ->

+ 1 - 6
src/macro/eval/evalEncode.ml

@@ -316,12 +316,7 @@ let encode_ref v convert tostr =
 		ikind = IRef (Obj.repr v);
 	}
 
-let encode_lazy f =
-	let rec r = ref (fun () ->
-		let v = f() in
-		r := (fun () -> v);
-		v
-	) in
+let encode_lazy r =
 	VLazy r
 
 let encode_option encode_value o =

+ 8 - 1
src/macro/eval/evalExceptions.ml

@@ -184,7 +184,14 @@ let catch_exceptions ctx ?(final=(fun() -> ())) f p =
 			let stack = get_stack ctx in
 			reset_ctx();
 			final();
-			let p = if p' = null_pos then p else p' in
+			let p,stack = match stack with
+				| p :: pl when p' = null_pos ->
+					(* If the exception position is null_pos we're probably in a built-in function. Let's use the topmost stack
+					   as error position. *)
+					p,pl
+				| _ ->
+					(if p' = null_pos then p else p'),stack
+			in
 			Error.raise_error (Error.make_error
 				~sub:(List.map (fun p -> Error.make_error (Error.Custom "Called from here") p) (List.rev stack))
 				(Error.Custom ("Uncaught exception " ^ (value_string v)))

+ 8 - 4
src/macro/eval/evalLuv.ml

@@ -94,6 +94,8 @@ let encode_uv_error (e:Error.t) =
 	| `EILSEQ -> 77
 	| `EOVERFLOW -> 78
 	| `ESOCKTNOSUPPORT -> 79
+	| `ENODATA -> 80
+	| `EUNATCH -> 81
 	)
 
 let decode_uv_error v : Error.t =
@@ -178,6 +180,8 @@ let decode_uv_error v : Error.t =
 	| 77 -> `EILSEQ
 	| 78 -> `EOVERFLOW
 	| 79 -> `ESOCKTNOSUPPORT
+	| 80 -> `ENODATA
+	| 81 -> `EUNATCH
 	| _ -> unexpected_value v "eval.luv.UVError"
 
 let luv_exception e =
@@ -1942,7 +1946,7 @@ let fs_event_fields = [
 					) events
 				in
 				encode_obj [
-					key_file,vnative_string file;
+					key_file,encode_nullable vnative_string file;
 					key_events,encode_array vevents;
 				]
 			) v4
@@ -2175,7 +2179,7 @@ let env_fields = [
 let time_fields = [
 	"getTimeOfDay", vfun0 (fun() ->
 		encode_result (fun (t:Time.t) ->
-			encode_obj [key_sec,VInt64 t.tv_sec; key_usec,vint32 t.tv_usec]
+			encode_obj [key_sec,VInt64 t.sec; key_usec,vint32 t.usec]
 		) (Time.gettimeofday())
 	);
 	"hrTime", vfun0 (fun() ->
@@ -2292,10 +2296,10 @@ let resource_fields = [
 		encode_array_a [|vfloat m1; vfloat m5; vfloat m15|];
 	);
 	"freeMemory", vfun0 (fun() ->
-		VUInt64 (Resource.free_memory())
+		encode_nullable (fun u -> VUInt64 u) (Resource.free_memory())
 	);
 	"totalMemory", vfun0 (fun() ->
-		VUInt64 (Resource.total_memory())
+		encode_nullable (fun u -> VUInt64 u) (Resource.total_memory())
 	);
 	"constrainedMemory", vfun0 (fun() ->
 		encode_nullable (fun u -> VUInt64 u) (Resource.constrained_memory())

+ 1 - 1
src/macro/eval/evalMain.ml

@@ -361,7 +361,7 @@ let value_signature v =
 		| VHandle _ ->
 			custom_name 'H'
 		| VLazy f ->
-			loop (!f())
+			loop (Lazy.force f)
 	and loop_fields fields =
 		List.iter (fun (name,v) ->
 			adds (rev_hash name);

+ 4 - 4
src/macro/eval/evalMisc.ml

@@ -155,9 +155,9 @@ let rec compare a b =
 		if f1 != f2 then CUndef
 		else compare v1 v2
 	| VLazy f1,_ ->
-		compare (!f1()) b
+		compare (Lazy.force f1) b
 	| _,VLazy f2 ->
-		compare a (!f2())
+		compare a (Lazy.force f2)
 	| _ -> CUndef
 
 let rec arrays_equal cmp a1 a2 =
@@ -184,8 +184,8 @@ and equals_structurally a b =
 	| VObject a,VObject b -> a == b || arrays_equal equals_structurally a.ofields b.ofields
 	| VEnumValue a,VEnumValue b -> a == b || a.eindex = b.eindex && arrays_equal equals_structurally a.eargs b.eargs && a.epath = b.epath
 	| VPrototype proto1,VPrototype proto2 -> proto1.ppath = proto2.ppath
-	| VLazy f1,_ -> equals_structurally (!f1()) b
-	| _,VLazy f2 -> equals_structurally a (!f2())
+	| VLazy f1,_ -> equals_structurally (Lazy.force f1) b
+	| _,VLazy f2 -> equals_structurally a (Lazy.force f2)
 	| _ -> a == b
 
 let is_true v = match v with

+ 1 - 1
src/macro/eval/evalPrinting.ml

@@ -164,7 +164,7 @@ and s_value ?(indent_level=0) depth v =
 	| VInstance {ikind=IRegex r} -> r.r_rex_string
 	| VInstance i -> (try call_to_string () with Not_found -> s_hash i.iproto.ppath)
 	| VObject o -> (try call_to_string () with Not_found -> s_object (depth + 1) indent_level o)
-	| VLazy f -> s_value ~indent_level depth (!f())
+	| VLazy f -> s_value ~indent_level depth (Lazy.force f)
 	| VPrototype proto ->
 		try
 			call_to_string()

+ 7 - 4
src/macro/eval/evalStdLib.ml

@@ -613,9 +613,12 @@ module StdContext = struct
 		else raise (EvalDebugMisc.BreakHere)
 	)
 
-	let callMacroApi = vfun1 (fun f ->
+	let callMacroApi = vfun1 (fun f  ->
 		let f = decode_string f in
-		Hashtbl.find GlobalState.macro_lib f
+		try
+			Hashtbl.find GlobalState.macro_lib f
+		with Not_found ->
+			exc_string ("Could not find macro function \"" ^ f ^ "\"")
 	)
 
 	let plugins = ref PMap.empty
@@ -2441,7 +2444,7 @@ end
 module StdStringTools = struct
 	let url_encode s =
 		let b = Buffer.create 0 in
-		Common.url_encode s (Buffer.add_char b);
+		StringHelper.url_encode s (Buffer.add_char b);
 		Buffer.contents b
 
 	let fastCodeAt = StdString.charCodeAt
@@ -3008,7 +3011,7 @@ module StdType = struct
 			| VEnumValue ve ->
 				7,[|get_static_prototype_as_value ctx ve.epath null_pos|]
 			| VLazy f ->
-				loop (!f())
+				loop (Lazy.force f)
 			| VInt64 _ | VUInt64 _ | VNativeString _ | VHandle _ -> 8,[||]
 		in
 		let i,vl = loop v in

+ 4 - 4
src/macro/eval/evalValue.ml

@@ -141,7 +141,7 @@ type value =
 	| VPrototype of vprototype
 	| VFunction of vfunc * bool
 	| VFieldClosure of value * vfunc
-	| VLazy of (unit -> value) ref
+	| VLazy of value Lazy.t
 	| VNativeString of string
 	| VHandle of vhandle
 	| VInt64 of Signed.Int64.t
@@ -323,8 +323,8 @@ let rec equals a b = match a,b with
 	| VFieldClosure(v1,f1),VFieldClosure(v2,f2) -> f1 == f2 && equals v1 v2
 	| VNativeString s1,VNativeString s2 -> s1 = s2
 	| VHandle h1,VHandle h2 -> same_handle h1 h2
-	| VLazy f1,_ -> equals (!f1()) b
-	| _,VLazy f2 -> equals a (!f2())
+	| VLazy f1,_ -> equals (Lazy.force f1) b
+	| _,VLazy f2 -> equals a (Lazy.force f2)
 	| _ -> a == b
 
 module ValueHashtbl = Hashtbl.Make(struct
@@ -354,5 +354,5 @@ let vnative_string s = VNativeString s
 let s_expr_pretty e = (Type.s_expr_pretty false "" false (Type.s_type (Type.print_context())) e)
 
 let rec vresolve v = match v with
-	| VLazy f -> vresolve (!f())
+	| VLazy f -> vresolve (Lazy.force f)
 	| _ -> v

+ 38 - 25
src/macro/macroApi.ml

@@ -39,7 +39,6 @@ type 'value compiler_api = {
 	resolve_complex_type : Ast.type_hint -> Ast.type_hint;
 	store_typed_expr : Type.texpr -> Ast.expr;
 	allow_package : string -> unit;
-	set_js_generator : (Genjs.ctx -> unit) -> unit;
 	get_local_type : unit -> t option;
 	get_expected_type : unit -> t option;
 	get_call_arguments : unit -> Ast.expr list option;
@@ -62,7 +61,6 @@ type 'value compiler_api = {
 	encode_expr : Ast.expr -> 'value;
 	encode_ctype : Ast.type_hint -> 'value;
 	decode_type : 'value -> t;
-	flush_context : (unit -> t) -> t;
 	info : ?depth:int -> string -> pos -> unit;
 	warning : ?depth:int -> Warning.warning -> string -> pos -> unit;
 	display_error : ?depth:int -> (string -> pos -> unit);
@@ -123,7 +121,7 @@ module type InterpApi = sig
 	val encode_array : value list -> value
 	val encode_string  : string -> value
 	val encode_obj : (string * value) list -> value
-	val encode_lazy : (unit -> value) -> value
+	val encode_lazy : value Lazy.t -> value
 
 	val vfun0 : (unit -> value) -> value
 	val vfun1 : (value -> value) -> value
@@ -171,8 +169,6 @@ module type InterpApi = sig
 
 	val value_string : value -> string
 
-	val flush_core_context : (unit -> t) -> t
-
 	val handle_decoding_error : (string -> unit) -> value -> Type.t -> (string * int) list
 
 	val get_api_call_pos : unit -> pos
@@ -413,7 +409,7 @@ and encode_display_kind dk =
 	| DKMarked -> 3, []
 	| DKPattern outermost -> 4, [vbool outermost]
 	in
-	encode_enum ~pos:None IDisplayKind tag pl
+	encode_enum IDisplayKind tag pl
 
 and encode_display_mode dm =
 	let tag, pl = match dm with
@@ -429,7 +425,7 @@ and encode_display_mode dm =
 		| DMModuleSymbols (Some s) -> 9, [(encode_string s)]
 		| DMSignature -> 10, []
 	in
-	encode_enum ~pos:None IDisplayMode tag pl
+	encode_enum IDisplayMode tag pl
 
 and encode_platform p =
 	let tag, pl = match p with
@@ -446,7 +442,7 @@ and encode_platform p =
 		| Eval -> 10, []
 		| CustomTarget s -> 11, [(encode_string s)]
 	in
-	encode_enum ~pos:None IPlatform tag pl
+	encode_enum IPlatform tag pl
 
 and encode_platform_config pc =
 	encode_obj [
@@ -474,7 +470,7 @@ and encode_capture_policy cp =
 		| CPWrapRef -> 1
 		| CPLoopVars -> 2
 	in
-	encode_enum ~pos:None ICapturePolicy tag []
+	encode_enum ICapturePolicy tag []
 
 and encode_var_scoping_config vsc =
 	encode_obj [
@@ -487,7 +483,7 @@ and encode_var_scope vs =
 		| FunctionScope -> 0
 		| BlockScope -> 1
 	in
-	encode_enum ~pos:None IVarScope tag []
+	encode_enum IVarScope tag []
 
 and encode_var_scoping_flags vsf =
 	let tag, pl = match vsf with
@@ -500,7 +496,7 @@ and encode_var_scoping_flags vsf =
 		| ReserveNames (names) -> 6, [encode_array (List.map encode_string names)]
 		| SwitchCasesNoBlocks -> 7, []
 	in
-	encode_enum ~pos:None IVarScopingFlags tag pl
+	encode_enum IVarScopingFlags tag pl
 
 and encode_exceptions_config ec =
 	encode_obj [
@@ -517,7 +513,7 @@ and encode_package_rule pr =
 		| Forbidden -> 0, []
 		| Remap (path) -> 2, [encode_string path]
 	in
-	encode_enum ~pos:None IPackageRule tag pl
+	encode_enum IPackageRule tag pl
 
 and encode_message cm =
 	let tag, pl = match cm.cm_severity with
@@ -525,7 +521,7 @@ and encode_message cm =
 		| Warning | Hint -> 1, [(encode_string cm.cm_message); (encode_pos cm.cm_pos)]
 		| Error -> Globals.die "" __LOC__
 	in
-	encode_enum ~pos:None IMessage tag pl
+	encode_enum IMessage tag pl
 
 and encode_efield_kind efk =
 	let i = match efk with
@@ -631,7 +627,7 @@ and encode_expr e =
 			"expr", encode_enum IExpr tag pl;
 		]
 	in
-	encode_lazy (fun () -> loop e)
+	encode_lazy (lazy (loop e))
 
 and encode_null_expr e =
 	match e with
@@ -756,7 +752,7 @@ let rec decode_ast_path t =
 	let p_full = field t "pos" in
 	let p_full = if p_full = vnull then Globals.null_pos else decode_pos p_full in
 	let p_path = field t "posPath" in
-	let p_path = if p_path = vnull then Globals.null_pos else decode_pos p_path in
+	let p_path = if p_path = vnull then p_full else decode_pos p_path in
 	make_ptp (mk_type_path ~params ?sub (pack,name)) ~p_path p_full
 
 and decode_tparam v =
@@ -1097,7 +1093,7 @@ and encode_cfield f =
 		"params", encode_type_params f.cf_params;
 		"meta", encode_meta f.cf_meta (fun m -> f.cf_meta <- m);
 		"expr", vfun0 (fun() ->
-			ignore (flush_core_context (fun() -> follow f.cf_type));
+			ignore (follow f.cf_type);
 			(match f.cf_expr with None -> vnull | Some e -> encode_texpr e)
 		);
 		"kind", encode_field_kind f.cf_kind;
@@ -1264,8 +1260,7 @@ and encode_lazy_type t =
 					| LAvailable t ->
 						encode_type t
 					| LWait _ ->
-						(* we are doing some typing here, let's flush our context if it's not already *)
-						encode_type (flush_core_context (fun() -> lazy_type f))
+						encode_type (lazy_type f)
 					| LProcessing _ ->
 						(* our type in on the processing stack, error instead of returning most likely an unbound mono *)
 						error_message "Accessing a type while it's being typed");
@@ -2012,8 +2007,7 @@ let macro_api ccom get_api =
 		);
 		"set_custom_js_generator", vfun1 (fun f ->
 			let f = prepare_callback f 1 in
-			(get_api()).set_js_generator (fun js_ctx ->
-				let com = ccom() in
+			let gen com js_ctx =
 				Genjs.setup_kwds com;
 				let api = encode_obj [
 					"outputFile", encode_string com.file;
@@ -2028,10 +2022,10 @@ let macro_api ccom get_api =
 						vbool (Hashtbl.mem Genjs.kwds (decode_string v))
 					);
 					"hasFeature", vfun1 (fun v ->
-						vbool (Common.has_feature com (decode_string v))
+						vbool (Gctx.has_feature com (decode_string v))
 					);
 					"addFeature", vfun1 (fun v ->
-						Common.add_feature com (decode_string v);
+						Gctx.add_feature com (decode_string v);
 						vnull
 					);
 					"quoteString", vfun1 (fun v ->
@@ -2060,6 +2054,12 @@ let macro_api ccom get_api =
 					);
 				] in
 				ignore(f [api]);
+			in
+			let com = ccom() in
+			com.js_gen <- Some (fun() ->
+				Path.mkdir_from_path com.file;
+				let js_ctx = Genjs.alloc_ctx (Common.to_gctx com) (Gctx.get_es_version com.defines) in
+				gen (Common.to_gctx com) js_ctx;
 			);
 			vnull
 		);
@@ -2266,8 +2266,10 @@ let macro_api ccom get_api =
 				let t = decode_type (field v "t") in
 				let default = None in (* we don't care here *)
 				let c = match t with
-					| TInst(c,_) -> c
-					| _ -> die "" __LOC__
+					| TInst(({cl_kind = KTypeParameter _} as c),_) ->
+						c
+					| _ ->
+						(get_api()).exc_string (Printf.sprintf "Unexpected type where type parameter was expected: %s" (s_type_kind t))
 				in
 				mk_type_param c TPHType default None
 			) (decode_array tpl) in
@@ -2281,7 +2283,18 @@ let macro_api ccom get_api =
 					end
 				| _ -> Type.map map t
 			in
-			encode_type (apply_params tpl tl (map (decode_type t)))
+			let t = (map (decode_type t)) in
+			let t = try
+				apply_params tpl tl t
+			with ApplyParamsMismatch ->
+				let msg = Printf.sprintf "Could not apply type parameters to %s:\n\tparams: %s\n\ttypes: %s"
+					(s_type_kind t)
+					(String.concat ", " (List.map (s_type_param s_type_kind) tpl))
+					(String.concat ", " (List.map s_type_kind tl))
+				in
+				(get_api()).exc_string msg
+			in
+			encode_type t
 		);
 		"include_file", vfun2 (fun file position ->
 			let file = decode_string file in

+ 1 - 1
src/optimization/dce.ml

@@ -87,7 +87,7 @@ let overrides_extern_field cf c =
 	loop c cf
 
 let is_std_file dce file =
-	List.exists (ExtString.String.starts_with file) dce.std_dirs
+	List.exists (fun dir -> ExtString.String.starts_with file dir) dce.std_dirs
 
 let keep_metas = [Meta.Keep;Meta.Expose]
 

+ 1 - 1
src/optimization/inline.ml

@@ -163,7 +163,7 @@ let api_inline ctx c field params p =
 			Some (Texpr.Builder.fcall (eJsSyntax()) "instanceof" [o;t] tbool p)
 	| (["haxe";"ds";"_Vector"],"Vector_Impl_"),("fromArrayCopy"),[{ eexpr = TArrayDecl args } as edecl] -> (try
 			let platf = match ctx.com.platform with
-				| Jvm -> "java"
+				| Jvm -> "jvm"
 				| _ -> raise Exit
 			in
 			let mpath = if field = "fromArrayCopy" then

+ 6 - 1
src/syntax/reification.ml

@@ -123,6 +123,8 @@ let reify in_macro =
 					("name", (efield(ei,"name"),p));
 					("sub", (efield(ei,"sub"),p));
 					("params", ea);
+					("pos", to_pos p);
+					("posPath", to_pos ptp.pos_path);
 				] in
 				to_obj fields p
 		end else begin
@@ -130,8 +132,11 @@ let reify in_macro =
 				("pack", to_array to_string t.tpackage p);
 				("name", to_string t.tname p);
 				("params", to_array to_tparam t.tparams p);
+				("pos", to_pos p);
+				("posPath", to_pos ptp.pos_path);
 			] in
-			to_obj (match t.tsub with None -> fields | Some s -> fields @ ["sub",to_string s p]) p
+			let fields = match t.tsub with None -> fields | Some s -> fields @ ["sub",to_string s p] in
+			to_obj fields p
 		end
 	and to_ctype t p =
 		let ct n vl = mk_enum "ComplexType" n vl p in

+ 17 - 4
src/typing/calls.ml

@@ -355,7 +355,7 @@ let call_to_string ctx ?(resume=false) e =
 			mk (TIf (check_null, string_null, Some (gen_to_string e))) ctx.t.tstring e.epos
 	end
 
-let type_bind ctx (e : texpr) (args,ret) params p =
+let type_bind ctx (e : texpr) (args,ret) params safe p =
 	let vexpr v = mk (TLocal v) v.v_type p in
 	let acount = ref 0 in
 	let alloc_name n =
@@ -409,10 +409,23 @@ let type_bind ctx (e : texpr) (args,ret) params p =
 			let e_var = alloc_var VGenerated gen_local_prefix e.etype e.epos in
 			(mk (TLocal e_var) e.etype e.epos), (mk (TVar(e_var,Some e)) ctx.t.tvoid e.epos) :: var_decls
 	in
-	let call = make_call ctx e ordered_args ret p in
+	let e_body = if safe then begin
+		let eobj, tempvar = get_safe_nav_base ctx e in
+		let sn = {
+			sn_pos = p;
+			sn_base = eobj;
+			sn_temp_var = tempvar;
+			sn_access = AKExpr e; (* This is weird, but it's not used by safe_nav_branch. *)
+		} in
+		safe_nav_branch ctx sn (fun () ->
+			make_call ctx eobj ordered_args ret p
+		)
+	end else
+		make_call ctx e ordered_args ret p
+	in
 	let body =
-		if ExtType.is_void (follow ret) then call
-		else mk (TReturn(Some call)) ret p
+		if ExtType.is_void (follow ret) then e_body
+		else mk (TReturn(Some e_body)) ret p
 	in
 	let arg_default optional t =
 		if optional then Some (Texpr.Builder.make_null t null_pos)

+ 5 - 0
src/typing/fields.ml

@@ -310,6 +310,9 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 			acc
 		) c.cl_implements
 	in
+	let no_no_lookup cf =
+		if has_class_field_flag cf CfNoLookup then display_error ctx.com "This field cannot be accessed explicitly" pfield
+	in
 	let rec type_field_by_type e t =
 		let field_access = field_access e in
 		match t with
@@ -334,6 +337,7 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 					begin try
 						let cf = PMap.find i c.cl_statics in
 						if has_class_field_flag cf CfImpl && not (has_class_field_flag cf CfEnum) then display_error ctx.com "Cannot access non-static abstract field statically" pfield;
+						no_no_lookup cf;
 						field_access cf (FHStatic c)
 					with Not_found ->
 						begin match c.cl_kind with
@@ -401,6 +405,7 @@ let type_field cfg ctx e i p mode (with_type : WithType.t) =
 				let c = find_some a.a_impl in
 				let f = PMap.find i c.cl_statics in
 				if not (has_class_field_flag f CfImpl) then raise Not_found;
+				no_no_lookup f;
 				field_access f (FHAbstract (a,tl,c))
 			with Not_found ->
 				type_field_by_forward_member type_field_by_type e a tl

+ 15 - 8
src/typing/finalization.ml

@@ -8,24 +8,31 @@ open Typecore
 (* ---------------------------------------------------------------------- *)
 (* FINALIZATION *)
 
-let get_main ctx types =
-	match ctx.com.main.main_class with
-	| None -> None
+let maybe_load_main tctx = match tctx.com.main.main_class with
 	| Some path ->
+		Some (Typeload.load_module tctx path null_pos)
+	| None ->
+		None
+
+
+let get_main ctx main_module types =
+	match main_module with
+	| None -> None
+	| Some main_module ->
 		let p = null_pos in
+		let path = main_module.m_path in
 		let pack,name = path in
-		let m = Typeload.load_module ctx (pack,name) p in
 		let c,f =
 			let p = ref p in
 			try
-				match m.m_statics with
+				match main_module.m_statics with
 				| None ->
 					raise Not_found
 				| Some c ->
 					p := c.cl_name_pos;
 					c, PMap.find "main" c.cl_statics
 			with Not_found -> try
-				let t = Typeload.find_type_in_module_raise ctx m name null_pos in
+				let t = Typeload.find_type_in_module_raise ctx main_module name null_pos in
 				match t with
 				| TEnumDecl _ | TTypeDecl _ | TAbstractDecl _ ->
 					raise_typing_error ("Invalid -main : " ^ s_type_path path ^ " is not a class") null_pos
@@ -196,6 +203,6 @@ let sort_types com (modules : module_lut) =
 	List.iter (fun m -> List.iter loop m.m_types) sorted_modules;
 	List.rev !types, sorted_modules
 
-let generate ctx =
+let generate ctx main_class =
 	let types,modules = sort_types ctx.com ctx.com.module_lut in
-	get_main ctx types,types,modules
+	get_main ctx main_class types,types,modules

+ 65 - 35
src/typing/forLoop.ml

@@ -55,10 +55,14 @@ let optimize_for_loop_iterator ctx v e1 e2 p =
 		mk (TWhile (ehasnext,eblock,NormalWhile)) ctx.t.tvoid p
 	]) ctx.t.tvoid p
 
+type unroll_parameters = {
+	expression_weight : int;
+}
+
 module IterationKind = struct
 	type t_kind =
 		| IteratorIntConst of texpr * texpr * bool (* ascending? *)
-		| IteratorIntUnroll of int * int * bool
+		| IteratorIntUnroll of int * int * bool * unroll_parameters
 		| IteratorInt of texpr * texpr
 		| IteratorArrayDecl of texpr list
 		| IteratorArray
@@ -84,7 +88,8 @@ module IterationKind = struct
 		(mk (TArray (arr,iexpr)) pt p)
 
 	let check_iterator ?(resume=false) ?last_resort ctx s e p =
-		let t,pt = Typeload.t_iterator ctx p in
+		let pt = spawn_monomorph ctx.e p in
+		let t = ctx.t.titerator pt in
 		let dynamic_iterator = ref None in
 		let e1 = try
 			let e = AbstractCast.cast_or_unify_raise ctx t e p in
@@ -169,7 +174,22 @@ module IterationKind = struct
 			)
 	 	| _ -> raise Not_found
 
-	let of_texpr ?(resume=false) ctx e unroll p =
+	let map_unroll_params ctx unroll_params i = match unroll_params with
+		| None ->
+			None
+		| Some unroll_params ->
+			let cost = i * unroll_params.expression_weight in
+			let max_cost = try
+				int_of_string (Common.defined_value ctx.com Define.LoopUnrollMaxCost)
+			with Not_found ->
+				250
+			in
+			if cost <= max_cost then
+				Some unroll_params
+			else
+				None
+
+	let of_texpr ?(resume=false) ctx e unroll_params p =
 		let dynamic_iterator e =
 			display_error ctx.com "You can't iterate on a Dynamic value, please specify Iterator or Iterable" e.epos;
 			IteratorDynamic,e,t_dynamic
@@ -210,9 +230,12 @@ module IterationKind = struct
 			let it = match efrom.eexpr,eto.eexpr with
 				| TConst (TInt a),TConst (TInt b) ->
 					let diff = Int32.to_int (Int32.sub a b) in
-					let unroll = unroll (abs diff) in
-					if unroll then IteratorIntUnroll(Int32.to_int a,abs(diff),diff <= 0)
-					else IteratorIntConst(efrom,eto,diff <= 0)
+					begin match map_unroll_params ctx unroll_params (abs diff) with
+					| Some unroll_params ->
+						IteratorIntUnroll(Int32.to_int a,abs(diff),diff <= 0,unroll_params)
+					| None ->
+						IteratorIntConst(efrom,eto,diff <= 0)
+					end
 				| _ ->
 					let eto = match follow eto.etype with
 						| TAbstract ({ a_path = ([],"Int") }, []) -> eto
@@ -222,8 +245,10 @@ module IterationKind = struct
 			in
 			it,e,ctx.t.tint
 		| TArrayDecl el,TInst({ cl_path = [],"Array" },[pt]) ->
-			let it = if unroll (List.length el) then IteratorArrayDecl el
-			else IteratorArray in
+			let it = match map_unroll_params ctx unroll_params (List.length el) with
+				| Some _ -> IteratorArrayDecl el
+				| None -> IteratorArray
+			in
 			(it,e,pt)
 		| _,TInst({ cl_path = [],"Array" },[pt])
 		| _,TInst({ cl_path = ["flash"],"Vector" },[pt]) ->
@@ -316,18 +341,31 @@ module IterationKind = struct
 		match iterator.it_kind with
 		| _ when not ctx.allow_transform ->
 			mk (TFor(v,e1,e2)) t_void p
-		| IteratorIntUnroll(offset,length,ascending) ->
+		| IteratorIntUnroll(offset,length,ascending,unroll_params) ->
 			check_loop_var_modification [v] e2;
 			if not ascending then raise_typing_error "Cannot iterate backwards" p;
-			let el = ExtList.List.init length (fun i ->
-				let ei = make_int ctx.t (if ascending then i + offset else offset - i) p in
-				let rec loop e = match e.eexpr with
-					| TLocal v' when v == v' -> {ei with epos = e.epos}
-					| _ -> map_expr loop e
+			let rec unroll acc i =
+				if i = length then
+					List.rev acc
+				else begin
+					let ei = make_int ctx.t (if ascending then i + offset else offset - i) p in
+					let local_vars = ref [] in
+					let rec loop e = match e.eexpr with
+					| TLocal v' when v == v' ->
+						{ei with epos = e.epos}
+					| TVar(v,eo) when has_var_flag v VStatic ->
+						if acc = [] then
+							local_vars := {e with eexpr = TVar(v,eo)} :: !local_vars;
+						mk (TConst TNull) t_dynamic null_pos
+					| _ ->
+						map_expr loop e
 				in
 				let e2 = loop e2 in
-				Texpr.duplicate_tvars e_identity e2
-			) in
+				let acc = acc @ !local_vars in
+				let e2 = Texpr.duplicate_tvars e_identity e2 in
+				unroll (e2 :: acc) (i + 1)
+			end in
+			let el = unroll [] 0 in
 			mk (TBlock el) t_void p
 		| IteratorIntConst(a,b,ascending) ->
 			check_loop_var_modification [v] e2;
@@ -407,7 +445,7 @@ module IterationKind = struct
 			mk (TFor(v,e1,e2)) t_void p
 end
 
-let is_cheap_enough ctx e2 i =
+let get_unroll_params ctx e2 =
 	let num_expr = ref 0 in
 	let rec loop e = match fst e with
 		| EContinue | EBreak ->
@@ -419,17 +457,13 @@ let is_cheap_enough ctx e2 i =
 	try
 		if ctx.com.display.dms_kind <> DMNone then raise Exit;
 		ignore(loop e2);
-		let cost = i * !num_expr in
-		let max_cost = try
-			int_of_string (Common.defined_value ctx.com Define.LoopUnrollMaxCost)
-		with Not_found ->
-			250
-		in
-		cost <= max_cost
+		Some {
+			expression_weight = !num_expr;
+		}
 	with Exit ->
-		false
+		None
 
-let is_cheap_enough_t ctx e2 i =
+let get_unroll_params_t ctx e2 =
 	let num_expr = ref 0 in
 	let rec loop e = match e.eexpr with
 		| TContinue | TBreak ->
@@ -441,15 +475,11 @@ let is_cheap_enough_t ctx e2 i =
 	try
 		if ctx.com.display.dms_kind <> DMNone then raise Exit;
 		ignore(loop e2);
-		let cost = i * !num_expr in
-		let max_cost = try
-			int_of_string (Common.defined_value ctx.com Define.LoopUnrollMaxCost)
-		with Not_found ->
-			250
-		in
-		cost <= max_cost
+		Some {
+			expression_weight = !num_expr;
+		}
 	with Exit ->
-		false
+		None
 
 type iteration_ident = string * pos * display_kind option
 
@@ -468,7 +498,7 @@ let type_for_loop ctx handle_display ik e1 e2 p =
 	in
 	match ik with
 	| IKNormal(i,pi,dko) ->
-		let iterator = IterationKind.of_texpr ctx e1 (is_cheap_enough ctx e2) p in
+		let iterator = IterationKind.of_texpr ctx e1 (get_unroll_params ctx e2) p in
 		let i = add_local_with_origin ctx TVOForVariable i iterator.it_type pi in
 		let e2 = type_expr ctx e2 NoValue in
 		check_display (i,pi,dko);

+ 13 - 17
src/typing/generic.ml

@@ -9,7 +9,7 @@ open FieldCallCandidate
 
 type generic_context = {
 	ctx : typer;
-	subst : (t * (t * texpr option)) list;
+	subst : (tclass * (t * texpr option)) list;
 	name : string;
 	p : pos;
 	mutable mg : module_def option;
@@ -64,7 +64,7 @@ let make_generic ctx ps pt debug p =
 	let rec loop acc_name acc_subst ttpl tl = match ttpl,tl with
 		| ttp :: ttpl,t :: tl ->
 			let name,t = try process t with Exit -> raise_typing_error ("Could not determine type for parameter " ^ ttp.ttp_name) p in
-			loop (name :: acc_name) ((ttp.ttp_type,t) :: acc_subst) ttpl tl
+			loop (name :: acc_name) ((ttp.ttp_class,t) :: acc_subst) ttpl tl
 		| [],[] ->
 			let name = String.concat "_" (List.rev acc_name) in
 			name,acc_subst
@@ -89,9 +89,9 @@ let rec generic_substitute_type' gctx allow_expr t =
 		let t = info.build_apply (List.map (generic_substitute_type' gctx true) tl2) in
 		(match follow t,gctx.mg with TInst(c,_), Some m -> add_dependency m c.cl_module MDepFromTyping | _ -> ());
 		t
-	| _ ->
-		try
-			let t,eo = List.assq t gctx.subst in
+	| TInst ({ cl_kind = KTypeParameter _ } as c, tl2) ->
+		(try
+			let t,eo = List.assq c gctx.subst in
 			(* Somewhat awkward: If we allow expression types, use the original KExpr one. This is so
 			   recursing into further KGeneric expands correctly. *)
 			begin match eo with
@@ -101,7 +101,9 @@ let rec generic_substitute_type' gctx allow_expr t =
 				generic_substitute_type' gctx false t
 			end
 		with Not_found ->
-			Type.map (generic_substitute_type' gctx allow_expr) t
+			Type.map (generic_substitute_type' gctx allow_expr) t)
+	| _ ->
+		Type.map (generic_substitute_type' gctx allow_expr) t
 
 let generic_substitute_type gctx t =
 	generic_substitute_type' gctx false t
@@ -136,11 +138,8 @@ let generic_substitute_expr gctx e =
 			end;
 		| TTypeExpr (TClassDecl ({cl_kind = KTypeParameter _;} as c)) when Meta.has Meta.Const c.cl_meta ->
 			let rec loop subst = match subst with
-				| (t1,(_,eo)) :: subst ->
-					begin match follow t1 with
-						| TInst(c2,_) when c == c2 -> eo
-						| _ -> loop subst
-					end
+				| (c2,(_,eo)) :: subst ->
+					if c == c2 then eo else loop subst
 				| [] -> raise Not_found
 			in
 			begin try
@@ -279,11 +278,8 @@ let build_generic_class ctx c p tl =
 		let m = c.cl_module in
 		if gctx.generic_debug then begin
 			print_endline (Printf.sprintf "[GENERIC] Building @:generic class %s as %s with:" (s_type_path c.cl_path) name);
-			List.iter (fun (t1,(t2,eo)) ->
-				let name = match follow t1 with
-					| TInst(c,_) -> snd c.cl_path
-					| _ -> die "" __LOC__
-				in
+			List.iter (fun (c,(t2,eo)) ->
+				let name = snd c.cl_path in
 				let expr = match eo with
 					| None -> ""
 					| Some e -> Printf.sprintf " (expr: %s)" (s_expr_debug e)
@@ -326,7 +322,7 @@ let build_generic_class ctx c p tl =
 		let build_field cf_old =
 			let params = List.map (fun ttp ->
 				let ttp' = clone_type_parameter gctx mg ([cf_old.cf_name],ttp.ttp_name) ttp in
-				(ttp.ttp_type,ttp')
+				(ttp.ttp_class,ttp')
 			) cf_old.cf_params in
 			let param_subst = List.map (fun (t,ttp) -> t,(ttp.ttp_type,None)) params in
 			let gctx = {gctx with subst = param_subst @ gctx.subst} in

+ 20 - 28
src/typing/macroContext.ml

@@ -22,7 +22,6 @@ open DisplayTypes.DisplayMode
 open Common
 open Type
 open Typecore
-open Resolution
 open Error
 open Globals
 
@@ -200,23 +199,11 @@ let make_macro_com_api com mcom p =
 		type_expr = (fun e ->
 			Interp.exc_string "unsupported"
 		);
-		flush_context = (fun f ->
-			Interp.exc_string "unsupported"
-		);
 		store_typed_expr = (fun te ->
 			let p = te.epos in
 			snd (Typecore.store_typed_expr com te p)
 		);
 		allow_package = (fun v -> Common.allow_package com v);
-		set_js_generator = (fun gen ->
-			com.js_gen <- Some (fun() ->
-				Path.mkdir_from_path com.file;
-				let js_ctx = Genjs.alloc_ctx com (get_es_version com) in
-				let t = macro_timer com ["jsGenerator"] in
-				gen js_ctx;
-				t()
-			);
-		);
 		get_local_type = (fun() ->
 			Interp.exc_string "unsupported"
 		);
@@ -417,9 +404,6 @@ let make_macro_api ctx mctx p =
 		MacroApi.type_expr = (fun e ->
 			typing_timer ctx true (fun ctx -> type_expr ctx e WithType.value)
 		);
-		MacroApi.flush_context = (fun f ->
-			typing_timer ctx true (fun _ -> f ())
-		);
 		MacroApi.get_local_type = (fun() ->
 			match ctx.c.get_build_infos() with
 			| Some (mt,tl,_) ->
@@ -506,7 +490,13 @@ let make_macro_api ctx mctx p =
 			let mpath = Ast.parse_path m in
 			begin try
 				let m = ctx.com.module_lut#find mpath in
-				ignore(TypeloadModule.type_types_into_module ctx.com ctx.g m types pos)
+				if m != ctx.m.curmod then begin
+					let pos = { pfile = (Path.UniqueKey.lazy_path m.m_extra.m_file); pmin = 0; pmax = 0 } in
+					raise_typing_error_ext (make_error ~sub:[
+						make_error ~depth:1 (Custom "Previously defined here") pos
+					] (Custom (Printf.sprintf "Cannot redefine module %s" (s_type_path mpath))) p);
+				end else
+					ignore(TypeloadModule.type_types_into_module ctx.com ctx.g m types pos)
 			with Not_found ->
 				let mnew = TypeloadModule.type_module ctx.com ctx.g mpath (ctx.com.file_keys#generate_virtual ctx.com.compilation_step) types pos in
 				mnew.m_extra.m_kind <- MFake;
@@ -602,16 +592,18 @@ let init_macro_interp mctx mint =
 and flush_macro_context mint mctx =
 	let t = macro_timer mctx.com ["flush"] in
 	let mctx = (match mctx.g.macros with None -> die "" __LOC__ | Some (_,mctx) -> mctx) in
+	let main_module = Finalization.maybe_load_main mctx in
 	Finalization.finalize mctx;
-	let _, types, modules = Finalization.generate mctx in
+	let _, types, modules = Finalization.generate mctx main_module in
 	mctx.com.types <- types;
 	mctx.com.Common.modules <- modules;
+	let ectx = Exceptions.create_exception_context mctx in
 	(* we should maybe ensure that all filters in Main are applied. Not urgent atm *)
 	let expr_filters = [
-		"handle_abstract_casts",AbstractCast.handle_abstract_casts mctx;
-		"local_statics",LocalStatic.run mctx;
-		"Exceptions",Exceptions.filter mctx;
-		"captured_vars",CapturedVars.captured_vars mctx.com;
+		"handle_abstract_casts",AbstractCast.handle_abstract_casts;
+		"local_statics",LocalStatic.run;
+		"Exceptions",(fun _ -> Exceptions.filter ectx);
+		"captured_vars",(fun _ -> CapturedVars.captured_vars mctx.com);
 	] in
 	(*
 		some filters here might cause side effects that would break compilation server.
@@ -655,7 +647,7 @@ and flush_macro_context mint mctx =
 	in
 	let type_filters = [
 		FiltersCommon.remove_generic_base;
-		Exceptions.patch_constructors mctx;
+		Exceptions.patch_constructors mctx ectx;
 		(fun mt -> AddFieldInits.add_field_inits mctx.c.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt);
 		Filters.update_cache_dependencies ~close_monomorphs:false mctx.com;
 		minimal_restore;
@@ -702,6 +694,7 @@ let create_macro_interp api mctx =
 
 let create_macro_context com =
 	let com2 = Common.clone com true in
+	enter_stage com2 CInitMacrosDone;
 	com.get_macros <- (fun() -> Some com2);
 	com2.package_rules <- PMap.empty;
 	(* Inherit most display settings, but require normal typing. *)
@@ -752,7 +745,7 @@ let load_macro_module mctx com cpath display p =
 	let old = mctx.com.display in
 	if display then mctx.com.display <- com.display;
 	let mloaded = TypeloadModule.load_module ~origin:MDepFromMacro mctx m p in
-	mctx.m <- {
+	(* mctx.m <- {
 		curmod = mloaded;
 		import_resolution = new resolution_list ["import";s_type_path cpath];
 		own_resolution = None;
@@ -760,7 +753,7 @@ let load_macro_module mctx com cpath display p =
 		module_using = [];
 		import_statements = [];
 		is_display_file = (com.display.dms_kind <> DMNone && DisplayPosition.display_position#is_in_file (Path.UniqueKey.lazy_key mloaded.m_extra.m_file));
-	};
+	}; *)
 	mloaded,(fun () -> mctx.com.display <- old)
 
 let load_macro'' com mctx display cpath f p =
@@ -794,7 +787,7 @@ let load_macro'' com mctx display cpath f p =
 		restore();
 		if not com.is_macro_context then flush_macro_context mint mctx;
 		mctx.com.cached_macros#add (cpath,f) meth;
-		mctx.m <- {
+		(* mctx.m <- {
 			curmod = null_module;
 			import_resolution = new resolution_list ["import";s_type_path cpath];
 			own_resolution = None;
@@ -802,7 +795,7 @@ let load_macro'' com mctx display cpath f p =
 			module_using = [];
 			import_statements = [];
 			is_display_file = false;
-		};
+		}; *)
 		t();
 		meth
 
@@ -1017,7 +1010,6 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 	e
 
 let call_macro mctx args margs call p =
-	mctx.c.curclass <- null_class;
 	let el, _ = CallUnification.unify_call_args mctx args margs t_dynamic p false false false in
 	call (List.map (fun e -> try Interp.make_const e with Exit -> raise_typing_error "Argument should be a constant" e.epos) el)
 

+ 9 - 3
src/typing/matcher/texprConverter.ml

@@ -349,9 +349,15 @@ let to_texpr ctx t_switch with_type dt =
 					let e_then = loop dt_rec params dt1 in
 					begin match e_then with
 					| None ->
-						if toplevel then
-							loop dt_rec params dt2
-						else if ignore_error ctx.com then
+						if toplevel then begin match loop dt_rec params dt2 with
+							| None ->
+								None
+							| Some e_else ->
+								(* In some cases like extractors, the original e expression might be significant for the
+								   output, so let's make sure it appears there (issue #11738). *)
+								let e = mk (TBlock [e;e_else]) e_else.etype e_else.epos in
+								Some e
+						end else if ignore_error ctx.com then
 							Some (mk (TConst TNull) (mk_mono()) dt2.dt_pos)
 						else
 							report_not_exhaustive !v_lookup e [(ConConst TNull,dt.dt_pos),dt.dt_pos]

+ 8 - 3
src/typing/operators.ml

@@ -333,12 +333,17 @@ let make_binop ctx op e1 e2 is_assign_op p =
 		with Error { err_message = Unify _ } ->
 			e1,AbstractCast.cast_or_unify ctx e1.etype e2 p
 		in
-		if not ctx.com.config.pf_supports_function_equality then begin match e1.eexpr, e2.eexpr with
+		begin match e1.eexpr, e2.eexpr with
 		| TConst TNull , _ | _ , TConst TNull -> ()
 		| _ ->
 			match follow e1.etype, follow e2.etype with
-			| TFun _ , _ | _, TFun _ -> warning ctx WClosureCompare "Comparison of function values is unspecified on this target, use Reflect.compareMethods instead" p
-			| _ -> ()
+			| TFun _ , _ | _, TFun _ when not ctx.com.config.pf_supports_function_equality ->
+				warning ctx WClosureCompare "Comparison of function values is unspecified on this target, use Reflect.compareMethods instead" p
+			| TEnum(en,_), _ | _, TEnum(en,_) ->
+				if not (Meta.has Meta.FlatEnum en.e_meta) then
+					warning ctx WUnsafeEnumEquality "Equality operations on this enum might lead to unexpected results because some constructors have arguments" p
+			| _ ->
+				()
 		end;
 		mk_op e1 e2 ctx.t.tbool
 	| OpGt

+ 1 - 1
src/typing/strictMeta.ml

@@ -79,7 +79,7 @@ let rec kind_of_type_against ctx t_want e_have =
 				unify ctx e.etype t_want e.epos
 		end;
 		e
-	| TInst({cl_path = (["java"],"NativeArray")},[t1]) ->
+	| TInst({cl_path = (["jvm"],"NativeArray")},[t1]) ->
 		begin match fst e_have with
 			| EArrayDecl el ->
 				let el = List.map (kind_of_type_against ctx t1) el in

+ 22 - 42
src/typing/typeload.ml

@@ -112,14 +112,7 @@ let find_type_in_current_module_context ctx pack name =
 			ImportHandling.mark_import_position ctx pi;
 			t
 	end else begin
-		(* All this is very weird *)
-		try
-			List.find (fun mt -> t_path mt = (pack,name)) ctx.m.curmod.m_types
-		with Not_found ->
-			(* see also https://github.com/HaxeFoundation/haxe/issues/9150 *)
-			let t,pi = ctx.m.import_resolution#find_type_import_weirdly pack name in
-			ImportHandling.mark_import_position ctx pi;
-		t
+		List.find (fun mt -> t_path mt = (pack,name)) ctx.m.curmod.m_types
 	end
 
 let find_in_wildcard_imports ctx mname p f =
@@ -137,7 +130,7 @@ let find_in_wildcard_imports ctx mname p f =
 					with Error { err_message = Module_not_found mpath } when mpath = path ->
 						raise Not_found
 				in
-				let r = f m ~resume:true in
+				let r = f m in
 				ImportHandling.mark_import_position ctx ppack;
 				r
 			with Not_found ->
@@ -146,48 +139,36 @@ let find_in_wildcard_imports ctx mname p f =
 	in
 	loop (ctx.m.import_resolution#extract_wildcard_packages)
 
-(* TODO: move these generic find functions into a separate module *)
-let find_in_modules_starting_from_current_package ~resume ctx mname p f =
+let find_in_modules_starting_from_current_package ctx mname p f =
 	let rec loop l =
 		let path = (List.rev l,mname) in
+		try
+			ctx.g.do_load_module ctx path p
+		with Error { err_message = Module_not_found mpath } when mpath = path ->
 		match l with
-		| [] ->
-			let m =
-				try
-					ctx.g.do_load_module ctx path p
-				with Error { err_message = Module_not_found mpath } when resume && mpath = path ->
-					raise Not_found
-			in
-			f m ~resume:resume
-		| _ :: sl ->
-			try
-				let m =
-					try
-						ctx.g.do_load_module ctx path p
-					with Error { err_message = Module_not_found mpath } when mpath = path ->
-						raise Not_found
-					in
-				f m ~resume:true;
-			with Not_found ->
+			| [] ->
+				raise Not_found
+			| _ :: sl ->
 				loop sl
 	in
 	let pack = fst ctx.m.curmod.m_path in
-	loop (List.rev pack)
+	let m = loop (List.rev pack) in
+	f m
 
-let find_in_unqualified_modules ctx name p f ~resume =
+let find_in_unqualified_modules ctx name p f =
 	try
 		find_in_wildcard_imports ctx name p f
 	with Not_found ->
-		find_in_modules_starting_from_current_package ctx name p f ~resume:resume
+		find_in_modules_starting_from_current_package ctx name p f
 
 let load_unqualified_type_def ctx mname tname p =
-	let find_type m ~resume =
-		if resume then
-			find_type_in_module m tname
-		else
-			find_type_in_module_raise ctx m tname p
+	let find_type m =
+		find_type_in_module_raise ctx m tname p
 	in
-	find_in_unqualified_modules ctx mname p find_type ~resume:false
+	try
+		find_in_unqualified_modules ctx mname p find_type
+	with Not_found ->
+		raise_error_msg (Module_not_found ([],mname)) p
 
 let load_module ctx path p =
 	try
@@ -414,7 +395,7 @@ and load_instance' ctx ptp get_params mode =
 		if t.tparams <> [] then raise_typing_error ("Class type parameter " ^ t.tname ^ " can't have parameters") ptp.pos_full;
 		pt
 	with Not_found ->
-		let mt = load_type_def ctx (if ptp.pos_path == null_pos then ptp.pos_full else ptp.pos_path) t in
+		let mt = load_type_def ctx ptp.pos_path t in
 		let info = ctx.g.get_build_info ctx mt ptp.pos_full in
 		if info.build_path = ([],"Dynamic") then match t.tparams with
 			| [] -> t_dynamic
@@ -644,9 +625,7 @@ and load_complex_type ctx allow_display mode (t,pn) =
 		if Diagnostics.error_in_diagnostics_run ctx.com err.err_pos then begin
 			delay ctx.g PForce (fun () -> DisplayToplevel.handle_unresolved_identifier ctx name err.err_pos true);
 			t_dynamic
-		end else if ignore_error ctx.com && not (DisplayPosition.display_position#enclosed_in pn) then
-			t_dynamic
-		else
+		end else
 			raise (Error err)
 
 and init_meta_overloads ctx co cf =
@@ -803,6 +782,7 @@ let load_core_class ctx c =
 	let ctx2 = (match ctx.g.core_api with
 		| None ->
 			let com2 = Common.clone ctx.com ctx.com.is_macro_context in
+			enter_stage com2 CInitMacrosDone;
 			com2.defines.Define.values <- PMap.empty;
 			Common.define com2 Define.CoreApi;
 			Common.define com2 Define.Sys;

+ 29 - 36
src/typing/typeloadFields.ml

@@ -538,10 +538,10 @@ let create_field_context ctx cctx cff is_display_file display_modifier =
 	if fctx.is_display_field then cctx.has_display_field <- true;
 	fctx
 
-let create_typer_context_for_field ctx cctx fctx cff =
+let create_typer_context_for_field ctx cctx fctx cff cf =
 	DeprecationCheck.check_is ctx.com ctx.m.curmod ctx.c.curclass.cl_meta cff.cff_meta (fst cff.cff_name) cff.cff_meta (snd cff.cff_name);
 	let params = if fctx.is_static && not fctx.is_abstract_member && not (Meta.has Meta.LibType cctx.tclass.cl_meta) (* TODO: remove this *) then [] else ctx.type_params in
-	let ctx = TyperManager.clone_for_field ctx null_field params in
+	let ctx = TyperManager.clone_for_field ctx cf params in
 
 	let c = cctx.tclass in
 	if (fctx.is_abstract && not (has_meta Meta.LibType c.cl_meta)) then begin
@@ -560,7 +560,7 @@ let create_typer_context_for_field ctx cctx fctx cff =
 	end;
 	ctx
 
-let is_public (ctx,cctx) access parent =
+let is_public cctx access parent =
 	let c = cctx.tclass in
 	if List.mem_assoc APrivate access then
 		false
@@ -890,7 +890,7 @@ let load_variable_type_hint ctx fctx eo p = function
 	| Some t ->
 		load_type_hint ctx p LoadNormal (Some t)
 
-let create_variable (ctx,cctx,fctx) c f t eo p =
+let create_variable (ctx,cctx,fctx) c f cf t eo p =
 	let is_abstract_enum_field = List.mem_assoc AEnum f.cff_access in
 	if fctx.is_abstract_member && not is_abstract_enum_field then raise_typing_error "Cannot declare member variable in abstract" p;
 	if fctx.is_inline && not fctx.is_static then invalid_modifier ctx.com fctx "inline" "non-static variable" p;
@@ -910,12 +910,8 @@ let create_variable (ctx,cctx,fctx) c f t eo p =
 	else
 		{ v_read = AccNormal ; v_write = AccNormal }
 	in
-	let cf = {
-		(mk_field (fst f.cff_name) ~public:(is_public (ctx,cctx) f.cff_access None) t f.cff_pos (pos f.cff_name)) with
-		cf_doc = f.cff_doc;
-		cf_meta = f.cff_meta;
-		cf_kind = Var kind;
-	} in
+	cf.cf_type <- t;
+	cf.cf_kind <- Var kind;
 	if fctx.is_final then begin
 		if missing_initialization && not fctx.is_static then
 			cctx.uninitialized_final <- cf :: cctx.uninitialized_final;
@@ -927,7 +923,6 @@ let create_variable (ctx,cctx,fctx) c f t eo p =
 		add_class_field_flag cf CfImpl;
 	end;
 	if is_abstract_enum_field then add_class_field_flag cf CfEnum;
-	ctx.f.curfield <- cf;
 	TypeBinding.bind_var ctx cctx fctx cf eo;
 	cf
 
@@ -1180,7 +1175,7 @@ let setup_args_ret ctx cctx fctx name fd p =
 	let args = new FunctionArguments.function_arguments ctx.com type_arg is_extern fctx.is_display_field abstract_this fd.f_args in
 	args,ret
 
-let create_method (ctx,cctx,fctx) c f fd p =
+let create_method (ctx,cctx,fctx) c f cf fd p =
 	let name = fst f.cff_name in
 	let params = TypeloadFunction.type_function_params ctx fd TPHMethod name p in
 	if fctx.is_generic then begin
@@ -1257,13 +1252,10 @@ let create_method (ctx,cctx,fctx) c f fd p =
 	ctx.type_params <- params @ ctx.type_params;
 	let args,ret = setup_args_ret ctx cctx fctx (fst f.cff_name) fd p in
 	let t = TFun (args#for_type,ret) in
-	let cf = {
-		(mk_field name ~public:(is_public (ctx,cctx) f.cff_access parent) t f.cff_pos (pos f.cff_name)) with
-		cf_doc = f.cff_doc;
-		cf_meta = f.cff_meta;
-		cf_kind = Method (if fctx.is_macro then MethMacro else if fctx.is_inline then MethInline else if dynamic then MethDynamic else MethNormal);
-		cf_params = params;
-	} in
+	cf.cf_type <- t;
+	cf.cf_kind <- Method (if fctx.is_macro then MethMacro else if fctx.is_inline then MethInline else if dynamic then MethDynamic else MethNormal);
+	cf.cf_params <- params;
+	if is_public cctx f.cff_access parent then add_class_field_flag cf CfPublic;
 	if fctx.is_final then add_class_field_flag cf CfFinal;
 	if fctx.is_extern then add_class_field_flag cf CfExtern;
 	if fctx.is_abstract then begin
@@ -1325,7 +1317,6 @@ let create_method (ctx,cctx,fctx) c f fd p =
 			if fctx.field_kind = CfrConstructor then FunConstructor else if fctx.is_static then FunStatic else FunMember
 	in
 	init_meta_overloads ctx (Some c) cf;
-	ctx.f.curfield <- cf;
 	if fctx.do_bind then
 		TypeBinding.bind_method ctx cctx fctx fmode cf t args ret fd.f_expr (match fd.f_expr with Some e -> snd e | None -> f.cff_pos)
 	else begin
@@ -1348,13 +1339,14 @@ let create_method (ctx,cctx,fctx) c f fd p =
 	end;
 	cf
 
-let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
+let create_property (ctx,cctx,fctx) c f cf (get,set,t,eo) p =
 	let name = fst f.cff_name in
 	let ret = (match t, eo with
 		| None, None -> raise_typing_error "Property requires type-hint or initialization" p;
 		| None, _ -> mk_mono()
 		| Some t, _ -> load_type_hint ctx p LoadNormal (Some t)
 	) in
+	cf.cf_type <- ret;
 	let t_get,t_set = match cctx.abstract with
 		| Some a when fctx.is_abstract_member ->
 			if Meta.has Meta.IsVar f.cff_meta then raise_typing_error "Abstract properties cannot be real variables" f.cff_pos;
@@ -1369,11 +1361,6 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 		end else
 			get_overloads ctx.com c m
 	in
-	let cf = {
-		(mk_field name ~public:(is_public (ctx,cctx) f.cff_access None) ret f.cff_pos (pos f.cff_name)) with
-		cf_doc = f.cff_doc;
-		cf_meta = f.cff_meta;
-	} in
 	if fctx.is_abstract_member then add_class_field_flag cf CfImpl;
 	let check_method m t is_getter =
 		try
@@ -1488,7 +1475,6 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 	cf.cf_kind <- Var { v_read = get; v_write = set };
 	if fctx.is_extern then add_class_field_flag cf CfExtern;
 	if List.mem_assoc AEnum f.cff_access then add_class_field_flag cf CfEnum;
-	ctx.f.curfield <- cf;
 	TypeBinding.bind_var ctx cctx fctx cf eo;
 	cf
 
@@ -1507,10 +1493,10 @@ let reject_final_static_method ctx cctx fctx f =
 		in
 		invalid_modifier_combination fctx ctx.com fctx "final" "static" p
 
-let init_field (ctx,cctx,fctx) f =
+let init_field (ctx,cctx,fctx) f cf =
 	let c = cctx.tclass in
 	let name = fst f.cff_name in
-	TypeloadCheck.check_global_metadata ctx f.cff_meta (fun m -> f.cff_meta <- m :: f.cff_meta) c.cl_module.m_path c.cl_path (Some name);
+	TypeloadCheck.check_global_metadata ctx f.cff_meta (fun m -> cf.cf_meta <- m :: cf.cf_meta) c.cl_module.m_path c.cl_path (Some name);
 	let p = f.cff_pos in
 	if not (has_class_flag c CExtern) && not (Meta.has Meta.Native f.cff_meta) then Naming.check_field_name ctx.com name p;
 	List.iter (fun acc ->
@@ -1539,17 +1525,16 @@ let init_field (ctx,cctx,fctx) f =
 	let cf =
 		match f.cff_kind with
 		| FVar (t,e) ->
-			create_variable (ctx,cctx,fctx) c f t e p
+			create_variable (ctx,cctx,fctx) c f cf t e p
 		| FFun fd ->
 			reject_final_static_method ctx cctx fctx f;
-			create_method (ctx,cctx,fctx) c f fd p
+			create_method (ctx,cctx,fctx) c f cf fd p
 		| FProp (get,set,t,eo) ->
-			create_property (ctx,cctx,fctx) c f (get,set,t,eo) p
+			create_property (ctx,cctx,fctx) c f cf (get,set,t,eo) p
 	in
 	(if (fctx.is_static || fctx.is_macro && ctx.com.is_macro_context) then add_class_field_flag cf CfStatic);
 	if Meta.has Meta.InheritDoc cf.cf_meta then
-		delay ctx.g PTypeField (fun() -> InheritDoc.build_class_field_doc ctx (Some c) cf);
-	cf
+		delay ctx.g PTypeField (fun() -> InheritDoc.build_class_field_doc ctx (Some c) cf)
 
 let check_overload ctx f fs is_extern_class =
 	try
@@ -1612,6 +1597,13 @@ let check_functional_interface ctx c =
 		add_class_flag c CFunctionalInterface;
 		ctx.com.functional_interface_lut#add c.cl_path (c,cf)
 
+let create_class_field cctx f  =
+	let cf = {(mk_field (fst f.cff_name) ~public:(is_public cctx f.cff_access None) t_dynamic f.cff_pos (pos f.cff_name)) with
+		cf_doc = f.cff_doc;
+		cf_meta = f.cff_meta
+	} in
+	cf
+
 let init_class ctx_c cctx c p herits fields =
 	let com = ctx_c.com in
 	if cctx.is_class_debug then print_endline ("Created class context: " ^ dump_class_context cctx);
@@ -1658,10 +1650,11 @@ let init_class ctx_c cctx c p herits fields =
 		let p = f.cff_pos in
 		let display_modifier = Typeload.check_field_access ctx_c f in
 		let fctx = create_field_context ctx_c cctx f ctx_c.m.is_display_file display_modifier in
-		let ctx = create_typer_context_for_field ctx_c cctx fctx f in
+		let cf = create_class_field cctx f in
+		let ctx = create_typer_context_for_field ctx_c cctx fctx f cf in
 		try
 			if fctx.is_field_debug then print_endline ("Created field context: " ^ dump_field_context fctx);
-			let cf = init_field (ctx,cctx,fctx) f in
+			init_field (ctx,cctx,fctx) f cf;
 			if fctx.field_kind = CfrInit then begin
 				if !has_init then
 					display_error ctx.com ("Duplicate class field declaration : " ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name) cf.cf_name_pos

+ 9 - 15
src/typing/typer.ml

@@ -605,15 +605,7 @@ and handle_efield ctx e p0 mode with_type =
 			   create safe navigation chain from the object expression *)
 			let acc_obj = type_access ctx eobj pobj MGet WithType.value in
 			let eobj = acc_get ctx acc_obj in
-			let eobj, tempvar = match (Texpr.skip eobj).eexpr with
-				| TLocal _ | TTypeExpr _ | TConst _ ->
-					eobj, None
-				| _ ->
-					let v = alloc_var VGenerated "tmp" eobj.etype eobj.epos in
-					let temp_var = mk (TVar(v, Some eobj)) ctx.t.tvoid v.v_pos in
-					let eobj = mk (TLocal v) v.v_type v.v_pos in
-					eobj, Some temp_var
-			in
+			let eobj, tempvar = get_safe_nav_base ctx eobj in
 			let access = field_chain ctx ((mk_dot_path_part s p) :: dot_path_acc) (AKExpr eobj) mode with_type in
 			AKSafeNav {
 				sn_pos = p;
@@ -637,7 +629,8 @@ and type_access ctx e p mode with_type =
 	match e with
 	| EConst (Ident s) ->
 		type_ident ctx s p mode with_type
-	| EField (e1,"new",efk_todo) ->
+	| EField (e1,"new",efk) ->
+		if efk = EFSafe then raise_typing_error "?.new is not supported" p;
 		let e1 = type_expr ctx e1 WithType.value in
 		begin match e1.eexpr with
 			| TTypeExpr (TClassDecl c) ->
@@ -710,7 +703,7 @@ and type_vars ctx vl p =
 				| Some e ->
 					let old_in_loop = ctx.e.in_loop in
 					if ev.ev_static then ctx.e.in_loop <- false;
-					let e = Std.finally (fun () -> ctx.e.in_loop <- old_in_loop) (type_expr ctx e) (WithType.with_type t) in
+					let e = Std.finally (fun () -> ctx.e.in_loop <- old_in_loop) (type_expr ctx e) (WithType.with_local_variable t n) in
 					let e = AbstractCast.cast_or_unify ctx t e p in
 					Some e
 			) in
@@ -1765,10 +1758,10 @@ and type_call_builtin ctx e el mode with_type p =
 	| (EField ((EConst (Ident "super"),_),_,_),_), _ ->
 		(* no builtins can be applied to super as it can't be a value *)
 		raise Exit
-	| (EField (e,"bind",efk_todo),p), args ->
+	| (EField (e,"bind",efk),p), args ->
 		let e = type_expr ctx e WithType.value in
 		(match follow e.etype with
-			| TFun signature -> type_bind ctx e signature args p
+			| TFun signature -> type_bind ctx e signature args (efk = EFSafe) p
 			| _ -> raise Exit)
 	| (EConst (Ident "$type"),_) , e1 :: el ->
 		let expected = match el with
@@ -1787,7 +1780,8 @@ and type_call_builtin ctx e el mode with_type p =
 		in
 		warning ctx WInfo s e1.epos;
 		e1
-	| (EField(e,"match",efk_todo),p), [epat] ->
+	| (EField(e,"match",efk),p), [epat] ->
+		if efk = EFSafe then raise_typing_error "?.match is not supported" p;
 		let et = type_expr ctx e WithType.value in
 		let rec has_enum_match t = match follow t with
 			| TEnum _ -> true
@@ -1899,7 +1893,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 			| _ -> follow_null tmin
 		in
 		let e1_null_t = if is_nullable e1.etype then e1.etype else ctx.t.tnull e1.etype in
-		let e1 = vr#as_var "tmp" {e1 with etype = e1_null_t} in
+		let e1 = vr#as_var (Option.default "tmp" (WithType.get_expected_name with_type)) {e1 with etype = e1_null_t} in
 		let e_null = Builder.make_null e1_null_t e1.epos in
 		let e_cond = mk (TBinop(OpNotEq,e1,e_null)) ctx.t.tbool e1.epos in
 		let e_if = mk (TIf(e_cond,cast e1,Some e2)) iftype p in

+ 11 - 1
src/typing/typerBase.ml

@@ -369,4 +369,14 @@ let safe_nav_branch ctx sn f_then =
 	let eif = mk (TIf(eneq,ethen,Some eelse)) tnull sn.sn_pos in
 	(match sn.sn_temp_var with
 	| None -> eif
-	| Some evar -> { eif with eexpr = TBlock [evar; eif] })
+	| Some evar -> { eif with eexpr = TBlock [evar; eif] })
+
+let get_safe_nav_base ctx eobj =
+	match (Texpr.skip eobj).eexpr with
+	| TLocal _ | TTypeExpr _ | TConst _ ->
+		eobj, None
+	| _ ->
+		let v = alloc_var VGenerated "tmp" eobj.etype eobj.epos in
+		let temp_var = mk (TVar(v, Some eobj)) ctx.t.tvoid v.v_pos in
+		let eobj = mk (TLocal v) v.v_type v.v_pos in
+		eobj, Some temp_var

+ 1 - 1
src/typing/typerDisplay.ml

@@ -518,7 +518,7 @@ and display_expr ctx e_ast e dk mode with_type p =
 		let fields = DisplayFields.collect ctx e_ast e dk with_type p in
 		let item = completion_item_of_expr ctx e in
 		let iterator = try
-			let it = (ForLoop.IterationKind.of_texpr ~resume:true ctx e (fun _ -> false) e.epos) in
+			let it = (ForLoop.IterationKind.of_texpr ~resume:true ctx e None e.epos) in
 			match follow it.it_type with
 				| TDynamic _ ->  None
 				| t -> Some t

Vissa filer visades inte eftersom för många filer har ändrats