Example #1
0
        /// <summary>
        /// Emits code to load a reference to a variable onto an evaluation stack.  Supports operators chaining.
        /// </summary>
        /// <param name="codeGenerator"></param>
        private PhpTypeCode EmitNodeReadRef(CodeGenerator codeGenerator)
        {
            ChainBuilder chain = codeGenerator.ChainBuilder;
            LocalBuilder local = codeGenerator.IL.DeclareLocal(typeof(object));

            // Case 3: a_[x]_[x] never reached
            Debug.Assert(chain.IsArrayItem == false, "ReadRef access shouldn't be set to array subchain nodes");

            // Case 4,5 never reached
            // 4: a[x]->...
            // 5: ...->a[]->...
            Debug.Assert(chain.IsMember == false);

            // 1, 2, 6, 7
            if (this.isMemberOf != null)
            {
                // last node of the field chain //

                // 6 , 7: ...->a[]_[]_ , ...->a_[]_
                chain.Create();
                chain.Begin();
                if (this.isMemberOf is FunctionCall)
                {
                    chain.LoadAddressOfFunctionReturnValue = true;
                }

                chain.SetObjectForLazyEmit(this);

                // let's emit the array subchain followed by the GetArrayItemRef:
                chain.IsArrayItem  = true;
                chain.IsLastMember = false;
                chain.Lengthen();                 // for own []
                chain.EmitGetArrayItemRef(array, index);
                chain.IsArrayItem = false;
                chain.EndRef();
                return(PhpTypeCode.PhpReference);
            }

            // 1, 2
            if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse)
            {
                // we are at the beginning of the field chain //

                // 2: a[]_[]_
                chain.Create();
                chain.Begin();
                chain.IsArrayItem  = true;
                chain.IsLastMember = true;
                chain.Lengthen();
                chain.EmitGetArrayItemRef(array, index);
                chain.IsArrayItem = false;
                chain.EndRef();
                return(PhpTypeCode.PhpReference);
            }

            // no chains //

            // 1: a_[x]_
            return(chain.EmitGetItemRef((SimpleVarUse)array, index));
        }
Example #2
0
        /// <summary>
        /// Emits code to prepare an evaluation stack for storing a reference into a variable.
        /// Supports operators chaining. Store is finished by calling <see cref="EmitAssign"/>.
        /// </summary>
        /// <param name="codeGenerator"></param>
        private PhpTypeCode EmitNodeWriteRef(CodeGenerator codeGenerator)
        {
            ChainBuilder chain = codeGenerator.ChainBuilder;

            // Case 3: a_[x]_[x] never reached
            Debug.Assert(chain.IsArrayItem == false);

            // Case 4,5 never reached
            // 4: a[x]->...
            // 5: ...->a[]->...
            Debug.Assert(chain.IsMember == false);

            // 1, 2, 6, 7
            if (this.isMemberOf != null)
            {
                // 6, 7: ...->a[x]_[x]_
                chain.Create();
                chain.Begin();
                // Store isMemberOf for lazy emit
                chain.SetObjectForLazyEmit(this);
                chain.IsArrayItem  = true;
                chain.IsLastMember = false;
                chain.Lengthen();                 // for own []
                array.Emit(codeGenerator);
                indexTypeCode = codeGenerator.EmitArrayKey(chain, index);

                // Note that EmitAssign will finish the work (SetArrayItem or PhpArray.Add)
            }
            else
            {
                // 1, 2
                Debug.Assert(this.isMemberOf == null);

                if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */)
                {
                    // 2: a[]_[]_
                    chain.Create();
                    chain.Begin();
                    chain.IsArrayItem  = true;
                    chain.IsLastMember = true;
                    array.Emit(codeGenerator);
                    indexTypeCode = codeGenerator.EmitArrayKey(chain, index);

                    // Note that further work will be done by EmitAssign (SetArrayItem or PhpArray.Add)
                }
                // 1: a_[x]_
                // Do nothing now, let the work be done in EmitAssign()
                // Note further work will be done by EmitAssign (either SetItem or SetItemRef);
            }
            return(PhpTypeCode.Unknown);
        }
