Probably should be doing other stuff.... buuuut this was too much fun to resist. After one day of development, I'm happy to announce Evil Haxe v2.0! This is a revival of an old collection of mods I made for the Haxe compiler. Only this time, it's super modular, organized, and allows for parser mods to be written using Haxe itself.
https://github.com/RobertBorghese/evil-haxe
#Evil Haxe
1 messages · Page 1 of 1 (latest)
How to Use Mods
The Evil Haxe compiler is a drop-in replacement for Haxe. It should be completely compatible with existing Haxe, and all the mods are intended to work as "additions" to Haxe. Furthermore, mods are not applied to normal Haxe code.
To enable Evil Haxe mods in a source file, the first top-level statement in the file must be #evil. This will enable all the default mods. To specify only certain mods, simply add arguments to the statement: #evil(pipe, pow).
Making Mods
Mods can be registered by running Haxe code in the pre-initialization phase. To make this possible, Evil Haxe adds a new compiler argument: --conspire. It works the same way as the --macro argument, just pass a call to your init function!
From there, the Evil.addParserMod function can be used to register the mod.
// Mod.hx
import evil.macro.TokenStream;
// --conspire Mod.init()
function init() {
Evil.addParserMod("loop_mod", {
onExpr: function(stream: TokenStream): Null<haxe.macro.Expr> {
return switch(stream.peek().token) {
case Const(CIdent("loop")): {
stream.consume();
final expr = stream.nextExpr();
macro while(true) $expr;
}
case _: {
null;
}
}
}
});
}
To use the mod, simply add the #evil statement to the top of another Haxe file.
// Main.hx
#evil(loop_mod)
function main() {
// New "loop" feature created by "loop_mod".
var i = 1;
loop {
i *= 2;
if(i > 20) {
break;
}
}
trace(i);
}
very evil
what kinds of evil things come with it?
By default, the only built-in mod is a mod that adds support for the pipe operator:
2 |> Math.pow(5) |> trace; // 25
But gonna add way more in the future!
neato!
i can think of a few evil things to add...
Ooo I wanna hear!
defer, and totally custom operators (in userspace--might be a hard one to parse)
or maybe one step past defer and doing scope guards from D https://tour.dlang.org/tour/en/gems/scope-guards
also UFCS would be evil (basically implicit using for every import)
Oh yeahh, user defined custom operators sounds awesome.... hmmmm might be possible if they're defined ahead of time or something... like with a macro or something 
I hadn't even heard of defer until now. That sounds cool af. Definitely making that a thing.
Gotta add more hooks to make it possible 
very nice, and actually only ~50 lines of code
it looks like in the case of an exception the defer won't run, right?
like
try {
defer trace("won't print");
throw "exception";
} catch (e) {
}
Yeah, all it does is literally move the statement to the end of the block scope. So in that case it wouldn't run.
It also doesn't evaluate the arguments at the defer location if it's a function call. So I guess there's a bit more that can be done. But works as a nice proof of concept.
When things get really complicated, might be better to implement as a build macro, then use the parsing mod to convert the syntax to metadata. 
what is defer?
a go thing iirc
I was thinking put everything after the defer in a try block and the defer expr in the finally block but thinking back i cant remember if haxe has finally
It doesn't, but it really should T-T
This seems fun but not really what I see useful, syntax sugars are usually more confusing than being useful
I thought maybe planning to add something like plugins? Although it already exists in part of haxe but not developed.
Imagine extending haxe API:
#evil(cABI)
@:cImport("stdio.h")
class Main {
static function main() {
printf("This comes from a C ABI?\n");
}
}
The whole thing is because haxe is written in OCamel and have difficulties to handle ABI with so they started Hashlink.
Also things like:
#evil(cABI)
@:c("
#ifndef MYLIB_H
#define MYLIB_H
#include <stdio.h>
void hello() {
printf("Hello like c++ extended style\n");
}
#endif // MYLIB_H
", hello);
// Just to demosterate #undef
@:cUndef("MYLIB_H")
class Main {
static function main() {
hello();
}
}
woah this is really cool AND useful what the fuck
It depends on the sugar, but there are definitely syntax changes that can improve readability, at least on a per project basis (like I've written a mod for Type* syntax in my Haxe -> C++ proj, and it's way nicer than having cpp.Pointer<Type> everywhere). This is why modular configuration is an important, one can pick and choose what's nice and what's overkill.
The cABI thing seems interesting, though I don't know why it couldn't be done with Haxe macros normally. Though maybe I'm missing something since I don't know much about the C ABI. 😅
Thanks!! 😁
Languages that have access to direct functions of executables I really have no experience with OCaml and don't know if it can access C ABI, internally, usually happens when the language actually compiles to Executable (not transpiled) the idea really needs work to be done through whole haxe echosystem OR generating direct C Code and injecting these parts like hxcpp.
When you are compiling the code to executable accessing C ABI during linking stage lets you access linked libraries API.
I have never been through that stage, never written a language that generates executable so don't know much either.
Just know that you can do that through llvm api or if using gnu during linker stage can access some stuff.
Also another idea that is not as unachievable as this one but intrinsics in Haxe is so much appriciated 😦
Yoooooo peak just released this is amazing
Why is my name Jason
hi jason
It is a beautiful day outside
birds are singing
flowers are blooming
on days like these,
kids like you
wtf
⒮⒣⒪⒰⒧⒟ ⒝⒠ ⒝⒰⒭⒩⒤⒩⒢ ⒤⒩ ⒣⒠⒧⒧ .
DELETE THIS MESSAGE IMMEDIATELY CHAIN DETROYER 

