예제 #1
0
 /// <summary>
 /// Visit expressions in PHP concat.
 /// </summary>
 /// <param name="x"></param>
 virtual public void VisitConcatEx(ConcatEx x)
 {
     VisitExpressions(x.Expressions);
 }
예제 #2
0
 /// <summary>
 /// Visit expressions in PHP concat.
 /// </summary>
 /// <param name="x"></param>
 virtual public void VisitConcatEx(ConcatEx x)
 {
     VisitExpressionList(x.Expressions);
 }
예제 #3
0
        /// <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);
        }