Beispiel #1
0
        internal override void Bind(Binder binder)
        {
            DeclaredVariable.KnownType = RedwoodType.GetForLambdaArgsTypes(
                typeof(InternalLambda),
                ReturnType == null ? RedwoodType.Void : ReturnType.GetIndicatedType(),
                Parameters.Select(param => param.Type.GetIndicatedType()).ToArray());

            base.Bind(binder);
            // No need to bind if we're a stub; we just need to communicate
            // our type to the outside world. Since no actual compilation will
            // go on, we don't need to be compiled.
            if (Body == null)
            {
                return;
            }

            binder.EnterFullScope();
            binder.PushReturnType(
                ReturnType == null ? RedwoodType.Void : ReturnType.GetIndicatedType()
                );

            foreach (ParameterDefinition param in Parameters)
            {
                param.Bind(binder);
            }

            Body.Bind(binder);
            ClosureSize = binder.GetClosureSize();
            binder.PopReturnType();
            StackSize = binder.LeaveFullScope();
        }
        private static RedwoodType ResolveBinaryOperator(
            BinaryOperator op,
            RedwoodType left,
            RedwoodType right,
            RedwoodType searchType,
            out Lambda lambda,
            out int?staticSlot,
            out int?index)
        {
            if (searchType.CSharpType == null)
            {
                staticSlot = searchType.staticSlotMap[RuntimeUtil.NameForOperator(op)];
                lambda     = null;

                RedwoodType overloadType = searchType.staticSlotTypes[staticSlot ?? -1];
                if (overloadType.CSharpType == typeof(LambdaGroup))
                {
                    if (!RuntimeUtil.TrySelectOverload(
                            new RedwoodType[] { left, right },
                            overloadType.GenericArguments
                            .Select(lambdaType => lambdaType
                                    .GenericArguments
                                    .SkipLast(1)
                                    .ToArray()
                                    )
                            .ToArray(),
                            out int resIndex
                            ))
                    {
                        index      = null;
                        staticSlot = null;
                        return(null);
                    }

                    index = resIndex;
                    return(overloadType.GenericArguments[resIndex]);
                }

                index = null;
                return(overloadType);
            }
            else
            {
                index      = null;
                staticSlot = null;
                if (!MemberResolver.TryResolveLambda(
                        searchType,
                        null,
                        RuntimeUtil.NameForOperator(op),
                        out Lambda lambdaOverloads))
                {
                    lambda = null;
                    return(null);
                }

                lambda = RuntimeUtil.SelectSingleOverload(
                    new RedwoodType[] { left, right },
                    lambdaOverloads
                    );

                return(RedwoodType.GetForLambdaArgsTypes(
                           typeof(ExternalLambda),
                           lambda.ReturnType,
                           lambda.ExpectedArgs.ToArray()
                           ));
            }
        }
