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