Beispiel #1
0
        public BoundPrimitiveTypeRef(PhpTypeCode type)
        {
            _type = type;

            //
            IsNullable = type == PhpTypeCode.Null || type == PhpTypeCode.Mixed;
        }
Beispiel #2
0
        public MethodInfo EmitLambda(string name, AST.DirectVarUse variable, AST.Expression /*!*/ expression,
                                     PhpTypeCode returnType)
        {
            MethodBuilder result = linqContextBuilder.DefineMethod(name, MethodAttributes.PrivateScope | MethodAttributes.SpecialName,
                                                                   PhpTypeCodeEnum.ToType(returnType), new Type[] { typeof(object) });

            ILEmitter il = new ILEmitter(result);

            EnterLambdaDeclaration(il);

            if (variable != null)
            {
                // <variable> = COPY(<argument>);
                variable.Emit(cg);
                il.Emit(OpCodes.Ldarg_1);
                cg.EmitVariableCopy(CopyReason.Assigned, null);
                variable.EmitAssign(cg);
            }

            cg.EmitConversion(expression, returnType);
            il.Emit(OpCodes.Ret);

            LeaveLambdaDeclaration();

            return(result);
        }
Beispiel #3
0
		public MethodInfo EmitLambda(string name, AST.DirectVarUse variable, AST.Expression/*!*/ expression,
			PhpTypeCode returnType)
		{
			MethodBuilder result = linqContextBuilder.DefineMethod(name, MethodAttributes.PrivateScope | MethodAttributes.SpecialName,
				PhpTypeCodeEnum.ToType(returnType), new Type[] { typeof(object) });

			ILEmitter il = new ILEmitter(result);

			EnterLambdaDeclaration(il);

			if (variable != null)
			{
				// <variable> = COPY(<argument>);
				variable.Emit(cg);
				il.Emit(OpCodes.Ldarg_1);
				cg.EmitVariableCopy(CopyReason.Assigned, null);
				variable.EmitAssign(cg);
			}

			cg.EmitConversion(expression, returnType);
			il.Emit(OpCodes.Ret);

			LeaveLambdaDeclaration();

			return result;
		}
Beispiel #4
0
        /// <summary>
        /// Emits code for loading the variable's value as a <see cref="PhpReference"/>. This function is called only
        /// by first AST node in chain.
        /// </summary>
        /// <param name="codeGenerator"></param>
        private PhpTypeCode EmitNodeReadRef(CodeGenerator codeGenerator)
        {
            // Cases 1, 4, 5, 6, 9 never reached
            Debug.Assert(codeGenerator.ChainBuilder.IsMember == false);

            // Case 3 never reached
            Debug.Assert(codeGenerator.ChainBuilder.IsArrayItem == false);

            // 2, 7, 8
            if (this.isMemberOf != null)
            {
                // 2: $b->a
                // 8: b[]->a
                codeGenerator.ChainBuilder.Create();
                codeGenerator.ChainBuilder.Begin();
                if (this.isMemberOf is FunctionCall)
                {
                    codeGenerator.ChainBuilder.LoadAddressOfFunctionReturnValue = true;
                }

                PhpTypeCode type_code = EmitReadField(codeGenerator, true);
                Debug.Assert(type_code == PhpTypeCode.PhpReference);

                codeGenerator.ChainBuilder.EndRef();
                return(PhpTypeCode.PhpReference);
            }

            // 7: $a
            EmitLoadRef(codeGenerator);
            return(PhpTypeCode.PhpReference);
        }
Beispiel #5
0
        /// <summary>
        /// Retrieves <see cref="Type"/> from a specified <see cref="PhpTypeCode"/>.
        /// </summary>
        public static Type ToType(PhpTypeCode code)
        {
            switch (code)
            {
            case PhpTypeCode.String: return(Types.String[0]);

            case PhpTypeCode.Integer: return(Types.Int[0]);

            case PhpTypeCode.LongInteger: return(Types.LongInt[0]);

            case PhpTypeCode.Boolean: return(Types.Bool[0]);

            case PhpTypeCode.Double: return(Types.Double[0]);

            case PhpTypeCode.Object: return(Types.Object[0]);

            case PhpTypeCode.PhpReference: return(Types.PhpReference[0]);

            case PhpTypeCode.PhpArray: return(Types.PhpArray[0]);

            case PhpTypeCode.DObject: return(Types.DObject[0]);

            case PhpTypeCode.PhpResource: return(typeof(PhpResource));

            case PhpTypeCode.PhpBytes: return(typeof(PhpBytes));

            case PhpTypeCode.PhpString: return(typeof(PhpString));

            case PhpTypeCode.Void: return(Types.Void);

            case PhpTypeCode.LinqSource: return(Types.IEnumerableOfObject);

            default: return(null);
            }
        }
            private PhpTypeCode EmitNodeReadRef(IndirectVarUse node, CodeGenerator codeGenerator)
            {
                // Cases 1, 4, 5, 6, 9 never reached
                Debug.Assert(codeGenerator.ChainBuilder.IsMember == false);

                // Case 3 never reached
                Debug.Assert(codeGenerator.ChainBuilder.IsArrayItem == false);

                // 2, 7, 8
                if (node.IsMemberOf != null)
                {
                    // 2: $b->a
                    // 8: b[]->a
                    codeGenerator.ChainBuilder.Create();
                    codeGenerator.ChainBuilder.Begin();
                    if (node.IsMemberOf is FunctionCall)
                    {
                        codeGenerator.ChainBuilder.LoadAddressOfFunctionReturnValue = true;
                    }
                    PhpTypeCode result = EmitReadField(node, codeGenerator, true);
                    codeGenerator.ChainBuilder.EndRef();

                    Debug.Assert(result == PhpTypeCode.PhpReference);
                }
                else
                {
                    // 7: $a
                    //codeGenerator.EmitVariableLoadRef(this);
                    EmitLoadRef(node, codeGenerator);
                }

                return(PhpTypeCode.PhpReference);
            }
        private PhpTypeCode EmitNodeReadUnknown(CodeGenerator codeGenerator)
        {
            if (codeGenerator.ChainBuilder.IsMember)
            {
                // 1,4,5,6,9
                if (this.isMemberOf != null)
                {
                    // 1: ...->$a->...
                    codeGenerator.ChainBuilder.Lengthen();                     // for hop over ->
                    PhpTypeCode res = isMemberOf.Emit(codeGenerator);
                    if (res != PhpTypeCode.PhpRuntimeChain)
                    {
                        codeGenerator.EmitBoxing(res);
                        codeGenerator.ChainBuilder.EmitCreateRTChain();
                    }
                    codeGenerator.ChainBuilder.EmitRTChainAddField(this);
                    return(PhpTypeCode.PhpRuntimeChain);
                }

                if (codeGenerator.ChainBuilder.IsArrayItem && !codeGenerator.ChainBuilder.IsLastMember)
                {
                    // 6: $b->${"a"}[3]
                    codeGenerator.ChainBuilder.EmitRTChainAddField(this);
                    return(PhpTypeCode.PhpRuntimeChain);
                }

                // 4: ${"a"}[][]
                // 5: $$a->b->c->...
                // 9: $$a->b
                this.EmitLoadRef(codeGenerator);
                codeGenerator.ChainBuilder.EmitCreateRTChain();
                return(PhpTypeCode.PhpRuntimeChain);
            }
            // 2,3,7,8
            if (this.isMemberOf != null)
            {
                // 2: $b->$a
                // 8: b[]->$a
                codeGenerator.ChainBuilder.Create();
                codeGenerator.ChainBuilder.Begin();
                codeGenerator.ChainBuilder.Lengthen();                 // for hop over ->
                PhpTypeCode res = isMemberOf.Emit(codeGenerator);
                if (res != PhpTypeCode.PhpRuntimeChain)
                {
                    codeGenerator.EmitBoxing(res);
                    codeGenerator.ChainBuilder.EmitCreateRTChain();
                }
                codeGenerator.ChainBuilder.EmitRTChainAddField(this);
                codeGenerator.ChainBuilder.End();
                return(PhpTypeCode.PhpRuntimeChain);
            }

            // 3: ${"a"}[3]
            // 7: $$a
            this.EmitLoadRef(codeGenerator);
            return(PhpTypeCode.PhpReference);
        }
Beispiel #8
0
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal PhpTypeCode Emit(CodeGenerator /*!*/ codeGenerator)
        {
            codeGenerator.ChainBuilder.Create();
            PhpTypeCode result = expression.Emit(codeGenerator);

            codeGenerator.ChainBuilder.End();

            return(result);
        }
