Example #1
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator)
		{
			Debug.Assert(access == AccessType.Read || access == AccessType.None);
			Statistics.AST.AddNode("UnaryEx");

			ILEmitter il = codeGenerator.IL;

			PhpTypeCode returned_typecode, o_typecode;

			switch (operation)
			{
				case Operations.AtSign:	// special arrangement
					// Template:
					//		context.DisableErrorReporting();
					//		s;
					//		context.EnableErrorReporting();
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.ScriptContext.DisableErrorReporting);
					returned_typecode = expr.Emit(codeGenerator);
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.ScriptContext.EnableErrorReporting);
					break;

				case Operations.BitNegation:
					//Template: "~x" Operators.BitNot(x)                                     
					codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
					il.Emit(OpCodes.Call, Methods.Operators.BitNot);
					returned_typecode = PhpTypeCode.Object;
					break;

				case Operations.Clone:
					// Template: clone x        Operators.Clone(x,DTypeDesc,ScriptContext)
					codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
					codeGenerator.EmitLoadClassContext();
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.Operators.Clone);
					returned_typecode = PhpTypeCode.Object;
					break;

				case Operations.LogicNegation:
					//Template: "!x"  !Convert.ObjectToBoolean(x);                              
                    if (((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.Boolean))
                    {
                        codeGenerator.EmitBoxing(returned_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
                    }
					il.Emit(OpCodes.Ldc_I4_0);
					il.Emit(OpCodes.Ceq);
					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.Minus:
					//Template: "-x"  Operators.Minus(x)
                    switch (o_typecode = expr.Emit(codeGenerator))
                    {
                        case PhpTypeCode.Double:
                            il.Emit(OpCodes.Neg);
                            returned_typecode = PhpTypeCode.Double;
                            break;
                        default:
					        codeGenerator.EmitBoxing(o_typecode);
                            returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Minus);
					        break;
                    }
                    break;

				case Operations.ObjectCast:
					//Template: "(object)x"   Convert.ObjectToDObject(x,ScriptContext)
					codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.Convert.ObjectToDObject);
					returned_typecode = PhpTypeCode.Object;
					break;

				case Operations.Plus:
					//Template: "+x"  Operators.Plus(x)
					codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
					il.Emit(OpCodes.Call, Methods.Operators.Plus);
					returned_typecode = PhpTypeCode.Object;
					break;

				case Operations.Print:
					codeGenerator.EmitEcho(this.expr);
					// Always returns 1
					il.Emit(OpCodes.Ldc_I4_1);
					returned_typecode = PhpTypeCode.Integer;
					break;

				case Operations.BoolCast:
					//Template: "(bool)x"     Convert.ObjectToBoolean(x)
                    if (((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.Boolean))
                    {
                        codeGenerator.EmitBoxing(returned_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
                        returned_typecode = PhpTypeCode.Boolean;
                    }
					break;

				case Operations.Int8Cast:
				case Operations.Int16Cast:
				case Operations.Int32Cast:
				case Operations.UInt8Cast:
				case Operations.UInt16Cast:
					// CALL int Convert.ObjectToInteger(<expr>)
                    o_typecode = expr.Emit(codeGenerator);
                    if (o_typecode != PhpTypeCode.Integer)
                    {
                        codeGenerator.EmitBoxing(o_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToInteger);
                    }

					// CONV for unsigned:
					switch (operation)
					{
						case Operations.UInt8Cast: il.Emit(OpCodes.Conv_U1); il.Emit(OpCodes.Conv_I4); break;
						case Operations.UInt16Cast: il.Emit(OpCodes.Conv_U2); il.Emit(OpCodes.Conv_I4); break;
					}

					returned_typecode = PhpTypeCode.Integer;
					break;

				case Operations.UInt64Cast:
				case Operations.UInt32Cast:
				case Operations.Int64Cast:
					// CALL long Convert.ObjectToLongInteger(<expr>)
                    o_typecode = expr.Emit(codeGenerator);
                    if (o_typecode != PhpTypeCode.LongInteger)
                    {
                        codeGenerator.EmitBoxing(o_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToLongInteger);
                    }

					// CONV for unsigned:
					switch (operation)
					{
						case Operations.UInt32Cast: il.Emit(OpCodes.Conv_U4); il.Emit(OpCodes.Conv_I8); break;
						case Operations.UInt64Cast: il.Emit(OpCodes.Conv_U8); il.Emit(OpCodes.Conv_I8); break;
					}

					returned_typecode = PhpTypeCode.LongInteger;
					break;

				case Operations.DecimalCast:
				case Operations.DoubleCast:
				case Operations.FloatCast:
					// CALL double Convert.ObjectToDouble(<expr>)
                    o_typecode = expr.Emit(codeGenerator);
                    if (o_typecode != PhpTypeCode.Double)
                    {
                        codeGenerator.EmitBoxing(o_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToDouble);
                    }
					returned_typecode = PhpTypeCode.Double;
					break;

				case Operations.UnicodeCast: // TODO
				case Operations.StringCast:
                    if ((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.String)
                    {
                        codeGenerator.EmitBoxing(returned_typecode);
                        //codeGenerator.EmitLoadClassContext();
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
                        returned_typecode = PhpTypeCode.String;
                    }
					break;

                case Operations.BinaryCast:
                    if ((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.PhpBytes)
                    {
                        codeGenerator.EmitBoxing(returned_typecode);
                        //codeGenerator.EmitLoadClassContext();
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpBytes);
                        returned_typecode = PhpTypeCode.PhpBytes;
                    }
                    break;

				case Operations.ArrayCast:
					//Template: "(array)x"   Convert.ObjectToArray(x)
                    o_typecode = expr.Emit(codeGenerator);
                    if (o_typecode != PhpTypeCode.PhpArray)
                    {
                        codeGenerator.EmitBoxing(o_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpArray);
                    }
					returned_typecode = PhpTypeCode.PhpArray;
					break;

				case Operations.UnsetCast:
					// Template: "(unset)x"  null
					il.Emit(OpCodes.Ldnull);
					returned_typecode = PhpTypeCode.Object;
					break;

				default:
					Debug.Assert(false, "illegal type of operation!");
					returned_typecode = PhpTypeCode.Void;
					break;
			}

			switch (access)
			{
				case AccessType.Read:
					// do nothing
					break;
				case AccessType.None:
					// pop operation's result value from stack
					if (returned_typecode != PhpTypeCode.Void)
						il.Emit(OpCodes.Pop);
					return PhpTypeCode.Void;
			}

			return returned_typecode;
		}
Example #2
0
		/// <summary>
		/// Emits IL instructions that unset an instance field.
		/// </summary>
		/// <remarks>
		/// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack.
		/// </remarks>
		private void EmitUnsetField(CodeGenerator codeGenerator)
		{
			// call UnsetProperty operator
			codeGenerator.ChainBuilder.Lengthen(); // for hop over ->
			IsMemberOf.Emit(codeGenerator);
			EmitName(codeGenerator);
			codeGenerator.EmitLoadClassContext();

			codeGenerator.IL.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
		}
Example #3
0
		private static void EmitCallSetObjectField(CodeGenerator/*!*/ codeGenerator, PhpTypeCode stackTypeCode)
		{
			// CALL Operators.SetObjectProperty(<STACK:instance>,<STACK:field name>,<STACK:field value>, <type desc>)
			codeGenerator.EmitLoadClassContext();

			codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.SetObjectProperty);
            
            //always when function with void return argument is called it's necesarry to add nop instruction due to debugger
            if (codeGenerator.Context.Config.Compiler.Debug)
            {
                codeGenerator.IL.Emit(OpCodes.Nop);
            }
		}
