/// <summary> /// Emits IL instructions that ensure that the specified variable is an instance of <see cref="PhpObject"/>. /// </summary> /// <param name="variable">Variable that should be examined.</param> /// <remarks> /// This method is used in operators chains. Nothing is expected on the evaluation stack. /// If the specified variable is an instance of <see cref="PhpObject"/> /// it is left on the evaluation stack. Otherwise the control is transfered to the end of /// the chain. /// </remarks> public void EmitEnsureVariableIsObject(SimpleVarUse variable) { ILEmitter il = codeGenerator.IL; DirectVarUse direct_variable = variable as DirectVarUse; if (direct_variable != null && direct_variable.VarName.IsThisVariableName) { // special treatment of $this 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, TopChain.ErrorLabel); il.MarkLabel(this_non_null, true); codeGenerator.EmitLoadSelf(); break; } case LocationTypes.FunctionDecl: { // always throws error codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext); il.Emit(OpCodes.Br, TopChain.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, TopChain.ErrorLabel); } else { // arg0 or <proxy> in instance methods codeGenerator.EmitLoadSelf(); } break; } default: Debug.Assert(false, "Invalid location type."); break; } } else { // Template: PhpObject EnsureVariableIsObject(ref object,ScriptContext) // Load variable's address // if (variable is FunctionCall) // { // variable.Emit(this); // EmitLoadScriptContext(); // il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject); // // Store the changed destVar into table of variables (do nothing in optimalized functions) // } // else // { variable.EmitLoadAddress(codeGenerator); codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject); // Store the changed destVar into table of variables (do nothing in optimalized functions) variable.EmitLoadAddress_StoreBack(codeGenerator); // } EmitErrorCheck(false); } }
/// <summary> /// Emits IL instructions that ensure that the specified variable is an instance of <see cref="PhpArray"/>. /// </summary> /// <param name="variable">Variable's name-index to a table of identifiers.</param> /// <remarks> /// This method is used in operators chains. Nothing is expected on the evaluation stack. /// If the specified variable is an instance of <see cref="PhpArray"/> /// it is left on the evaluation stack. Otherwise the control is transfered to the end of /// the chain. /// </remarks> public void EmitEnsureVariableIsArray(SimpleVarUse variable) { // Template: PhpArray EnsureVariableIsArray(ref object) // Load variable's address //this.EmitVariableLoadAddress(variable); variable.EmitLoadAddress(codeGenerator); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsArray); // Store the changed destVar into table of variables (do nothing in optimalized functions) variable.EmitLoadAddress_StoreBack(codeGenerator); EmitErrorCheck(true); }