Example #3
0
        internal override void EmitUnset(CodeGenerator codeGenerator)
        {
            ChainBuilder chain = codeGenerator.ChainBuilder;

            // Template: "unset(x[y])"  Operators.UnsetItem(object obj,object index)

            // Case 3: a_[x]_[x] never reached
            Debug.Assert(chain.IsArrayItem == false);
            // Case 4,5 never reached
            // 4: a[x]->...
            // 5: ...->a[]->...
            Debug.Assert(chain.IsMember == false);

            chain.QuietRead = true;

            // 1, 2, 6, 7
            if (this.isMemberOf != null)
            {
                // 6 , 7: ...->a[]_[]_ , ...->a_[]_
                chain.Create();
                chain.Begin();
                chain.Lengthen();                 // for hop over ->
                isMemberOf.Emit(codeGenerator);
                chain.IsArrayItem  = true;
                chain.IsLastMember = false;
                chain.EmitUnsetItem(array, index);
                chain.IsArrayItem = false;
                chain.End();
                return;
            }
            // 1, 2
            if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */)
            {
                // 2: a[]_[]_
                chain.Create();
                chain.Begin();
                chain.IsArrayItem  = true;
                chain.IsLastMember = true;
                chain.EmitUnsetItem(array, index);
                chain.IsArrayItem = false;
                chain.End();
                return;
            }
            // 1: a_[x]_
            chain.IsArrayItem  = true;
            chain.IsLastMember = true;
            chain.EmitUnsetItem(array, index);
            chain.IsArrayItem = false;
        }
Example #4
0
        private PhpTypeCode EmitNodeWrite(CodeGenerator codeGenerator)
        {
            ChainBuilder chain = codeGenerator.ChainBuilder;

            if (chain.IsMember)
            {
                // 1,4,5,6,9
                if (this.isMemberOf != null)
                {
                    // 1:  ...->a->...
                    chain.Lengthen();
                    chain.EmitEnsureProperty(isMemberOf, this, false);
                    return(PhpTypeCode.DObject);
                }
                if (chain.IsArrayItem)
                {
                    // 4,6
                    if (chain.IsLastMember)
                    {
                        // 4: a[][]
                        chain.EmitEnsureVariableIsArray(this);
                    }
                    else
                    {
                        // 6: $b->a[3]
                        ChainBuilder.ObjectFieldLazyEmitInfo object_info = chain.GetObjectForLazyEmit();
                        // Lengthen for hop over ->
                        chain.EmitEnsureProperty(object_info.ObjectForLazyEmit, this, true);
                        chain.ReleaseObjectForLazyEmit(object_info);
                        chain.IsArrayItem  = true;
                        chain.IsLastMember = false;
                    }

                    return(PhpTypeCode.PhpArray);
                }
                if (chain.Exists)
                {
                    // 5: $a->b->c->...
                    chain.EmitEnsureVariableIsObject(this);
                    return(PhpTypeCode.DObject);
                }
                else
                {
                    // 9: $a->b
                    this.EmitLoadAddress(codeGenerator);
                    return(PhpTypeCode.ObjectAddress);
                }
            }
            // 2,3,7,8
            if (this.isMemberOf != null)
            {
                // 2: $b->a
                // 8: b[]->a
                chain.Create();
                chain.Begin();
                assignmentCallback = EmitWriteField(codeGenerator, false);
                // Note: more work is done in EmitAssign

                // some data are preloaded but nothing that can be consumed is loaded on stack:
                return(PhpTypeCode.Unknown);
            }
            // 3,7
            if (codeGenerator.ChainBuilder.IsArrayItem)
            {
                // 3: a[3]
                EmitLoadAddress(codeGenerator);
                return(PhpTypeCode.ObjectAddress);
            }
            else
            {
                // 7: $a
                EmitStorePrepare(codeGenerator);
                return(PhpTypeCode.Unknown);
            }
        }
Example #5
0
            private PhpTypeCode EmitNodeWrite(IndirectVarUse node, CodeGenerator codeGenerator)
            {
                ChainBuilder chain = codeGenerator.ChainBuilder;

                if (chain.IsMember)
                {
                    // 1,4,5,6,9
                    if (node.IsMemberOf != null)
                    {
                        // 1:  ...->$a->...
                        chain.Lengthen();
                        chain.EmitEnsureProperty(node.IsMemberOf, node, false);
                        return(PhpTypeCode.DObject);
                    }

                    if (chain.IsArrayItem)
                    {
                        // 4,6
                        if (chain.IsLastMember)
                        {
                            // 4: ${"a"}[][]
                            chain.EmitEnsureVariableIsArray(node);
                            return(PhpTypeCode.PhpArray);
                        }
                        else
                        {
                            // 6: $b->${"a"}[3]
                            ChainBuilder.ObjectFieldLazyEmitInfo object_info = chain.GetObjectForLazyEmit();
                            // Lengthen for hop over ->
                            chain.EmitEnsureProperty(object_info.ObjectForLazyEmit, node, true);
                            chain.ReleaseObjectForLazyEmit(object_info);
                            chain.IsArrayItem  = true;
                            chain.IsLastMember = false;
                            return(PhpTypeCode.PhpArray);
                        }
                    }

                    if (chain.Exists)
                    {
                        // 5: $$a->b->c->...
                        chain.EmitEnsureVariableIsObject(node);
                        return(PhpTypeCode.DObject);
                    }
                    else
                    {
                        // 9: $$a->b
                        this.EmitLoadAddress(node, codeGenerator);
                        return(PhpTypeCode.ObjectAddress);
                    }
                }

                // 2,3,7,8
                if (node.IsMemberOf != null)
                {
                    // 2: $b->a
                    // 8: b[]->a
                    chain.Create();
                    chain.Begin();
                    assignmentCallback = EmitWriteField(node, codeGenerator, false);
                    // Note: more work is done in EmitAssign
                    return(PhpTypeCode.Unknown);
                }

                // 3,7
                if (codeGenerator.ChainBuilder.IsArrayItem)
                {
                    // 3: ${"a"}[3]
                    this.EmitLoadAddress(node, codeGenerator);
                    return(PhpTypeCode.ObjectAddress);
                }

                // 7: $a
                //codeGenerator.EmitVariableStorePrepare(this);
                this.EmitStorePrepare(node, codeGenerator);
                return(PhpTypeCode.Unknown);
            }
