public static void TrapClosure(this ILambdaTransfer node, ComputationContext ctx, ref IExpression source) { if (TrapLambdaClosure(node, ctx, ref source)) { return; } if (source is NameReference name_ref && name_ref.Binding.Match.Instance.Target is FunctionDefinition func) { if (func.Name.Arity > 0 && !name_ref.TemplateArguments.Any()) { ctx.AddError(ErrorCode.SelectingAmbiguousTemplateFunction, name_ref); } IExpression this_obj = name_ref.GetContext(func); // example scenario // f = my_object.my_square // f(4) // so we have to grab "my_object", make closure around it, and then put it instead of "my_object.my_square" name_ref.DetachFrom(node); if (name_ref.Prefix != null) { name_ref.Prefix.DetachFrom(name_ref); name_ref.Prefix.DereferencedCount_LEGACY = 0; // we have to clear it because we will reuse it } TypeDefinition closure_type = buildTypeOfReference(ctx, name_ref, this_obj); node.AddClosure(closure_type); if (this_obj != null) { source = ExpressionFactory.HeapConstructor(closure_type.InstanceOf.NameOf, FunctionArgument.Create(name_ref.Prefix)); } else { source = ExpressionFactory.HeapConstructor(closure_type.InstanceOf.NameOf); } source.AttachTo(node); closure_type.Surfed(ctx); closure_type.Evaluated(ctx, EvaluationCall.AdHocCrossJump); closure_type.InvokeFunctions().First().MetaThisParameter.Evaluated(ctx, EvaluationCall.AdHocCrossJump); source.Evaluated(ctx, EvaluationCall.Nested); } }
public static bool TrapLambdaClosure(this ILambdaTransfer node, ComputationContext ctx, ref IExpression source) { if (!(source is FunctionDefinition lambda)) { return(false); } // example scenario // f = (x) => x*x // f(4) // we already have tracked all the variables used inside lambda (which are declared outside, locals are OK), // so all we have to do it is to remove it and put into closure type if (!lambda.IsComputed) { throw new Exception("Internal error"); } lambda.DetachFrom(node); TypeDefinition closure_type = buildTypeOfLambda(ctx, lambda, lambda.LambdaTrap.Fields); node.AddClosure(closure_type); source = ExpressionFactory.HeapConstructor(closure_type.InstanceOf.NameOf, lambda.LambdaTrap.Fields.Select(it => FunctionArgument.Create(NameReference.Create(it.Name.Name))).ToArray()); source.AttachTo(node); lambda.LambdaTrap = null; // we have to manually evaluate this expression, because it is child of current node, and child nodes // are evaluated before their parents closure_type.Surfed(ctx); closure_type.Evaluated(ctx, EvaluationCall.AdHocCrossJump); // todo: this is ugly -- we are breaking into details of separate type // since the function is already computed, it won't evaluate meta this parameter lambda.MetaThisParameter.Evaluated(ctx, EvaluationCall.AdHocCrossJump); source.Evaluated(ctx, EvaluationCall.Nested); return(true); }