コード例 #1
0
            bool TryConstructRuntimeChainElement(BoundExpression expr, out RuntimeChainElement runtimeChainElement)
            {
                Debug.Assert(expr != null);

                runtimeChainElement = null;

                if (expr.IsConstant())
                {
                    return(false);
                }

                // 1/ $$->{field}
                // should be a not resolved field reference (dynamic), otherwise it's unnecessary
                if (expr is BoundFieldRef fieldref &&
                    fieldref.IsInstanceField &&
                    ((Microsoft.CodeAnalysis.Operations.IFieldReferenceOperation)fieldref).Field == null)
                {
                    runtimeChainElement = new RuntimeChainElement(_cg.CoreTypes.RuntimeChain_Property_T, fieldref.Instance)
                    {
                        Fields = new List <KeyValuePair <string, BoundOperation> >(1)
                        {
                            new KeyValuePair <string, BoundOperation>("Name", fieldref.FieldName),
                        }
                    };
                }

                // 2/ $$[Key], $$[]
                if (expr is BoundArrayItemEx arritem)
                {
                    if (arritem.Index != null)
                    {
                        runtimeChainElement = new RuntimeChainElement(_cg.CoreTypes.RuntimeChain_ArrayItem_T, arritem.Array)
                        {
                            Fields = new List <KeyValuePair <string, BoundOperation> >(1)
                            {
                                new KeyValuePair <string, BoundOperation>("Key", arritem.Index),
                            }
                        };
                    }
                    else
                    {
                        runtimeChainElement = new RuntimeChainElement(_cg.CoreTypes.RuntimeChain_ArrayNewItem_T, arritem.Array)
                        {
                        };
                    }
                }

                // TODO: 3/ StaticProperty, ClassConstant

                //
                return(runtimeChainElement != null);
            }
コード例 #2
0
            /// <summary>Emits argument to be passed to callsite.</summary>
            void EmitArg(BoundArgument a)
            {
                var expr = a.Value;

                if (a.IsUnpacking)
                {
                    EmitUnpackingParam(_cg.Emit(expr));
                }
                else
                {
                    RuntimeChainElement runtimeChain = null;

                    // construct the runtime chain if possible:
                    while (TryConstructRuntimeChainElement(expr, out var element))
                    {
                        element.Next = runtimeChain ?? new RuntimeChainElement(_cg.CoreTypes.RuntimeChain_ChainEnd);
                        if (element.Type.Arity == 1)
                        {
                            // construct Element<TNext> // TNext:typeof(element.Next)
                            element.Type = element.Type.Construct(element.Next.Type);
                        }
                        runtimeChain = element;

                        //
                        if (element.Parent == null)
                        {
                            break;
                        }

                        expr = element.Parent;
                    }

                    // emit the root of the chain:
                    TypeSymbol t     = null;
                    bool       byref = false;

                    if (!expr.IsConstant() && expr is BoundReferenceExpression varref)
                    {
                        // try to read the value by ref so it can be changed if necessary
                        var place = varref.Place();
                        if (place != null)
                        {
                            if (place.HasAddress && place.Type == _cg.CoreTypes.PhpValue)
                            {
                                place.EmitLoadAddress(_cg.Builder);
                                t     = place.Type;
                                byref = true;
                            }
                        }
                        else if (varref.BindPlace(_cg) is LocalVariableReference loc && !loc.IsOptimized)
                        {
                            t = loc.LoadIndirectLocal(_cg); // IndirectLocal wrapper
                        }
                    }

                    if (t == null)
                    {
                        // load by value
                        t = _cg.Emit(expr);
                    }

                    if (t.SpecialType == SpecialType.System_Void)
                    {
                        Debug.WriteLine("Unexpected: argument evaluates to 'void'.");
                        // NOTE: this should be handled in diagnostics
                        t = _cg.Emit_PhpValue_Null();
                    }

                    //
                    AddArg(t, byref: byref);

                    // emit the chain eventually:
                    // after the root of the chain, order matters!
                    if (runtimeChain != null)
                    {
                        AddArg(runtimeChain.EmitRuntimeChain(_cg), byref: false);
                    }
                }
            }