Reflaxe
Haxe framework for creating compilation targets using macros
Install / Use
/learn @SomeRanDev/ReflaxeREADME
<a href="https://discord.gg/uvq5gPEWCa"><img src="https://discordapp.com/api/guilds/162395145352904705/widget.png?style=shield" alt="Reflaxe Thread"/></a>
A framework for creating Haxe language compilation targets using macros.
All you need to worry about is programming the conversion from Haxe's typed AST to your desired programming language. Reflaxe handles organizing the input AST, reading user configuration, and generating the output file(s), while also providing various configuration options and helper functions for Haxe target developers.
Table of Contents
| Topic | Description | | --- | --- | | Automatic Installation | How to generate a Reflaxe project using the "new" command. | | Building | How to build for library for submission. | | Reflaxe Properties | How to configure unique properties for your Reflaxe project. | | Compiler Code Sample | How to code the compiler. | | CompilerInit Code Sample | How to code the init macro call. | | extraParams.hxml Sample | How to configure your library. | | compile.hxml Sample | How to use your library on other Haxe projects. | | BaseCompiler Functions | The functions used to configure your compiler's behavior and code output. | | BaseCompiler Options | Various options passed to Reflaxe for controlling your compiler's input/output. |
Automatic Installation
Reflaxe provides an easy script to help get started!
First install Reflaxe (THE 4.0.0-beta PART IS IMPORTANT):
haxelib install reflaxe 4.0.0-beta
Then run the following command to generate a new Reflaxe project:
haxelib run reflaxe new
To test your compiler, enter the directory and use Test.hxml:
cd reflaxe_<langname>
haxelib run reflaxe test
Building
If you generated your project using the Reflaxe new script, you may notice your project has multiple source paths. One is for the compiler code, and the other is used for your language's API. Since Haxelib libraries are only allowed one source path, your project must be "built" before distribution.
To do this, simply run the build command:
haxelib run reflaxe build
This will make a copy of your project in the _Build/ folder, with all of the API files combined into a single directory. When submitting your project to haxelib, zip the files only in the _Build folder and submit that.
Reflaxe Properties
You can also configure your multiple directories within haxelib.json.
Entering into haxelib.json, you'll find a new "reflaxe" property that should look something like this:
"reflaxe": {
"name": "Langauge",
"abbv": "lang",
"stdPaths": ["std", "std/lang/_std"]
}
You may add as many paths to the "stdPaths" as you like, and these will be combined together upon building the project.
Compiler Code Sample
For starters, you must fill out the abstract functions from DirectToStringCompiler to define how Haxe AST is converted into a String representation of your target language.
class MyLangCompiler extends reflaxe.DirectToStringCompiler {
//---------
// fill out just these 3 functions and Reflaxe takes care of the rest
//---------
public function compileClassImpl(classType: ClassType, varFields: Array<ClassVarData>, funcFields: Array<ClassFuncData>): Null<String> {
// ...
}
public function compileEnumImpl(enumType: EnumType, options: Array<EnumOptionData>): Null<String> {
// ...
}
public function compileExpressionImpl(expr: TypedExpr, topLevel: Bool): Null<String> {
// ...
}
}
Compiler Init Code Sample
Reflaxe projects also require an initialization macro call to setup the various properties for your target. While you can add this "Start" function to your compiler class, the standard for Reflaxe projects is to have this code in a separate class:
class MyLangCompilerInit {
//---------
// call this from your library's hxml file using --macro
public static function Start() {
final options = {
fileOutputExtension: ".mylang",
outputDirDefineName: "mylang_out",
fileOutputType: FilePerClass
};
//---------
// pass an instance of your compiler w/ desired options
reflaxe.ReflectCompiler.AddCompiler(new MyLangCompiler(), options);
}
}
extraParams.hxml Sample
This framework is expected to be used to create Haxe libraries that "add" an output target. These Haxe libraries are then added to other projects and used to compile Haxe code to the target.
As haxelib only supports one class path per library, combine your class files for the compiler macro classes, target-specific classes, and Haxe standard lib overrides into a single folder.
Your Haxe library using Reflaxe should include an extraParams.hxml file that:
- Defines unique definitions for your target for use in conditional compilation.
- Runs an initialization macro similar to the
MyLangCompilerInit.Startfunction shown above.
-D mylang
--macro MyLangCompilerInit.Start()
compiler.hxml Sample
The Haxe project that uses your library must first add it to their .hxml file. This will cause the Haxe project to use your custom compiler target. All that is left is to define the "outputDirDefineName" define to configure the directory or filename of the output for your compiler target.
# your target will be used when your lib is included
-lib haxe-to-mylang
# set the output directory to "outputDir"
-D mylang_out=outputDir
BaseCompiler Options
This is the list of options that can be passed to ReflectCompiler.AddCompiler to configure how your compiler works.
While these all have default values, it is recommended fileOutputExtension and outputDirDefineName are defined for your language at the bare minimum.
/**
How the source code files are outputted.
**/
public var fileOutputType: BaseCompilerFileOutputType = FilePerClass;
/**
This `String` is appended to the filename for each output file.
**/
public var fileOutputExtension: String = ".hxoutput";
/**
This is the define that decides where the output is placed.
For example, this define will place the output in the "out" directory.
-D hxoutput=out
**/
public var outputDirDefineName: String = "hxoutput";
/**
If "fileOutputType" is `SingleFile`, this is the name of
the file generated if a directory is provided.
**/
public var defaultOutputFilename: String = "output";
/**
A list of type paths that will be ignored and not generated.
Useful in cases where you can optimize the generation of
certain Haxe classes to your target's native syntax.
For example, ignoring `haxe.iterators.ArrayIterator` and
generating to the target's native for-loop.
**/
public var ignoreTypes: Array<String> = [];
/**
A list of variable names that cannot be used in the
generated output. If these are used in the Haxe source,
an underscore is appended to the name in the output.
**/
public var reservedVarNames: Array<String> = [];
/**
The name of the function used to inject code directly
to the target. Set to `null` to disable this feature.
**/
public var targetCodeInjectionName: Null<String> = null;
/**
If `true`, null-safety will be enforced for all the code
compiled to the target. Useful for ensuring null is only
used on types explicitly marked as nullable.
**/
public var enforceNullTyping: Bool = false;
/**
If `true`, typedefs will be converted to their internal
class or enum type before being processed and generated.
**/
public var unwrapTypedefs: Bool = true;
/**
Whether Haxe's "Everything is an Expression" is normalized.
**/
public var normalizeEIE: Bool = true;
/**
Whether variables of the same name are allowed to be
redeclarated in the same scope or a subscope.
**/
public var preventRepeatVars: Bool = true;
/**
Whether variables captured by lambdas are wrapped in
an `Array`. Useful as certain targets can't capture and
modify a value unless stored by reference.
**/
public var wrapLambdaCaptureVarsInArray: Bool = false;
/**
If `true`, during the EIE normalization phase, all
instances of null coalescence are converted to a
null-check if statement.
**/
public var convertNullCoal: Bool = false;
/**
If `true`, during the EIE normalization phase, all
instances of prefix/postfix increment and decrement
are converted to a Binop form.
Helpful on Python-like targets that do not support
the `++` or `--` operators.
**/
public var convertUnopIncrement: Bool = false;
/**
When enabled, function properties that are referenced
as a value will be wrapped in a lambda.
For example this:
```haxe
var fcc = String.fromCharCode
```
Gets converted to this:
```haxe
var fcc = function(i: Int): String {
return String.fromCharCode(i);
}
```
**/
public var wrapFunctionReferences: LambdaWrapType = ExternOnly;
/**
If `wrapFunctionReferences` is set to either `NativeMetaOnly`
or `ExternOnly`, the metadata listed here will trigger a
function to be wrapped in a lambda.
Metadata that will modify the code that's generated for a
function at its call-site should be included here.
**/
public var wrapFunctionMetadata: Array<String> = [
":nati
Related Skills
node-connect
343.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
90.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
343.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
343.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
