Skip to content

Instantly share code, notes, and snippets.

@nadako
Created May 26, 2014 14:28
Show Gist options
  • Save nadako/7fd2372342d814ceabd5 to your computer and use it in GitHub Desktop.
Save nadako/7fd2372342d814ceabd5 to your computer and use it in GitHub Desktop.
Main.main = function() {
var a = JSON.parse("{}");
if(!Object.prototype.hasOwnProperty.call(a,"a")) throw "a.a: required field missing";
if(!js.Boot.__instanceof(a.a,Int)) throw "a.a: Not an integer";
if(!Object.prototype.hasOwnProperty.call(a,"b")) throw "a.b: required field missing";
if(!(typeof(a.b) == "number")) throw "a.b: Not a float";
if(Object.prototype.hasOwnProperty.call(a,"c") && !(typeof(a.c) == "boolean")) throw "a.c: Not a boolean";
if(!Object.prototype.hasOwnProperty.call(a,"d")) throw "a.d: required field missing";
if(!((a.d instanceof Array) && a.d.__enum__ == null)) throw "a.d: Not an array";
var _g = 0;
var _g1 = a.d;
while(_g < _g1.length) {
var elem = _g1[_g];
++_g;
if(!Object.prototype.hasOwnProperty.call(elem,"f")) throw "elem.f: required field missing";
if(!(typeof(elem.f) == "string")) throw "elem.f: Not a string";
}
};
class Main {
static function main() {
var a:{a:Int, b:Float, ?c:Bool, d:Array<{f:String}>} = haxe.Json.parse("{}");
check(a);
}
static macro function check(e) {
return TypeCheck.genCheck(e, haxe.macro.Context.typeof(e));
}
}
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
using haxe.macro.Tools;
#if macro
class TypeCheck {
public static function genCheck(e:Expr, t:Type):Expr {
var estr = e.toString();
var edyn = macro ($e : Dynamic);
var checks = [];
switch (t.follow()) {
case TAbstract(_.get() => {pack: [], name: "Int"}, _):
checks.push(macro if (!Std.is($edyn, Int)) throw $v{estr + ": Not an integer"});
case TAbstract(_.get() => {pack: [], name: "Float"}, _):
checks.push(macro if (!Std.is($edyn, Float)) throw $v{estr + ": Not a float"});
case TAbstract(_.get() => {pack: [], name: "Bool"}, _):
checks.push(macro if (!Std.is($edyn, Bool)) throw $v{estr + ": Not a boolean"});
case TInst(_.get() => {pack: [], name: "String"}, _):
checks.push(macro if (!Std.is($edyn, String)) throw $v{estr + ": Not a string"});
case TInst(_.get() => {pack: [], name: "Array"}, [elemType]):
checks.push(macro if (!Std.is($edyn, Array)) throw $v{estr + ": Not an array"});
checks.push(macro for (elem in ($edyn : Array<Dynamic>)) ${genCheck(macro elem, elemType)});
case TAnonymous(_.get() => anon):
for (field in anon.fields) {
var opt = field.meta.has(":optional");
var fieldName = field.name;
var fieldCheck = genCheck(macro $e.$fieldName, field.type);
var hasField = macro Reflect.hasField($edyn, $v{fieldName});
if (!opt) {
checks.push(macro if (!$hasField) throw $v{estr + "." + fieldName + ": required field missing"});
checks.push(fieldCheck);
} else {
switch (fieldCheck.expr) {
// inline simple if-checks with hasField check
case EBlock([{expr: EIf(cond, error, null)}]):
checks.push(macro if ($hasField && $cond) $error);
default:
checks.push(macro if ($hasField) $fieldCheck);
}
}
}
default:
throw "Unsupported type " + t.toString();
}
return macro $b{checks};
}
}
#end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment