/// <summary> /// Visit expressions in PHP concat. /// </summary> /// <param name="x"></param> virtual public void VisitConcatEx(ConcatEx x) { VisitExpressions(x.Expressions); }
/// <summary> /// Visit expressions in PHP concat. /// </summary> /// <param name="x"></param> virtual public void VisitConcatEx(ConcatEx x) { VisitExpressionList(x.Expressions); }
/// <remarks> /// Nothing is expected at the evaluation stack. If AST node is read by other node, /// the operation result is left at the stack, otherwise it is poped from the stack. /// </remarks> /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override PhpTypeCode Emit(CodeGenerator codeGenerator) { Debug.Assert(access == AccessType.None || access == AccessType.Read); Statistics.AST.AddNode("BinaryEx"); PhpTypeCode returned_typecode; PhpTypeCode lo_typecode; PhpTypeCode ro_typecode; switch (operation) { #region Arithmetic Operations case Operations.Add: // Template: x + y : Operators.Add(x,y) [overloads] switch (lo_typecode = leftExpr.Emit(codeGenerator)) { case PhpTypeCode.Double: switch (ro_typecode = rightExpr.Emit(codeGenerator)) { case PhpTypeCode.Integer: codeGenerator.IL.Emit(OpCodes.Conv_R8); goto case PhpTypeCode.Double; // fallback: case PhpTypeCode.Double: codeGenerator.IL.Emit(OpCodes.Add); returned_typecode = PhpTypeCode.Double; break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Double_Object); break; } break; default: codeGenerator.EmitBoxing(lo_typecode); ro_typecode = rightExpr.Emit(codeGenerator); switch (ro_typecode) { case PhpTypeCode.Integer: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Int32); break; case PhpTypeCode.Double: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Double); break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Object); break; } break; } break; case Operations.Sub: //Template: "x - y" Operators.Subtract(x,y) [overloads] lo_typecode = leftExpr.Emit(codeGenerator); switch (lo_typecode) { case PhpTypeCode.Integer: codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Int32_Object); break; case PhpTypeCode.Double: switch (ro_typecode = rightExpr.Emit(codeGenerator)) { case PhpTypeCode.Integer: codeGenerator.IL.Emit(OpCodes.Conv_R8); goto case PhpTypeCode.Double; // fallback: case PhpTypeCode.Double: codeGenerator.IL.Emit(OpCodes.Sub); returned_typecode = PhpTypeCode.Double; break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Double_Object); break; } break; default: codeGenerator.EmitBoxing(lo_typecode); ro_typecode = rightExpr.Emit(codeGenerator); if (ro_typecode == PhpTypeCode.Integer) { returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Int); } else { codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Object); } break; } break; case Operations.Div: //Template: "x / y" Operators.Divide(x,y) lo_typecode = leftExpr.Emit(codeGenerator); switch (lo_typecode) { case PhpTypeCode.Integer: codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Int32_Object); break; case PhpTypeCode.Double: switch (ro_typecode = rightExpr.Emit(codeGenerator)) { case PhpTypeCode.Double: codeGenerator.IL.Emit(OpCodes.Div); returned_typecode = PhpTypeCode.Double; break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Double_Object); break; } break; default: codeGenerator.EmitBoxing(lo_typecode); ro_typecode = rightExpr.Emit(codeGenerator); switch (ro_typecode) { case PhpTypeCode.Integer: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Int32); break; case PhpTypeCode.Double: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Double); break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Object); break; } break; } break; case Operations.Mul: switch (lo_typecode = leftExpr.Emit(codeGenerator)) { case PhpTypeCode.Double: // "x * (double)y" // Operators.Multiply((double)x,(object)y) switch (ro_typecode = rightExpr.Emit(codeGenerator)) { case PhpTypeCode.Integer: codeGenerator.IL.Emit(OpCodes.Conv_R8); goto case PhpTypeCode.Double; // fallback: case PhpTypeCode.Double: codeGenerator.IL.Emit(OpCodes.Mul); returned_typecode = PhpTypeCode.Double; break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Double_Object); break; } break; default: //Template: "x * y" Operators.Multiply((object)x,y) [overloads] codeGenerator.EmitBoxing(lo_typecode); ro_typecode = rightExpr.Emit(codeGenerator); switch (ro_typecode) { case PhpTypeCode.Integer: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Int32); break; case PhpTypeCode.Double: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Double); break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Object); break; } break; } break; case Operations.Mod: //Template: "x % y" Operators.Remainder(x,y) codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); ro_typecode = rightExpr.Emit(codeGenerator); switch (ro_typecode) { case PhpTypeCode.Integer: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Int32); break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Object); break; } break; case Operations.ShiftLeft: // LOAD Operators.ShiftLeft(box left, box right); codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftLeft); break; case Operations.ShiftRight: // LOAD Operators.ShiftRight(box left, box right); codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftRight); break; #endregion #region Boolean and Bitwise Operations case Operations.And: returned_typecode = EmitBinaryBooleanOperation(codeGenerator, true); break; case Operations.Or: returned_typecode = EmitBinaryBooleanOperation(codeGenerator, false); break; case Operations.Xor: // LOAD <(bool) leftSon> == <(bool) rightSon>; codeGenerator.EmitConversion(leftExpr, PhpTypeCode.Boolean); codeGenerator.EmitConversion(rightExpr, PhpTypeCode.Boolean); codeGenerator.IL.Emit(OpCodes.Ceq); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; case Operations.BitAnd: returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.And); break; case Operations.BitOr: returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.Or); break; case Operations.BitXor: returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.Xor); break; #endregion #region Comparing Operations case Operations.Equal: // LOAD PhpComparer.Default.CompareEq returned_typecode = EmitComparison(codeGenerator, true); break; case Operations.NotEqual: // LOAD PhpComparer.Default.CompareEq == false EmitComparison(codeGenerator, true); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; case Operations.GreaterThan: // LOAD PhpComparer.Default.Compare > 0; EmitComparison(codeGenerator, false); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Cgt); returned_typecode = PhpTypeCode.Boolean; break; case Operations.LessThan: // LOAD PhpComparer.Default.Compare < 0; EmitComparison(codeGenerator, false); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Clt); returned_typecode = PhpTypeCode.Boolean; break; case Operations.GreaterThanOrEqual: // LOAD PhpComparer.Default.Compare >= 0 (not less than) EmitComparison(codeGenerator, false); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Clt); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; case Operations.LessThanOrEqual: // LOAD PhpComparer.Default.Compare >= 0 (not greater than) EmitComparison(codeGenerator, false); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Cgt); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; case Operations.Identical: // LOAD Operators.StrictEquality(box left,box right); codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality); returned_typecode = PhpTypeCode.Boolean; break; case Operations.NotIdentical: // LOAD Operators.StrictEquality(box left,box right) == false; codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; #endregion case Operations.Concat: returned_typecode = ConcatEx.EmitConcat(codeGenerator, leftExpr, rightExpr); break; default: throw null; } switch (access) { case AccessType.Read: // Result is read, do nothing. break; case AccessType.None: // Result is not read, pop the result codeGenerator.IL.Emit(OpCodes.Pop); returned_typecode = PhpTypeCode.Void; break; } return(returned_typecode); }