Beispiel #9
0
 /// <summary>
 /// <c>True</c> iff given <paramref name="code"/> represents value that can be copied (is IPhpCloneable and implements some logic in Copy method).
 /// </summary>
 /// <param name="code"><see cref="PhpTypeCode"/>.</param>
 /// <returns>Wheter given <paramref name="code"/> represents value that can be copied.</returns>
 internal static bool IsDeeplyCopied(PhpTypeCode code)
 {
     return
         (code != PhpTypeCode.Void &&
          code != PhpTypeCode.String &&
          code != PhpTypeCode.Boolean &&
          code != PhpTypeCode.Double &&
          code != PhpTypeCode.Integer &&
          code != PhpTypeCode.LongInteger &&
          code != PhpTypeCode.PhpResource);
 }
Beispiel #10
0
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override PhpTypeCode Emit(CodeGenerator /*!*/ codeGenerator)
        {
            Statistics.AST.AddNode("IndirectVarUse");
            PhpTypeCode result = PhpTypeCode.Invalid;

            switch (codeGenerator.SelectAccess(access))
            {
            // This case occurs everytime we want to get current variable value
            // All we do is push the value onto the IL stack
            case AccessType.Read:                     // Push value onto a IL stack
                result = EmitNodeRead(codeGenerator);
                break;

            // This case occurs when the varible is written ($a = $b, then $a has Write mark)
            // We only prepare the stack for storing, the work will be done later,
            // by EmitAssign()
            case AccessType.Write:
                result = EmitNodeWrite(codeGenerator);
                break;

            case AccessType.None:
                EmitNodeRead(codeGenerator);
                codeGenerator.IL.Emit(OpCodes.Pop);
                result = PhpTypeCode.Void;
                break;

            case AccessType.ReadRef:
                // if the selector is set to the ReadRef, the chain is emitted as if it was written
                // (chained nodes are marked as ReadAndWrite):
                if (codeGenerator.AccessSelector == AccessType.ReadRef)
                {
                    codeGenerator.AccessSelector = AccessType.Write;
                }

                result = EmitNodeReadRef(codeGenerator);
                Debug.Assert(result == PhpTypeCode.PhpReference);
                break;

            case AccessType.ReadUnknown:
                result = EmitNodeReadUnknown(codeGenerator);
                break;

            case AccessType.WriteRef:
                EmitNodeWriteRef(codeGenerator);
                result = PhpTypeCode.PhpReference;
                break;

            default:
                result = PhpTypeCode.Invalid;
                Debug.Fail();
                break;
            }
            return(result);
        }
Beispiel #11
0
        /// <summary>
        /// Emits code that loads a specified parameter on the evaluation stack.
        /// </summary>
        /// <param name="paramInfo">The parameter to load.</param>
        /// <param name="requiredTypeCode">Specifies whether <see cref="PhpReference"/>
        /// (<see cref="PhpTypeCode.PhpReference"/>), <see cref="object"/> (<see cref="PhpTypeCode.Object"/>),
        /// or the most fitting of these two should be loaded.</param>
        public void EmitLoadClrParameter(ParameterInfo /*!*/ paramInfo, PhpTypeCode requiredTypeCode)
        {
            if (paramInfo.IsOut)
            {
                il.Emit(OpCodes.Ldnull);
            }
            else
            {
                il.Ldarg(paramInfo.Position + paramOffset);

                // dereference ref param
                Type param_type = paramInfo.ParameterType;
                if (param_type.IsByRef)
                {
                    param_type = param_type.GetElementType();

                    il.Ldind(param_type);
                }

                // convert the parameter to PHP type
                PhpTypeCode type_code = ClrOverloadBuilder.EmitConvertToPhp(
                    il,
                    param_type /*,
                                * scriptContextPlace*/);

                il.EmitBoxing(type_code);
            }

            // check whether we have to create a PhpReference
            if (requiredTypeCode == PhpTypeCode.Object ||
                (requiredTypeCode == PhpTypeCode.Unknown && !paramInfo.ParameterType.IsByRef))
            {
                return;
            }

            if (paramInfo.ParameterType.IsByRef)
            {
                LocalBuilder ref_local = il.DeclareLocal(Types.PhpReference[0]);

                // remember the PhpReference in a local
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
                il.Emit(OpCodes.Dup);
                il.Stloc(ref_local);

                referenceLocals[paramInfo.Position] = ref_local;
            }
            else
            {
                // no reference store-back is necessary
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
            }
        }
Beispiel #12
0
            public override PhpTypeCode Emit(ArrayEx node, CodeGenerator codeGenerator)
            {
                Debug.Assert(access == AccessType.Read || access == AccessType.None);
                ILEmitter il = codeGenerator.IL;

                // count integer and string keys:
                int int_count    = 0;
                int string_count = 0;

                DetermineCapacities(node, out int_count, out string_count);

                // array = new PhpArray(<int_count>, <string_count>);
                il.Emit(OpCodes.Ldc_I4, int_count);
                il.Emit(OpCodes.Ldc_I4, string_count);
                il.Emit(OpCodes.Newobj, Constructors.PhpArray.Int32_Int32);

                if (codeGenerator.Context.Config.Compiler.Debug)
                {
                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Nop);
                }

                foreach (var item in node.Items)
                {
                    var itemcompiler = item.NodeCompiler <ItemCompiler>();
                    // CALL array.SetArrayItemRef(z, p);
                    // CALL array.SetArrayItem(x, PhpVariable.Copy(y, CopyReason.Assigned));
                    // CALL array.SetArrayItem(PhpVariable.Copy(x, CopyReason.Assigned))
                    // CALL array.AddToEnd(x)

                    il.Emit(OpCodes.Dup);
                    PhpTypeCode index_type_code = itemcompiler.EmitIndex(item, codeGenerator);
                    itemcompiler.EmitValue(item, codeGenerator);
                    codeGenerator.EmitSetArrayItem(index_type_code, item.Index, item is RefItem, true);
                }

                switch (this.access)
                {
                case AccessType.Read:
                    // keep array on the stack
                    return(PhpTypeCode.PhpArray);

                case AccessType.None:
                    // pop array from the stack
                    il.Emit(OpCodes.Pop);
                    return(PhpTypeCode.Void);
                }

                throw new InvalidOperationException();
                //return PhpTypeCode.Invalid;
            }
Beispiel #13
0
            public override PhpTypeCode Emit(EvalEx node, CodeGenerator codeGenerator)
            {
                // not emitted in release mode:
                Debug.Assert(access == AccessType.None || access == AccessType.Read || access == AccessType.ReadRef);
                Debug.Assert(codeGenerator.RTVariablesTablePlace != null, "Function should have variables table.");
                Statistics.AST.AddNode("EvalEx");

                PhpTypeCode result = codeGenerator.EmitEval(EvalKinds.ExplicitEval, node.Code, node.Span, null, null);

                // handles return value according to the access type:
                codeGenerator.EmitReturnValueHandling(node, false, ref result);
                return(result);
            }
Beispiel #14
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);
        }
Beispiel #15
0
        /// <summary>
        /// Emit <see cref="PhpVariable.Copy"/> if needed. It means <see cref="Expression.Access"/> has to be <see cref="AccessType.Read"/> and <paramref name="returnType"/> has to be copiable.
        /// </summary>
        /// <param name="il">The <see cref="ILEmitter"/>.</param>
        /// <param name="returnType"><see cref="PhpTypeCode"/> of function call return value.</param>
        protected void EmitReturnValueCopy(ILEmitter/*!*/il, PhpTypeCode returnType)
        {
            Debug.Assert(il != null);

            // copy only if we are reading the return value &&
            // only if return type is copiable:
            if (access != AccessType.None &&   // reading, not literals:
                PhpTypeCodeEnum.IsDeeplyCopied(returnType) &&
                returnType != PhpTypeCode.PhpReference) // PhpSmartReference can be an issue if method returns an object field (but this is handled by binders)
            {
                il.LdcI4((int)CopyReason.ReturnedByCopy);
                il.Emit(OpCodes.Call, Methods.PhpVariable.Copy);
            }
        }
