diff --git a/src/kiss/Helpers.hx b/src/kiss/Helpers.hx index 76ffaeb..547ec54 100644 --- a/src/kiss/Helpers.hx +++ b/src/kiss/Helpers.hx @@ -374,6 +374,15 @@ class Helpers { }; } + public static function argList(exp:ReaderExp, forThis:String):Array { + return switch (exp.def) { + case ListExp(argExps): + argExps; + default: + throw CompileError.fromExp(exp, '$forThis arg list should be a list expression'); + }; + } + public static function bindingList(exp:ReaderExp, forThis:String):Array { return switch (exp.def) { case ListExp(bindingExps) if (bindingExps.length > 0 && bindingExps.length % 2 == 0): diff --git a/src/kiss/Macros.hx b/src/kiss/Macros.hx index d3749bf..99f4731 100644 --- a/src/kiss/Macros.hx +++ b/src/kiss/Macros.hx @@ -529,11 +529,11 @@ class Macros { // TODO test defnew macros["defnew"] = (wholeExp:ReaderExp, exps:Array, k:KissState) -> { wholeExp.checkNumArgs(2, null, "(defnew [[args...]] [[property bindings...]] [body...]"); + + var args = exps[0]; var bindingList = exps[1].bindingList("defnew"); var bindingPairs = Prelude.groups(bindingList, 2); - // TODO allow &prop in the arg list to bind it directly to a same-named variable - var propertyDefs = [for (bindingPair in bindingPairs) { var b = bindingPair[0].expBuilder(); b.call(b.symbol("defprop"), [bindingPair[0]]); @@ -543,11 +543,33 @@ class Macros { b.call(b.symbol("set"), [b.symbol(Helpers.varName("a defprop property binding", bindingPair[0])), bindingPair[1]]); }]; + var argList = []; + // &prop in the argument list defines a property supplied directly as an argument + for (arg in Helpers.argList(args, "defnew")) { + var b = arg.expBuilder(); + switch (arg.def) { + case MetaExp("prop", propExp): + argList.push(propExp); + propertyDefs.push( + b.call(b.symbol("defprop"), [propExp])); + switch (propExp.def) { + case TypedExp(_, {pos: _, def: Symbol(name)}): + propertySetExps.push( + b.call(b.symbol("set"), [b.field(name, b.symbol("this")), b.symbol(name)])); + default: + throw CompileError.fromExp(arg, "invalid use of &prop in defnew"); + } + default: + argList.push(arg); + } + } + var b = wholeExp.expBuilder(); + return b.begin(propertyDefs.concat([ b.call(b.symbol("defmethod"), [ b.symbol("new"), - exps[0] + b.list(argList) ].concat(propertySetExps).concat(exps.slice(2))) ])); };