Created
May 7, 2013 18:49
-
-
Save Simn/5535082 to your computer and use it in GitHub Desktop.
printf for haxe using GADT and macros
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
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. | |
} | |
} |
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
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