Beispiel #16
0
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override PhpTypeCode Emit(CodeGenerator /*!*/ codeGenerator)
        {
            Statistics.AST.AddNode("ItemUse");
            PhpTypeCode result = PhpTypeCode.Invalid;

            switch (codeGenerator.SelectAccess(access))
            {
            case AccessType.None:
                result = EmitNodeRead(codeGenerator, Operators.GetItemKinds.Get);
                codeGenerator.IL.Emit(OpCodes.Pop);
                break;

            case AccessType.Read:
                result = EmitNodeRead(codeGenerator, Operators.GetItemKinds.Get);
                break;

            case AccessType.Write:
                // prepares for write:
                result = EmitNodeWrite(codeGenerator);
                break;

            case AccessType.ReadRef:
                // if the selector is set to the ReadRef, the chain is emitted as if it was written
                // (chained nodes are marked as ReadAndWrite):
                if (codeGenerator.AccessSelector == AccessType.ReadRef)
                {
                    codeGenerator.AccessSelector = AccessType.Write;
                }

                result = EmitNodeReadRef(codeGenerator);
                break;

            case AccessType.ReadUnknown:
                result = EmitNodeReadUnknown(codeGenerator);
                break;

            case AccessType.WriteRef:
                // prepares for write:
                result = EmitNodeWriteRef(codeGenerator);
                break;

            default:
                Debug.Fail();
                break;
            }

            return(result);
        }
Beispiel #17
0
        public void EmitConvertReturnValue(Type /*!*/ returnType, PhpTypeCode expectedTypeCode)
        {
            if (returnType == Types.Void)
            {
                il.Emit(OpCodes.Pop);
            }
            else
            {
                if (expectedTypeCode == PhpTypeCode.PhpReference)
                {
                    // dereference
                    il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                    expectedTypeCode = PhpTypeCode.Object;
                }

                ClrOverloadBuilder.EmitConvertToClr(
                    il,
                    expectedTypeCode,
                    returnType);
            }
        }
Beispiel #18
0
            /// <summary>
            /// Emits load of an argument of a concatenation.
            /// </summary>
            private static PhpTypeCode EmitConcatExpressionLoad(CodeGenerator /*!*/ codeGenerator, Expression /*!*/ expression)
            {
                // tries to evaluate the expression:
                if (expression.HasValue())
                {
                    var value = expression.GetValue();
                    if (value is PhpBytes)
                    {
                        codeGenerator.IL.LoadLiteral(value);
                        return(PhpTypeCode.PhpBytes);
                    }
                    else
                    {
                        // evaluated expression is converted to a string if necessary:
                        codeGenerator.IL.Emit(OpCodes.Ldstr, Convert.ObjectToString(value));
                        return(PhpTypeCode.String);
                    }
                }
                else
                {
                    // emits non-evaluable expression:
                    PhpTypeCode result = expression.Emit(codeGenerator);

                    // the result should be converted to string: (so we know the type for the further analysis)
                    if (result != PhpTypeCode.String && // string already
                        result != PhpTypeCode.Object && // object can contain PhpBytes, should be converted just when we know we need string
                        result != PhpTypeCode.PhpBytes  // keep PhpBytes
                        )
                    {
                        codeGenerator.EmitBoxing(result);   // in case of value-type
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
                        result = PhpTypeCode.String;
                    }

                    return(result);
                }
            }
Beispiel #19
0
 /// <summary>
 /// Emits code for loading the variable's value onto the evaluation stack. Supports operators chaining.
 /// </summary>
 /// <param name="codeGenerator"></param>
 private PhpTypeCode EmitNodeRead(CodeGenerator codeGenerator)
 {
     if (codeGenerator.ChainBuilder.IsMember)
     {
         // 1,4,5,6,9
         if (this.isMemberOf != null)
         {
             // 1: ...->a->...
             codeGenerator.ChainBuilder.Lengthen();
             return(EmitReadField(codeGenerator, false));
         }
         if (codeGenerator.ChainBuilder.IsArrayItem && !codeGenerator.ChainBuilder.IsLastMember)
         {
             // 6: $b->a[3]
             return(codeGenerator.ChainBuilder.EmitGetProperty(this));
         }
         // 4: a[][]
         // 5: $a->b->c->...
         // 9: $a->b
         return(this.EmitLoad(codeGenerator));
     }
     // 2,3,7,8
     if (this.isMemberOf != null)
     {
         // 2: $b->a
         // 8: b[]->a
         codeGenerator.ChainBuilder.Create();
         codeGenerator.ChainBuilder.Begin();
         PhpTypeCode result = EmitReadField(codeGenerator, false);
         codeGenerator.ChainBuilder.End();
         return(result);
     }
     // 3: a[3]
     // 7: $a
     return(this.EmitLoad(codeGenerator));
 }
Beispiel #20
0
		internal void EmitSetItem(PhpTypeCode keyTypeCode, Expression keyExpr, bool reference)
		{
			MethodInfo method;
			switch (keyTypeCode)
			{
				case PhpTypeCode.Integer:
					method = (reference) ? Methods.Operators.SetItemRef.Int32 : Methods.Operators.SetItem.Int32;
					break;

				case PhpTypeCode.String:
					if (reference)
					{
						method = Methods.Operators.SetItemRef.String;
					}
					else
					{					
						if (EmitExactStringKeyHash(keyTypeCode, keyExpr))
							method = Methods.Operators.SetItemExact;
						else
							method = Methods.Operators.SetItem.String;
					}
					break;

				case PhpTypeCode.Object:
					method = (reference) ? Methods.Operators.SetItemRef.Object : Methods.Operators.SetItem.Object;
					break;

				case PhpTypeCode.Invalid:
					method = Methods.Operators.SetItem.Keyless;
					break;

				default:
                    throw new ArgumentException();
			}
			il.Emit(OpCodes.Call, method);
		}
Beispiel #21
0
		internal void EmitSetArrayItem(PhpTypeCode keyTypeCode, Expression keyExpr, bool reference, bool ctor)
		{
			MethodInfo method; 
			switch (keyTypeCode)
			{
				case PhpTypeCode.Integer:
					method = (reference) ? Methods.PhpArray.SetArrayItemRef_Int32 : Methods.PhpArray.SetArrayItem_Int32;
					break;

				case PhpTypeCode.String:
					if (reference)
					{
						method = Methods.PhpArray.SetArrayItemRef_String;
					}
					else
					{
						if (EmitExactStringKeyHash(keyTypeCode, keyExpr))
							method = Methods.PhpArray.SetArrayItemExact_String;
						else
							method = Methods.PhpArray.SetArrayItem_String;
					}
					break;

				case PhpTypeCode.Object:
                    method = reference ? Methods.PhpArray.SetArrayItemRef_Object : Methods.PhpArray.SetArrayItem_Object;
					break;
					
				case PhpTypeCode.Invalid:
					method = ctor ? Methods.PhpArray.AddToEnd_Object : Methods.PhpArray.SetArrayItem;
					break;
					
				default:
                    throw new ArgumentException();
			}
            il.Emit(method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, method);
		}
Beispiel #22
0
		private bool EmitExactStringKeyHash(PhpTypeCode keyTypeCode, Expression keyExpr)
		{
			if (keyExpr != null && keyTypeCode == PhpTypeCode.String && keyExpr.HasValue())
			{
                string skey = (string)keyExpr.GetValue();
				IntStringKey array_key = Convert.StringToArrayKey(skey);
				if (array_key.IsString && skey == array_key.String) // skey was not converted to int
				{
                    il.LdcI4(array_key.GetHashCode());  // == array_key.Integer == IntStringKey.StringKeyToArrayIndex(skey) // previously: skey.GetHashCode()
					return true;
				}
			}
			return false;
		}
Beispiel #23
0
		/// <summary>
		/// Emits code that loads a specified parameter on the evaluation stack.
		/// </summary>
		/// <param name="paramInfo">The parameter to load.</param>
		/// <param name="requiredTypeCode">Specifies whether <see cref="PhpReference"/>
		/// (<see cref="PhpTypeCode.PhpReference"/>), <see cref="object"/> (<see cref="PhpTypeCode.Object"/>),
		/// or the most fitting of these two should be loaded.</param>
		public void EmitLoadClrParameter(ParameterInfo/*!*/ paramInfo, PhpTypeCode requiredTypeCode)
		{
			if (paramInfo.IsOut) il.Emit(OpCodes.Ldnull);
			else
			{
				il.Ldarg(paramInfo.Position + paramOffset);

				// dereference ref param
				Type param_type = paramInfo.ParameterType;
				if (param_type.IsByRef)
				{
					param_type = param_type.GetElementType();

					il.Ldind(param_type);
				}

				// convert the parameter to PHP type
				PhpTypeCode type_code = ClrOverloadBuilder.EmitConvertToPhp(
					il,
					param_type/*,
					scriptContextPlace*/);

				il.EmitBoxing(type_code);
			}

			// check whether we have to create a PhpReference
			if (requiredTypeCode == PhpTypeCode.Object ||
				(requiredTypeCode == PhpTypeCode.Unknown && !paramInfo.ParameterType.IsByRef)) return;

			if (paramInfo.ParameterType.IsByRef)
			{
				LocalBuilder ref_local = il.DeclareLocal(Types.PhpReference[0]);

				// remember the PhpReference in a local
				il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
				il.Emit(OpCodes.Dup);
				il.Stloc(ref_local);

				referenceLocals[paramInfo.Position] = ref_local;
			}
			else
			{
				// no reference store-back is necessary
				il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
			}
		}
