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() )); } }
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; } } }