internal override TypeSymbol Emit(CodeGenerator cg) { var result_type = cg.DeclaringCompilation.GetTypeFromTypeRef(cg.Routine, this.TypeRefMask); if (this.IfTrue != null) { object trueLbl = new object(); object endLbl = new object(); // Cond ? True : False cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean); // i4 cg.Builder.EmitBranch(ILOpCode.Brtrue, trueLbl); // false: cg.EmitConvert(this.IfFalse, result_type); cg.Builder.EmitBranch(ILOpCode.Br, endLbl); cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder // trueLbl: cg.Builder.MarkLabel(trueLbl); cg.EmitConvert(this.IfTrue, result_type); // endLbl: cg.Builder.MarkLabel(endLbl); } else { object trueLbl = new object(); object endLbl = new object(); // Cond ?: False // <stack> = <cond_var> = Cond var cond_type = cg.Emit(this.Condition); var cond_var = cg.GetTemporaryLocal(cond_type); cg.Builder.EmitOpCode(ILOpCode.Dup); cg.Builder.EmitLocalStore(cond_var); cg.EmitConvertToBool(cond_type, this.Condition.TypeRefMask); cg.Builder.EmitBranch(ILOpCode.Brtrue, trueLbl); // false: cg.EmitConvert(this.IfFalse, result_type); cg.Builder.EmitBranch(ILOpCode.Br, endLbl); cg.Builder.AdjustStack(-1); // workarounds assert in ILBuilder.MarkLabel, we're doing something wrong with ILBuilder // trueLbl: cg.Builder.MarkLabel(trueLbl); cg.Builder.EmitLocalLoad(cond_var); cg.EmitConvert(cond_type, this.Condition.TypeRefMask, result_type); // endLbl: cg.Builder.MarkLabel(endLbl); // cg.ReturnTemporaryLocal(cond_var); } // if (Access.IsNone) { cg.EmitPop(result_type); result_type = cg.CoreTypes.Void; } // return result_type; }
internal override TypeSymbol Emit(CodeGenerator cg) { Debug.Assert(Access.IsRead || Access.IsNone); TypeSymbol returned_type; switch (this.Operation) { case Operations.AtSign: // special arrangement // Template: // context.DisableErrorReporting(); // s; // context.EnableErrorReporting(); returned_type = cg.EmitWithDisabledErrorReporting(Operand); break; case Operations.BitNegation: //Template: "~x" Operators.BitNot(x) returned_type = EmitBitNot(cg); break; case Operations.Clone: // Template: clone x Debug.WriteLine("TODO: clone(object)"); returned_type = cg.Emit(Operand); // TODO: clone break; case Operations.LogicNegation: //Template: !(bool)(x); cg.EmitConvertToBool(this.Operand, true); returned_type = cg.CoreTypes.Boolean; break; case Operations.Minus: //Template: "-x" returned_type = EmitMinus(cg); break; case Operations.Plus: //Template: "+x" returned_type = EmitPlus(cg); break; case Operations.ObjectCast: //Template: "(object)x" cg.EmitConvert(this.Operand, cg.CoreTypes.Object); returned_type = cg.CoreTypes.Object; break; case Operations.Print: cg.EmitEcho(this.Operand); if (Access.IsRead) { // Always returns 1 cg.Builder.EmitLongConstant(1); returned_type = cg.CoreTypes.Long; } else { // nobody reads the result anyway returned_type = cg.CoreTypes.Void; } break; case Operations.BoolCast: //Template: "(bool)x" cg.EmitConvert(this.Operand, cg.CoreTypes.Boolean); returned_type = cg.CoreTypes.Boolean; break; case Operations.Int8Cast: case Operations.Int16Cast: case Operations.Int32Cast: case Operations.UInt8Cast: case Operations.UInt16Cast: case Operations.UInt64Cast: case Operations.UInt32Cast: case Operations.Int64Cast: cg.EmitConvert(this.Operand, cg.CoreTypes.Long); returned_type = cg.CoreTypes.Long; break; case Operations.DecimalCast: case Operations.DoubleCast: case Operations.FloatCast: cg.EmitConvert(this.Operand, cg.CoreTypes.Double); returned_type = cg.CoreTypes.Double; break; case Operations.UnicodeCast: // TODO case Operations.StringCast: // (string)x cg.EmitConvert(this.Operand, cg.CoreTypes.String); // TODO: to String or PhpString ? to not corrupt single-byte string return cg.CoreTypes.String; case Operations.BinaryCast: //if ((returned_typecode = node.Expr.Emit(codeGenerator)) != PhpTypeCode.PhpBytes) //{ // codeGenerator.EmitBoxing(returned_typecode); // //codeGenerator.EmitLoadClassContext(); // il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpBytes); // returned_typecode = PhpTypeCode.PhpBytes; //} //break; throw new NotImplementedException(); case Operations.ArrayCast: //Template: "(array)x" cg.EmitConvert(this.Operand, cg.CoreTypes.PhpArray); // TODO: EmitArrayCast() returned_type = cg.CoreTypes.PhpArray; break; case Operations.UnsetCast: // Template: "(unset)x" null cg.EmitPop(cg.Emit(this.Operand)); if (this.Access.IsRead) { cg.Builder.EmitNullConstant(); returned_type = cg.CoreTypes.Object; } else { returned_type = cg.CoreTypes.Void; } break; default: throw ExceptionUtilities.Unreachable; } switch (Access.Flags) { case AccessMask.Read: Debug.Assert(returned_type.SpecialType != SpecialType.System_Void); // do nothing break; case AccessMask.None: // pop operation's result value from stack cg.EmitPop(returned_type); returned_type = cg.CoreTypes.Void; break; default: throw ExceptionUtilities.UnexpectedValue(Access); } return returned_type; }