HaxeFoundation / haxe

Haxe - The Cross-Platform Toolkit
https://haxe.org
6.11k stars 648 forks source link

Haxe-in-Haxe notes #6843

Open ncannasse opened 6 years ago

ncannasse commented 6 years ago

The first goal is to have the compiler written in Haxe and generating the corresponding OCaml code, allowing for a more familiar syntax for potential contributors and compiler team. At longer term, this will allow the compiler to run on other platforms although this is not something that will be possible or that we should focus at first.

The following needs to be resolved to have a working Haxe-in-Haxe implementation.

Note to Haxe users : this is an exploration of the possibility, we are not sure yet we will have something working in the end.

OCaml Haxe target (Haxe-to-OCaml) (@ncannasse) :

Automated Haxe compiler OCaml-to-Haxe ML2HX (@nadako) :

Merge of both ML target and ML2HX :

ncannasse commented 6 years ago

I have added :: operator and ability to construct and pattern match immutable lists, this can be followed on this branch https://github.com/HaxeFoundation/haxe/tree/genml

nanjizal commented 6 years ago

Since Haxe currently support C# would F# provide a simpler path. http://web.archive.org/web/20080410181630/http://research.microsoft.com/fsharp/manual/ml-compat.aspx https://stackoverflow.com/questions/179492/f-changes-to-ocaml The task could then be split between modifying the C# target to support F#, and a task to change the compiler to F# code while keeping information on changes made so that Ocaml can be supported later. Haxe c# dll could be consumed which would allow you to plugin hard functionality fairly early on and optimise and rewrite as needed. Anyway just an idea I have no idea if it fits the needs but if someone was able to get a minimal F# version of Haxe compiler working quickly it would prove the concept.

nanjizal commented 6 years ago

I have compiled F# mono graphics examples on mac so it's not just windows although doubt it would provide the same speed as Ocaml initially?

nanjizal commented 6 years ago

I also wonder about using hxcpp but I suppose libraries like https://github.com/GJDuck/libf Don't produce the richness that Ocaml has.

ncannasse commented 6 years ago

@nanjizal I don't think F# produces as fast code as OCaml do, as it's built on top of DotNet

nanjizal commented 6 years ago

http://fsharpnews.blogspot.co.uk/2012/09/performance-of-compiler-translated-from.html

ncannasse commented 6 years ago

@nanjizal anyway I have little interest in targeting F#, and this requires extra profiling and extensive changes as the article explains

kevinresol commented 6 years ago

@nanjizal let's not diverge the focus here. Porting from the compiler from OCaml to Haxe is a big task already. Let keep this post focused on this single aspect.

Using other target language is beyond the scope of the post as said in OP already:

... to run on other platforms ... is not something ... that we should focus at first.

markknol commented 6 years ago

Awesome, Keep up the good work guys! I think this will improve Haxe a lot!

mikicho commented 6 years ago

@ncannasse what about performance? I mean, if feature X will develop in Haxe->Ocamel it will be slower than if written in Ocamel directly? the difference is negligible?

nanjizal commented 6 years ago

It would be very interesting if there was an example of what Haxe code might look like for targeting Ocaml so a snippet showing a small aspect of functionality. I am not even sure on what support Haxe has for immutable code at the moment ( there is now final, but I have not seen it used ). I think it would be really helpful to flush out some small examples even if incomplete, rather than just describe them above, because when we can start to see how Haxe might be used it gives more idea of current limitations. For instance to capture the input and interest of really able Haxe developers who don't use Ocaml currently. Also I would be keen if macros were used sparingly, I think they are very powerful but increase the entry point of contribution and could make code more difficult than the current Ocaml codebase.

ncannasse commented 6 years ago

@mikicho the idea is to have 0 loss of performance in the process, so we are looking for something almost 1-to-1 conversion

nadako commented 6 years ago