Example #4
0
		/// <summary>
		/// Emits IL instructions that read the value of an instance field.
		/// </summary>
		/// <param name="codeGenerator">The current <see cref="CodeGenerator"/>.</param>
		/// <param name="wantRef">If <B>false</B> the field value should be left on the evaluation stack,
		/// if <B>true</B> the <see cref="PhpReference"/> should be left on the evaluation stack.</param>
		/// <returns>
		/// Nothing is expected on the evaluation stack. A <see cref="PhpReference"/> (if <paramref name="wantRef"/>
		/// is <B>true</B>) or the field value itself (if <paramref name="wantRef"/> is <B>false</B>) is left on the
		/// evaluation stack.
		/// </returns>
		internal virtual PhpTypeCode EmitReadField(CodeGenerator codeGenerator, bool wantRef)
		{
			ILEmitter il = codeGenerator.IL;

			DirectVarUse direct_instance = isMemberOf as DirectVarUse;
			if (direct_instance != null && direct_instance.IsMemberOf == null && direct_instance.VarName.IsThisVariableName)
			{
				return EmitReadFieldOfThis(codeGenerator, wantRef);
			}
            		

			if (!wantRef)
			{
                //codeGenerator.ChainBuilder.Lengthen();
                //PhpTypeCode type_code = isMemberOf.Emit(codeGenerator);
                //Debug.Assert(type_code == PhpTypeCode.Object || type_code == PhpTypeCode.DObject);

                //// CALL Operators.GetProperty(STACK,<field name>,<type desc>,<quiet>);
                //EmitName(codeGenerator);
                //codeGenerator.EmitLoadClassContext();
                //il.LoadBool(codeGenerator.ChainBuilder.QuietRead);
                //il.Emit(OpCodes.Call, Methods.Operators.GetProperty);
                //return PhpTypeCode.Object;

                string fieldName = (this is DirectVarUse) ? ((DirectVarUse)this).VarName.Value : null;
                Expression fieldNameExpr = (this is IndirectVarUse) ? ((IndirectVarUse)this).VarNameEx : null;
                bool quietRead = wantRef ? false : codeGenerator.ChainBuilder.QuietRead;
                return codeGenerator.CallSitesBuilder.EmitGetProperty(
                    codeGenerator, wantRef,
                    isMemberOf, null, null,
                    null,
                    fieldName, fieldNameExpr,
                    quietRead);
			}

            // call GetProperty/GetObjectPropertyRef
			codeGenerator.ChainBuilder.Lengthen();
            // loads the variable which field is gotten:
            PhpTypeCode var_type_code = isMemberOf.Emit(codeGenerator);

			if (codeGenerator.ChainBuilder.Exists)
			{
				Debug.Assert(var_type_code == PhpTypeCode.DObject);

				// CALL Operators.GetObjectPropertyRef(STACK,<field name>,<type desc>);
				EmitName(codeGenerator);
				codeGenerator.EmitLoadClassContext();
				il.Emit(OpCodes.Call, Methods.Operators.GetObjectPropertyRef);
			}
			else
			{
				Debug.Assert(var_type_code == PhpTypeCode.ObjectAddress);

				// CALL Operators.GetPropertyRef(ref STACK,<field name>,<type desc>,<script context>);
				EmitName(codeGenerator);
				codeGenerator.EmitLoadClassContext();
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.Operators.GetPropertyRef);

				// stores the value of variable back:
				SimpleVarUse simple_var = isMemberOf as SimpleVarUse;
				if (simple_var != null)
					simple_var.EmitLoadAddress_StoreBack(codeGenerator);
			}

			return PhpTypeCode.PhpReference;
		}
