/// <summary> /// Defines generic parameters according to the given template and re-maps relevant parameters. /// </summary> public static void DefineStubGenericParameters(MethodBuilder /*!*/ stub, Type[] /*!!*/ genericParameters, PhpRoutineSignature /*!*/ targetSignature, Type[] /*!!*/ parameters) { // determine generic parameter names string[] generic_param_names = new string[genericParameters.Length]; for (int j = 0; j < generic_param_names.Length; j++) { if (j < targetSignature.GenericParamCount) { generic_param_names[j] = targetSignature.GenericParams[j].Name.ToString(); } else { generic_param_names[j] = genericParameters[j].Name; } } GenericTypeParameterBuilder[] generic_params = stub.DefineGenericParameters(generic_param_names); // determine generic parameter attributes and constraints for (int j = 0; j < generic_params.Length; j++) { Type template_type = genericParameters[j]; // attributes generic_params[j].SetGenericParameterAttributes(template_type.GenericParameterAttributes); // constraints Type[] template_constraints = template_type.GetGenericParameterConstraints(); List <Type> interface_constraints = new List <Type>(); for (int k = 0; k < template_constraints.Length; k++) { if (template_constraints[k].IsClass) { generic_params[j].SetBaseTypeConstraint(template_constraints[k]); } else { interface_constraints.Add(template_constraints[k]); } } generic_params[j].SetInterfaceConstraints(interface_constraints.ToArray()); } // re-map base method generic parameters to the newly defined generic parameters for (int j = 0; j < parameters.Length; j++) { if (parameters[j].IsGenericParameter && parameters[j].DeclaringMethod != null) { // method generic parameter parameters[j] = generic_params[parameters[j].GenericParameterPosition]; } } }
/// <summary> /// Add at runtime a method to a type /// </summary> /// <param name="typedesc">Type to modify</param> /// <param name="attributes">New method attributes</param> /// <param name="func_name">Method name</param> /// <param name="callback">Method body</param> /// <remarks>Used by PDO_SQLITE</remarks> public void AddMethodToType(DTypeDesc typedesc, PhpMemberAttributes attributes, string func_name, Func <object, PhpStack, object> callback) { Debug.Assert(typedesc != null); var name = new Name(func_name); var method_desc = new PhpRoutineDesc(typedesc, attributes); if (!typedesc.Methods.ContainsKey(name)) { typedesc.Methods.Add(name, method_desc); // assign member: if (method_desc.Member == null) { Func <ScriptContext, object> dummyArgFullCallback = DummyArgFull; PhpMethod method = new PhpMethod(name, (PhpRoutineDesc)method_desc, dummyArgFullCallback.Method, (callback != null) ? callback.Method : null); method.WriteUp(PhpRoutineSignature.FromArgfullInfo(method, dummyArgFullCallback.Method)); method_desc.Member = method; } } }
/// <summary> /// reflect global functions in <Script> class /// TODO: consider merging with PhpTypeDesc.FullReflectMethods /// </summary> /// <param name="functions">Dictionary for functions</param> /// <param name="scriptType">The type to reflect from.</param> private static void ReflectScriptTypeFunctions(Type scriptType, Dictionary <string, DRoutineDesc> functions) { MethodInfo[] real_methods = scriptType.GetMethods(DTypeDesc.MembersReflectionBindingFlags); Dictionary <string, MethodInfo> argless_stubs = new Dictionary <string, MethodInfo>(real_methods.Length / 3); // first pass - fill argless_stubs for (int i = 0; i < real_methods.Length; i++) { MethodInfo info = real_methods[i]; if ((info.Attributes & MethodAttributes.MemberAccessMask) != MethodAttributes.PrivateScope) { if (PhpFunctionUtils.IsArglessStub(info, null)) { argless_stubs.Add(info.Name, info); real_methods[i] = null; } } else { real_methods[i] = null; // expunge private scope methods } } // second pass - match argfulls foreach (MethodInfo info in real_methods) { // argfull detection: if (info == null || !PhpFunctionUtils.IsArgfullOverload(info, null)) { continue; } // TODO: namespaces!! if (functions.ContainsKey(info.Name)) { throw new InvalidOperationException("Function '" + info.Name + "' redeclaration."); // compilation unit contains more functions with the same name } // find the argless: MethodInfo argless_info = null; if (!argless_stubs.TryGetValue(info.Name, out argless_info)) { // argless has to be generated on-the-fly throw new NotImplementedException("Generating argless stubs for imported PHP types is not yet implemented"); } if (!PhpFunctionUtils.IsRealConditionalDefinition(info.Name)) { Name name = new Name(info.Name); DRoutineDesc func_desc; PhpMemberAttributes attrs = Enums.GetMemberAttributes(info); // this method has not been populated -> create a new PhpRoutineDesc func_desc = new PhpRoutineDesc(attrs, (RoutineDelegate)Delegate.CreateDelegate(Types.RoutineDelegate, argless_info), true); functions.Add(info.Name, func_desc); // if (func_desc.Member == null) { PhpFunction func = new PhpFunction(new QualifiedName(name), (PhpRoutineDesc)func_desc, info, argless_info); func.WriteUp(PhpRoutineSignature.FromArgfullInfo(func, info)); func_desc.Member = func; } } } }
/// <summary> /// Enumerates all export overloads for the given target PHP method. /// </summary> public static IEnumerable <StubInfo> DefineMethodExportStubs( PhpRoutine /*!*/ target, MethodAttributes attributes, bool defineConstructors, StubSignatureFilter /*!*/ signatureFilter) { Debug.Assert(target.Builder != null); Type return_type = Types.Object[0]; PhpRoutineSignature signature = target.Signature; List <AST.FormalParam> formal_params = target.Builder.Signature.FormalParams; List <AST.FormalTypeParam> formal_type_params = target.Builder.TypeSignature.TypeParams; int gen_sig_count = signature.GenericParamCount - signature.MandatoryGenericParamCount + 1; int arg_sig_count = signature.ParamCount - signature.MandatoryParamCount + 1; // TODO: return type hints // HACK: change return type to void for methods that are apparently event handlers if (signature.GenericParamCount == 0 && arg_sig_count == 1 && signature.ParamCount == 2 && (signature.TypeHints[0] == null || signature.TypeHints[0].RealType == Types.Object[0]) && (signature.TypeHints[1] != null && typeof(EventArgs).IsAssignableFrom(signature.TypeHints[1].RealType))) { return_type = Types.Void; } for (int gen_sig = 0; gen_sig < gen_sig_count; gen_sig++) { for (int arg_sig = 0; arg_sig < arg_sig_count; arg_sig++) { // determine parameter types (except for method mandatory generic parameters) object[] parameter_types = GetStubParameterTypes( arg_sig + signature.MandatoryParamCount, gen_sig + signature.MandatoryGenericParamCount, signature, formal_type_params); // determine generic parameter names string[] generic_param_names = new string[target.Signature.MandatoryGenericParamCount + gen_sig]; for (int i = 0; i < generic_param_names.Length; i++) { generic_param_names[i] = formal_type_params[i].Name.ToString(); } // are we allowed to generate this signature? if (!signatureFilter(generic_param_names, parameter_types, return_type)) { continue; } GenericTypeParameterBuilder[] generic_params = StubInfo.EmptyGenericParameters; MethodBase method_base = null; MethodBuilder method = null; if (!defineConstructors) { method = target.DeclaringType.RealTypeBuilder.DefineMethod(target.FullName, attributes); // determine generic parameters if (generic_param_names.Length > 0) { generic_params = method.DefineGenericParameters(generic_param_names); } method_base = method; } ParameterInfo[] parameters = new ParameterInfo[parameter_types.Length]; // fill in parameter infos Type[] real_parameter_types = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { Type type = parameter_types[i] as Type; // generic method parameter fixup if (type == null) { int index = (int)parameter_types[i]; if (index < 0) { type = generic_params[-(index + 1)].MakeByRefType(); } else { type = generic_params[index]; } } string param_name; ParameterAttributes param_attrs; if (i < formal_params.Count) { param_name = formal_params[i].Name.ToString(); param_attrs = (formal_params[i].IsOut ? ParameterAttributes.Out : ParameterAttributes.None); } else { param_name = "args" + (i + 1); param_attrs = ParameterAttributes.None; } parameters[i] = new StubParameterInfo(i, type, param_attrs, param_name); real_parameter_types[i] = type; } if (method != null) { method.SetParameters(real_parameter_types); method.SetReturnType(return_type); method.SetCustomAttribute(AttributeBuilders.DebuggerHidden); } else { // constructor is never a generic method attributes |= MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; attributes &= ~MethodAttributes.Virtual; ConstructorBuilder constructor = target.DeclaringType.RealTypeBuilder.DefineConstructor( attributes, CallingConventions.Standard, real_parameter_types); constructor.SetCustomAttribute(AttributeBuilders.DebuggerHidden); method_base = constructor; } yield return(new StubInfo(method_base, parameters, generic_params, return_type)); } } }
private static object[] GetStubParameterTypes( int paramCount, int typeParamCount, PhpRoutineSignature /*!*/ signature, List <PHP.Core.AST.FormalTypeParam> /*!*/ formalTypeParams) { object[] parameter_types = new object[paramCount]; for (int i = 0; i < paramCount; i++) { DType type_hint = signature.TypeHints[i]; if (type_hint != null && !type_hint.IsUnknown) { GenericParameter gen_type_hint = type_hint as GenericParameter; if (gen_type_hint != null) { // this is a generic parameter - declared by either the method or type if (gen_type_hint.DeclaringMember is PhpRoutine) { if (gen_type_hint.Index < typeParamCount) { // unknown at this point - fixed-up later parameter_types[i] = gen_type_hint.Index; } else { // default generic parameter DType default_type = formalTypeParams[gen_type_hint.Index].DefaultType as DType; parameter_types[i] = (default_type == null ? Types.Object[0] : default_type.RealType); } } else { parameter_types[i] = gen_type_hint.RealGenericTypeParameterBuilder; } } else { parameter_types[i] = type_hint.RealType; } } else { parameter_types[i] = Types.Object[0]; } // make it byref if declared with & if (signature.AliasMask[i]) { Type type = parameter_types[i] as Type; if (type != null) { parameter_types[i] = type.MakeByRefType(); } else { parameter_types[i] = -((int)parameter_types[i] + 1); } } Debug.Assert(parameter_types[i] != null); } return(parameter_types); }