Example #6
0
        /// <summary>
        /// Emits code to prepare an evaluation stack for storing a value into a variable.
        /// Supports operators chaining. Store is finished by calling <see cref="EmitAssign"/>.
        /// </summary>
        /// <param name="codeGenerator"></param>
        private PhpTypeCode EmitNodeWrite(CodeGenerator codeGenerator)
        {
            ChainBuilder chain = codeGenerator.ChainBuilder;

            if (chain.IsArrayItem)
            {
                // 3: a_[x]_[v]
                Debug.Assert(this.isMemberOf == null);
                return(chain.EmitEnsureItem(array, index, true));
            }

            // 1, 2, 4, 5, 6, 7
            if (chain.IsMember)
            {
                // 4, 5
                if (this.isMemberOf != null)
                {
                    // 5: ...->a[]->...
                    // Store isMemberOf for lazy emit
                    chain.SetObjectForLazyEmit(this);
                    chain.IsArrayItem  = true;
                    chain.IsLastMember = false;
                }
                else
                {
                    // 4: a_[x]_->c->..., a[x]_[x]_->c->...
                    chain.IsArrayItem  = true;
                    chain.IsLastMember = true;
                }

                PhpTypeCode result = chain.EmitEnsureItem(array, index, false);
                chain.IsArrayItem = false;
                return(result);
            }

            // 1, 2, 6, 7
            if (this.isMemberOf != null)
            {
                // 6, 7: ...->a[x]_[x]_
                chain.Create();
                chain.Begin();
                // Store isMemberOf for lazy emit
                chain.SetObjectForLazyEmit(this);
                chain.IsArrayItem  = true;
                chain.IsLastMember = false;
                chain.Lengthen();                 // for own []
                array.Emit(codeGenerator);
                indexTypeCode = codeGenerator.EmitArrayKey(chain, index);

                // Note that EmitAssign will finish the work (SetArrayItem or PhpArray.Add)
                return(PhpTypeCode.Unknown);
            }
            // 1, 2
            Debug.Assert(this.isMemberOf == null);

            if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */)
            {
                // 2: a[]_[]_
                chain.Create();
                chain.Begin();
                chain.IsArrayItem  = true;
                chain.IsLastMember = true;
                array.Emit(codeGenerator);
                indexTypeCode = codeGenerator.EmitArrayKey(chain, index);


                // Note that further work will be done by EmitAssign (SetArrayItem or PhpArray.Add)
                return(PhpTypeCode.Unknown);
            }

            // 1: a_[x]_
            // Do nothing now, let the work be done in EmitAssign()
            return(PhpTypeCode.Unknown);
        }
Example #7
0
        /// <summary>
        /// Emits code to load <see cref="PhpRuntimeChain"/> onto an evaluation stack. Supports operators chaining.
        /// </summary>
        /// <param name="codeGenerator"></param>
        private PhpTypeCode EmitNodeReadUnknown(CodeGenerator codeGenerator)
        {
            ChainBuilder chain  = codeGenerator.ChainBuilder;
            PhpTypeCode  result = PhpTypeCode.PhpRuntimeChain;

            if (chain.IsArrayItem)
            {
                // 3: a_[x]_[x]
                chain.Lengthen();                 // for []
                chain.EmitRTChainAddItem(this);
                return(result);
            }
            // 1,2,4,5,6,7
            if (chain.IsMember)
            {
                // 4, 5
                if (this.isMemberOf != null)
                {
                    // 5: ...->a[]->...

                    // Lengthen chain for isMemberOf
                    chain.Lengthen();                     // for hop over ->
                    PhpTypeCode res = isMemberOf.Emit(codeGenerator);
                    if (res != PhpTypeCode.PhpRuntimeChain)
                    {
                        codeGenerator.EmitBoxing(res);
                        chain.EmitCreateRTChain();
                    }
                    // Lengthen chain for own []
                    chain.Lengthen();
                    chain.IsArrayItem  = true;
                    chain.IsLastMember = false;
                    chain.EmitRTChainAddItem(this);
                    chain.IsArrayItem = false;
                    return(result);
                }
                // 4: a[x]->...
                // Lengthen chain for itself
                chain.Lengthen();                 // for own []
                chain.IsArrayItem  = true;
                chain.IsLastMember = true;
                chain.EmitRTChainAddItem(this);
                chain.IsArrayItem = false;
                return(result);
            }
            // 1, 2, 6, 7
            if (this.isMemberOf != null)
            {
                // 6 , 7: ...->a[]_[]_ , ...->a_[]_
                bool quiet_read = chain.QuietRead;
                chain.Create();
                chain.Begin();
                chain.QuietRead = quiet_read;
                chain.Lengthen();                 // for hop over ->
                PhpTypeCode res = isMemberOf.Emit(codeGenerator);
                if (res != PhpTypeCode.PhpRuntimeChain)
                {
                    codeGenerator.EmitBoxing(res);
                    chain.EmitCreateRTChain();
                }
                chain.IsArrayItem  = true;
                chain.IsLastMember = false;
                chain.EmitRTChainAddItem(this);
                chain.IsArrayItem = false;
                chain.End();
                return(result);
            }
            // 1, 2
            if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */)
            {
                // 2: a[]_[]_
                bool quiet_read = chain.QuietRead;
                chain.Create();
                chain.Begin();
                chain.QuietRead    = quiet_read;
                chain.IsArrayItem  = true;
                chain.IsLastMember = true;
                chain.EmitRTChainAddItem(this);
                chain.IsArrayItem = false;
                chain.End();
                return(result);
            }
            // 1: a_[x]_
            chain.IsArrayItem  = true;
            chain.IsLastMember = true;
            chain.EmitRTChainAddItem(this);
            chain.IsArrayItem = false;
            return(result);
        }
Example #8
0
        /// <summary>
        /// Emits code to load variable onto the evaluation stack. Supports operators chaining.
        /// </summary>
        /// <param name="codeGenerator">A geenrator.</param>
        /// <param name="itemGetterKind">Whether to load for "get", "isset", or "empty".</param>
        private PhpTypeCode EmitNodeRead(CodeGenerator /*!*/ codeGenerator, Operators.GetItemKinds itemGetterKind)
        {
            ChainBuilder chain = codeGenerator.ChainBuilder;
            PhpTypeCode  result;

            if (chain.IsArrayItem)
            {
                // we are in the array subchain //

                // 3: a_[x]_[x]
                chain.Lengthen();                 // for []
                result = chain.EmitGetItem(array, index, itemGetterKind);
                return(result);
            }

            // 1,2,4,5,6,7
            if (chain.IsMember)
            {
                // we are in the field chain //

                // 4, 5
                if (this.isMemberOf != null)
                {
                    // we are in the middle of the field chain //

                    // 5: ...->a[]->...

                    // Lengthen chain for isMemberOf
                    chain.Lengthen();                     // for hop over ->

                    isMemberOf.Emit(codeGenerator);

                    // Lengthen chain for own []
                    chain.Lengthen();

                    chain.IsArrayItem  = true;
                    chain.IsLastMember = false;

                    result = chain.EmitGetItem(array, index, itemGetterKind);

                    chain.IsArrayItem = false;
                    return(result);
                }
                else
                {
                    // we are at the beginning of the field chain //

                    // 4: a[x]->...
                    // Lengthen chain for itself
                    chain.Lengthen();                     // for own []
                    chain.IsArrayItem  = true;
                    chain.IsLastMember = true;

                    result = chain.EmitGetItem(array, index, itemGetterKind);

                    chain.IsArrayItem = false;
                    return(result);
                }
            }

            // 1, 2, 6, 7
            if (this.isMemberOf != null)
            {
                // last node of the field chain //

                // 6 , 7: ...->a[]_[]_ , ...->a_[]_
                bool quiet_read = chain.QuietRead;
                chain.Create();
                chain.Begin();
                chain.QuietRead = quiet_read;
                chain.Lengthen();                 // for hop over ->

                isMemberOf.Emit(codeGenerator);

                // let's emit the array subchain followed by the GetItem:
                chain.IsArrayItem  = true;
                chain.IsLastMember = false;
                result             = chain.EmitGetItem(array, index, itemGetterKind);
                chain.IsArrayItem  = false;
                chain.End();
                return(result);
            }

            // 1, 2
            if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse)
            {
                // we are at the beginning of the field chain //

                // 2: a[]_[]_
                bool quiet_read = chain.QuietRead;
                chain.Create();
                chain.Begin();
                chain.QuietRead    = quiet_read;
                chain.IsArrayItem  = true;
                chain.IsLastMember = true;

                result = chain.EmitGetItem(array, index, itemGetterKind);

                chain.IsArrayItem = false;
                chain.End();
                return(result);
            }

            // no chains //

            // 1: a_[x]_
            chain.IsArrayItem  = true;
            chain.IsLastMember = true;
            result             = chain.EmitGetItem(array, index, itemGetterKind);
            chain.IsArrayItem  = false;
            return(result);
        }