rough implementation of redefineWithObjectArgs

This commit is contained in:
2024-03-11 12:23:24 +01:00
parent 73af20b7a6
commit 73aeb3fce6
2 changed files with 107 additions and 1 deletions

View File

@@ -25,6 +25,8 @@ class FieldForms {
funcOrMethod("function", k);
funcOrMethod("method", k);
k.doc("redefineWithObjectArgs", 2, 3, '(redefineWithObjectArgs <function or method name> <new function or method name> <optional [<preserved list args...>]>)');
k.fieldForms["redefineWithObjectArgs"] = redefineWithObjectArgs;
}
static function fieldAccess(formName:String, fieldName:String, nameExp:ReaderExp, ?access:Array<Access>) {
@@ -130,6 +132,105 @@ class FieldForms {
}
}
static function redefineWithObjectArgs(wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState):Field {
switch (args[0].def) {
case Symbol(field):
var originalFunction = k.fieldDict[field];
if (originalFunction == null) {
throw KissError.fromExp(wholeExp, 'Function or method $field does not exist to be redefined');
}
switch (args[1].def) {
case Symbol(newFieldName):
var newField = {
pos: wholeExp.macroPos(),
name: newFieldName,
meta: originalFunction.meta,
access: originalFunction.access,
kind: FFun(switch(originalFunction.kind) {
case FFun({ret: ret, params: params, args: originalArgs}):
var argIndexMap = new Map<String,Int>();
var argMap = new Map<String,Null<FunctionArg>>();
for (idx in 0... originalArgs.length) {
var originalArg = originalArgs[idx];
argIndexMap[originalArg.name] = idx;
argMap[originalArg.name] = originalArg;
}
var callExpArgs:Array<Expr> = [for (_ in 0... originalArgs.length) macro null];
var newArgs = if (args.length > 2) {
[for (argSymbol in Helpers.argList(args[2], "redefineWithObjectArgs"))
switch (argSymbol.def) {
case Symbol(argName):
if (!argMap.exists(argName)) {
throw KissError.fromExp(argSymbol, '$argName is not an argument in the original function or method $field');
}
var arg = argMap[argName];
var index = argIndexMap[argName];
argMap.remove(argName);
argIndexMap.remove(argName);
callExpArgs[index] = macro $i{argName};
arg;
default:
throw KissError.fromExp(argSymbol, 'arguments in an arg list for (redefineWithObjectArgs...) should be plain symbols matching arg names of the original function or method');
}
];
} else {
[];
};
var additionalArgsName = 'additionalArgs${uuid.Uuid.v4().replace("-", "_")}';
var isOpt = true;
var fields:Array<Field> = [];
for (argName => arg in argMap) {
if (arg.opt == null || arg.opt == false)
isOpt = false;
fields.push({
name: argName,
pos: wholeExp.macroPos(),
meta: arg.meta,
kind: FVar(arg.type, null)
});
callExpArgs[argIndexMap[argName]] = macro $i{additionalArgsName}?.$argName;
}
var additionalArgType = TAnonymous(fields);
newArgs.push({
name: additionalArgsName,
opt: isOpt,
type: additionalArgType
});
var exp = macro $i{field}($a{callExpArgs});
switch (ret) {
case TPath({pack:[], name: "Void"}):
default:
exp = macro return $exp;
}
{
ret: ret,
params: params,
args: newArgs,
expr: exp
};
default:
throw KissError.fromExp(args[0], '$field is not a function or method');
})
};
return newField;
default:
throw KissError.fromExp(wholeExp, "The second argument to (redefineWithObjectArgs...) should be a plain symbol of a new function or method name");
}
default:
throw KissError.fromExp(args[0], "The first argument to (redefineWithObjectArgs...) should be a plain symbol of a function or method name");
}
}
static function funcOrMethod(formName:String, k:KissState) {
k.doc(formName, 2, null, '($formName <optional &dynamic> <optional :Type> <name> [<argNames...>] <body...>)');
k.fieldForms[formName] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {

View File

@@ -998,10 +998,15 @@ From:[(assert false (+ \"false \" \"should \" \"have \" \"been \" \"true\"))]" m
(function :Void voidFuncWithMultipleArgs [:Int num :String str :Float num2]
(+ str (+ num num2)))
(function funcWithMultipleOptArgs [&opt :Int num :String str :Float num2]
null)
(redefineWithObjectArgs funcWithMultipleArgs funcWithObjectArgs [str])
(redefineWithObjectArgs voidFuncWithMultipleArgs voidFuncWithObjectArgs [str])
(redefineWithObjectArgs funcWithMultipleOptArgs funcWithOptObjectArgs [])
(function _testRedefineWithObjectArgs []
(voidFuncWithObjectArgs "hey" (object num 5 num2 0.5))
(Assert.equals "hey5.5" (funcWithObjectArgs "hey" (object num 5 num2 0.5)))
(Assert.equals "hey5.5" (funcWithObjectArgs "hey" (object num2 4.5 num 1))))
(Assert.equals "hey5.5" (funcWithObjectArgs "hey" (object num2 4.5 num 1)))
(Assert.equals null (funcWithOptObjectArgs)))