So I started a little ocaml project for converting ml to hx here https://github.com/nadako/ml2hx. It's really rough but the foundation is there to improve upon. It works by invoking ocaml as a lib and processing the typed AST to generate Haxe code. Currently requires 4.06 and probably won't compile with earlier versions, because the compiler API incompatibilities, but oh well.

back2dos commented 6 years ago

I'm a little surprised this didn't get mentioned: https://github.com/elnabo/haxe_in_haxe ^^

Either way, this is very exciting news. I really hope something will come out of it ;)

nanjizal commented 6 years ago

@nadako hi very interesting, obviously my first thought was to try the code on itself so I can understand the Ocaml code better:

$ ./main main.ml File "main.ml", line 2, characters 5-13: Error: Unbound module Asttypes

Should this work?

( By the way could the make file work without ocamlfind and use opam instead, it's not in homebrew and not needed for make haxe compiler? Well I have installed ocamlfind here, but for other mac users might be better to avoid? I don't know? )

mikicho commented 6 years ago

@nanjizal Please discuss about his awesome project in its repo. Guys, please stay focus on the subject, we want this issue will be readable in the near future :)

fullofcaffeine commented 6 years ago

Could someone shed some light on https://github.com/elnabo/haxe_in_haxe? Is it a coincidence that the creation of this repo somehow matches the creation of this issue?

I guess the idea is to first automatically transpile the OCaml codebase to Haxe using https://github.com/nadako/ml2hx. and then fix / improve manually as we go?

That said, those are really great news! 🎉

nadako commented 6 years ago

Is it a coincidence that the creation of this repo somehow matches the creation of this issue?

It's not, it was published when discussions started about Haxe in Haxe :) I'm not sure about the fate of this repo though, since porting this amount of code by hand is not really an option.

I guess the idea is to first automatically transpile the OCaml codebase to Haxe using https://github.com/nadako/ml2hx. and then fix / improve manually as we go?

Yeah, that's the idea at the moment. Thanks to the fact Haxe is actually quite similar to ocaml (enums, pattern matching, var shadowing, everything as expression, etc.), it's pretty straightforward to generate readable-ish haxe code from ocaml.

elnabo commented 6 years ago

Could someone shed some light on https://github.com/elnabo/haxe_in_haxe? Is it a coincidence that the creation of this repo somehow matches the creation of this issue?

I started to try and do a copy of the compiler in Haxe a month ago. And when the issue of writing Haxe in Haxe arose, @ibilon told me to make my code public.

I don't know how long, I'll continue it, because it's likely other options will succeed first. But for the moment, it help me understand a bit better the compiler.

nanjizal commented 6 years ago

@elnabo well it may turn out that for hxcpp this approach is better, we can't assume that ocaml/functional output will provide the best results, but I can imagine that an automated initial port that nadako has started should provide a solution that more easily covers all the edge cases currently. But you can never be sure where such projects leads I certainly urge you to continue sometimes working from different angles also brings a better overall solution and new opportunities. Can you compile the JS target with your code?

elnabo commented 6 years ago

I tried to compile with hxnodejs but I get weird error Class<Sys> has no field stderr so I must have misconfigured something.

But as I try to be as similar to the source as possible. Me and nadako should end with similar looking code. Except I'm likely to have bugs hidden somewhere, as I think I currently have.

Simn commented 5 years ago

Rant

You're crazy

I just read through this issue properly for the first time and think y'all are crazy. Porting the Haxe sources to Haxe only to then compile them back to OCaml is insanity.

Let's look at what's bad about OCaml:

  1. It's a pain the ass to set up, especially if you're not on Linux.
  2. Its compilation time can be very slow.
  3. It does not support true parallelism.
  4. Its tooling in general is a bit shit, even if you are on Linux.