Beispiel #24
0
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override PhpTypeCode Emit(CodeGenerator /*!*/ codeGenerator)
        {
            Statistics.AST.AddNode("FieldUse.Static");
            ChainBuilder chain  = codeGenerator.ChainBuilder;
            PhpTypeCode  result = PhpTypeCode.Invalid;

            switch (codeGenerator.SelectAccess(access))
            {
            case AccessType.Read:
                result = EmitRead(codeGenerator, false);
                if (chain.IsMember)
                {
                    chain.Lengthen();
                }
                break;

            case AccessType.ReadUnknown:
                result = EmitRead(codeGenerator, true);
                if (chain.IsMember)
                {
                    chain.Lengthen();
                }
                break;

            case AccessType.ReadRef:
                if (chain.IsMember)
                {
                    chain.Lengthen();
                    result = EmitRead(codeGenerator, false);
                }
                else
                {
                    result = EmitRead(codeGenerator, true);
                }
                break;

            case AccessType.Write:
                if (chain.IsMember)
                {
                    result = EmitEnsure(codeGenerator, chain);
                    chain.Lengthen();
                }
                else
                {
                    assignmentCallback = EmitWrite(codeGenerator, false);
                    result             = PhpTypeCode.Unknown;
                }
                break;

            case AccessType.WriteRef:
                if (chain.IsMember)
                {
                    result = EmitEnsure(codeGenerator, chain);
                    chain.Lengthen();
                }
                else
                {
                    assignmentCallback = EmitWrite(codeGenerator, true);
                    result             = PhpTypeCode.Unknown;
                }
                break;

            case AccessType.None:
                result = PhpTypeCode.Void;
                break;
            }

            return(result);
        }
Beispiel #25
0
		private static void EmitPopValue(CodeGenerator/*!*/ codeGenerator, PhpTypeCode stackTypeCode)
		{
			// just pop the value that was meant to be written
			codeGenerator.IL.Emit(OpCodes.Pop);
		}
Beispiel #26
0
		internal void EmitSetConversion(ILEmitter/*!*/ il, PhpTypeCode sourceTypeCode, Type/*!*/ targetType)
		{
			LocalBuilder strictness = il.GetTemporaryLocal(typeof(PHP.Core.ConvertToClr.ConversionStrictness));
			if (!ClrOverloadBuilder.EmitConvertToClr(il, sourceTypeCode, targetType, strictness))
			{
				Label label_ok = il.DefineLabel();

				il.Ldloc(strictness);
				il.LdcI4((int)PHP.Core.ConvertToClr.ConversionStrictness.Failed);
				il.Emit(OpCodes.Ceq);
				il.Emit(OpCodes.Brfalse, label_ok);

				il.Emit(OpCodes.Ldstr, Property.DeclaringType.FullName);
				il.Emit(OpCodes.Ldstr, Property.FullName);
				il.Emit(OpCodes.Call, Methods.PhpException.PropertyTypeMismatch);

				il.MarkLabel(label_ok, true);
			}
			il.ReturnTemporaryLocal(strictness);
		}
Beispiel #27
0
 public void EmitLoad(ILEmitter /*!*/ il)
 {
     Debug.Assert(ReferenceEquals(il, codeGenerator.IL));
     typeCode = expression.Emit(codeGenerator);
 }
Beispiel #28
0
        /// <summary>
        /// Emits concatenation of a pair of expressions.
        /// </summary>
        /// <param name="codeGenerator">A code generator.</param>
        /// <param name="x">The first expression.</param>
        /// <param name="y">The second expression.</param>
        /// <returns>The resulting type code.</returns>
        internal static PhpTypeCode EmitConcat(CodeGenerator /*!*/ codeGenerator, Expression /*!*/ x, Expression /*!*/ y)
        {
            PhpTypeCode type_code_x = EmitConcatExpressionLoad(codeGenerator, x);
            PhpTypeCode type_code_y = EmitConcatExpressionLoad(codeGenerator, y);

            if (type_code_x == PhpTypeCode.String)
            {
                if (type_code_y == PhpTypeCode.String)
                {
                    // string.string:
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.String_Concat_String_String);

                    return(PhpTypeCode.String);
                }
                else if (type_code_y == PhpTypeCode.PhpBytes)
                {
                    // check the return type:
                    Debug.Assert(Methods.PhpBytes.Concat_Object_PhpBytes.ReturnType == typeof(PhpBytes));

                    // string.PhpBytes:
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.PhpBytes.Concat_Object_PhpBytes);

                    return(PhpTypeCode.PhpBytes);
                }
                else
                {
                    // string.object:
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.Concat.String_Object);

                    return(PhpTypeCode.Object);
                }
            }
            else if (type_code_x == PhpTypeCode.PhpBytes)
            {
                if (type_code_y == PhpTypeCode.PhpBytes)
                {
                    // check the return type:
                    Debug.Assert(Methods.PhpBytes.Concat_PhpBytes_PhpBytes.ReturnType == typeof(PHP.Core.PhpBytes));

                    // PhpBytes.PhpBytes
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.PhpBytes.Concat_PhpBytes_PhpBytes);
                }
                else
                {
                    // check the return type:
                    Debug.Assert(Methods.PhpBytes.Concat_PhpBytes_Object.ReturnType == typeof(PHP.Core.PhpBytes));

                    // PhpBytes.object:
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.PhpBytes.Concat_PhpBytes_Object);
                }

                return(PhpTypeCode.PhpBytes);
            }
            else
            {
                if (type_code_y == PhpTypeCode.String)
                {
                    // check the return type:
                    //Debug.Assert(Methods.Operators.Concat.Object_String.ReturnType == typeof(object));

                    // object.string:
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.Concat.Object_String);
                    return(PhpTypeCode.Object);
                }
                else if (type_code_y == PhpTypeCode.PhpBytes)
                {
                    // check the return type:
                    Debug.Assert(Methods.PhpBytes.Concat_Object_PhpBytes.ReturnType == typeof(PhpBytes));

                    // object.PhpBytes:
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.PhpBytes.Concat_Object_PhpBytes);
                    return(PhpTypeCode.PhpBytes);
                }
                else
                {   // object.object:
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.Concat.Object_Object);
                    return(PhpTypeCode.Object);
                }
            }
        }
		/// <summary>
		/// Converts a PHP value to the given CLR type (the caller passes a <paramref name="strictnessLocal"/> that will
		/// receive one of the <see cref="PHP.Core.ConvertToClr.ConversionStrictness"/> enumeration values that
		/// describe the conversion result (the Failed value indicates that conversion was not successful).
		/// </summary>
		/// <returns><B>True</B> if it the conversion will surely succeed.</returns>
		internal static bool EmitConvertToClr(ILEmitter/*!*/ il, PhpTypeCode typeCode,
			Type/*!*/ formalType, LocalBuilder/*!*/ strictnessLocal)
		{
			Debug.Assert(strictnessLocal.LocalType == typeof(ConversionStrictness));

			// preprocess the value according to the PHP type code
			switch (typeCode)
			{
				case PhpTypeCode.PhpReference:
					{
						// dereference
						il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
						typeCode = PhpTypeCode.Object;
						break;
					}

				case PhpTypeCode.ObjectAddress:
					{
						// dereference
						il.Emit(OpCodes.Ldind_Ref);
						typeCode = PhpTypeCode.Object;
						break;
					}

				case PhpTypeCode.LinqSource:
				case PhpTypeCode.PhpRuntimeChain:
					{
						Debug.Fail();
						return true;
					}
			}

			// special treatment for generic parameters
			if (formalType.IsGenericParameter)
			{
				EmitConvertToClrGeneric(il, formalType, strictnessLocal);
				return false;
			}

			// convert CLR type
			return EmitConvertObjectToClr(il, typeCode, formalType, strictnessLocal);
		}
		private void EmitConversionToAmbiguousVararg(int argIndex, Type/*!*/ formalParamType, LocalBuilder/*!*/ tmpStrictness,
			PhpTypeCode argLocalTypeCode, LocalBuilder/*!*/ argLocal, LocalBuilder[] formals)
		{
			Debug.Assert(formalParamType.IsArray);
			Type element_type = formalParamType.GetElementType();
			Label success_label = il.DefineLabel();

			// IF (overloadStrictness == ImplExactMatch) GOTO <success_label>
			il.Ldloc(tmpStrictness); 
			il.LdcI4((int)ConversionStrictness.ImplExactMatch);
			il.Emit(OpCodes.Beq, success_label);

			// formal = new ELEMENT_TYPE[1] { CONVERT(stack, out strictness) };
			EmitCreateParamsArray(element_type, formals[argIndex], 1);

			il.Ldloc(formals[argIndex]);
			il.LdcI4(0);

			// reload the argument
			il.Ldloc(argLocal);

			bool ct_ok = EmitConvertToClr(il, argLocalTypeCode, element_type, tmpStrictness);
			il.Stelem(element_type);
			il.MarkLabel(success_label, true);
		}
