/// <summary> /// Emit publically accessible stub that just calls argfull of <paramref name="function"/>. /// </summary> /// <returns><see cref="MethodInfo"/> of newly created function stub.</returns> private MethodInfo/*!*/EmitPhpFunctionPublicStub(ref TypeBuilder publicsContainer, PhpFunction/*!*/function) { Debug.Assert(function != null); Debug.Assert(function.ArgFullInfo != null, "!function.ArgFullInfo"); if (publicsContainer == null) { publicsContainer = PureAssemblyBuilder.RealModuleBuilder.DefineType( string.Format("{1}<{0}>", StringUtils.ToClsCompliantIdentifier(Path.ChangeExtension(PureAssemblyBuilder.FileName, "")), QualifiedName.Global.ToString()), TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.SpecialName); } Type returnType; var parameterTypes = function.Signature.ToArgfullSignature(1, out returnType); parameterTypes[0] = Types.ScriptContext[0]; var mi = publicsContainer.DefineMethod(function.GetFullName(), MethodAttributes.Public | MethodAttributes.Static, returnType, parameterTypes); var il = new ILEmitter(mi); // load arguments for (int i = 0; i < parameterTypes.Length; i++) { if (function.Builder != null) mi.DefineParameter(i + 1, ParameterAttributes.None, function.Builder.ParameterBuilders[i].Name); il.Ldarg(i); } // call function.ArgFullInfo il.Emit(OpCodes.Call, function.ArgFullInfo); // .ret il.Emit(OpCodes.Ret); // return mi; }
/// <summary> /// Called when a <see cref="PHP.Core.AST.FunctionDecl"/> AST node is entered during the emit phase. /// </summary> /// <param name="function">The function to enter.</param> /// <returns><B>true</B> if the function should be emitted, <B>false</B> if it should not be emitted /// (an error was emitted instead due to the incorrect declaration).</returns> public bool EnterFunctionDeclaration(PhpFunction/*!*/ function) { return EnterFunctionDeclarationInternal(function, function.QualifiedName); }
/// <summary> /// Emits call to <see cref="ScriptContext.DeclareFunction"/>. /// </summary> internal static void EmitDeclareFunction(ILEmitter/*!*/il, IPlace/*!*/scriptContextPlace, PhpFunction/*!*/ function) { Label lbl_fieldinitialized = il.DefineLabel(); // private static PhpRoutine <routine>'function = null; var attrs = FieldAttributes.Static | FieldAttributes.Private; var field = il.TypeBuilder.DefineField(string.Format("<routine>'{0}", function.FullName), typeof(PhpRoutineDesc), attrs); // if (<field> == null) il.Emit(OpCodes.Ldsfld, field); il.Emit(OpCodes.Brtrue, lbl_fieldinitialized); { // <field> = new PhpRoutineDesc(<attributes>, new RoutineDelegate(null, <delegate>)) // LOAD <attributes>; il.LdcI4((int)function.MemberDesc.MemberAttributes); // new RoutineDelegate(null, <delegate>, true) il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldftn, function.ArgLessInfo); il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate); il.LoadBool(true); // new PhpRoutineDesc: il.Emit(OpCodes.Newobj, Constructors.PhpRoutineDesc_Attr_Delegate_Bool); // <field> = <STACK> il.Emit(OpCodes.Stsfld, field); // new PurePhpFunction(<field>, fullName, argfull); // writes desc.Member il.Emit(OpCodes.Ldsfld, field); il.Emit(OpCodes.Ldstr, function.FullName); CodeGenerator.EmitLoadMethodInfo(il, function.ArgFullInfo/*, AssemblyBuilder.DelegateBuilder*/); il.Emit(OpCodes.Newobj, Constructors.PurePhpFunction); il.Emit(OpCodes.Pop); } il.MarkLabel(lbl_fieldinitialized); // CALL ScriptContent.DeclareFunction(<field>, <name>); scriptContextPlace.EmitLoad(il); // LOAD <field> il.Emit(OpCodes.Ldsfld, field); // LOAD <fullName> il.Emit(OpCodes.Ldstr, function.FullName); // il.Emit(OpCodes.Call, Methods.ScriptContext.DeclareFunction); }
/// <summary> /// Emits call to <see cref="ScriptContext.DeclareFunction"/>. /// </summary> internal void EmitDeclareFunction(PhpFunction/*!*/ function) { EmitDeclareFunction(il, ScriptContextPlace, function); }
public FunctionDecl(SourceUnit/*!*/ sourceUnit, Position position, Position entireDeclarationPosition, ShortPosition headingEndPosition, ShortPosition declarationBodyPosition, bool isConditional, Scope scope, PhpMemberAttributes memberAttributes, string/*!*/ name, NamespaceDecl ns, bool aliasReturn, List<FormalParam>/*!*/ formalParams, List<FormalTypeParam>/*!*/ genericParams, List<Statement>/*!*/ body, List<CustomAttribute> attributes) : base(position) { Debug.Assert(genericParams != null && name != null && formalParams != null && body != null); this.name = new Name(name); this.ns = ns; this.signature = new Signature(aliasReturn, formalParams); this.typeSignature = new TypeSignature(genericParams); this.attributes = new CustomAttributes(attributes); this.body = body; this.entireDeclarationPosition = entireDeclarationPosition; this.headingEndPosition = headingEndPosition; this.declarationBodyPosition = declarationBodyPosition; QualifiedName qn = (ns != null) ? new QualifiedName(this.name, ns.QualifiedName) : new QualifiedName(this.name); function = new PhpFunction(qn, memberAttributes, signature, typeSignature, isConditional, scope, sourceUnit, position); function.WriteUp(typeSignature.ToPhpRoutineSignature(function)); function.Declaration.Node = this; }
/// <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; } } } }