Which of these problems would be alleviated by having the Haxe sources in Haxe and compiling them to OCaml? Well, we would still be stuck with the same crappy toolkit, except that we now have another layer on top of it which makes most of the issues even worse:

  1. We still have to set up OCaml in order to compile Haxe.
  2. We still have a slow OCaml compile time, plus we now add the Haxe compile time.
  3. We could still not use parallelism because we go through OCaml.
  4. Alright, we could use some of Haxe's better tooling.

Furthermore, all that is assuming that we would even make it that far in the first place. I don't share your optimism that the code base could be converted to maintainable Haxe and be generated back to efficient OCaml. There's no way that you could generate idiomatic Haxe to efficient OCaml in general, so we would have to gimp ourselves by essentially writing OCaml-idiomatic code in Haxe.

Alternatives

So in summary, I think this entire idea of going through OCaml should be dropped. Which obviously raises the question of what we should do instead. Given that we want to write Haxe-in-Haxe, I can see two possibilities:

  1. Write a JVM-target and use that.
  2. Focus on hxcpp.

Given that 1. requires an additional step, it would seem that 2. is the best option. At this point, hxcpp is pretty battle-hardened. And guess what, it already has a generational GC, which is the reason why Nicolas clings to OCaml. I can't speak to the efficiency of it, but in my experience all it takes to get Hugh on a job is a benchmark showing a problem.

What's more, hxcpp supports parallelism. Even if its GC doesn't beat OCaml's (which I expect to be the case), I'd wager that the usage of multithreading would make up for that.

And yes I'm implying that we should rewrite Haxe instead of trying to awkwardly port it. I know people think it's not an option, but I disagree. We're currently sitting at just above 100kloc, which is not much. I can easily write you a parser + typer + optimizer + JS generator in one month of focused effort if I have a clear vision of what to go for.

I'd have to think a bit about how to port eval, but that can also be figured out. The analyzer would require some redesign that doesn't depend on functors. Porting generators requires some manpower, but there's nothing inherently difficult about it either.

IMO this is what we should go for with Haxe 5. There's a million questions still to be answered obviously, but I really want to get the point across that targeting OCaml is a huge strategic mistake in 2019.

nadako commented 5 years ago

I'm not sure how much different the rewrite would look like from the "OCaml-idiomatic code", especially if we talk about multi-threading. I'm pretty sure it'll still be a bunch of recursive pattern matching functions and persistent data structures, unless "we" want to go for the OOP visitor pattern madness (I can see different array handling and some proper non-exception based control flow though:)). That's why I think that automated port is technically viable, even though with all the extra punctuation that Haxe will bring, our single-letter names will look even more messy :)

Personally I have no problems with OCaml nowadays, and it's tooling is slowly getting better, but I could of course work on Haxe in Haxe. In some situations Haxe would be actually nicer (e.g. reification and/or macros for expr building).

Regarding the run-time, I was recently writing a compiler for AS3 in a functional style, simiilar to how Haxe is written, and I can say this requires a really really good GC, because even V8 (node.js) chokes badly with a lot of persistent data object allocations. I had to add quite some boilerplate checks to do less allocations so it doesn't die. HXCPP seemed to perform better, but I didn't do deeper benchmarking, but I feel like at this point "we" have a lot of experince to improve GC :)

ncannasse commented 5 years ago

I partly agree with the rant against OCaml and its "difficulties" to setup and use.

I think an interesting question would be ask ourselves why OCaml performs so good. I think it boils down to two things:

a) good code analysis / auto inlining / tail call optimization, resulting in functional code being entirely lifted into more imperative constructors b) a very efficient generational GC that allows to allocate a lot of small objects very fast

I think we could provide the (a) as part of some of our native targets (HxCPP and/or HL) The (b) excludes Java and DotNet IMHO, we could have a specific GC for either HxCPP or HL - or even port Ocaml's one there - but that's not a small work.

ncannasse commented 5 years ago

Regarding multithreading, I there it could work well for some very specific cases (pure map, some truly parallel stateless filters, etc.) but most of the rest of the compiler code has to remain single threaded for our own sanity.