Beispiel #31
0
		/// <summary>
		/// Emits IL instructions that sets the value to an <see cref="PHP.Core.PhpArray"/> item.
		/// </summary>
		/// <remarks>This method is used to set the item of an array having the index determined (not <B>null</B>).
		/// This method is called only in simple cases when operators chained are <b>not</b> involved.
		/// See short example of PHP code below.
		/// Expects that the reference to the object whose item should be set, the index and the value
		/// are loaded on the evaluation stack. Nothing is left on the evaluation stack.
		/// stack. 
		/// </remarks>
		/// <example>$a[3] = "foo"; $a[] = "foo";</example>
		/// <example>$x[y] =&amp; p; $x[] =&amp; p;</example>
		public void EmitSetItem(PhpTypeCode keyTypeCode, Expression index, bool reference)
		{
			codeGenerator.EmitSetItem(keyTypeCode, index, reference);
		}
Beispiel #32
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);
            }
Beispiel #33
0
 private PhpNumber(long value) : this()
 {
     _typeCode = PhpTypeCode.Long;
     _long     = value;
 }
Beispiel #34
0
 public PrimitiveTypeRef(PhpTypeCode code)
 {
     _code = code;
 }
Beispiel #35
0
 private PhpNumber(double value) : this()
 {
     _typeCode = PhpTypeCode.Double;
     _double   = value;
 }
Beispiel #36
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;
		}
Beispiel #37
0
		public void EmitLoad(ILEmitter/*!*/ il)
		{
			Debug.Assert(ReferenceEquals(il, codeGenerator.IL));
			typeCode = expression.Emit(codeGenerator);
		}
Beispiel #38
0
		private static void EmitCallSetObjectField(CodeGenerator/*!*/ codeGenerator, PhpTypeCode stackTypeCode)
		{
			// CALL Operators.SetObjectProperty(<STACK:instance>,<STACK:field name>,<STACK:field value>, <type desc>)
			codeGenerator.EmitLoadClassContext();

			codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.SetObjectProperty);
            
            //always when function with void return argument is called it's necesarry to add nop instruction due to debugger
            if (codeGenerator.Context.Config.Compiler.Debug)
            {
                codeGenerator.IL.Emit(OpCodes.Nop);
            }
		}
Beispiel #39
0
		/// <summary>
		/// Finishes the write operation starte by <see cref="Emit"/>.
		/// </summary>
		internal override PhpTypeCode EmitAssign(CodeGenerator/*!*/ codeGenerator)
		{
			ChainBuilder chain = codeGenerator.ChainBuilder;
			PhpTypeCode result;

			switch (access)
			{
				case AccessType.WriteAndReadRef:
				case AccessType.WriteAndReadUnknown:
				case AccessType.ReadAndWrite:
				case AccessType.ReadAndWriteAndReadRef:
				case AccessType.ReadAndWriteAndReadUnknown:
				case AccessType.Write:
				case AccessType.WriteRef:
					{
						bool reference = access == AccessType.WriteRef;

						// Note that some work was done in Emit() !
						// In cases 3, 4, 5 EmitAssign is not called

						if (isMemberOf != null ||
						   (isMemberOf == null && (array is DirectStFldUse || array is IndirectStFldUse || array is ItemUse)))
						{
							// 2, 6, 7
							chain.EmitSetArrayItem(indexTypeCode, index, reference);
							chain.End();
						}
						else
						{
							// Note: The value which should be stored is already loaded on the evaluation stack.
							//				Push the destination array and index and call the operator
							// 1: a_[x]_
							Debug.Assert(array is SimpleVarUse);
							chain.IsArrayItem = true;
							chain.IsLastMember = true;
							indexTypeCode = codeGenerator.EmitArrayKey(chain, index);
							array.Emit(codeGenerator);
							chain.EmitSetItem(indexTypeCode, index, reference);

							// Store the changed variable into table of variables (do nothing in optimalized functions)
							((SimpleVarUse)array).EmitLoadAddress_StoreBack(codeGenerator);
						}

						result = PhpTypeCode.Void;
						break;
					}

				case AccessType.None:
					// do nothing
					result = PhpTypeCode.Void;
					break;

				case AccessType.Read:
					// do nothing
					result = PhpTypeCode.Object;
					break;

				case AccessType.ReadRef:
					// Do nothing
					result = PhpTypeCode.PhpReference;
					break;

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

			return result;
		}
Beispiel #40
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);
        }
Beispiel #41
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;
		}
Beispiel #42
0
		// Obsolete:
		// <summary>
		// A <see cref="Stack{T}"/> class that stores temporarily used variables. See Remarks for more information.
		// </summary>
		// <remarks>This stack stores locals that are used to obtain address of a variable stored in
		// a runtime variables table while calling methods from <see cref="PHP.Core.Operators"/> having
		// a <c>ref</c> argument. Those variables are not so short-live to be obtained by <see cref="GetTemporaryLocal"/>,
		// but can be reused within a defining scope under certain circumstances.
		// When <see cref="GetAddressStorageLocal"/> method is called, the temporary
		// local is either popped from the cache or a new local is defined if the cache is empty.
		// If the variable become useless, <see cref="ReturnAddressStorageLocal"/> method should
		// be called to push the variable back to cache. Once the variable is returned to cache it must not have
		// been used unless it is obtained again by <see cref="GetAddressStorageLocal"/> method.
		// The cache is created when the first local is returned.
		// </remarks>

		#endregion

		#region PHP Specific

		internal void EmitBoxing(PhpTypeCode type)
		{
			switch (type)
			{
				case PhpTypeCode.Integer:
					il.Emit(OpCodes.Box, typeof(Int32));
					break;

				case PhpTypeCode.LongInteger:
					il.Emit(OpCodes.Box, typeof(Int64));
					break;

				case PhpTypeCode.Double:
					il.Emit(OpCodes.Box, typeof(Double));
					break;

				case PhpTypeCode.Boolean:
					il.Emit(OpCodes.Box, typeof(Boolean));
					break;

				case PhpTypeCode.Void:
					il.Emit(OpCodes.Ldnull);
					break;
			}
		}
