internal override void EmitUnset(CodeGenerator codeGenerator) { ChainBuilder chain = codeGenerator.ChainBuilder; // Template: "unset(x[y])" Operators.UnsetItem(object obj,object index) // 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); chain.QuietRead = true; // 1, 2, 6, 7 if (this.isMemberOf != null) { // 6 , 7: ...->a[]_[]_ , ...->a_[]_ chain.Create(); chain.Begin(); chain.Lengthen(); // for hop over -> isMemberOf.Emit(codeGenerator); chain.IsArrayItem = true; chain.IsLastMember = false; chain.EmitUnsetItem(array, index); chain.IsArrayItem = false; chain.End(); return; } // 1, 2 if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */) { // 2: a[]_[]_ chain.Create(); chain.Begin(); chain.IsArrayItem = true; chain.IsLastMember = true; chain.EmitUnsetItem(array, index); chain.IsArrayItem = false; chain.End(); return; } // 1: a_[x]_ chain.IsArrayItem = true; chain.IsLastMember = true; chain.EmitUnsetItem(array, index); chain.IsArrayItem = false; }
private void EmitNodeWriteAssign(CodeGenerator codeGenerator) { ChainBuilder chain = codeGenerator.ChainBuilder; // Note that for cases 1,3,4,5,6,9 EmitAssign is never called!!! // 2,7,8 if (chain.IsMember) { // 2,8 if (chain.Exists) { // 8: b[]->$a chain.EmitSetObjectField(); } else { // 2: $b->a Debug.Assert(this.isMemberOf is SimpleVarUse || this.isMemberOf is FunctionCall); if (this.isMemberOf is FunctionCall) { codeGenerator.ChainBuilder.LoadAddressOfFunctionReturnValue = true; } assignmentCallback(codeGenerator, PhpTypeCode.Object); SimpleVarUse svu = this.isMemberOf as SimpleVarUse; if (svu != null) { svu.EmitLoadAddress_StoreBack(codeGenerator); } // else do nothing } chain.End(); } else { // 7: $a //codeGenerator.EmitVariableStoreAssign(this); this.EmitStoreAssign(codeGenerator); } }
/// <summary> /// Emits code to load <see cref="PhpRuntimeChain"/> onto an evaluation stack. Supports operators chaining. /// </summary> /// <param name="codeGenerator"></param> private PhpTypeCode EmitNodeReadUnknown(CodeGenerator codeGenerator) { ChainBuilder chain = codeGenerator.ChainBuilder; PhpTypeCode result = PhpTypeCode.PhpRuntimeChain; if (chain.IsArrayItem) { // 3: a_[x]_[x] chain.Lengthen(); // for [] chain.EmitRTChainAddItem(this); return(result); } // 1,2,4,5,6,7 if (chain.IsMember) { // 4, 5 if (this.isMemberOf != null) { // 5: ...->a[]->... // Lengthen chain for isMemberOf chain.Lengthen(); // for hop over -> PhpTypeCode res = isMemberOf.Emit(codeGenerator); if (res != PhpTypeCode.PhpRuntimeChain) { codeGenerator.EmitBoxing(res); chain.EmitCreateRTChain(); } // Lengthen chain for own [] chain.Lengthen(); chain.IsArrayItem = true; chain.IsLastMember = false; chain.EmitRTChainAddItem(this); chain.IsArrayItem = false; return(result); } // 4: a[x]->... // Lengthen chain for itself chain.Lengthen(); // for own [] chain.IsArrayItem = true; chain.IsLastMember = true; chain.EmitRTChainAddItem(this); chain.IsArrayItem = false; return(result); } // 1, 2, 6, 7 if (this.isMemberOf != null) { // 6 , 7: ...->a[]_[]_ , ...->a_[]_ bool quiet_read = chain.QuietRead; chain.Create(); chain.Begin(); chain.QuietRead = quiet_read; chain.Lengthen(); // for hop over -> PhpTypeCode res = isMemberOf.Emit(codeGenerator); if (res != PhpTypeCode.PhpRuntimeChain) { codeGenerator.EmitBoxing(res); chain.EmitCreateRTChain(); } chain.IsArrayItem = true; chain.IsLastMember = false; chain.EmitRTChainAddItem(this); chain.IsArrayItem = false; chain.End(); return(result); } // 1, 2 if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */) { // 2: a[]_[]_ bool quiet_read = chain.QuietRead; chain.Create(); chain.Begin(); chain.QuietRead = quiet_read; chain.IsArrayItem = true; chain.IsLastMember = true; chain.EmitRTChainAddItem(this); chain.IsArrayItem = false; chain.End(); return(result); } // 1: a_[x]_ chain.IsArrayItem = true; chain.IsLastMember = true; chain.EmitRTChainAddItem(this); chain.IsArrayItem = false; return(result); }
/// <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); }
/// <summary> /// Finishes the write operation starte by <see cref="Emit"/>. /// </summary> internal override PhpTypeCode EmitAssign(CodeGenerator /*!*/ codeGenerator) { ChainBuilder chain = codeGenerator.ChainBuilder; PhpTypeCode result; switch (access) { case AccessType.WriteAndReadRef: case AccessType.WriteAndReadUnknown: case AccessType.ReadAndWrite: case AccessType.ReadAndWriteAndReadRef: case AccessType.ReadAndWriteAndReadUnknown: case AccessType.Write: case AccessType.WriteRef: { bool reference = access == AccessType.WriteRef; // Note that some work was done in Emit() ! // In cases 3, 4, 5 EmitAssign is not called if (isMemberOf != null || (isMemberOf == null && (array is DirectStFldUse || array is IndirectStFldUse || array is ItemUse))) { // 2, 6, 7 chain.EmitSetArrayItem(indexTypeCode, index, reference); chain.End(); } else { // Note: The value which should be stored is already loaded on the evaluation stack. // Push the destination array and index and call the operator // 1: a_[x]_ Debug.Assert(array is SimpleVarUse); chain.IsArrayItem = true; chain.IsLastMember = true; indexTypeCode = codeGenerator.EmitArrayKey(chain, index); array.Emit(codeGenerator); chain.EmitSetItem(indexTypeCode, index, reference); // Store the changed variable into table of variables (do nothing in optimalized functions) ((SimpleVarUse)array).EmitLoadAddress_StoreBack(codeGenerator); } result = PhpTypeCode.Void; break; } case AccessType.None: // do nothing result = PhpTypeCode.Void; break; case AccessType.Read: // do nothing result = PhpTypeCode.Object; break; case AccessType.ReadRef: // Do nothing result = PhpTypeCode.PhpReference; break; default: Debug.Fail(); result = PhpTypeCode.Invalid; break; } return(result); }