Exemplo n.º 1
0
		/// <summary>
		/// Emits IL instructions that ensure that the specified property of an object is
		/// of the <see cref="PhpArray"/> type.
		/// </summary>
		/// <param name="varObject">Represents the instance whose property should be examined.</param>
		/// <param name="fieldName">A <see cref="SimpleVarUse"/> that evaluates to the property name.</param>
		/// <param name="ensureArray">Whether to ensure that static property is an array (or an object).</param>
		/// <remarks>Nothing is expected on the evaluation stack. If the property is of <see cref="PhpArray"/> type
		/// it is left on the evaluation stack. Otherwise the control is transfered to the end of chain.</remarks>
		public PhpTypeCode EmitEnsureProperty(VarLikeConstructUse/*!*/ varObject, SimpleVarUse/*!*/ fieldName, bool ensureArray)
		{
			// Template: PhpArray EnsurePropertyIsArray(DObject,field,DTypeDesc)
			Debug.Assert(varObject != null && fieldName != null);
			Debug.Assert(fieldName is DirectVarUse || fieldName is IndirectVarUse);

			LocationTypes location;
			DProperty property = ResolveProperty(varObject, fieldName, out location);

			ILEmitter il = codeGenerator.IL;

			PhpField php_field = property as PhpField;
			if (php_field != null) // we can emit code that manipulates the property directly
			{
				// HACK HACK
				EmitEnsurePhpFieldDirect(php_field, fieldName, ensureArray);
			}
			else
			{
				switch (location)
				{
					case LocationTypes.GlobalCode:
						{
							// call EnsurePropertyIsArray
							codeGenerator.EmitLoadSelf();
							fieldName.EmitName(codeGenerator);
							codeGenerator.EmitLoadClassContext();

							if (ensureArray)
							{
								il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsArray);
							}
							else
							{
								codeGenerator.EmitLoadScriptContext();
								il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsObject);
							}
							break;
						}

					case LocationTypes.MethodDecl:
						{
							if (ensureArray) this.Lengthen(); // for hop over ->
							FunctionCall func = varObject as FunctionCall;
							if (func == null)
							{
								varObject.Emit(codeGenerator);
							}
							else
							{
								this.LoadAddressOfFunctionReturnValue = true;
								func.Emit(codeGenerator);
								RecastValueReturnedByFunctionCall();
							}
							fieldName.EmitName(codeGenerator);
							codeGenerator.EmitLoadClassContext();

							if (ensureArray)
							{
								il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsArray);
							}
							else
							{
								codeGenerator.EmitLoadScriptContext();
								il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsObject);
							}
							EmitErrorCheck(ensureArray);
							break;
						}

					// if the location was FunctionDecl, appropriate code was already generated by GetDProperty
				}
			}
			return (ensureArray ? PhpTypeCode.PhpArray : PhpTypeCode.DObject);
		}
Exemplo n.º 2
0
        /// <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);
        }