private void Bake() { if (types != null) { bakedTypes = new KeyValuePair <string, PhpTypeDesc> [types.Count]; int i = 0; foreach (Declaration declaration in types.Values) { PhpType type = (PhpType)declaration.Declaree; // store full name before calling Bake() as it nulls the PhpType: string full_name = type.FullName; PhpTypeDesc baked = type.Bake(); // baked is null if the type is indefinite // (its base class may be evaluated when the module's main method is executed): if (baked != null && !declaration.IsConditional) { bakedTypes[i++] = new KeyValuePair <string, PhpTypeDesc>(full_name, baked); } } // trim: Array.Resize(ref bakedTypes, i); types = null; } if (functions != null) { bakedFunctions = new KeyValuePair <string, PhpRoutineDesc> [functions.Count]; int i = 0; foreach (Declaration declaration in functions.Values) { PhpFunction function = (PhpFunction)declaration.Declaree; string full_name = function.FullName; PhpRoutineDesc baked = function.Bake(); if (!declaration.IsConditional) { bakedFunctions[i++] = new KeyValuePair <string, PhpRoutineDesc>(full_name, baked); } } // trim: Array.Resize(ref bakedFunctions, i); functions = null; } if (constants != null) { bakedConstants = new KeyValuePair <string, DConstantDesc> [constants.Count]; int i = 0; foreach (Declaration declaration in constants.Values) { GlobalConstant constant = (GlobalConstant)declaration.Declaree; string full_name = constant.FullName; DConstantDesc baked = constant.Bake(); if (!declaration.IsConditional) { bakedConstants[i++] = new KeyValuePair <string, DConstantDesc>(full_name, baked); } } // trim: Array.Resize(ref bakedConstants, i); constants = null; } }
/// <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> /// Used by full-reflect. /// </summary> public PurePhpFunction(PhpRoutineDesc/*!*/routine, string name, MethodInfo/*!*/argfull) : base(routine) { Debug.Assert(routine != null); Debug.Assert(argfull != null); this.name = new Name(name); this.argfull = argfull; this.signature = PhpRoutineSignature.FromArgfullInfo(this, argfull); }
/// <summary> /// Used by full-reflect. /// </summary> internal PhpMethod(Name name, PhpRoutineDesc/*!*/ routineDesc, MethodInfo/*!*/ argfull, MethodInfo argless) : base(routineDesc) { Debug.Assert(argless != null ^ IsAbstract); this.name = name; this.argfull = argfull; this.argless = argless; // if the function needs to be called via argless stub, update the properties if (NeedsArglessAttribute.IsSet(argfull)) this.Properties |= RoutineProperties.UseVarArgs; // the function calls some arg-aware class-library function so it has to be called with PhpStack if (UsesLateStaticBindingAttribute.IsSet(argfull)) this.Properties |= RoutineProperties.LateStaticBinding; // this method uses late static binding }
/// <summary> /// Used by full-reflect. /// </summary> internal PhpFunction(QualifiedName name, PhpRoutineDesc/*!*/ routineDesc, MethodInfo/*!*/ argfull, MethodInfo argless) : base(routineDesc) { Debug.Assert(argless != null); this.qualifiedName = name; this.argfull = argfull; this.argless = argless; // if the function needs to be called via argless stub, update the property if (NeedsArglessAttribute.IsSet(argfull)) this.Properties |= RoutineProperties.UseVarArgs; // the function calls some arg-aware class-library function so it has to be called with PhpStack Debug.Assert(!UsesLateStaticBindingAttribute.IsSet(argfull), "Function cannot use late static binding! Only methods can."); }
/// <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; } } } }