Skip to content

Instantly share code, notes, and snippets.

@Simn
Created May 7, 2013 18:49
Show Gist options
  • Save Simn/5535082 to your computer and use it in GitHub Desktop.
Save Simn/5535082 to your computer and use it in GitHub Desktop.
printf for haxe using GADT and macros
class Main {
static public function main () {
var v = Printf.sprintf("The sum of $i and $i is $s.", 3, 5, "8");
trace(v); // The sum of 3 and 5 is 8.
}
}
import haxe.macro.Context;
import haxe.macro.Expr;
using Lambda;
using StringTools;
using haxe.macro.Tools;
enum ParserState {
Normal;
Placeholder;
}
enum Fmt<A,B> {
Lit(s:String):Fmt<A,A>;
Int:Fmt<A,Int -> A>;
Str:Fmt<A,String -> A>;
Cat<C>(a:Fmt<B,C>, b:Fmt<A,B>):Fmt<A,C>;
}
class Printf {
#if macro
static function parse(s:String, pos:Position) {
var buf = new StringBuf();
var p = 0;
var c = s.fastCodeAt(p);
var state = Normal;
var out:Fmt<Dynamic, Dynamic> = Lit("");
function mkPos() {
var pos = Context.getPosInfos(pos);
pos.min += p + 1;
pos.max = pos.min + 1;
return Context.makePosition(pos);
}
while (!StringTools.isEof(c)) {
switch [c,state] {
case ['$'.code, Normal]:
out = Cat(out, Lit(buf.toString()));
buf = new StringBuf();
state = Placeholder;
case [_, Normal]:
buf.addChar(c);
case ['$'.code, Placeholder]:
Context.error('Unexpected $', pos);
case ['i'.code, Placeholder]:
out = Cat(out, Int);
state = Normal;
case ['s'.code, Placeholder]:
out = Cat(out, Str);
state = Normal;
case _:
Context.error('Unexpected ${String.fromCharCode(c)}', mkPos());
}
c = s.fastCodeAt(++p);
}
return Cat(out, Lit(buf.toString()));
}
#end
macro static public function sprintf(fmt:ExprOf<String>, args:Array<Expr>) {
var s = switch(fmt.expr) {
case EConst(CString(s)): s;
case _: Context.error("String expected", fmt.pos);
}
var f = parse(s, fmt.pos);
var e = macro Printf.eval($v{f}, function(x) return x);
for (arg in args) {
e = macro $e($arg);
}
return e;
}
static function eval<A,B>(fmt:Fmt<A,B>, f:String -> A):B {
return switch(fmt) {
case Lit(str): f(str);
case Int: function(x) return f(Std.string(x));
case Str: function(x) return f(x);
case Cat(a, b): eval(a, function(sa) return eval(b, function(sb) return f(sa + sb)));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment