示例#1
0
            private PhpTypeCode EmitDestVarRead(AssignEx /*!*/ node, CodeGenerator codeGenerator)
            {
                PhpTypeCode result;

                codeGenerator.AccessSelector = AccessType.Read;
                codeGenerator.ChainBuilder.Create();
                result = node.LValue.Emit(codeGenerator);
                codeGenerator.ChainBuilder.End();
                codeGenerator.AccessSelector = AccessType.None;

                return(result);
            }
示例#2
0
            public override Evaluation Analyze(AssignEx node, Analyzer analyzer, ExInfoFromParent info)
            {
                access = info.Access;
                ExInfoFromParent lvalue_info = new ExInfoFromParent(node);
                ExInfoFromParent rvalue_info = new ExInfoFromParent(node);

                lvalue_info.Access = AccessType.WriteRef;
                rvalue_info.Access = AccessType.ReadRef;

                var refassignex = (RefAssignEx)node;

                node.lvalue        = (VariableUse)node.LValue.Analyze(analyzer, lvalue_info).Expression;
                refassignex.rvalue = refassignex.RValue.Analyze(analyzer, rvalue_info).Literalize();

                if (refassignex.RValue is NewEx)
                {
                    //PhpException.Throw(PhpError.Deprecated, CoreResources.GetString("assign_new_as_ref_is_deprecated"));
                    analyzer.ErrorSink.Add(Warnings.AssignNewByRefDeprecated, analyzer.SourceUnit, node.Span);
                }

                return(new Evaluation(node));
            }
示例#3
0
 public sealed override void VisitAssignEx(AssignEx x)
 {
     throw new InvalidOperationException();
 }
示例#4
0
 /// <summary>
 /// Visit l-value of assignment.
 /// </summary>
 /// <param name="x"></param>
 virtual public void VisitAssignEx(AssignEx x)
 {
     VisitElement(x.LValue);
 }
示例#5
0
 override public void VisitAssignEx(AssignEx x)
 {
     base.VisitAssignEx(x);
 }
示例#6
0
            public override PhpTypeCode Emit(AssignEx node, CodeGenerator codeGenerator)
            {
                Debug.Assert(access == AccessType.None || access == AccessType.Read || access == AccessType.ReadRef ||
                             access == AccessType.ReadUnknown);
                Statistics.AST.AddNode("Assign.Ref");

                //ChainBuilder.RefErrorLabelInfo labelInfo;

                // Strict Standards: Only variables should be assigned by reference

                /*if (rvalue is FunctionCall)//TODO: only variables (but also variables given by function call return value!)
                 * {
                 *  il.LdcI4( (int)PhpError.Strict );
                 *  il.Emit(OpCodes.Ldstr, CoreResources.GetString("only_vars_assign ed_by_ref"));
                 *  codeGenerator.EmitPhpException(il,Methods.PhpException.Throw);
                 * }*/

                // PREPARE:
                codeGenerator.ChainBuilder.Create();
                node.LValue.Emit(codeGenerator);

                // LOAD <right hand side>:
                codeGenerator.ChainBuilder.Create();
                ((RefAssignEx)node).RValue.Emit(codeGenerator);
                codeGenerator.ChainBuilder.End();

                PhpTypeCode result;

                // Dup source value if assignment is read
                switch (access)
                {
                case AccessType.Read:
                case AccessType.ReadUnknown:
                case AccessType.ReadRef:
                {
                    // DUP
                    codeGenerator.IL.Emit(OpCodes.Dup);

                    // STORE tmp
                    codeGenerator.IL.Stloc(codeGenerator.IL.GetAssignmentLocalRef());

                    // STORE prepared,result
                    VariableUseHelper.EmitAssign(node.LValue, codeGenerator);

                    // LOAD DEREF tmp
                    codeGenerator.IL.Ldloc(codeGenerator.IL.GetAssignmentLocalRef());

                    if (access == AccessType.Read)
                    {
                        codeGenerator.IL.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                        result = PhpTypeCode.Object;
                    }
                    else
                    {
                        result = PhpTypeCode.PhpReference;
                    }
                    break;
                }

                case AccessType.None:
                    VariableUseHelper.EmitAssign(node.LValue, codeGenerator);
                    result = PhpTypeCode.Void;
                    break;

                default:
                    throw new InvalidOperationException();
                    //result = PhpTypeCode.Invalid;
                    //break;
                }
                codeGenerator.ChainBuilder.End();

                return(result);
            }