zicklag commented 5 years ago

I think it would be a lot nicer to skip the OCaml layer if we could use something like HashLink or HxCPP instead. I really like how tiny HashLink is and how easy it is to compile. Reducing the need for OCaml tooling to just needing a C/C++ compiler would go a long way in making it easier to get setup for development.

nanjizal commented 5 years ago

This is quite interesting on lack of parrallel Ocaml, but I expect you have read it, but there are many interesting aspects if you read all the comments. https://www.reddit.com/r/ocaml/comments/61pep4/ocaml_multicore_support/

Simn commented 5 years ago

HL

The reason I didn't mention HL is because I'm not sure if this kind of performance is going to be your focus. At the moment, our mandelbrot benchmark is 40 times slower on HL than it is on hxcpp, Java and nodejs. This benchmark is very relevant to the performance discussion here because it creates a lot of small objects.

If we can address this, HL could be considered as an alternative. It would require quite a bit of energy to bring the GC to the required level, but I'm not saying it's impossible.

P.S.: Don't underestimate Java performance. A JVM target would be a tough contender, believe it or not.

Multi-threading

I'm quite sure that we could at least run large parts of our post-processing multi-threaded. Some things are obviously linear, like DCE and purity-inference, but there's also a lot of local mapping going on.

Technically, it should be possible to run our compiler passes multi-threaded as well. That's more challenging though and I'm inclined to agree that it's better for our sanity to not venture down that area.

ncannasse commented 5 years ago

@Simon : yes, the mandelbrot benchmark is actually very GC oriented, unless compiled with -D reduce_allocs, I think outside of GC you should get similar or better perfs in HL/C than in HxCPP. But yes HL GC is very basic compared to what would be necessary for Haxe-in-Haxe Regarding JVM : yes I know the JIT is quite good, but I'm not sure how much the GC can cope with functional approach. Maybe writing a small example which does build some kind of expr and do a lot of stupid "map" over it would be a good micro benchmark to compare different platforms ?

On Tue, Mar 19, 2019 at 7:51 AM Simon Krajewski notifications@github.com wrote:

HL

The reason I didn't mention HL is because I'm not sure if this kind of performance is going to be your focus. At the moment, our mandelbrot benchmark https://github.com/HaxeFoundation/haxe/tree/development/tests/benchs/mandelbrot is 40 times slower on HL than it is on hxcpp, Java and nodejs. This benchmark is very relevant to the performance discussion here because it creates a lot of small objects.

If we can address this, HL could be considered as an alternative. It would require quite a bit of energy to bring the GC to the required level, but I'm not saying it's impossible.

P.S.: Don't underestimate Java performance. A JVM target would be a tough contender, believe it or not. Multi-threading

I'm quite sure that we could at least run large parts of our post-processing multi-threaded. Some things are obviously linear, like DCE and purity-inference, but there's also a lot of local mapping going on.

Technically, it should be possible to run our compiler passes multi-threaded as well. That's more challenging though and I'm inclined to agree that it's better for our sanity to not venture down that area.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/HaxeFoundation/haxe/issues/6843#issuecomment-474219544, or mute the thread https://github.com/notifications/unsubscribe-auth/AA-bwL5Nfgb79GGojoQ53ZvKqkraj-orks5vYIj3gaJpZM4SA3nI .

Simn commented 5 years ago

yes, the mandelbrot benchmark is actually very GC oriented, unless compiled with -D reduce_allocs, I think outside of GC you should get similar or better perfs in HL/C than in HxCPP.

Yes, it's only slightly slower than hxcpp with -D reduce_allocs. But that's a bit like saying that your parser tests work fine except for the failing parser tests.

One appealing thing about HL is its non-ridiculous compilation time. But overall this is all moot unless we get a GC that can compete. I suppose we would ultimately write this in a way that we could compile it to one or the other anyway, so the main question for now isn't really "what target should we use?" but "is there a target that might be/become viable?".

