// This helper can produce a builder for types that are directly supported by Variant. private static SimpleArgBuilder GetSimpleArgBuilder(Type elementType, VarEnum elementVarEnum) { SimpleArgBuilder argBuilder; switch (elementVarEnum) { case VarEnum.VT_BSTR: argBuilder = new StringArgBuilder(elementType); break; case VarEnum.VT_BOOL: argBuilder = new BoolArgBuilder(elementType); break; case VarEnum.VT_DATE: argBuilder = new DateTimeArgBuilder(elementType); break; case VarEnum.VT_CY: argBuilder = new CurrencyArgBuilder(elementType); break; case VarEnum.VT_DISPATCH: argBuilder = new DispatchArgBuilder(elementType); break; case VarEnum.VT_UNKNOWN: argBuilder = new UnknownArgBuilder(elementType); break; case VarEnum.VT_VARIANT: case VarEnum.VT_ARRAY: case VarEnum.VT_RECORD: argBuilder = new VariantArgBuilder(elementType); break; case VarEnum.VT_ERROR: argBuilder = new ErrorArgBuilder(elementType); break; default: var marshalType = GetManagedMarshalType(elementVarEnum); if (elementType == marshalType) { argBuilder = new SimpleArgBuilder(elementType); } else { argBuilder = new ConvertArgBuilder(elementType, marshalType); } break; } return(argBuilder); }
private void MapParameterReduceByRef(ParameterInfo pi) { Debug.Assert(_returnArgs != null); // See KeywordArgBuilder.BuilderExpectsSingleParameter int indexForArgBuilder = 0; int nameIndex = -1; if (!CompilerHelpers.IsOutParameter(pi)) { nameIndex = _argNames.IndexOf(pi.Name); if (nameIndex == -1) { indexForArgBuilder = _argIndex++; } } ArgBuilder ab; if (CompilerHelpers.IsOutParameter(pi)) { _returnArgs.Add(_arguments.Count); ab = new OutArgBuilder(pi); } else if (pi.ParameterType.IsByRef) { // if the parameter is marked as [In] it is not returned. if ((pi.Attributes & (ParameterAttributes.In | ParameterAttributes.Out)) != ParameterAttributes.In) { _returnArgs.Add(_arguments.Count); } _parameters.Add(new ParameterWrapper(pi, pi.ParameterType.GetElementType(), pi.Name, false, false, false, false)); ab = new ReturnReferenceArgBuilder(pi, indexForArgBuilder); } else if (BinderHelpers.IsParamDictionary(pi)) { _paramsDict = new ParameterWrapper(pi); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } else { _parameters.Add(new ParameterWrapper(pi)); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } if (nameIndex == -1) { _arguments.Add(ab); } else { Debug.Assert(KeywordArgBuilder.BuilderExpectsSingleParameter(ab)); _arguments.Add(new KeywordArgBuilder(ab, _argNames.Count, nameIndex)); } }
public void MapParameter(ParameterInfo pi) { int indexForArgBuilder; int nameIndex = _argNames.IndexOf(pi.Name); if (nameIndex == -1) { // positional argument, we simply consume the next argument indexForArgBuilder = _argIndex++; } else { // keyword argument, we just tell the simple arg builder to consume arg 0. // KeywordArgBuilder will then pass in the correct single argument based // upon the actual argument number provided by the user. indexForArgBuilder = 0; } // if the parameter is default we need to build a default arg builder and then // build a reduced method at the end. if (!CompilerHelpers.IsMandatoryParameter(pi)) { // We need to build the default builder even if we have a parameter for it already to // get good consistency of our error messages. But consider a method like // def foo(a=1, b=2) and the user calls it as foo(b=3). Then adding the default // value breaks an otherwise valid call. This is because we only generate MethodCandidates // filling in the defaults from right to left (so the method - 1 arg requires a, // and the method minus 2 args requires b). So we only add the default if it's // a positional arg or we don't already have a default value. if (nameIndex == -1 || !_hasDefaults) { _defaultArguments.Add(new DefaultArgBuilder(pi)); _hasDefaults = true; } else { _defaultArguments.Add(null); } } else if (_defaultArguments.Count > 0) { // non-contigious default parameter _defaultArguments.Add(null); } ArgBuilder ab; if (pi.ParameterType.IsByRef) { _hasByRefOrOut = true; Type refType = typeof(StrongBox<>).MakeGenericType(pi.ParameterType.GetElementType()); _parameters.Add(new ParameterWrapper(pi, refType, pi.Name, true, false, false, false)); ab = new ReferenceArgBuilder(pi, refType, indexForArgBuilder); } else if (BinderHelpers.IsParamDictionary(pi)) { _paramsDict = new ParameterWrapper(pi); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } else if (pi.Position == 0 && CompilerHelpers.IsExtension(pi.Member)) { _parameters.Add(new ParameterWrapper(pi, pi.ParameterType, pi.Name, true, false, false, true)); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } else { _hasByRefOrOut |= CompilerHelpers.IsOutParameter(pi); _parameters.Add(new ParameterWrapper(pi)); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } if (nameIndex == -1) { _arguments.Add(ab); } else { Debug.Assert(KeywordArgBuilder.BuilderExpectsSingleParameter(ab)); _arguments.Add(new KeywordArgBuilder(ab, _argNames.Count, nameIndex)); } }
internal ConversionArgBuilder(Type parameterType, SimpleArgBuilder innerBuilder) { _parameterType = parameterType; _innerBuilder = innerBuilder; }
// This helper can produce a builder for types that are directly supported by Variant. private static SimpleArgBuilder GetSimpleArgBuilder(Type elementType, VarEnum elementVarEnum) { SimpleArgBuilder argBuilder; switch (elementVarEnum) { case VarEnum.VT_BSTR: argBuilder = new StringArgBuilder(elementType); break; case VarEnum.VT_BOOL: argBuilder = new BoolArgBuilder(elementType); break; case VarEnum.VT_DATE: argBuilder = new DateTimeArgBuilder(elementType); break; case VarEnum.VT_CY: argBuilder = new CurrencyArgBuilder(elementType); break; case VarEnum.VT_DISPATCH: argBuilder = new DispatchArgBuilder(elementType); break; case VarEnum.VT_UNKNOWN: argBuilder = new UnknownArgBuilder(elementType); break; case VarEnum.VT_VARIANT: case VarEnum.VT_ARRAY: case VarEnum.VT_RECORD: argBuilder = new VariantArgBuilder(elementType); break; case VarEnum.VT_ERROR: argBuilder = new ErrorArgBuilder(elementType); break; default: var marshalType = GetManagedMarshalType(elementVarEnum); if (elementType == marshalType) { argBuilder = new SimpleArgBuilder(elementType); } else { argBuilder = new ConvertArgBuilder(elementType, marshalType); } break; } return argBuilder; }
private void AddBasicMethodTargets(MethodTracker method) { List<Parameter> parameters = new List<Parameter>(); int argIndex = 0; ArgBuilder instanceBuilder; if (!method.IsStatic) { parameters.Add(new Parameter(method.DeclaringType)); instanceBuilder = new SimpleArgBuilder(argIndex++, parameters[0]); } else { instanceBuilder = new NullArgBuilder(); } List<ArgBuilder> argBuilders = new List<ArgBuilder>(); List<ArgBuilder> defaultBuilders = new List<ArgBuilder>(); bool hasByRef = false; foreach (ParameterInfo pi in method.GetParameters()) { if (pi.ParameterType == typeof(ICallerContext)) { argBuilders.Add(new ContextArgBuilder()); continue; } if (pi.DefaultValue != DBNull.Value) { defaultBuilders.Add(new DefaultArgBuilder(pi.ParameterType, pi.DefaultValue)); } else if (defaultBuilders.Count > 0) { // If we get a bad method with non-contiguous default values, then just use the contiguous list defaultBuilders.Clear(); } if (pi.ParameterType.IsByRef) { hasByRef = true; Parameter param = new ByRefParameter(pi.ParameterType.GetElementType(), pi.IsOut && !pi.IsIn); parameters.Add(param); argBuilders.Add(new ReferenceArgBuilder(argIndex++, param)); } else { Parameter param = new Parameter(pi.ParameterType); parameters.Add(param); argBuilders.Add(new SimpleArgBuilder(argIndex++, param)); } } ReturnBuilder returnBuilder = new ReturnBuilder(CompilerHelpers.GetReturnType(method.Method)); for (int i = 1; i < defaultBuilders.Count + 1; i++) { List<ArgBuilder> defaultArgBuilders = argBuilders.GetRange(0, argBuilders.Count - i); defaultArgBuilders.AddRange(defaultBuilders.GetRange(defaultBuilders.Count - i, i)); AddTarget(new MethodTarget(method, parameters.GetRange(0, parameters.Count - i), instanceBuilder, defaultArgBuilders, returnBuilder)); } if (hasByRef) AddSimpleTarget(MakeByRefReducedMethodTarget(method, parameters, instanceBuilder, argBuilders)); AddSimpleTarget(new MethodTarget(method, parameters, instanceBuilder, argBuilders, returnBuilder)); }
private MethodCandidate MakeByRefReducedMethodTarget(MethodBase method) { List<ParameterWrapper> parameters = new List<ParameterWrapper>(); int argIndex = 0; ArgBuilder instanceBuilder; if (!CompilerHelpers.IsStatic(method)) { parameters.Add(new ParameterWrapper(_binder, method.DeclaringType, true)); instanceBuilder = new SimpleArgBuilder(argIndex++, parameters[0].Type); } else { instanceBuilder = new NullArgBuilder(); } List<ArgBuilder> argBuilders = new List<ArgBuilder>(); List<int> returnArgs = new List<int>(); if (CompilerHelpers.GetReturnType(method) != typeof(void)) { returnArgs.Add(-1); } int paramCount = 0; foreach (ParameterInfo pi in method.GetParameters()) { if (pi.ParameterType == typeof(CodeContext) && paramCount == 0) { argBuilders.Add(new ContextArgBuilder()); continue; } paramCount++; int newIndex = 0, kwIndex = -1; if (!CompilerHelpers.IsOutParameter(pi)) { kwIndex = GetKeywordIndex(pi); if (kwIndex == -1) { newIndex = argIndex++; } } ArgBuilder ab; if (CompilerHelpers.IsOutParameter(pi)) { returnArgs.Add(argBuilders.Count); ab = new OutArgBuilder(pi); } else if (pi.ParameterType.IsByRef) { returnArgs.Add(argBuilders.Count); ParameterWrapper param = new ParameterWrapper(_binder, pi.ParameterType.GetElementType(), SymbolTable.StringToId(pi.Name)); parameters.Add(param); ab = new ReturnReferenceArgBuilder(newIndex, pi.ParameterType.GetElementType()); } else { ParameterWrapper param = new ParameterWrapper(_binder, pi); parameters.Add(param); ab = new SimpleArgBuilder(newIndex, param.Type, pi); } if (kwIndex == -1) { argBuilders.Add(ab); } else { argBuilders.Add(new KeywordArgBuilder(ab, _kwArgs.Length, kwIndex)); } } ReturnBuilder returnBuilder = MakeKeywordReturnBuilder( new ByRefReturnBuilder(_binder, returnArgs), method.GetParameters(), parameters); return MakeMethodCandidate(method, parameters, instanceBuilder, argBuilders, returnBuilder); }
private MethodCandidate MakeDefaultCandidate(MethodBase method, List<ParameterWrapper> parameters, ArgBuilder instanceBuilder, List<ArgBuilder> argBuilders, List<ArgBuilder> defaultBuilders, ReturnBuilder returnBuilder, int defaultsUsed) { List<ArgBuilder> defaultArgBuilders = new List<ArgBuilder>(argBuilders); // argBuilders.GetRange(0, argBuilders.Count - i); List<ParameterWrapper> necessaryParams = parameters.GetRange(0, parameters.Count - defaultsUsed); for (int curDefault = 0; curDefault < defaultsUsed; curDefault++) { int readIndex = defaultBuilders.Count - defaultsUsed + curDefault; int writeIndex = defaultArgBuilders.Count - defaultsUsed + curDefault; if (defaultBuilders[readIndex] != null) { defaultArgBuilders[writeIndex] = defaultBuilders[readIndex]; } else { necessaryParams.Add(parameters[parameters.Count - defaultsUsed + curDefault]); } } // shift any arguments forward that need to be... int curArg = CompilerHelpers.IsStatic(method) ? 0 : 1; for (int i = 0; i < defaultArgBuilders.Count; i++) { if (defaultArgBuilders[i] is DefaultArgBuilder || defaultArgBuilders[i] is ContextArgBuilder || defaultArgBuilders[i] is KeywordArgBuilder) { continue; } ReferenceArgBuilder rab = defaultArgBuilders[i] as ReferenceArgBuilder; if (rab != null) { defaultArgBuilders[i] = new ReferenceArgBuilder(curArg++, rab.Type); continue; } SimpleArgBuilder sab = (SimpleArgBuilder)defaultArgBuilders[i]; Debug.Assert(sab.GetType() == typeof(SimpleArgBuilder)); defaultArgBuilders[i] = new SimpleArgBuilder(curArg++, sab.Type, sab.IsParamsArray, sab.IsParamsDict); } return MakeMethodCandidate(method, necessaryParams, instanceBuilder, defaultArgBuilders, returnBuilder); }
private void AddBasicMethodTargets(MethodBase method) { List<ParameterWrapper> parameters = new List<ParameterWrapper>(); int argIndex = 0; ArgBuilder instanceBuilder; bool hasDefaults = false; if (!CompilerHelpers.IsStatic(method)) { parameters.Add(new ParameterWrapper(_binder, method.DeclaringType, true)); instanceBuilder = new SimpleArgBuilder(argIndex++, parameters[0].Type); } else { instanceBuilder = new NullArgBuilder(); } ParameterInfo[] methodParams = method.GetParameters(); List<ArgBuilder> argBuilders = new List<ArgBuilder>(methodParams.Length); List<ArgBuilder> defaultBuilders = new List<ArgBuilder>(); bool hasByRefOrOut = false; foreach (ParameterInfo pi in methodParams) { if (pi.ParameterType == typeof(CodeContext) && argBuilders.Count == 0) { argBuilders.Add(new ContextArgBuilder()); continue; } int newIndex, kwIndex = GetKeywordIndex(pi); if (kwIndex == -1) { if (!CompilerHelpers.IsMandatoryParameter(pi)) { defaultBuilders.Add(new DefaultArgBuilder(pi.ParameterType, pi.DefaultValue)); hasDefaults = true; } else if (defaultBuilders.Count > 0) { defaultBuilders.Add(null); } newIndex = argIndex++; } else { defaultBuilders.Add(null); newIndex = 0; } ArgBuilder ab; if (pi.ParameterType.IsByRef) { hasByRefOrOut = true; Type refType = typeof(StrongBox<>).MakeGenericType(pi.ParameterType.GetElementType()); ParameterWrapper param = new ParameterWrapper(_binder, refType, true, SymbolTable.StringToId(pi.Name)); parameters.Add(param); ab = new ReferenceArgBuilder(newIndex, param.Type); } else { hasByRefOrOut |= CompilerHelpers.IsOutParameter(pi); ParameterWrapper param = new ParameterWrapper(_binder, pi); parameters.Add(param); ab = new SimpleArgBuilder(newIndex, param.Type, pi); } if (kwIndex == -1) { argBuilders.Add(ab); } else { argBuilders.Add(new KeywordArgBuilder(ab, _kwArgs.Length, kwIndex)); } } ReturnBuilder returnBuilder = MakeKeywordReturnBuilder( new ReturnBuilder(CompilerHelpers.GetReturnType(method)), methodParams, parameters); if (hasDefaults) { for (int defaultsUsed = 1; defaultsUsed < defaultBuilders.Count + 1; defaultsUsed++) { // if the left most default we'll use is not present then don't add a default. This happens in cases such as: // a(a=1, b=2, c=3) and then call with a(a=5, c=3). We'll come through once for c (no default, skip), // once for b (default present, emit) and then a (no default, skip again). W/o skipping we'd generate the same // method multiple times. This also happens w/ non-contigious default values, e.g. foo(a, b=3, c) where we don't want // to generate a default candidate for just c which matches the normal method. if (defaultBuilders[defaultBuilders.Count - defaultsUsed] != null) { AddTarget(MakeDefaultCandidate( method, parameters, instanceBuilder, argBuilders, defaultBuilders, returnBuilder, defaultsUsed)); } } } if (hasByRefOrOut) AddSimpleTarget(MakeByRefReducedMethodTarget(method)); AddSimpleTarget(MakeMethodCandidate(method, parameters, instanceBuilder, argBuilders, returnBuilder)); }