示例#7
0
            public override Evaluation Analyze(AssignEx node, Analyzer analyzer, ExInfoFromParent info)
            {
                access = info.Access;

                var valueassignex = (ValueAssignEx)node;

                ExInfoFromParent lvalue_info = new ExInfoFromParent(node);

                // x[] = y
                if (node.LValue is ItemUse && ((ItemUse)node.LValue).Index == null)
                {
                    if (node.Operation != Operations.AssignValue)
                    {
                        var oldop = node.Operation;
                        valueassignex.operation = Operations.AssignValue;

                        // x[] .= y -> x[] = null . y
                        if (oldop == Operations.AssignAppend)
                        {
                            valueassignex.rvalue = new BinaryEx(node.Span, Operations.Concat, new NullLiteral(node.Span), valueassignex.rvalue);
                        }
                        // x[] += y -> x[] = 0 + y
                        else if (oldop == Operations.AssignAdd)
                        {
                            valueassignex.rvalue = new BinaryEx(node.Span, Operations.Add, new NullLiteral(node.Span), valueassignex.rvalue);
                        }
                        // x[] -= y -> x[] = 0 - y
                        else if (oldop == Operations.AssignSub)
                        {
                            valueassignex.rvalue = new BinaryEx(node.Span, Operations.Sub, new NullLiteral(node.Span), valueassignex.rvalue);
                        }
                        // x[] *= y -> x[] = 0 * y
                        else if (oldop == Operations.AssignMul)
                        {
                            valueassignex.rvalue = new BinaryEx(node.Span, Operations.Mul, new NullLiteral(node.Span), valueassignex.rvalue);
                        }
                        // x[] **= y -> x[] = 0 * y
                        else if (oldop == Operations.AssignPow)
                        {
                            valueassignex.rvalue = new BinaryEx(node.Span, Operations.Pow, new NullLiteral(node.Span), valueassignex.rvalue);
                        }
                        // x[] /= y -> x[] = 0 / y
                        else if (oldop == Operations.AssignDiv)
                        {
                            valueassignex.rvalue = new BinaryEx(node.Span, Operations.Div, new NullLiteral(node.Span), valueassignex.rvalue);
                        }
                        // x[] &= y -> x[] = 0 & y
                        else if (oldop == Operations.AssignAnd)
                        {
                            valueassignex.rvalue = new BinaryEx(node.Span, Operations.BitAnd, new NullLiteral(node.Span), valueassignex.rvalue);
                        }
                        else
                        {
                            Debug.Fail("Unhandled operation " + oldop.ToString() + " must be reduced!");
                            valueassignex.operation = oldop;  // change it back, this will result in compile time exception
                        }
                    }
                }

                // stop evaluation:
                valueassignex.rvalue = valueassignex.rvalue.Analyze(analyzer, ExInfoFromParent.DefaultExInfo).Literalize();

                if (node.Operation == Operations.AssignValue)
                {
                    // elimination of $x = $x . expr
                    var          concat = valueassignex.rvalue as ConcatEx;
                    DirectVarUse vur;
                    DirectVarUse vul = valueassignex.lvalue as DirectVarUse;

                    if (concat != null && concat.Expressions.Length >= 2 && vul != null && vul.IsMemberOf == null)
                    {
                        if ((vur = concat.Expressions[0] as DirectVarUse) != null && vur.VarName.Equals(vul.VarName) && vur.IsMemberOf == null)
                        {
                            // $x = $x.a.b.c
                            // =>
                            // $x .= a.b.c

                            valueassignex.operation = Operations.AssignAppend;
                            lvalue_info.Access      = AccessType.ReadAndWrite;

                            //rvalue = concat.RightExpr;
                            concat.Expressions = concat.Expressions.TakeArray(1, concat.Expressions.Length - 1);
                        }
                        else if ((vur = concat.Expressions[concat.Expressions.Length - 1] as DirectVarUse) != null && vur.VarName.Equals(vul.VarName) && vur.IsMemberOf == null)
                        {
                            // $x = a.b.c.$x
                            // =>
                            // $x =. a.b.c

                            valueassignex.operation = Operations.AssignPrepend;
                            lvalue_info.Access      = AccessType.ReadAndWrite;

                            //rvalue = (Expression)concat.LeftExpr;
                            concat.Expressions = concat.Expressions.TakeArray(0, concat.Expressions.Length - 1);
                        }
                        else
                        {
                            lvalue_info.Access = AccessType.Write;
                        }
                    }
                    else
                    {
                        lvalue_info.Access = AccessType.Write;
                    }
                }
                else
                {
                    lvalue_info.Access = AccessType.ReadAndWrite;
                }

                // If this ValueAssignEx is actual param that is to be passed by reference,
                // AccessType of the destVar has to be changed, because its reference will be
                // (potencially) passeed
                ActualParam ap = info.Parent as ActualParam;

                if (ap != null)
                {
                    if (analyzer.ActParamDeclIsUnknown())
                    {
                        if (lvalue_info.Access == AccessType.Write)
                        {
                            lvalue_info.Access = AccessType.WriteAndReadUnknown;
                        }
                        else
                        {
                            lvalue_info.Access = AccessType.ReadAndWriteAndReadUnknown;
                        }
                    }
                    else if (analyzer.ActParamPassedByRef())
                    {
                        if (lvalue_info.Access == AccessType.Write)
                        {
                            lvalue_info.Access = AccessType.WriteAndReadRef;
                        }
                        else
                        {
                            lvalue_info.Access = AccessType.ReadAndWriteAndReadRef;
                        }
                    }
                }

                valueassignex.lvalue.Analyze(analyzer, lvalue_info); //retval not needed ...

                return(new Evaluation(node));
            }