Example #5
0
		/// <summary>
		/// Emits IL instructions that unset an instance field.
		/// </summary>
		/// <remarks>
		/// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack.
		/// </remarks>
		private void EmitUnsetField(CodeGenerator/*!*/ codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;

			DirectVarUse direct_instance = isMemberOf as DirectVarUse;
			if (direct_instance != null && direct_instance.VarName.IsThisVariableName)
			{
				// $this->a
				switch (codeGenerator.LocationStack.LocationType)
				{
					case LocationTypes.GlobalCode:
						{
							// load $this from one of Main's arguments and check for null
							Label this_non_null = il.DefineLabel();

							codeGenerator.EmitLoadSelf();
							il.Emit(OpCodes.Brtrue_S, this_non_null);
							codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
							il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
							il.MarkLabel(this_non_null, true);

							// call UnsetProperty
							codeGenerator.EmitLoadSelf();
							il.Emit(OpCodes.Ldstr, varName.ToString()); // TODO
							codeGenerator.EmitLoadClassContext();

							il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
							return;
						}

					case LocationTypes.FunctionDecl:
						{
							// always throws error
							codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
							il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
							break;
						}

					case LocationTypes.MethodDecl:
						{
							CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
							if (context.Method.IsStatic)
							{
								// always throws error
								codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
								il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
							}
							else
							{
								DProperty property;
								if (context.Type.GetProperty(varName, context.Type, out property) == GetMemberResult.OK &&
									!property.IsStatic)
								{
									// ask the DProperty to emit its unsetting code
									property.EmitUnset(codeGenerator, IndexedPlace.ThisArg, null, false);
								}
								else
								{
									// unable to resolve the field -> call UnsetProperty
									codeGenerator.EmitLoadSelf();
									il.Emit(OpCodes.Ldstr, varName.ToString());
									codeGenerator.EmitLoadClassContext();

									il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
								}
							}
						}
						break;
				}
			}
			else
			{
				// call UnsetProperty
				isMemberOf.Emit(codeGenerator);
				il.Emit(OpCodes.Ldstr, varName.ToString());
				codeGenerator.EmitLoadClassContext();

				il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
			}
		}