And I want that answer to be "yes". If none of the Haxe targets is suitable for running a compiler, we're back to being just a bunch of clowns who used to make flash games.

ncannasse commented 5 years ago

That's a bit oversimplifying : a compiler is a quite specific piece of software which can highly benefit from some very particular runtime features (highly GC dependent, TCO, low memory overhead per "object") etc.

As I suggested the next step to evaluate our best target candidate would be to write some micro benchmarks evaluating these things, and see if some platform is already on-par with what OCaml provides.

Simn commented 5 years ago

I agree. Fortunately, we have nadako working on his Actionscript compiler at the moment and we should get some nice performance metrics from that.

ncannasse commented 5 years ago

I don't this that's the best benchmark. Unless @nadako widely uses ocaml-like lists the way we do in Haxe compiler?

On Tue, Mar 19, 2019 at 5:49 PM Simon Krajewski notifications@github.com wrote:

I agree. Fortunately, we have nadako working on his Actionscript compiler at the moment and we should get some nice performance metrics from that.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/HaxeFoundation/haxe/issues/6843#issuecomment-474465738, or mute the thread https://github.com/notifications/unsubscribe-auth/AA-bwMWk1jpM9GC12Kyel4zmsVrICHUGks5vYRUjgaJpZM4SA3nI .

Simn commented 5 years ago

That's what I meant regarding Haxe-idiomatic and OCaml-idiomatic. Cons lists are very untypical for Haxe and our Haxe-in-Haxe should certainly avoid them. It's not an option without a reliance on TCO anyway. They are nice in many situations, but not a hard necessity for compilers.

nadako commented 5 years ago

I don't use cons-lists, but I do use a lot of enums and immutable structures (I even have a a.with(field=value) macro).

back2dos commented 5 years ago

Perhaps we could salvage https://github.com/elnabo/haxe_in_haxe for performance metrics?

Also C# might be an interesting target too, since you can explicitly hint things to be structs (not so good for the recursive enums, but things like Field/ClassField could be quite a bit cheaper). Also AOT is a lot more mature for .NET/mono, and since the compiler doesn't have much need to use all the bells and whistles from the framework, chances are not-so-huge standalone binaries might fall out in the end.

As a side question: has anyone with experience in these matters tried what happens if you try building Haxe via js_of_ocaml / BuckleScript / ReasonML?

nanjizal commented 5 years ago

Not sure it's ideal for haxe to follow c# NET core even if there maybe some interesting approaches to explore. OCaml-to-F#-conversions console F# with NET core - notice they target web and mobile net-lib Program.dll ??

djaonourside commented 5 years ago

What's the current strategy of the haxe in haxe implementation?

ncannasse commented 4 years ago

We discussed extensively again Haxe-in-Haxe today. We agree that we need more data before making a decision regarding if OCaml should be the runtime VS JVM or HL or HxCPP.

One solution I propose to learn about this is to port a "mini compiler" from Haxe to OCaml, and I think HScript Parser + Checker would be a good candidate as it's "vanilla" Haxe with no much optimizations.

Once ported, I can provide several medium sized scripts from our games in order to benchmark this. Depending on the benchmark results, we can tell a few things:

hughsando commented 4 years ago

I think the OCaml target is completely unnecessary for moving forward. It should go:

  1. Write ocaml ast -> haxe generator
  2. try it

We can worry about whether ocaml is going to be faster or not later. My guess is it will all depend on how Dynamic the code looks.

I would also add that a Lexer is a very finite piece of code and should be hand-optimized with haxe idioms rather than with ocaml conversion (Arrays vs list, loops vs recursion etc). There are several ways of writing a parser, but again, it is a finite piece of code and can be rewritten especially for haxe. Removing the ocaml dependence is the main point of this exercise. It is going to be easier than writing a new target.