Beispiel #43
0
        ///// <summary>
        ///// Emits IL instructions for calling the best overload of <see cref="PHP.Core.ScriptContext.Echo"/> method.
        ///// </summary>
        ///// <param name="typecode"><see cref="PHP.Core.PhpTypeCode"/> of the parameter.</param>
        ///// <remarks>GetUserEntryPoint parameters are expected on the evaluation stack. Nothing is left on the evaluation stack.</remarks>
        //private void EmitEchoCall(PhpTypeCode typecode)
        //{
        //    switch (typecode)
        //    {
        //        case PhpTypeCode.Object:
        //            il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.Object);
        //            break;

        //        case PhpTypeCode.String:
        //            il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.String);
        //            break;

        //        case PhpTypeCode.PhpBytes:
        //            il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.PhpBytes);
        //            break;

        //        case PhpTypeCode.Integer:
        //            il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.Int);
        //            break;

        //        case PhpTypeCode.LongInteger:
        //            il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.LongInt);
        //            break;

        //        case PhpTypeCode.Double:
        //            il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.Double);
        //            break;

        //        case PhpTypeCode.Boolean:
        //            il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.Bool);
        //            break;

        //        default:
        //            il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.Object);
        //            break;
        //    }
        //}

        /// <summary>
        /// Emits IL instructions for calling the best overload of <see cref="PHP.Core.ScriptContext.Echo"/> static method.
        /// </summary>
        /// <param name="typecode"><see cref="PHP.Core.PhpTypeCode"/> of the parameter.</param>
        /// <remarks>Nothing is left on the evaluation stack. Emitted method call expects two parameters on the evaluation stack: (value, ScriptContext).</remarks>
        private void EmitEchoStaticCall(PhpTypeCode typecode)
        {
            switch (typecode)
            {
                case PhpTypeCode.Object:
                    il.Emit(OpCodes.Call, Methods.ScriptContext.EchoStatic.Object);
                    break;

                case PhpTypeCode.String:
                    il.Emit(OpCodes.Call, Methods.ScriptContext.EchoStatic.String);
                    break;

                case PhpTypeCode.PhpBytes:
                    il.Emit(OpCodes.Call, Methods.ScriptContext.EchoStatic.PhpBytes);
                    break;

                case PhpTypeCode.Integer:
                    il.Emit(OpCodes.Call, Methods.ScriptContext.EchoStatic.Int);
                    break;

                case PhpTypeCode.LongInteger:
                    il.Emit(OpCodes.Call, Methods.ScriptContext.EchoStatic.LongInt);
                    break;

                case PhpTypeCode.Double:
                    il.Emit(OpCodes.Call, Methods.ScriptContext.EchoStatic.Double);
                    break;

                case PhpTypeCode.Boolean:
                    il.Emit(OpCodes.Call, Methods.ScriptContext.EchoStatic.Bool);
                    break;

                default:
                    il.Emit(OpCodes.Call, Methods.ScriptContext.EchoStatic.Object);
                    break;
            }
        }
Beispiel #44
0
		public void EmitConvertReturnValue(Type/*!*/ returnType, PhpTypeCode expectedTypeCode)
		{
			if (returnType == Types.Void) il.Emit(OpCodes.Pop);
			else
			{
				if (expectedTypeCode == PhpTypeCode.PhpReference)
				{
					// dereference
					il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
					expectedTypeCode = PhpTypeCode.Object;
				}

				ClrOverloadBuilder.EmitConvertToClr(
					il,
					expectedTypeCode,
					returnType);
			}
		}
		/// <summary>
		/// Converts a PHP value to the given CLR type (the caller is not interested in the success of the conversion).
		/// </summary>
		public static void EmitConvertToClr(ILEmitter/*!*/ il, PhpTypeCode typeCode, Type/*!*/ formalType)
		{
			EmitConvertToClr(il, typeCode, formalType, il.GetTemporaryLocal(typeof(ConversionStrictness), true));
		}
Beispiel #46
0
        /// <summary>
        /// Emits IL instructions to process the <B>echo</B> and <B>print</B> commands.
        /// </summary>
        /// <param name="expressions">List of expressions to be echoed. They will be evaluated first. The list cannot be null and it must contain at least one element.</param>
        public void EmitEcho(Expression[]/*!*/expressions)
        {
            Debug.Assert(expressions != null);
            Debug.Assert(expressions.Length > 0);

            // known types of resulting values
            PhpTypeCode[] types = new PhpTypeCode[expressions.Length];

            // construct the array with values
            // to preserve the proper order of evaluation and output
            il.LdcI4(expressions.Length);
            il.Emit(OpCodes.Newarr, typeof(object));

            for (int i = 0; i < expressions.Length; ++i)
            {
                // array[<i>] = <expressions[i]>;
                il.Emit(OpCodes.Dup);
                il.LdcI4(i);
                EmitBoxing(types[i] = expressions[i].Emit(this));
                il.Emit(OpCodes.Stelem_Ref);
            }

            // echo the values
            for (int i = 0; i < expressions.Length; ++i)
            {
                il.Emit(OpCodes.Dup);   // array
                il.LdcI4(i);            // <i>
                il.Emit(OpCodes.Ldelem_Ref);    // object array[<i>]
                il.EmitUnboxingForArg(types[i]);  // UnBox value type, if value-type was boxed here, prepared for method call argument
                // convert object to string or PhpBytes to hold the right type on the stack (valid IL)
                if (types[i] == PhpTypeCode.PhpBytes)   il.Emit(OpCodes.Castclass, Types.PhpBytes[0]);
                else if (types[i] == PhpTypeCode.String) il.Emit(OpCodes.Castclass, Types.String[0]);
                EmitLoadScriptContext();
                // CALL ScriptContext.Echo(<obj>, <ScriptContext>)
                EmitEchoStaticCall(types[i]);
            }

            il.Emit(OpCodes.Pop);// remove the array from the stack
        }
		/// <summary>
		/// Converts object to CLR type
		/// </summary>
		private static bool EmitConvertObjectToClr(ILEmitter il, PhpTypeCode typeCode, Type formalType, LocalBuilder strictnessLocal)
		{
			MethodInfo convert_method = null;
			switch (Type.GetTypeCode(formalType))
			{
				case TypeCode.Boolean: if (typeCode != PhpTypeCode.Boolean)
						convert_method = Methods.ConvertToClr.TryObjectToBoolean; break;
				case TypeCode.Int32: if (typeCode != PhpTypeCode.Integer)
						convert_method = Methods.ConvertToClr.TryObjectToInt32; break;
				case TypeCode.Int64: if (typeCode != PhpTypeCode.LongInteger)
						convert_method = Methods.ConvertToClr.TryObjectToInt64; break;
				case TypeCode.Double: if (typeCode != PhpTypeCode.Double)
						convert_method = Methods.ConvertToClr.TryObjectToDouble; break;
				case TypeCode.String: if (typeCode != PhpTypeCode.String)
						convert_method = Methods.ConvertToClr.TryObjectToString; break;

				case TypeCode.SByte: convert_method = Methods.ConvertToClr.TryObjectToInt8; break;
				case TypeCode.Int16: convert_method = Methods.ConvertToClr.TryObjectToInt16; break;
				case TypeCode.Byte: convert_method = Methods.ConvertToClr.TryObjectToUInt8; break;
				case TypeCode.UInt16: convert_method = Methods.ConvertToClr.TryObjectToUInt16; break;
				case TypeCode.UInt32: convert_method = Methods.ConvertToClr.TryObjectToUInt32; break;
				case TypeCode.UInt64: convert_method = Methods.ConvertToClr.TryObjectToUInt64; break;
				case TypeCode.Single: convert_method = Methods.ConvertToClr.TryObjectToSingle; break;
				case TypeCode.Decimal: convert_method = Methods.ConvertToClr.TryObjectToDecimal; break;
				case TypeCode.Char: convert_method = Methods.ConvertToClr.TryObjectToChar; break;
				case TypeCode.DateTime: convert_method = Methods.ConvertToClr.TryObjectToDateTime; break;
				case TypeCode.DBNull: convert_method = Methods.ConvertToClr.TryObjectToDBNull; break;

				case TypeCode.Object:
					{
						if (formalType.IsValueType)
						{
							if (formalType.IsGenericType && NullableType == formalType.GetGenericTypeDefinition())
							{
								// This is an ugly corner case (using generic TryObjectToStruct wouldn't work, because
								// for nullables .IsValueType returns true, but it doesn't match "T : struct" constraint)!
								// We have to try converting object to Nullable<T> first and then to T
								// (which requires a new call to 'EmitConvertObjectToClr') 
								Type nullableArg = formalType.GetGenericArguments()[0];
								Type nullableType = NullableType.MakeGenericType(nullableArg);
								
								LocalBuilder tmpVar = il.DeclareLocal(typeof(object));
								
								// This succeeds only for exact match
								il.Emit(OpCodes.Call, Methods.ConvertToClr.UnwrapNullable);
								il.Emit(OpCodes.Dup);
								il.Stloc(tmpVar);

								// <stack_0> = tmpVar = UnwrapNullable(...)
								// if (<stack_0> != null) 
								Label lblNull = il.DefineLabel(), lblDone = il.DefineLabel();
								il.Emit(OpCodes.Ldnull);
								il.Emit(OpCodes.Beq, lblNull);
								// {

								// Convert tmpVar to T and wrap it into Nullable<T>
								il.Ldloc(tmpVar);
								bool ret = EmitConvertObjectToClr(il, typeCode, nullableArg, strictnessLocal);
								// TODO: use reflection cache?
								il.Emit(OpCodes.Newobj, nullableType.GetConstructors()[0]);
								il.Emit(OpCodes.Br, lblDone);
								
								// } else /* == null */ {
								il.MarkLabel(lblNull);

								// return (T?)null;
								LocalBuilder tmpNull = il.DeclareLocal(nullableType);
								il.Ldloca(tmpNull);
								il.Emit(OpCodes.Initobj, nullableType);
								il.Ldloc(tmpNull);
								// }
								
								il.MarkLabel(lblDone);
								return ret;
							}
							else
								convert_method = Methods.ConvertToClr.TryObjectToStruct.MakeGenericMethod(formalType);
						}
						else
						{
							if (formalType.IsArray)
								convert_method = Methods.ConvertToClr.TryObjectToArray.MakeGenericMethod(formalType.GetElementType());
							else if (typeof(Delegate).IsAssignableFrom(formalType))
								convert_method = Methods.ConvertToClr.TryObjectToDelegate.MakeGenericMethod(formalType);
							else
								convert_method = Methods.ConvertToClr.TryObjectToClass.MakeGenericMethod(formalType);
						}
						break;
					}

				default:
					Debug.Fail();
					return true;
			}

			if (convert_method != null)
			{
				il.Ldloca(strictnessLocal);
				il.Emit(OpCodes.Call, convert_method);
				return false;
			}
			else return true;
		}