Example #6
0
		/// <summary>
		/// Emits dynamic inclusion.
		/// </summary>
		private PhpTypeCode EmitDynamicInclusion(CodeGenerator/*!*/ codeGenerator)
		{
			// do not generate dynamic auto inclusions:
			if (InclusionTypesEnum.IsAutoInclusion(inclusionType))
				return PhpTypeCode.Void;

			ILEmitter il = codeGenerator.IL;

			// CALL context.DynamicInclude(<file name>,<relative includer source path>,variables,self,includer);
			codeGenerator.EmitLoadScriptContext();
			codeGenerator.EmitConversion(fileNameEx, PhpTypeCode.String);
			il.Emit(OpCodes.Ldstr, codeGenerator.SourceUnit.SourceFile.RelativePath.ToString());
			codeGenerator.EmitLoadRTVariablesTable();
			codeGenerator.EmitLoadSelf();
			codeGenerator.EmitLoadClassContext();
			il.LoadLiteral(inclusionType);
			il.Emit(OpCodes.Call, Methods.ScriptContext.DynamicInclude);

			return PhpTypeCode.Object;
		}
		/// <summary>
		/// Emits a static inclusion.
		/// </summary>
		private PhpTypeCode EmitStaticInclusion(CodeGenerator/*!*/ codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;
			Label endif_label = il.DefineLabel();
			Label else_label = il.DefineLabel();
			MethodInfo method;

			// if the expression should be emitted:
			if (characteristic == Characteristic.StaticArgEvaluated)
			{
                if (!(fileNameEx is StringLiteral || fileNameEx is BinaryStringLiteral))
                {
                    // emits expression evaluation and ignores the result:
                    fileNameEx.Emit(codeGenerator);
                    il.Emit(OpCodes.Pop);
                }
			}

			if (characteristic == Characteristic.StaticAutoInclusion)
			{
				// calls the Main routine only if this script is the main one:
				il.Ldarg(ScriptBuilder.ArgIsMain);
			}
			else
			{
                RelativePath relativePath = new RelativePath(inclusion.Includee.RelativeSourcePath);    // normalize the relative path

				// CALL context.StaticInclude(<relative included script source path>,<this script type>,<inclusion type>);
				codeGenerator.EmitLoadScriptContext();
                il.Emit(OpCodes.Ldc_I4, (int)relativePath.Level);
                il.Emit(OpCodes.Ldstr, relativePath.Path);
				il.Emit(OpCodes.Ldtoken, inclusion.Includee.ScriptClassType);
				il.LoadLiteral(inclusionType);
				il.Emit(OpCodes.Call, Methods.ScriptContext.StaticInclude);
			}

			// IF (STACK)
			il.Emit(OpCodes.Brfalse, else_label);
			if (true)
			{
				// emits a call to the main helper of the included script:
				method = inclusion.Includee.MainHelper;

				// CALL <Main>(context, variables, self, includer, false):
				codeGenerator.EmitLoadScriptContext();
				codeGenerator.EmitLoadRTVariablesTable();
				codeGenerator.EmitLoadSelf();
				codeGenerator.EmitLoadClassContext();
				il.Emit(OpCodes.Ldc_I4_0);
				il.Emit(OpCodes.Call, method);

				il.Emit(OpCodes.Br, endif_label);
			}

			// ELSE

			il.MarkLabel(else_label);
			if (true)
			{
				// LOAD <PhpScript.SkippedIncludeReturnValue>;                          
				il.LoadLiteral(ScriptModule.SkippedIncludeReturnValue);
				il.Emit(OpCodes.Box, ScriptModule.SkippedIncludeReturnValue.GetType());
			}

			il.MarkLabel(endif_label);
			// END IF 

			return PhpTypeCode.Object;
		}