mingodad commented 3 years ago

I have added :: operator and ability to construct and pattern match immutable lists, this can be followed on this branch https://github.com/HaxeFoundation/haxe/tree/genml

I'm trying to understand and possible make haxe_in_haxe run with Haxe 4.2.1 and I'm getting errors referring to the genml extension that doesn't seem to have any documentation explaining how/what it's suppose to mean/do, could someone shed some light here:

haxe "build.hxml"
src/compiler/Main.hx:67: characters 18-19 : Expected }
...
            case Flash:
                function loop (l:ImmutableList<{a:Float, b:String}>) {
                    switch (l) {
                        case []:
                        case {a:v}::_ if (v > com.flash_version): //!!!!<<< here
                        case {a:v, b:def}::l:
                            var l:ImmutableList<{a:Float, b:String}> = l;
                            context.Common.raw_define(com, "flash"+def);
                            loop(l);
                    }
                }
                loop(context.Common.flash_versions);
                context.Common.raw_define(com, "flash");
                com.package_rules = PMap.remove("flash", com.package_rules);
                add_std("flash");
                "swf";
...
haxe "build.hxml"
src/compiler/Main.hx:121: characters 62-63 : Missing ;
...
            case Cpp:
                context.Common.define_value(com, HxcppApiLevel, "332");
                add_std("cpp");
                if (context.Common.defined(com, Cppia)) {
                    classes = core.Path.parse_path("cpp.cppia.HostClasses") :: classes; //!!!!<<< here
                }
                "cpp";
elnabo commented 3 years ago

If I remember correctly, the :: operator is used to manipulate list the same way as ocaml

In the context of a switch it is used to separate the elements of the list. The last value is the rest of the list.

So in the first example in {a:v}::_ {a:v} would be l[0] and the _ would be l.slice(1)

Otherwise it is an operator that create a new list that start with the value before :: and is followed by the values after.

So in the second example with parse_path(...) :: classes it would be similar to