示例#8
0
 /// <include file='Doc/Nodes.xml' path='doc/method[@name="IsDeeplyCopied"]/*'/>
 /// <param name="node">Instance.</param>
 /// <returns>
 /// The copy-on-assignment value of the right hand side.
 /// </returns>
 public override bool IsDeeplyCopied(AssignEx node, CopyReason reason, int nestingLevel)
 {
     return(true); // J: once assigned value must be copied again // rvalue.IsDeeplyCopied(reason, nestingLevel + 1);
 }
示例#9
0
            /// <summary>
            /// Emits assignment.
            /// </summary>
            /// <remarks>
            /// Pattern: a op= b
            ///
            /// PREPARE a      (prepared)
            /// LOAD a         (prepared,a)
            /// LOAD b         (prepared,a,b)
            /// OP             (prepared,result)
            /// *DUP           (prepared,result,result)
            /// *STORE tmp     (prepared,result)           must be this stack here!
            /// STORE a        ()
            /// *LOAD tmp      (result)
            ///
            /// * only if the resulting value needs to be propagated to the right
            ///
            /// Note: There is a possible improvement: some store operations (SetVariable) may return the value set
            /// which would replace DUP and second temp op.
            /// </remarks>
            public override PhpTypeCode Emit(AssignEx node, CodeGenerator codeGenerator)
            {
                Debug.Assert(access == AccessType.Read || access == AccessType.None || access == AccessType.ReadRef ||
                             access == AccessType.ReadUnknown);
                Statistics.AST.AddNode("Assign.Value");

                AccessType old_selector = codeGenerator.AccessSelector;

                codeGenerator.ChainBuilder.Create();

                PhpTypeCode result;

                if (node.Operation == Operations.AssignValue)
                {
                    //
                    // Access Type = ReadRef/ReadUnknown
                    // ---------------------------------
                    //
                    // f(&$x) { }
                    //
                    // f($a = $b);
                    // f($a = $b =& $c);
                    //
                    // Destination variable $a is prepared for reference write.
                    // A new reference is created and its value set to a deep copy of the result of RHS ($b, $b =& $c).
                    // RHS has Read access => it has been dereferenced.
                    //

                    // PREPARE a:
                    codeGenerator.AccessSelector = AccessType.Write;
                    node.lvalue.Emit(codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;

                    PhpTypeCode src_type_code = EmitSourceValRead((ValueAssignEx)node, codeGenerator);

                    // RHS should have Read access => should be dereferenced
                    Debug.Assert(src_type_code != PhpTypeCode.PhpReference);

                    // LOAD BOX b
                    codeGenerator.EmitBoxing(src_type_code);

                    // makes a copy if necessary:
                    if (PhpTypeCodeEnum.IsDeeplyCopied(src_type_code))
                    {
                        codeGenerator.EmitVariableCopy(CopyReason.Assigned, ((ValueAssignEx)node).rvalue);
                    }
                }
                else
                {
                    // PREPARE a:
                    codeGenerator.AccessSelector = AccessType.Write;
                    node.LValue.Emit(codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;

                    // LOAD b,a (rvalue must be processed first, than +-*/ with lvalue, since lvalu can be changed by rvalue expression)
                    //must be the second operand// EmitDestVarRead(codeGenerator);
                    PhpTypeCode right_type = EmitSourceValRead((ValueAssignEx)node, codeGenerator);
                    var         rvalue_tmp = codeGenerator.IL.GetTemporaryLocal(PhpTypeCodeEnum.ToType(right_type), false);
                    codeGenerator.IL.Emit(OpCodes.Stloc, rvalue_tmp);
                    EmitDestVarRead(node, codeGenerator);
                    codeGenerator.IL.Emit(OpCodes.Ldloc, rvalue_tmp);
                    codeGenerator.IL.ReturnTemporaryLocal(rvalue_tmp);

                    switch (node.Operation)
                    {
                        #region Arithmetic

                    case Operations.AssignAdd:
                    {
                        switch (right_type)
                        {
                        case PhpTypeCode.Integer:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Int32);
                            break;

                        case PhpTypeCode.Double:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Double);
                            break;

                        default:
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Object);
                            break;
                        }
                        break;
                    }

                    case Operations.AssignSub:
                    {
                        switch (right_type)
                        {
                        case PhpTypeCode.Integer:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Int);
                            break;

                        default:
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Object);
                            break;
                        }
                        break;
                    }

                    case Operations.AssignDiv:
                    {
                        switch (right_type)
                        {
                        case PhpTypeCode.Integer:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Int32);
                            break;

                        case PhpTypeCode.Double:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Double);
                            break;

                        default:
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Object);
                            break;
                        }
                        break;
                    }

                    case Operations.AssignMul:
                    {
                        switch (right_type)
                        {
                        case PhpTypeCode.Integer:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Int32);
                            break;

                        case PhpTypeCode.Double:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Double);
                            break;

                        default:
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Object);
                            break;
                        }
                        break;
                    }

                    case Operations.AssignPow:
                        codeGenerator.EmitBoxing(right_type);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.Pow.Object_Object);
                        break;

                    case Operations.AssignMod:

                        if (right_type == PhpTypeCode.Integer)
                        {
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Int32);
                        }
                        else
                        {
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Object);
                        }
                        break;


                        #endregion

                        #region Bitwise

                    case Operations.AssignAnd:
                        codeGenerator.EmitBoxing(right_type);
                        codeGenerator.IL.Emit(OpCodes.Ldc_I4, (int)Operators.BitOp.And);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.BitOperation);
                        break;

                    case Operations.AssignOr:
                        codeGenerator.EmitBoxing(right_type);
                        codeGenerator.IL.Emit(OpCodes.Ldc_I4, (int)Operators.BitOp.Or);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.BitOperation);
                        break;

                    case Operations.AssignXor:
                        codeGenerator.EmitBoxing(right_type);
                        codeGenerator.IL.Emit(OpCodes.Ldc_I4, (int)Operators.BitOp.Xor);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.BitOperation);
                        break;

                    case Operations.AssignShiftLeft:
                        codeGenerator.EmitBoxing(right_type);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.ShiftLeft);
                        break;

                    case Operations.AssignShiftRight:
                        codeGenerator.EmitBoxing(right_type);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.ShiftRight);
                        break;

                        #endregion

                        #region String

                    case Operations.AssignAppend:
                    {
                        if (right_type == PhpTypeCode.String)
                        {
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Append.Object_String);
                        }
                        else if (right_type == PhpTypeCode.PhpBytes)
                        {
                            result = codeGenerator.EmitMethodCall(Methods.PhpBytes.Append_Object_PhpBytes);
                        }
                        else
                        {
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Append.Object_Object);
                        }
                        break;
                    }

                    case Operations.AssignPrepend:
                    {
                        if (right_type == PhpTypeCode.String)
                        {
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Prepend.Object_String);
                        }
                        else
                        {
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Prepend.Object_Object);
                        }
                        break;
                    }

                        #endregion

                    default:
                        throw new InvalidOperationException();
                    }

                    codeGenerator.IL.EmitBoxing(result);
                }

                switch (access)
                {
                case AccessType.Read:
                {
                    // DUP
                    codeGenerator.IL.Emit(OpCodes.Dup);

                    // STORE tmp
                    codeGenerator.IL.Stloc(codeGenerator.IL.GetAssignmentLocal());

                    // STORE prepared, result
                    codeGenerator.AccessSelector = AccessType.Write;
                    result = VariableUseHelper.EmitAssign(node.LValue, codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;
                    Debug.Assert(result == PhpTypeCode.Void);

                    // LOAD result
                    codeGenerator.IL.Ldloc(codeGenerator.IL.GetAssignmentLocal());

                    result = PhpTypeCode.Object;
                    break;
                }

                case AccessType.ReadRef:
                case AccessType.ReadUnknown:

                    // STORE prepared,result
                    codeGenerator.AccessSelector = AccessType.Write;
                    result = VariableUseHelper.EmitAssign(node.LValue, codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;
                    Debug.Assert(result == PhpTypeCode.Void);

                    // loads a reference on the LHS variable:
                    codeGenerator.AccessSelector = access;
                    codeGenerator.ChainBuilder.Create();
                    result = node.LValue.Emit(codeGenerator);
                    codeGenerator.ChainBuilder.EndRef();
                    codeGenerator.AccessSelector = AccessType.None;
                    break;

                case AccessType.None:

                    // STORE a:
                    codeGenerator.AccessSelector = AccessType.Write;
                    result = VariableUseHelper.EmitAssign(node.LValue, codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;
                    Debug.Assert(result == PhpTypeCode.Void);

                    break;

                default:
                    Debug.Fail("Invalid access type.");
                    result = PhpTypeCode.Invalid;
                    break;
                }

                codeGenerator.ChainBuilder.End();

                codeGenerator.AccessSelector = old_selector;

                return(result);
            }