Exemplo n.º 1
0
        void EmitToString(Emit.PEModuleBuilder module)
        {
            if (this.IsInterface || this.IsTrait)
            {
                return;
            }

            var __tostring = this.GetMembersByPhpName(SpecialMethodNames.Tostring.Value).OfType <MethodSymbol>().FirstOrDefault();

            if (__tostring != null)    // implement ToString if: there is __toString() function
            {
                // lookup base string ToString()
                var overriden = this.LookupMember <MethodSymbol>(
                    WellKnownMemberNames.ObjectToString,
                    m => OverrideHelper.SignaturesMatch(m, (MethodSymbol)DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_Object__ToString)));

                Debug.Assert(overriden != null);

                if (overriden == null || overriden.IsSealed || overriden.ContainingType == this)
                {
                    // cannot be overriden
                    return;
                }

                // public sealed override string ToString()
                var tostring = new SynthesizedMethodSymbol(this, WellKnownMemberNames.ObjectToString, false, true, DeclaringCompilation.CoreTypes.String, Accessibility.Public, isfinal: false, phphidden: true)
                {
                    ExplicitOverride = overriden,
                    ForwardedCall    = __tostring,
                };

                module.SetMethodBody(tostring, MethodGenerator.GenerateMethodBody(module, tostring, il =>
                {
                    var thisPlace = new ArgPlace(this, 0);
                    var cg        = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, new FieldPlace(thisPlace, this.ContextStore, module), thisPlace);

                    if (__tostring != null)
                    {
                        // __tostring().ToString()
                        cg.EmitConvert(cg.EmitForwardCall(__tostring, tostring, callvirt: true), 0, tostring.ReturnType);
                    }
                    else
                    {
                        // PhpException.ObjectToStringNotSupported(this)
                        cg.EmitThis();
                        cg.EmitPop(cg.EmitCall(ILOpCode.Call, cg.CoreTypes.PhpException.Method("ObjectToStringNotSupported", cg.CoreTypes.Object)));

                        // return ""
                        cg.Builder.EmitStringConstant(string.Empty);
                    }
                    cg.EmitRet(tostring.ReturnType);
                }, null, DiagnosticBag.GetInstance(), false));
                module.SynthesizedManager.AddMethod(this, tostring);
            }
        }