classes = classes.copy(); // due to immutability
classes.unshift(parse_path(...)

The :: operator was only defined in the genml branch and worked with the specific ImmutableList type. I think they never lived outside of the branch. Unless someone implement them in a 4.2 branch, the best bet would be to do the operation manually using enums or to use Array.

hughsando commented 3 years ago

From the name (genml) I would say it is an experimental ml target. I would say comment out any reference to the target, but keep the AST changes. IIRC, the target was for presumed speed and is therefore an optimization that can be added once correctness is achieved.

mingodad commented 3 years ago

So if I understood it correctly this one will become (see bellow):

    public static function process_params(create:ImmutableList<String>->compiler.Server.Context, pl:ImmutableList<String>) {
        var each_params = new Ref<ImmutableList<String>>([]);
        function loop (acc:ImmutableList<String>, l:ImmutableList<String>) : Void {
            switch (l) {
                case []:
                    var ctx = create(List.append(each_params.get(), List.rev(acc)));
                    init(ctx);
                    ctx.flush();
                case "--next"::l if (acc == Tl): // skip empty --next
                    loop([], l);
                case "--next"::l:
                    var ctx = create(List.append(each_params.get(), List.rev(acc)));
                    ctx.has_next = true;
                    init(ctx);
                    ctx.flush();
                    loop([], l);
                case "--each"::l:
                    each_params.set(List.rev(acc));
                    loop([], l);
...
    public static function process_params(create:ImmutableList<String>->compiler.Server.Context, pl:ImmutableList<String>) {
        var each_params = new Ref<ImmutableList<String>>([]);
        function loop (acc:ImmutableList<String>, l:ImmutableList<String>) : Void {
            switch (l) {
                case []:
                    var ctx = create(List.append(each_params.get(), List.rev(acc)));
                    init(ctx);
                    ctx.flush();
                case "--next" if (acc == Tl): // skip empty --next
                    l = l.slice(1);
                    loop([], l);
                case "--next":
                    l = l.slice(1);
                    var ctx = create(List.append(each_params.get(), List.rev(acc)));
                    ctx.has_next = true;
                    init(ctx);
                    ctx.flush();
                    loop([], l);
                case "--each":
                    l = l.slice(1);
                    each_params.set(List.rev(acc));
                    loop([], l);
...
mingodad commented 3 years ago

And this ones will become:

                case "--cwd"::(dir::l):
                    // we need to change it immediately since it will affect hxml loading
                    try {
                        std.Sys.setCwd(dir);
                    }
                    catch (_:Dynamic) {
                        throw new ocaml.Arg.Bad("Invalid directory: " + dir);
                    }
                    loop(acc, l);
                case "--connect"::(hp::l):
...
                case "--cwd":
                    var dir = l.slice(1);
                    l = l.slice(2);
                    // we need to change it immediately since it will affect hxml loading
                    try {
                        std.Sys.setCwd(dir);
                    }
                    catch (_:Dynamic) {
                        throw new ocaml.Arg.Bad("Invalid directory: " + dir);
                    }
                    loop(acc, l);
                case "--connect":
                    var hp = l.slice(1);
                    l = l.slice(2);
...
mingodad commented 3 years ago

Probably the second should become this:

                case "--cwd":
                    var dir = l[1];
                    l = l.slice(2);
                    // we need to change it immediately since it will affect hxml loading
                    try {
                        std.Sys.setCwd(dir);
                    }
                    catch (_:Dynamic) {
                        throw new ocaml.Arg.Bad("Invalid directory: " + dir);
                    }
                    loop(acc, l);
                case "--connect":
                    var hp = l[1];
                    l = l.slice(2);
...
mingodad commented 3 years ago

And now I can see that for it to possible work I'll need to get the extra haxe.ds data structures like haxe.ds.ImmutableList from this branch https://github.com/HaxeFoundation/haxe/tree/genml and so on.

It seems that this thread/idea lost traction !

Simn commented 3 years ago

I mean, you've been replying to a thread where the last activity was almost a year ago, and that last activity was someone questioning the approach that was taken here.

I still maintain that involving OCaml in this process is silly, and it doesn't even matter what kind of benchmarks we could construct to suggest otherwise.

mingodad commented 3 years ago

I somehow agree with you, one point that holds me to invest more time and effort in learn/adopt Haxe is it's implementation in Ocaml that I do not know (and I did some attempt to learn it but for several reasons I didn't went forward with it).

I like a lot the overall idea behind Haxe but not been able to adapt/change it to my needs is a hard to swallow pill.

I saw this thread and thought that if Haxe could bootstrap itself and run in all targets that would make a lot easier for several users to jump in and fix/add new targets and improve the compiler itself.

hughsando commented 3 years ago

Yes, forget OCaml as a target initially. Forget adding AST components. Forget changing the haxe compiler at all - these are just distractions. The is a project written in haxe, not ocaml. No new "switch" syntax - just use if/else - after all, you are generating code so you can be as verbose as you like. For the list matching, I think you want some kind of "Array View" class to refer to ranges within an immutable Array somewhere.

So

 ... (l:ListView<String>) : Void {
            switch (l) {
                case []:
                case "--next" if (acc == Tl): // skip empty --next
                case "--next":

becomes:

   if (l.empty())
      ...
   else if (l.startsWith("--next") && acc==TI)
      ...
   else if ( l.startsWith("--next"))
    ...

and recursion would be something like:

  function sum(l:ListView<Int>)
  {
      if (l.empty()) return 0;
      if (l.size==1) return l[0];
      return l.head() + sum(l.afterHead());
  }

where l.afterHead creates a new list view starting at the next element

No changes to the haxe compiler are required for this. You just need to start with a haxe-readable ocaml ast dump of some sort.