internal static object GetUserArrayItem(DObject /*!*/ arrayAccess, object index, Operators.GetItemKinds kind) { PhpStack stack = ScriptContext.CurrentContext.Stack; switch (kind) { case Operators.GetItemKinds.Isset: // pass isset() ""/null to say true/false depending on the value returned from "offsetExists": stack.AddFrame(index); return(Core.Convert.ObjectToBoolean(arrayAccess.InvokeMethod(offsetExists, null, stack.Context)) ? "" : null); case Operators.GetItemKinds.Empty: // if "offsetExists" returns false, the empty()/isset() returns false (pass null to say true/false): // otherwise, "offsetGet" is called to retrieve the value, which is passed to isset(): stack.AddFrame(index); if (!Core.Convert.ObjectToBoolean(arrayAccess.InvokeMethod(offsetExists, null, stack.Context))) { return(null); } else { goto default; } default: // regular getter: stack.AddFrame(index); return(PhpVariable.Dereference(arrayAccess.InvokeMethod(offsetGet, null, stack.Context))); } }
/// <summary> /// Emits code to load variable onto the evaluation stack. Supports operators chaining. /// </summary> /// <param name="codeGenerator">A geenrator.</param> /// <param name="itemGetterKind">Whether to load for "get", "isset", or "empty".</param> private PhpTypeCode EmitNodeRead(CodeGenerator /*!*/ codeGenerator, Operators.GetItemKinds itemGetterKind) { ChainBuilder chain = codeGenerator.ChainBuilder; PhpTypeCode result; if (chain.IsArrayItem) { // we are in the array subchain // // 3: a_[x]_[x] chain.Lengthen(); // for [] result = chain.EmitGetItem(array, index, itemGetterKind); return(result); } // 1,2,4,5,6,7 if (chain.IsMember) { // we are in the field chain // // 4, 5 if (this.isMemberOf != null) { // we are in the middle of the field chain // // 5: ...->a[]->... // Lengthen chain for isMemberOf chain.Lengthen(); // for hop over -> isMemberOf.Emit(codeGenerator); // Lengthen chain for own [] chain.Lengthen(); chain.IsArrayItem = true; chain.IsLastMember = false; result = chain.EmitGetItem(array, index, itemGetterKind); chain.IsArrayItem = false; return(result); } else { // we are at the beginning of the field chain // // 4: a[x]->... // Lengthen chain for itself chain.Lengthen(); // for own [] chain.IsArrayItem = true; chain.IsLastMember = true; result = chain.EmitGetItem(array, index, itemGetterKind); chain.IsArrayItem = false; return(result); } } // 1, 2, 6, 7 if (this.isMemberOf != null) { // last node of the field chain // // 6 , 7: ...->a[]_[]_ , ...->a_[]_ bool quiet_read = chain.QuietRead; chain.Create(); chain.Begin(); chain.QuietRead = quiet_read; chain.Lengthen(); // for hop over -> isMemberOf.Emit(codeGenerator); // let's emit the array subchain followed by the GetItem: chain.IsArrayItem = true; chain.IsLastMember = false; result = chain.EmitGetItem(array, index, itemGetterKind); chain.IsArrayItem = false; chain.End(); return(result); } // 1, 2 if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse) { // we are at the beginning of the field chain // // 2: a[]_[]_ bool quiet_read = chain.QuietRead; chain.Create(); chain.Begin(); chain.QuietRead = quiet_read; chain.IsArrayItem = true; chain.IsLastMember = true; result = chain.EmitGetItem(array, index, itemGetterKind); chain.IsArrayItem = false; chain.End(); return(result); } // no chains // // 1: a_[x]_ chain.IsArrayItem = true; chain.IsLastMember = true; result = chain.EmitGetItem(array, index, itemGetterKind); chain.IsArrayItem = false; return(result); }