Skip to content

Instantly share code, notes, and snippets.

@danielo515
Forked from kLabz/Job.hx
Created December 11, 2022 10:53

Revisions

  1. @kLabz kLabz revised this gist Dec 11, 2022. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion Job.hx
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,8 @@ import haxe.macro.TypeTools;
    @:remove // Doesn't seem to work on lua, eh
    interface Job<TJobOpt:{}> {}

    function checkOpts<T:{}, TJob:Job<T>>(job:Class<TJob>, opts:T):Void {}
    @:pure
    extern function checkOpts<T:{}, TJob:Job<T>>(job:Class<TJob>, opts:T):Void;

    macro function make(type:Expr, args:Expr):Expr {
    var fieldExprs = switch (args.expr) {
  2. @kLabz kLabz revised this gist Dec 10, 2022. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions Job.hx
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,7 @@ import haxe.macro.Expr;
    import haxe.macro.TypeTools;
    #end

    @:remove // Doesn't seem to work on lua, eh
    interface Job<TJobOpt:{}> {}

    function checkOpts<T:{}, TJob:Job<T>>(job:Class<TJob>, opts:T):Void {}
  3. @kLabz kLabz revised this gist Dec 10, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Job.hx
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@ interface Job<TJobOpt:{}> {}

    function checkOpts<T:{}, TJob:Job<T>>(job:Class<TJob>, opts:T):Void {}

    macro function make(type, args:Expr):Expr {
    macro function make(type:Expr, args:Expr):Expr {
    var fieldExprs = switch (args.expr) {
    case EObjectDecl(fields):
    [for (f in fields) f.field => f.expr];
  4. @kLabz kLabz revised this gist Dec 10, 2022. 1 changed file with 3 additions and 15 deletions.
    18 changes: 3 additions & 15 deletions Job.hx
    Original file line number Diff line number Diff line change
    @@ -4,21 +4,9 @@ import haxe.macro.Expr;
    import haxe.macro.TypeTools;
    #end

    #if !macro @:autoBuild(Job.buildJob()) #end
    interface Job<TJobOpt:{}> {}

    macro function buildJob():Array<Field> {
    var cls = Context.getLocalClass().get();

    var CTJobOpts = [for (i in cls.interfaces) {
    if (i.t.get().name != "Job") continue;
    TypeTools.toComplexType(i.params[0]);
    }][0];

    return Context.getBuildFields().concat((macro class A {
    static inline function checkOpts(opts:$CTJobOpts):Void {}
    }).fields);
    }
    function checkOpts<T:{}, TJob:Job<T>>(job:Class<TJob>, opts:T):Void {}

    macro function make(type, args:Expr):Expr {
    var fieldExprs = switch (args.expr) {
    @@ -47,7 +35,7 @@ macro function make(type, args:Expr):Expr {

    return macro @:mergeBlock {
    // Type checking; should be removed by dce
    @:privateAccess @:pos(args.pos) $type.checkOpts($args);
    @:pos(args.pos) Job.checkOpts($type, $args);

    // Actual table creation
    untyped __lua__("{0}:new({1})", $type, lua.Table.create(null, $obj));
    @@ -56,4 +44,4 @@ macro function make(type, args:Expr):Expr {
    case _:
    throw "Must be called with an anonymous object";
    }
    }
    }
  5. @kLabz kLabz revised this gist Dec 10, 2022. 2 changed files with 77 additions and 50 deletions.
    59 changes: 59 additions & 0 deletions Job.hx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    #if macro
    import haxe.macro.Context;
    import haxe.macro.Expr;
    import haxe.macro.TypeTools;
    #end

    #if !macro @:autoBuild(Job.buildJob()) #end
    interface Job<TJobOpt:{}> {}

    macro function buildJob():Array<Field> {
    var cls = Context.getLocalClass().get();

    var CTJobOpts = [for (i in cls.interfaces) {
    if (i.t.get().name != "Job") continue;
    TypeTools.toComplexType(i.params[0]);
    }][0];

    return Context.getBuildFields().concat((macro class A {
    static inline function checkOpts(opts:$CTJobOpts):Void {}
    }).fields);
    }

    macro function make(type, args:Expr):Expr {
    var fieldExprs = switch (args.expr) {
    case EObjectDecl(fields):
    [for (f in fields) f.field => f.expr];

    case _:
    throw "Must be called with an anonymous object";
    };

    switch (Context.typeof(args)) {
    case TAnonymous(_.get().fields => fields):
    var objFields:Array<ObjectField> = [
    for (f in fields) {
    switch (f.type) {
    case TInst(_.toString() => "Array", [TInst(_.toString() => "String", [])]):
    {field: f.name, expr: macro lua.Table.create(${fieldExprs.get(f.name)})};

    case _:
    {field: f.name, expr: macro ${fieldExprs.get(f.name)}};
    }
    }
    ];

    var obj = {expr: EObjectDecl(objFields), pos: args.pos};

    return macro @:mergeBlock {
    // Type checking; should be removed by dce
    @:privateAccess @:pos(args.pos) $type.checkOpts($args);

    // Actual table creation
    untyped __lua__("{0}:new({1})", $type, lua.Table.create(null, $obj));
    };

    case _:
    throw "Must be called with an anonymous object";
    }
    }
    68 changes: 18 additions & 50 deletions Main.hx
    Original file line number Diff line number Diff line change
    @@ -1,63 +1,31 @@
    #if macro
    import haxe.macro.Expr;
    #else
    import lua.Table;
    #end

    typedef Job_opts = {
    typedef Job1_opts = {
    final command:String;
    final cwd:Null<String>;
    final arguments:Array<String>;
    }

    extern class Job {
    #if !macro
    static inline function create(args:Table<String, Dynamic>):Job {
    return untyped __lua__("{0}:new({1})", Job, args);
    }
    #end
    }

    // Note that ExprOf<T> isn't really checking that types do match
    macro function makeJob(args:ExprOf<Job_opts>):ExprOf<Job> {
    var fieldExprs = switch (args.expr) {
    case EObjectDecl(fields):
    [for (f in fields) f.field => f.expr];

    case _:
    throw "Must be called with an anonymous object";
    };

    switch (haxe.macro.Context.typeof(args)) {
    case TAnonymous(_.get().fields => fields):
    var objFields:Array<ObjectField> = [
    for (f in fields) {
    switch (f.type) {
    case TInst(_.toString() => "Array", [TInst(_.toString() => "String", [])]):
    {field: f.name, expr: macro Table.create(${fieldExprs.get(f.name)})};
    extern class MyJob1 implements Job<Job1_opts> {}

    case _:
    {field: f.name, expr: macro ${fieldExprs.get(f.name)}};
    }
    }
    ];

    var obj = {expr: EObjectDecl(objFields), pos: args.pos};
    return macro Job.create(Table.create(null, $obj));

    case _:
    throw "Must be called with an anonymous object";
    }
    typedef Job2_opts = {
    final command:String;
    final cwd:Null<String>;
    final arguments:Array<String>;
    }

    #if !macro
    // Used like this:
    extern class MyJob2 implements Job<Job2_opts> {}

    function main() {
    var job = makeJob({
    var job = Job.make(MyJob1, {
    command: "chezmoi",
    cwd: "/Users/danielo/",
    arguments: ['-v']
    });
    // Vim.print(job);
    }
    #end
    // local job = MyJob1:new(({arguments = ({"-v"}), command = "chezmoi", cwd = "/Users/danielo/"}));

    var job = Job.make(MyJob2, {
    command: "chezmoi",
    cwd: "/Users/danielo/",
    arguments: ['-v']
    });
    // local job = MyJob2:new(({arguments = ({"-v"}), command = "chezmoi", cwd = "/Users/danielo/"}));
    }
  6. @kLabz kLabz created this gist Dec 10, 2022.
    63 changes: 63 additions & 0 deletions Main.hx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,63 @@
    #if macro
    import haxe.macro.Expr;
    #else
    import lua.Table;
    #end

    typedef Job_opts = {
    final command:String;
    final cwd:Null<String>;
    final arguments:Array<String>;
    }

    extern class Job {
    #if !macro
    static inline function create(args:Table<String, Dynamic>):Job {
    return untyped __lua__("{0}:new({1})", Job, args);
    }
    #end
    }

    // Note that ExprOf<T> isn't really checking that types do match
    macro function makeJob(args:ExprOf<Job_opts>):ExprOf<Job> {
    var fieldExprs = switch (args.expr) {
    case EObjectDecl(fields):
    [for (f in fields) f.field => f.expr];

    case _:
    throw "Must be called with an anonymous object";
    };

    switch (haxe.macro.Context.typeof(args)) {
    case TAnonymous(_.get().fields => fields):
    var objFields:Array<ObjectField> = [
    for (f in fields) {
    switch (f.type) {
    case TInst(_.toString() => "Array", [TInst(_.toString() => "String", [])]):
    {field: f.name, expr: macro Table.create(${fieldExprs.get(f.name)})};

    case _:
    {field: f.name, expr: macro ${fieldExprs.get(f.name)}};
    }
    }
    ];

    var obj = {expr: EObjectDecl(objFields), pos: args.pos};
    return macro Job.create(Table.create(null, $obj));

    case _:
    throw "Must be called with an anonymous object";
    }
    }

    #if !macro
    // Used like this:
    function main() {
    var job = makeJob({
    command: "chezmoi",
    cwd: "/Users/danielo/",
    arguments: ['-v']
    });
    // Vim.print(job);
    }
    #end