/// <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); }