void EmitPhpCallable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { var __invoke = TryGetMagicInvoke(); if (__invoke == null || IsAlreadyImplemented(__invoke) || IsAlreadyImplemented(DeclaringCompilation.CoreTypes.IPhpCallable)) { // already implemented in a base class return; } // // IPhpCallable.Invoke(Context <ctx>, PhpVaue[] arguments) // var invoke = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(), ForwardedCall = __invoke, }; invoke.SetParameters( new SpecialParameterSymbol(invoke, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0), new SynthesizedParameterSymbol(invoke, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, name: "arguments", isParams: true)); module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il => { var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0)) { CallerType = this, }; cg.EmitRet(cg.EmitForwardCall(__invoke, invoke, callvirt: true)); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, invoke); // // IPhpCallable.ToPhpValue() // var tophpvalue = new SynthesizedMethodSymbol(this, "IPhpCallable.ToPhpValue", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("ToPhpValue").Single(), }; // module.SetMethodBody(tophpvalue, MethodGenerator.GenerateMethodBody(module, tophpvalue, 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); // return PhpValue.FromClass(this) cg.EmitThis(); cg.EmitRet(cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.FromClass_Object)); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, tophpvalue); }
internal override TypeSymbol GetSZArrayTypeSymbol(PEModuleSymbol moduleSymbol, TypeSymbol elementType, ImmutableArray <ModifierInfo <TypeSymbol> > customModifiers) { if (elementType is UnsupportedMetadataTypeSymbol) { return(elementType); } return(ArrayTypeSymbol.CreateSZArray(moduleSymbol.ContainingAssembly, elementType, CSharpCustomModifier.Convert(customModifiers))); }
TypeSymbol ResolveType() { if (IsThis) { // <this> parameter if (_routine is SourceGlobalMethodSymbol) { // "AnyType" in case of $this in global scope return(DeclaringCompilation.CoreTypes.PhpValue); } return(ContainingType); } //return DeclaringCompilation.GetTypeFromTypeRef(_routine, _routine.ControlFlowGraph.GetParamTypeMask(this)); // determine parameter type from the signature: // aliased parameter: if (_syntax.IsOut || _syntax.PassedByRef) { return(DeclaringCompilation.CoreTypes.PhpAlias); } // 1. specified type hint var result = DeclaringCompilation.GetTypeFromTypeRef(_syntax.TypeHint); // 2. optionally type specified in PHPDoc if (result == null && _ptagOpt != null && _ptagOpt.TypeNamesArray.Length != 0 && (DeclaringCompilation.Options.PhpDocTypes & PhpDocTypes.ParameterTypes) != 0) { var typectx = _routine.TypeRefContext; var tmask = FlowAnalysis.PHPDoc.GetTypeMask(typectx, _ptagOpt.TypeNamesArray, _routine.GetNamingContext()); if (!tmask.IsVoid && !tmask.IsAnyType) { result = DeclaringCompilation.GetTypeFromTypeRef(typectx, tmask); } } // 3 default: if (result == null) { // TODO: use type from overriden method result = DeclaringCompilation.CoreTypes.PhpValue; } // variadic (result[]) if (_syntax.IsVariadic) { result = ArrayTypeSymbol.CreateSZArray(this.ContainingAssembly, result); } // return(result); }
private ArrayTypeSymbol SubstituteArrayType(ArrayTypeSymbol t) { var oldElement = new TypeWithModifiers(t.ElementType, t.CustomModifiers); TypeWithModifiers element = oldElement.SubstituteType(this); if (element == oldElement) { return(t); } if (t.IsSZArray) { ImmutableArray <NamedTypeSymbol> interfaces = t.Interfaces; //.InterfacesNoUseSiteDiagnostics(); Debug.Assert(0 <= interfaces.Length && interfaces.Length <= 2); if (interfaces.Length == 1) { Debug.Assert(interfaces[0] is NamedTypeSymbol); // IList<T> interfaces = ImmutableArray.Create <NamedTypeSymbol>((NamedTypeSymbol)SubstituteType(interfaces[0]).AsTypeSymbolOnly()); } else if (interfaces.Length == 2) { Debug.Assert(interfaces[0] is NamedTypeSymbol); // IList<T> interfaces = ImmutableArray.Create <NamedTypeSymbol>((NamedTypeSymbol)SubstituteType(interfaces[0]).AsTypeSymbolOnly(), (NamedTypeSymbol)SubstituteType(interfaces[1]).AsTypeSymbolOnly()); } else if (interfaces.Length != 0) { throw ExceptionUtilities.Unreachable; } return(ArrayTypeSymbol.CreateSZArray( element.Type, t.BaseType, //.BaseTypeNoUseSiteDiagnostics, interfaces, element.CustomModifiers)); } return(ArrayTypeSymbol.CreateMDArray( element.Type, t.Rank, t.Sizes, t.LowerBounds, t.BaseType, //.BaseTypeNoUseSiteDiagnostics, element.CustomModifiers)); }
/// <summary> /// In case the class implements <c>__invoke</c> method, we create special Invoke() method that is compatible with IPhpCallable interface. /// </summary> internal SynthesizedMethodSymbol EnsureInvokeMethod() { if (_lazyInvokeSymbol == null) { if (GetMembers(Pchp.Syntax.Name.SpecialMethodNames.Invoke.Value).Any(s => s is MethodSymbol)) { _lazyInvokeSymbol = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(), }; _lazyInvokeSymbol.SetParameters( new SpecialParameterSymbol(_lazyInvokeSymbol, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0), new SpecialParameterSymbol(_lazyInvokeSymbol, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), "arguments", 1)); _lazyMembers = _lazyMembers.Add(_lazyInvokeSymbol); } } return(_lazyInvokeSymbol); }
/// <summary> /// In case the class implements <c>__invoke</c> method, we create special Invoke() method that is compatible with IPhpCallable interface. /// </summary> internal SynthesizedMethodSymbol EnsureInvokeMethod(Emit.PEModuleBuilder module) { if (_lazyInvokeSymbol == null) { if (IsInvokable) { _lazyInvokeSymbol = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(), }; _lazyInvokeSymbol.SetParameters( new SpecialParameterSymbol(_lazyInvokeSymbol, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0), new SynthesizedParameterSymbol(_lazyInvokeSymbol, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, "arguments")); // module.SynthesizedManager.AddMethod(this, _lazyInvokeSymbol); } } return(_lazyInvokeSymbol); }
/// <summary> /// Gets array of parameter symbols. /// Lazily ensures there is the variadic parameter at the end if needed. /// </summary> ImmutableArray <ParameterSymbol> GetParameters() { if ((Flags & RoutineFlags.RequiresParams) != 0 && (this is SourceFunctionSymbol || this is SourceMethodSymbol)) { if (_params.Length == 0 || !_params.Last().IsParams) { // lazily add [params] PhpValue[] <params> var p = new SynthesizedParameterSymbol( // IsImplicitlyDeclared, IsParams this, ArrayTypeSymbol.CreateSZArray(this.ContainingAssembly, this.DeclaringCompilation.CoreTypes.PhpValue), _params.Length, RefKind.None, SpecialParameterSymbol.ParamsName, true); // _params = _params.Add(p); } } // return(_params); }
void EmitPhpCallable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { var iphpcallable = DeclaringCompilation.CoreTypes.IPhpCallable; var __invoke = TryGetMagicInvoke(); if (__invoke == null || IsAlreadyImplemented(__invoke) || IsAlreadyImplemented(iphpcallable)) { // already implemented in a base class return; } // // IPhpCallable.Invoke(Context <ctx>, PhpVaue[] arguments) // var invoke = new SynthesizedMethodSymbol(this, iphpcallable.FullName + ".Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: true) { ExplicitOverride = (MethodSymbol)iphpcallable.Symbol.GetMembers("Invoke").Single(), ForwardedCall = __invoke, }; invoke.SetParameters( new SpecialParameterSymbol(invoke, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0), new SynthesizedParameterSymbol(invoke, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, name: "arguments", isParams: true)); module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il => { var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0)) { CallerType = this, }; var rtype = invoke.ReturnType; // Template: return (T)__invoke() cg.EmitConvert(cg.EmitForwardCall(__invoke, invoke, callvirt: true), default, rtype);
void EmitPhpCallable(Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { var __invoke = TryGetMagicInvoke(); if (__invoke == null || __invoke.OverriddenMethod != null) { return; } // // IPhpCallable.Invoke(Context, PhpVaue[]) // var invoke = new SynthesizedMethodSymbol(this, "IPhpCallable.Invoke", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("Invoke").Single(), }; invoke.SetParameters( new SpecialParameterSymbol(invoke, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0), new SynthesizedParameterSymbol(invoke, ArrayTypeSymbol.CreateSZArray(ContainingAssembly, DeclaringCompilation.CoreTypes.PhpValue.Symbol), 1, RefKind.None, "arguments")); module.SetMethodBody(invoke, MethodGenerator.GenerateMethodBody(module, invoke, il => { var cg = new CodeGenerator(il, module, diagnostics, OptimizationLevel.Release, false, this, new ParamPlace(invoke.Parameters[0]), new ArgPlace(this, 0)); var argsplace = new ParamPlace(invoke.Parameters[1]); var args_element = ((ArrayTypeSymbol)argsplace.TypeOpt).ElementType; var ps = __invoke.Parameters; // Template: this.__invoke(args[0], args[1], ...) cg.EmitThis(); for (int i = 0; i < ps.Length; i++) { var p = ps[i]; // LOAD args[i] // Template: (i < args.Length) ? (T)args[i] : default(T) var lbldefault = new NamedLabel("args_default"); var lblend = new NamedLabel("args_end"); cg.Builder.EmitIntConstant(i); // <i> argsplace.EmitLoad(cg.Builder); // <args> cg.EmitArrayLength(); // .Length cg.Builder.EmitBranch(ILOpCode.Bge, lbldefault); // (T)args[i] if (p.IsImplicitlyDeclared) { throw new NotImplementedException(); } else if (p.Type == cg.CoreTypes.PhpAlias) { // args[i].EnsureAlias() argsplace.EmitLoad(cg.Builder); // <args> cg.Builder.EmitIntConstant(i); // <i> cg.Builder.EmitOpCode(ILOpCode.Ldelema); // ref args[i] cg.EmitSymbolToken(args_element, null); cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.EnsureAlias); } else { // (T)args[i] argsplace.EmitLoad(cg.Builder); // <args> cg.Builder.EmitIntConstant(i); // <i> cg.Builder.EmitOpCode(ILOpCode.Ldelem); // args[i] cg.EmitSymbolToken(args_element, null); cg.EmitConvert(args_element, 0, p.Type); } cg.Builder.EmitBranch(ILOpCode.Br, lblend); // default(T) cg.Builder.MarkLabel(lbldefault); cg.EmitParameterDefaultValue(p); // cg.Builder.MarkLabel(lblend); } cg.EmitCall(ILOpCode.Callvirt, __invoke); cg.EmitRet(invoke.ReturnType); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, invoke); // // IPhpCallable.ToPhpValue() // var tophpvalue = new SynthesizedMethodSymbol(this, "IPhpCallable.ToPhpValue", false, true, DeclaringCompilation.CoreTypes.PhpValue, isfinal: false) { ExplicitOverride = (MethodSymbol)DeclaringCompilation.CoreTypes.IPhpCallable.Symbol.GetMembers("ToPhpValue").Single(), }; // module.SetMethodBody(tophpvalue, MethodGenerator.GenerateMethodBody(module, tophpvalue, il => { var thisPlace = new ArgPlace(this, 0); var cg = new CodeGenerator(il, module, diagnostics, OptimizationLevel.Release, false, this, new FieldPlace(thisPlace, this.ContextStore), thisPlace); // return PhpValue.FromClass(this) cg.EmitThis(); cg.EmitRet(cg.EmitCall(ILOpCode.Call, cg.CoreMethods.PhpValue.FromClass_Object)); }, null, diagnostics, false)); module.SynthesizedManager.AddMethod(this, tophpvalue); }
TypeSymbol ResolveType() { if (IsThis) { // <this> parameter if (_routine is SourceGlobalMethodSymbol) { // "AnyType" in case of $this in global scope return(DeclaringCompilation.CoreTypes.PhpValue); } return(ContainingType); } //return DeclaringCompilation.GetTypeFromTypeRef(_routine, _routine.ControlFlowGraph.GetParamTypeMask(this)); // determine parameter type from the signature: // aliased parameter: if (_syntax.IsOut || _syntax.PassedByRef) { if (_syntax.IsVariadic) { // PhpAlias[] return(ArrayTypeSymbol.CreateSZArray(this.ContainingAssembly, DeclaringCompilation.CoreTypes.PhpAlias)); } else { // PhpAlias return(DeclaringCompilation.CoreTypes.PhpAlias); } } // 1. specified type hint var typeHint = _syntax.TypeHint; if (typeHint is ReservedTypeRef rtref) { // workaround for https://github.com/peachpiecompiler/peachpie/issues/281 // remove once it gets updated in parser if (rtref.Type == ReservedTypeRef.ReservedType.self) { return(_routine.ContainingType); // self } } var result = DeclaringCompilation.GetTypeFromTypeRef(typeHint, _routine.ContainingType as SourceTypeSymbol, nullable: DefaultsToNull); // 2. optionally type specified in PHPDoc if (result == null && _ptagOpt != null && _ptagOpt.TypeNamesArray.Length != 0 && (DeclaringCompilation.Options.PhpDocTypes & PhpDocTypes.ParameterTypes) != 0) { var typectx = _routine.TypeRefContext; var tmask = FlowAnalysis.PHPDoc.GetTypeMask(typectx, _ptagOpt.TypeNamesArray, _routine.GetNamingContext()); if (!tmask.IsVoid && !tmask.IsAnyType) { result = DeclaringCompilation.GetTypeFromTypeRef(typectx, tmask); } } // 3 default: if (result == null) { // TODO: use type from overriden method result = DeclaringCompilation.CoreTypes.PhpValue; } // variadic (result[]) if (_syntax.IsVariadic) { result = ArrayTypeSymbol.CreateSZArray(this.ContainingAssembly, result); } // return(result); }