Beispiel #3
0
        internal override void Bind(Binder binder)
        {
            // We have a series of temporary variables, so we will need
            // to discard them after the call is made
            binder.Bookmark();

            // We have the process
            // Eval arg i, assign variable i, eval arg i+1, assign variable i+1
            // so if we, for instance, bind every argument, then bind every temp
            // variable, we are sure to clobber our own arguments
            for (int i = 0; i < Arguments.Length; i++)
            {
                Arguments[i].Bind(binder);
                binder.BindVariable(ArgumentVariables[i]);
            }

            binder.Checkout();

            bool fullyResolvedTypes;

            if (Callee == null)
            {
                fullyResolvedTypes = FunctionName.GetKnownType() != null;
            }
            else
            {
                fullyResolvedTypes = Callee.GetKnownType() != null;
            }

            RedwoodType[] argumentTypes = new RedwoodType[Arguments.Length];
            for (int i = 0; i < Arguments.Length; i++)
            {
                argumentTypes[i] = Arguments[i].GetKnownType();
                // Not really sure whether we care about this, but it might be useful
                // for compiling variable assignments
                ArgumentVariables[i].KnownType = argumentTypes[i];
                fullyResolvedTypes            &= argumentTypes[i] != null;
            }

            // If we have fully resolved types (ie. all argument types are known
            // and so is the callee type) we definitely know the return type
            FullyResolved = fullyResolvedTypes;
            // We have two options for determining an exact type, either:
            // 1) The method is fully resolved. One lambda type will come out of
            //    the many,
            // or
            // 2) the method is not fully resolved, but the provided arguments
            //    narrow the methods down a single option.
            if (Callee == null)
            {
                LambdaType = FunctionName.GetKnownType();
                // If we have a lambda group, we should try to resolve it
                ResolveLambdaGroupOverload(argumentTypes);
            }
            else if (Callee.GetKnownType() == null)
            {
                LambdaType = null;
            }
            else if (Callee.GetKnownType().CSharpType == null)
            {
                LambdaType = Callee
                             .GetKnownType()
                             .GetKnownTypeOfMember(FunctionName.Name);

                // Make sure that calls to class functions also have the correct
                // lambda type
                ResolveLambdaGroupOverload(argumentTypes);
            }
            else if (Callee.GetKnownType().CSharpType == typeof(RedwoodType))
            {
                if (!Callee.Constant)
                {
                    LambdaType = null;
                }
                else if (Callee.EvaluateConstant() is RedwoodType calleeType)
                {
                    if (calleeType.CSharpType == null)
                    {
                        LambdaType = calleeType
                                     .GetKnownTypeForStaticMember(FunctionName.Name);
                        ResolveLambdaGroupOverload(argumentTypes);
                    }
                    else
                    {
                        MethodInfo[] infos;
                        bool         methodExists = MemberResolver.TryResolveMethod(
                            null,
                            calleeType,
                            FunctionName.Name,
                            true,
                            out infos);

                        if (!methodExists)
                        {
                            throw new NotImplementedException();
                        }

                        BindExternal(infos);
                    }
                }
                else
                {
                    // This should never happen?
                    throw new NotImplementedException();
                }
            }
            else
            {
                MethodInfo[] infos;
                bool         methodExists = MemberResolver.TryResolveMethod(
                    null,
                    Callee.GetKnownType(),
                    FunctionName.Name,
                    false,
                    out infos);

                if (!methodExists)
                {
                    // TODO: Can an object have a lambda field?
                    throw new NotImplementedException();
                }

                BindExternal(infos);
            }

            void BindExternal(MethodInfo[] infos)
            {
                ExternalMethodGroup = new MethodGroup(infos);
                ExternalMethodGroup.SelectOverloads(argumentTypes);

                if (ExternalMethodGroup.infos.Length == 0)
                {
                    throw new NotImplementedException();
                }
                else if (ExternalMethodGroup.infos.Length == 1)
                {
                    RedwoodType returnType =
                        RedwoodType.GetForCSharpType(ExternalMethodGroup.infos[0].ReturnType);

                    RedwoodType[] paramTypes = ExternalMethodGroup.infos[0].GetParameters()
                                               .Select(param => RedwoodType.GetForCSharpType(param.ParameterType))
                                               .ToArray();

                    LambdaType = RedwoodType.GetForLambdaArgsTypes(
                        typeof(ExternalLambda),
                        returnType,
                        paramTypes);
                }
            }
        }
        internal override void Bind(Binder binder)
        {
            binder.Bookmark();

            foreach (Variable variable in TemporaryVariables)
            {
                binder.BindVariable(variable);
            }

            Left.Bind(binder);
            Right.Bind(binder);

            binder.Checkout();

            RedwoodType leftType  = Left.GetKnownType();
            RedwoodType rightType = Right.GetKnownType();

            if (SpecialHandling(Operator) || leftType == null || rightType == null)
            {
                return;
            }
            else if (leftType.CSharpType != null && rightType.CSharpType != null)
            {
                // Resolve the static method
                MemberResolver.TryResolveOperator(
                    null,
                    null,
                    Left.GetKnownType(),
                    Right.GetKnownType(),
                    Operator,
                    out Lambda binaryOperationLambda);

                if (binaryOperationLambda == null)
                {
                    throw new NotImplementedException();
                }

                ResolvedOperator = binaryOperationLambda;
                LambdaType       = RedwoodType.GetForLambdaArgsTypes(
                    typeof(ExternalLambda),
                    binaryOperationLambda.ReturnType,
                    binaryOperationLambda.ExpectedArgs.ToArray()
                    );
            }
            else
            {
                RedwoodType[] lambdaTypes = new RedwoodType[2];
                Lambda[]      lambdas     = new Lambda[2];
                int?[]        slots       = new int?[2];
                int?[]        indexes     = new int?[2];

                // Search both the left and the right types for
                // static lambdas

                lambdaTypes[0] = ResolveBinaryOperator(
                    Operator,
                    leftType,
                    rightType,
                    leftType,
                    out lambdas[0],
                    out slots[0],
                    out indexes[0]
                    );

                lambdaTypes[1] = ResolveBinaryOperator(
                    Operator,
                    leftType,
                    rightType,
                    rightType,
                    out lambdas[1],
                    out slots[1],
                    out indexes[1]
                    );

                if (lambdaTypes[0] == null && lambdaTypes[1] == null)
                {
                    // There's no compatible operator between the two
                    throw new NotImplementedException();
                }
                else if (lambdaTypes[0] == null)
                {
                    LambdaType            = lambdaTypes[1];
                    ResolvedOperator      = lambdas[1];
                    ResolvedStaticSlot    = slots[1];
                    ResolvedOverloadIndex = indexes[1];
                    UsingLeftOperator     = false;
                }
                else if (lambdaTypes[1] == null)
                {
                    LambdaType            = lambdaTypes[0];
                    ResolvedOperator      = lambdas[0];
                    ResolvedStaticSlot    = slots[0];
                    ResolvedOverloadIndex = indexes[0];
                    UsingLeftOperator     = true;
                }
                else
                {
                    // TODO: This couldn't return null, could it?
                    RuntimeUtil.TrySelectOverload(
                        new RedwoodType[] { leftType, rightType },
                        lambdaTypes
                        .Select(lambdaType => lambdaType
                                .GenericArguments
                                .SkipLast(1)
                                .ToArray()
                                )
                        .ToArray(),
                        out int res
                        );

                    LambdaType            = lambdaTypes[res];
                    ResolvedOperator      = lambdas[res];
                    ResolvedStaticSlot    = slots[res];
                    ResolvedOverloadIndex = indexes[res];
                    UsingLeftOperator     = res == 0;
                }
            }
        }