defnew &prop

This commit is contained in:
2021-05-16 17:18:56 -06:00
parent 1680bbe517
commit 4739c0f881
2 changed files with 34 additions and 3 deletions

View File

@@ -374,6 +374,15 @@ class Helpers {
}; };
} }
public static function argList(exp:ReaderExp, forThis:String):Array<ReaderExp> {
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<ReaderExp> { public static function bindingList(exp:ReaderExp, forThis:String):Array<ReaderExp> {
return switch (exp.def) { return switch (exp.def) {
case ListExp(bindingExps) if (bindingExps.length > 0 && bindingExps.length % 2 == 0): case ListExp(bindingExps) if (bindingExps.length > 0 && bindingExps.length % 2 == 0):

View File

@@ -529,11 +529,11 @@ class Macros {
// TODO test defnew // TODO test defnew
macros["defnew"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> { macros["defnew"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {
wholeExp.checkNumArgs(2, null, "(defnew [[args...]] [[property bindings...]] [body...]"); wholeExp.checkNumArgs(2, null, "(defnew [[args...]] [[property bindings...]] [body...]");
var args = exps[0];
var bindingList = exps[1].bindingList("defnew"); var bindingList = exps[1].bindingList("defnew");
var bindingPairs = Prelude.groups(bindingList, 2); 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 propertyDefs = [for (bindingPair in bindingPairs) {
var b = bindingPair[0].expBuilder(); var b = bindingPair[0].expBuilder();
b.call(b.symbol("defprop"), [bindingPair[0]]); 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]]); 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(); var b = wholeExp.expBuilder();
return b.begin(propertyDefs.concat([ return b.begin(propertyDefs.concat([
b.call(b.symbol("defmethod"), [ b.call(b.symbol("defmethod"), [
b.symbol("new"), b.symbol("new"),
exps[0] b.list(argList)
].concat(propertySetExps).concat(exps.slice(2))) ].concat(propertySetExps).concat(exps.slice(2)))
])); ]));
}; };