/// <summary> /// Emits code to load a reference to a variable onto an evaluation stack. Supports operators chaining. /// </summary> /// <param name="codeGenerator"></param> private PhpTypeCode EmitNodeReadRef(CodeGenerator codeGenerator) { ChainBuilder chain = codeGenerator.ChainBuilder; LocalBuilder local = codeGenerator.IL.DeclareLocal(typeof(object)); // Case 3: a_[x]_[x] never reached Debug.Assert(chain.IsArrayItem == false, "ReadRef access shouldn't be set to array subchain nodes"); // Case 4,5 never reached // 4: a[x]->... // 5: ...->a[]->... Debug.Assert(chain.IsMember == false); // 1, 2, 6, 7 if (this.isMemberOf != null) { // last node of the field chain // // 6 , 7: ...->a[]_[]_ , ...->a_[]_ chain.Create(); chain.Begin(); if (this.isMemberOf is FunctionCall) { chain.LoadAddressOfFunctionReturnValue = true; } chain.SetObjectForLazyEmit(this); // let's emit the array subchain followed by the GetArrayItemRef: chain.IsArrayItem = true; chain.IsLastMember = false; chain.Lengthen(); // for own [] chain.EmitGetArrayItemRef(array, index); chain.IsArrayItem = false; chain.EndRef(); return(PhpTypeCode.PhpReference); } // 1, 2 if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse) { // we are at the beginning of the field chain // // 2: a[]_[]_ chain.Create(); chain.Begin(); chain.IsArrayItem = true; chain.IsLastMember = true; chain.Lengthen(); chain.EmitGetArrayItemRef(array, index); chain.IsArrayItem = false; chain.EndRef(); return(PhpTypeCode.PhpReference); } // no chains // // 1: a_[x]_ return(chain.EmitGetItemRef((SimpleVarUse)array, index)); }
/// <summary> /// Emits code to prepare an evaluation stack for storing a reference into a variable. /// Supports operators chaining. Store is finished by calling <see cref="EmitAssign"/>. /// </summary> /// <param name="codeGenerator"></param> private PhpTypeCode EmitNodeWriteRef(CodeGenerator codeGenerator) { ChainBuilder chain = codeGenerator.ChainBuilder; // Case 3: a_[x]_[x] never reached Debug.Assert(chain.IsArrayItem == false); // Case 4,5 never reached // 4: a[x]->... // 5: ...->a[]->... Debug.Assert(chain.IsMember == false); // 1, 2, 6, 7 if (this.isMemberOf != null) { // 6, 7: ...->a[x]_[x]_ chain.Create(); chain.Begin(); // Store isMemberOf for lazy emit chain.SetObjectForLazyEmit(this); chain.IsArrayItem = true; chain.IsLastMember = false; chain.Lengthen(); // for own [] array.Emit(codeGenerator); indexTypeCode = codeGenerator.EmitArrayKey(chain, index); // Note that EmitAssign will finish the work (SetArrayItem or PhpArray.Add) } else { // 1, 2 Debug.Assert(this.isMemberOf == null); if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */) { // 2: a[]_[]_ chain.Create(); chain.Begin(); chain.IsArrayItem = true; chain.IsLastMember = true; array.Emit(codeGenerator); indexTypeCode = codeGenerator.EmitArrayKey(chain, index); // Note that further work will be done by EmitAssign (SetArrayItem or PhpArray.Add) } // 1: a_[x]_ // Do nothing now, let the work be done in EmitAssign() // Note further work will be done by EmitAssign (either SetItem or SetItemRef); } return(PhpTypeCode.Unknown); }
/// <summary> /// Emits code to prepare an evaluation stack for storing a value into a variable. /// Supports operators chaining. Store is finished by calling <see cref="EmitAssign"/>. /// </summary> /// <param name="codeGenerator"></param> private PhpTypeCode EmitNodeWrite(CodeGenerator codeGenerator) { ChainBuilder chain = codeGenerator.ChainBuilder; if (chain.IsArrayItem) { // 3: a_[x]_[v] Debug.Assert(this.isMemberOf == null); return(chain.EmitEnsureItem(array, index, true)); } // 1, 2, 4, 5, 6, 7 if (chain.IsMember) { // 4, 5 if (this.isMemberOf != null) { // 5: ...->a[]->... // Store isMemberOf for lazy emit chain.SetObjectForLazyEmit(this); chain.IsArrayItem = true; chain.IsLastMember = false; } else { // 4: a_[x]_->c->..., a[x]_[x]_->c->... chain.IsArrayItem = true; chain.IsLastMember = true; } PhpTypeCode result = chain.EmitEnsureItem(array, index, false); chain.IsArrayItem = false; return(result); } // 1, 2, 6, 7 if (this.isMemberOf != null) { // 6, 7: ...->a[x]_[x]_ chain.Create(); chain.Begin(); // Store isMemberOf for lazy emit chain.SetObjectForLazyEmit(this); chain.IsArrayItem = true; chain.IsLastMember = false; chain.Lengthen(); // for own [] array.Emit(codeGenerator); indexTypeCode = codeGenerator.EmitArrayKey(chain, index); // Note that EmitAssign will finish the work (SetArrayItem or PhpArray.Add) return(PhpTypeCode.Unknown); } // 1, 2 Debug.Assert(this.isMemberOf == null); if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */) { // 2: a[]_[]_ chain.Create(); chain.Begin(); chain.IsArrayItem = true; chain.IsLastMember = true; array.Emit(codeGenerator); indexTypeCode = codeGenerator.EmitArrayKey(chain, index); // Note that further work will be done by EmitAssign (SetArrayItem or PhpArray.Add) return(PhpTypeCode.Unknown); } // 1: a_[x]_ // Do nothing now, let the work be done in EmitAssign() return(PhpTypeCode.Unknown); }