Exemplo n.º 2
0
        void EmitToString(Emit.PEModuleBuilder module)
        {
            if (this.IsInterface || this.IsTrait)
            {
                return;
            }

            var __tostring = this.GetMembers(SpecialMethodNames.Tostring.Value, true).OfType <MethodSymbol>().FirstOrDefault();

            if (__tostring != null || this.Syntax.BaseClass == null)    // implement ToString if: there is __tostring() function or ToString is not overriden yet
            {
                // public override string ToString()
                // Note, there might be two ToString methods with same parameters only differing by their return type, CLR allows that
                var tostring = new SynthesizedMethodSymbol(this, "ToString", false, true, DeclaringCompilation.CoreTypes.String, Accessibility.Public, isfinal: false)
                {
                    ExplicitOverride = (MethodSymbol)DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_Object__ToString),
                    ForwardedCall    = __tostring,
                };

                module.SetMethodBody(tostring, MethodGenerator.GenerateMethodBody(module, tostring, il =>
                {
                    var thisPlace = new ArgPlace(this, 0);
                    var cg        = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, new FieldPlace(thisPlace, this.ContextStore, module), thisPlace);

                    if (__tostring != null)
                    {
                        // __tostring().ToString()
                        cg.EmitConvert(cg.EmitForwardCall(__tostring, tostring, callvirt: true), 0, tostring.ReturnType);
                    }
                    else
                    {
                        // PhpException.ObjectToStringNotSupported(this)
                        cg.EmitThis();
                        cg.EmitPop(cg.EmitCall(ILOpCode.Call, cg.CoreTypes.PhpException.Method("ObjectToStringNotSupported", cg.CoreTypes.Object)));

                        // return ""
                        cg.Builder.EmitStringConstant(string.Empty);
                    }
                    cg.EmitRet(tostring.ReturnType);
                }, null, DiagnosticBag.GetInstance(), false));
                module.SynthesizedManager.AddMethod(this, tostring);
            }
        }
        void EmitDisposable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics)
        {
            var __destruct = TryGetDestruct();

            if (__destruct == null ||
                IsAlreadyImplemented(__destruct) ||
                IsAlreadyImplemented(DeclaringCompilation.GetSpecialType(SpecialType.System_IDisposable)))
            {
                // already implemented in a base class
                return;
            }

            //
            // IDisposable.Dispose()
            //
            var dispose = new SynthesizedMethodSymbol(this, "IDisposable.Dispose", false, true, DeclaringCompilation.GetSpecialType(SpecialType.System_Void), isfinal: true)
            {
                ExplicitOverride = (MethodSymbol)DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose),
                ForwardedCall    = __destruct,
            };

            module.SetMethodBody(dispose, MethodGenerator.GenerateMethodBody(module, dispose, il =>
            {
                var thisPlace = new ArgPlace(this, 0);
                var ctxPlace  = new FieldPlace(thisPlace, this.ContextStore, module);
                var cg        = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace)
                {
                    CallerType = this,
                };

                // private bool <>b_disposed;
                var disposedField = cg.Module.SynthesizedManager.GetOrCreateSynthesizedField(this, DeclaringCompilation.CoreTypes.Boolean, WellKnownPchpNames.SynthesizedDisposedFieldName, Accessibility.Private, false, false, false);
                var disposedPlace = new FieldPlace(thisPlace, disposedField, cg.Module);

                // if (<>b_disposed) return;
                var lblContinue = new object();
                disposedPlace.EmitLoad(cg.Builder);
                cg.Builder.EmitBranch(ILOpCode.Brfalse, lblContinue);
                cg.EmitRet(DeclaringCompilation.CoreTypes.Void);
                cg.Builder.MarkLabel(lblContinue);

                // <>b_disposed = true;
                disposedPlace.EmitStorePrepare(cg.Builder);
                cg.Builder.EmitBoolConstant(true);
                disposedPlace.EmitStore(cg.Builder);

                // __destruct()
                cg.EmitPop(cg.EmitForwardCall(__destruct, dispose, callvirt: true));

                // .ret
                cg.EmitRet(DeclaringCompilation.GetSpecialType(SpecialType.System_Void));
            }, null, diagnostics, false));

            module.SynthesizedManager.AddMethod(this, dispose);

            ////
            //// Finalize()
            ////
            //var finalize = new SynthesizedFinalizeSymbol(this)
            //{
            //    ForwardedCall = dispose,
            //};

            //Debug.Assert(finalize.OverriddenMethod != null);

            //module.SetMethodBody(finalize, MethodGenerator.GenerateMethodBody(module, finalize, il =>
            //{
            //    var thisPlace = new ArgPlace(this, 0);
            //    var ctxPlace = new FieldPlace(thisPlace, this.ContextStore, module);
            //    var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace)
            //    {
            //        CallerType = this,
            //    };

            //    //
            //    cg.Builder.OpenLocalScope(ScopeType.TryCatchFinally);
            //    // try {
            //    cg.Builder.OpenLocalScope(ScopeType.Try);

            //    // Dispose()
            //    cg.EmitPop(cg.EmitForwardCall(dispose, finalize, callvirt: false));
            //    //if (cg.EmitPdbSequencePoints) cg.Builder.EmitOpCode(ILOpCode.Nop);

            //    // }
            //    cg.Builder.CloseLocalScope();
            //    // finally {
            //    cg.Builder.OpenLocalScope(ScopeType.Finally);

            //    // base.Finalize()
            //    thisPlace.EmitLoad(cg.Builder);
            //    cg.EmitCall(ILOpCode.Call, finalize.ExplicitOverride);
            //    //if (cg.EmitPdbSequencePoints) cg.Builder.EmitOpCode(ILOpCode.Nop);

            //    // }
            //    cg.Builder.CloseLocalScope();
            //    cg.Builder.CloseLocalScope();

            //    // .ret
            //    cg.EmitRet(DeclaringCompilation.GetSpecialType(SpecialType.System_Void));

            //}, null, diagnostics, false));

            //module.SynthesizedManager.AddMethod(this, finalize);
        }