Example #1
0
        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);
            }
        }
Example #2
0
        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);
        }