Last active
September 12, 2020 10:58
-
-
Save jcward/4669dd9f1e79948d6a5e to your computer and use it in GitHub Desktop.
Haxe typed compile time constants example macro (parsing or evaluating)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-main Main | |
-lib hscript | |
-neko test.n | |
-D host="my.example.com" | |
-D port=8080 | |
-D timestamp_expr=Date.now().getTime() | |
--next | |
-cmd neko test.n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note: Commandline escaping is different from build.hxml escaping | |
haxe -lib hscript -main Main -neko test.n -D host='"my.example.com"' -D port=8080 -D timestamp_expr="Date.now().getTime()" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// In a build system, I like to pass typed compile-time constants to my code | |
// via compiler defines. For example, a host String and a port Int. The | |
// following macros provide functionality to either parse or eval a compiler | |
// define as Haxe code. Since they operate at compile time and inject the | |
// resulting expressions into your code, this retains all type features -- | |
// from type inference to type checking. | |
// | |
// Note that $type prints the type at compile time, while trace prints | |
// the value at runtime. Neko is called simply to demonstrate the latter. | |
import haxe.macro.Context; | |
class Main { | |
static function main() | |
{ | |
// -D host='"my.example.com"' | |
var host = parseDefine("host"); | |
#if !macro $type(host); #end // String | |
trace(host); | |
// -D port=8080 | |
var port = parseDefine("port"); | |
#if !macro $type(port); #end // Int | |
trace(port); | |
// parseDefine parses a define into an expression that evaluates at runtime: | |
// -D timestamp_expr="Date.now().getTime()" | |
var run_timestamp = parseDefine("timestamp_expr"); | |
#if !macro $type(run_timestamp); #end // Float | |
trace(" Now timestamp: "+run_timestamp); | |
// evalDefine parses and then evaluates a define, resulting in an | |
// expression (often a constant) at runtime: | |
// -D timestamp_expr="Date.now().getTime()" | |
var build_timestamp = evalDefine("timestamp_expr"); | |
#if !macro $type(build_timestamp); #end // Float | |
trace("Build timestamp: "+build_timestamp); | |
} | |
macro public static function parseDefine(key:String) | |
{ | |
return Context.parse(Context.definedValue(key), Context.currentPos()); | |
} | |
macro public static function evalDefine(key:String) | |
{ | |
var e = new hscript.Parser().parseString(Context.definedValue(key)); | |
var interp = new hscript.Interp(); | |
// hscript: export some useful classes | |
interp.variables.set("Array", Array); | |
interp.variables.set("DateTools", DateTools); | |
interp.variables.set("Date", Date); | |
interp.variables.set("Math", Math); | |
interp.variables.set("StringTools", StringTools); | |
interp.variables.set("Sys", Sys); | |
interp.variables.set("Xml", Xml); | |
interp.variables.set("sys", { | |
"FileSystem": sys.FileSystem, | |
"io": { | |
"File": sys.io.File | |
}, | |
"net": { | |
"Host": sys.net.Host | |
} | |
}); | |
interp.variables.set("haxe", { | |
"Json": haxe.Json, | |
"Http": haxe.Http, | |
"Serializer": haxe.Serializer, | |
"Unserializer": haxe.Unserializer | |
}); | |
return Context.makeExpr(interp.execute(e), Context.currentPos()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Thanks to Simn, nadako, dstrekelj, and grepsuzette for chatting on IRC about this. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ETA: Ok, I've updated the gist to support either
parseDefine
orevalDefine
, the latter currently relying on hscript to execute the code (sinceContext.eval
is not yet available). Unfortunately it appears you have to manually add Haxe types to the scope of hscript, so be aware depending on what types your define snippets use.