Beispiel #48
0
        internal void EmitName(string fullName, Expression nameExpr, bool createChain, PhpTypeCode dstType)
        {
            Debug.Assert(fullName != null ^ nameExpr != null);

            if (fullName != null)
            {
                il.Emit(OpCodes.Ldstr, fullName);
            }
            else
            {
                if (createChain) ChainBuilder.Create();
                EmitConversion(nameExpr, dstType);
                if (createChain) ChainBuilder.End();
            }
        }
Beispiel #49
0
 public ExpressionPlace(CodeGenerator /*!*/ codeGenerator, Expression /*!*/ expression)
 {
     this.codeGenerator = codeGenerator;
     this.expression    = expression;
     this.typeCode      = PhpTypeCode.Invalid;
 }
Beispiel #50
0
		/// <summary>
		/// Emits instructions to conform a required access type.
		/// </summary>
		/// <param name="callExpression">Expression emitting the call.</param>
		/// <param name="loadAddress">Whether to load an address of the return value.</param>
		/// <param name="result">The type code of a top item of the evaluation stack.</param>
		public void EmitReturnValueHandling(Expression/*!*/ callExpression, bool loadAddress, ref PhpTypeCode result)
		{
			Debug.Assert(callExpression != null);

			if (loadAddress)
			{
                if (result == PhpTypeCode.PhpReference)
				{
					// LOADADDR STACK.Value;
					il.Emit(OpCodes.Ldflda, Fields.PhpReference_Value);
				}
				else
				{
                    if (result == PhpTypeCode.Void)
                        il.Emit(OpCodes.Ldnull);
                    
                    // local = STACK; 
					// LOADADDR local;
					LocalBuilder local = il.GetTemporaryLocal(PhpTypeCodeEnum.ToType(result), true);
					il.Stloc(local);
					il.Ldloca(local);
				}
				result = PhpTypeCode.ObjectAddress;
				return;
			}

			switch (callExpression.GetAccess())
			{
				case AccessType.None:

					// return value is discarded:
					if (result != PhpTypeCode.Void)
					{
						il.Emit(OpCodes.Pop);
						result = PhpTypeCode.Void;
					}
					break;

				case AccessType.ReadUnknown:
				case AccessType.ReadRef:

					if (result != PhpTypeCode.PhpReference)
					{
						// return value is "boxed" to PhpReference:
						if (result != PhpTypeCode.Void)
						{
							EmitBoxing(result);
							EmitVariableCopy(CopyReason.ReturnedByCopy, callExpression);
							il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
						}
						else
						{
							il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
						}

						result = PhpTypeCode.PhpReference;
					}
					break;

				case AccessType.Read:

					if (result == PhpTypeCode.PhpReference)
					{
						// return value is dereferenced:
						il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
						result = PhpTypeCode.Object;
					}
					else if (result == PhpTypeCode.Void)
					{
						// null value is loaded as a result:
						il.Emit(OpCodes.Ldnull);
						result = PhpTypeCode.Object;
					}
					break;

				default:
					Debug.Fail(null);
					break;
			}
		}
Beispiel #51
0
		public ExpressionPlace(CodeGenerator/*!*/ codeGenerator, Expression/*!*/ expression)
		{
			this.codeGenerator = codeGenerator;
			this.expression = expression;
			this.typeCode = PhpTypeCode.Invalid;
		}
Beispiel #52
0
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override PhpTypeCode Emit(CodeGenerator codeGenerator)
        {
            Statistics.AST.AddNode("IncDecEx");
            Debug.Assert(access == AccessType.Read || access == AccessType.None);

            AccessType old_selector = codeGenerator.AccessSelector;

            PhpTypeCode returned_typecode = PhpTypeCode.Void;

            codeGenerator.AccessSelector = AccessType.Write;
            codeGenerator.ChainBuilder.Create();
            variable.Emit(codeGenerator);
            codeGenerator.AccessSelector = AccessType.Read;
            codeGenerator.ChainBuilder.Create();
            variable.Emit(codeGenerator);
            codeGenerator.ChainBuilder.End();

            LocalBuilder old_value = null;

            if (access == AccessType.Read && post)
            {
                old_value = codeGenerator.IL.DeclareLocal(Types.Object[0]);
                // Save variable's value for later use
                codeGenerator.IL.Emit(OpCodes.Dup);
                codeGenerator.IL.Stloc(old_value);
            }

            if (this.inc)
            {
                // Increment
                codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.Increment);
            }
            else
            {
                // Decrement
                codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.Decrement);
            }

            codeGenerator.AccessSelector = AccessType.Write;
            if (access == AccessType.Read)
            {
                if (post)
                {
                    variable.EmitAssign(codeGenerator);
                    // Load original value (as was before operation)
                    codeGenerator.IL.Ldloc(old_value);
                }
                else
                {
                    old_value = codeGenerator.IL.DeclareLocal(Types.Object[0]);
                    // pre-incrementation
                    // Load variable's value after operation
                    codeGenerator.IL.Emit(OpCodes.Dup);
                    codeGenerator.IL.Stloc(old_value);
                    variable.EmitAssign(codeGenerator);
                    codeGenerator.IL.Ldloc(old_value);
                }

                returned_typecode = PhpTypeCode.Object;
            }
            else
            {
                variable.EmitAssign(codeGenerator);
            }
            codeGenerator.AccessSelector = old_selector;

            codeGenerator.ChainBuilder.End();

            return(returned_typecode);
        }
Beispiel #53
0
		/// <summary>
		/// Emits IL instructions that convert the top of evaluation stack to a specified type.
		/// </summary>
		/// <remarks>
		/// Emits a call to one of <see cref="PHP.Core.Convert"/> methods to do the conversion.
		/// The method result is left on the evaluation stack.
		/// </remarks>
		internal void EmitConversion(Expression/*!*/ expression, PhpTypeCode dst)
		{
			// expression is evaluable:
			if (expression.HasValue())
			{
				switch (dst)
				{
					case PhpTypeCode.String:
						il.Emit(OpCodes.Ldstr, PHP.Core.Convert.ObjectToString(expression.GetValue()));
						break;

					case PhpTypeCode.Boolean:
                        il.LdcI4(PHP.Core.Convert.ObjectToBoolean(expression.GetValue()) ? 1 : 0);
						break;

					case PhpTypeCode.Integer:
                        il.LdcI4(PHP.Core.Convert.ObjectToInteger(expression.GetValue()));
						break;

					case PhpTypeCode.Double:
                        il.Emit(OpCodes.Ldc_R8, PHP.Core.Convert.ObjectToDouble(expression.GetValue()));
						break;

					case PhpTypeCode.Object:
                        il.LoadLiteral(expression.GetValue());
						break;

					default:
						Debug.Fail("Conversion not implemented.");
						break;
				}
			}
			else
			{
				// emits the expression:
				PhpTypeCode src = expression.Emit(this);

				// emits no conversion if types are the same:
				if (src == dst) return;

				// emits boxing if needed (conversion methods takes object):
				EmitBoxing(src);

				switch (dst)
				{
					case PhpTypeCode.String:
						il.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
						break;

					case PhpTypeCode.Boolean:
						il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
						break;

					case PhpTypeCode.Integer:
						il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
						break;

					case PhpTypeCode.Double:
						il.Emit(OpCodes.Call, Methods.Convert.ObjectToDouble);
						break;

					case PhpTypeCode.Object:
						// nop //
						break;

					default:
						Debug.Fail("Conversion is not implemented.");
						break;
				}
			}
		}
