Пример #1
0
		/// <summary>
		/// Emits IL instructions that add an object field access to the current <see cref="PhpRuntimeChain"/>.
		/// </summary>
		/// <param name="varUse">AST node representing the field access.</param>
		/// <remarks>
		/// A reference to <see cref="PhpRuntimeChain"/> is expected and left on the evaluation stack.
		/// </remarks>
		public void EmitRTChainAddField(SimpleVarUse varUse)
		{
			codeGenerator.IL.Emit(OpCodes.Dup);
			varUse.EmitName(codeGenerator);
			codeGenerator.IL.EmitCall(OpCodes.Call, Methods.PhpRuntimeChain.AddField, null);
		}
Пример #2
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);
		}
Пример #3
0
		/// <summary>
		/// I do not like PHP-specific access code emission here. TODO: Move to PhpField
		/// </summary>
		/// <param name="field"></param>
		/// <param name="fieldName"></param>
		/// <param name="ensureArray"></param>
		private void EmitEnsurePhpFieldDirect(PhpField/*!*/ field, SimpleVarUse/*!*/ fieldName, bool ensureArray)
		{
			ILEmitter il = codeGenerator.IL;

			// check whether the field is set
			il.Ldarg(FunctionBuilder.ArgThis);
			il.Emit(OpCodes.Ldfld, field.RealField);

			Label direct_ensure = il.DefineLabel();
			Label ensuring_over = il.DefineLabel();

			// test whether it is set
			il.Emit(OpCodes.Callvirt, Properties.PhpReference_IsSet.GetGetMethod());
			il.Emit(OpCodes.Brtrue, direct_ensure);

			// the field has been unset -> must call operator that handles __get/__set
			if (ensureArray) this.Lengthen();  // TODO: ???
			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);
			}
			il.Emit(OpCodes.Br, ensuring_over);

			// read the field again and call EnsureVariableIsArray
			il.MarkLabel(direct_ensure, true);
			il.Ldarg(FunctionBuilder.ArgThis);
			il.Emit(OpCodes.Ldfld, field.RealField);
			il.Emit(OpCodes.Ldflda, Fields.PhpReference_Value);

			if (ensureArray)
			{
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsArray);
			}
			else
			{
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject);
			}

			il.MarkLabel(ensuring_over, true);
			EmitErrorCheck(ensureArray);
		}