Beispiel #54
0
        private static void EmitCallSetObjectField(CodeGenerator /*!*/ codeGenerator, PhpTypeCode stackTypeCode)
        {
            // CALL Operators.SetObjectProperty(<STACK:instance>,<STACK:field name>,<STACK:field value>, <type desc>)
            codeGenerator.EmitLoadClassContext();

            codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.SetObjectProperty);

            //always when function with void return argument is called it's necesarry to add nop instruction due to debugger
            if (codeGenerator.Context.Config.Compiler.Debug)
            {
                codeGenerator.IL.Emit(OpCodes.Nop);
            }
        }
Beispiel #55
0
        /// <summary>
        /// Emits IL instructions that read the value of an instance field.
        /// </summary>
        /// <param name="codeGenerator">The current <see cref="CodeGenerator"/>.</param>
        /// <param name="wantRef">If <B>false</B> the field value should be left on the evaluation stack,
        /// if <B>true</B> the <see cref="PhpReference"/> should be left on the evaluation stack.</param>
        /// <returns>
        /// Nothing is expected on the evaluation stack. A <see cref="PhpReference"/> (if <paramref name="wantRef"/>
        /// is <B>true</B>) or the field value itself (if <paramref name="wantRef"/> is <B>false</B>) is left on the
        /// evaluation stack.
        /// </returns>
        internal virtual PhpTypeCode EmitReadField(CodeGenerator codeGenerator, bool wantRef)
        {
            ILEmitter il = codeGenerator.IL;

            DirectVarUse direct_instance = isMemberOf as DirectVarUse;

            if (direct_instance != null && direct_instance.IsMemberOf == null && direct_instance.VarName.IsThisVariableName)
            {
                return(EmitReadFieldOfThis(codeGenerator, wantRef));
            }


            if (!wantRef)
            {
                //codeGenerator.ChainBuilder.Lengthen();
                //PhpTypeCode type_code = isMemberOf.Emit(codeGenerator);
                //Debug.Assert(type_code == PhpTypeCode.Object || type_code == PhpTypeCode.DObject);

                //// CALL Operators.GetProperty(STACK,<field name>,<type desc>,<quiet>);
                //EmitName(codeGenerator);
                //codeGenerator.EmitLoadClassContext();
                //il.LoadBool(codeGenerator.ChainBuilder.QuietRead);
                //il.Emit(OpCodes.Call, Methods.Operators.GetProperty);
                //return PhpTypeCode.Object;

                string     fieldName     = (this is DirectVarUse) ? ((DirectVarUse)this).VarName.Value : null;
                Expression fieldNameExpr = (this is IndirectVarUse) ? ((IndirectVarUse)this).VarNameEx : null;
                bool       quietRead     = wantRef ? false : codeGenerator.ChainBuilder.QuietRead;
                return(codeGenerator.CallSitesBuilder.EmitGetProperty(
                           codeGenerator, wantRef,
                           isMemberOf, null, null,
                           null,
                           fieldName, fieldNameExpr,
                           quietRead));
            }

            // call GetProperty/GetObjectPropertyRef
            codeGenerator.ChainBuilder.Lengthen();
            // loads the variable which field is gotten:
            PhpTypeCode var_type_code = isMemberOf.Emit(codeGenerator);

            if (codeGenerator.ChainBuilder.Exists)
            {
                Debug.Assert(var_type_code == PhpTypeCode.DObject);

                // CALL Operators.GetObjectPropertyRef(STACK,<field name>,<type desc>);
                EmitName(codeGenerator);
                codeGenerator.EmitLoadClassContext();
                il.Emit(OpCodes.Call, Methods.Operators.GetObjectPropertyRef);
            }
            else
            {
                Debug.Assert(var_type_code == PhpTypeCode.ObjectAddress);

                // CALL Operators.GetPropertyRef(ref STACK,<field name>,<type desc>,<script context>);
                EmitName(codeGenerator);
                codeGenerator.EmitLoadClassContext();
                codeGenerator.EmitLoadScriptContext();
                il.Emit(OpCodes.Call, Methods.Operators.GetPropertyRef);

                // stores the value of variable back:
                SimpleVarUse simple_var = isMemberOf as SimpleVarUse;
                if (simple_var != null)
                {
                    simple_var.EmitLoadAddress_StoreBack(codeGenerator);
                }
            }

            return(PhpTypeCode.PhpReference);
        }
Beispiel #56
0
		internal void EmitReferenceDereference(ref PhpTypeCode typeCode, bool wantRef)
		{
			if (wantRef)
			{
				// make reference:
				if (typeCode != PhpTypeCode.PhpReference)
				{
					EmitBoxing(typeCode);
					il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
				}

				typeCode = PhpTypeCode.PhpReference;
			}
			else
			{
				// dereference:
				if (typeCode == PhpTypeCode.PhpReference)
				{
					il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
					typeCode = PhpTypeCode.Object;
				}
			}
		}
Beispiel #57
0
 private static void EmitPopValue(CodeGenerator /*!*/ codeGenerator, PhpTypeCode stackTypeCode)
 {
     // just pop the value that was meant to be written
     codeGenerator.IL.Emit(OpCodes.Pop);
 }
Beispiel #58
0
		/// <summary>
		/// Emits IL instructions that box a literal value into its object representation.
		/// </summary>
		/// <param name="type"><see cref="PhpTypeCode"/> of the top item placed on evaluation stack.</param>
		/// <returns>The type code of an item on the top of evaluatuion stack after call.</returns>
		/// <remarks>
		/// The <see cref="PHP.Core.AST.Literal"/> to be boxed is expected on the evaluation stack.
		/// The boxed value is left on the evaluation stack.
		/// </remarks>
		public void EmitBoxing(PhpTypeCode type)
		{
			il.EmitBoxing(type);
		}
Beispiel #59
0
        /// <summary>
        /// UnBox object containing value-type.
        /// </summary>
        /// <param name="type">Type of object to UnBox.</param>
        /// <remarks>Extracts the value contained within obj (of type O), it is equivalent to unbox followed by ldobj.</remarks>
        internal void EmitUnboxingForArg(PhpTypeCode type)
        {
            switch (type)
            {
                case PhpTypeCode.Integer:
                    il.Emit(OpCodes.Unbox_Any, typeof(Int32));
                    break;

                case PhpTypeCode.LongInteger:
                    il.Emit(OpCodes.Unbox_Any, typeof(Int64));
                    break;

                case PhpTypeCode.Double:
                    il.Emit(OpCodes.Unbox_Any, typeof(Double));
                    break;

                case PhpTypeCode.Boolean:
                    il.Emit(OpCodes.Unbox_Any, typeof(Boolean));
                    break;

                case PhpTypeCode.Void:
                    il.Emit(OpCodes.Pop);
                    break;
            }
        }
Beispiel #60
0
        /// <summary>
        /// Ensures the object on top of the evaluation stack is writable,
        /// and so not shared by more PHP variables.
        /// </summary>
        internal void EmitEnsureWritable(PhpTypeCode typeCode)
        {
            switch (typeCode)
            {
                case PhpTypeCode.Boolean:
                case PhpTypeCode.Double:
                case PhpTypeCode.Integer:
                case PhpTypeCode.PhpCallable:
                case PhpTypeCode.PhpResource:
                case PhpTypeCode.PhpReference:
                case PhpTypeCode.String:
                case PhpTypeCode.Void:
                case PhpTypeCode.LongInteger:
                    // these types cannot be lazy copied for sure
                    break;

                default:
                    // Operators.EnsureObjectIsWritable( <TOP> )
                    this.IL.Emit(OpCodes.Dup);
                    this.EmitBoxing(typeCode);
                    this.IL.Emit(OpCodes.Call, new Action<object>(Operators.EnsureObjectIsWritable).Method);
                    break;
            }
        }