Example #1
0
        private static Expression/*!*/ GeneratePeekPseudoGenericArgument(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int index)
        {
            bool optional = index >= routine.Signature.MandatoryGenericParamCount;
            int indexTransformed = index + 1; // in PHP indexes of arguments starts from index 1

            if (optional)
                return PeekTypeOptional(routine, scriptContext, arg, indexTransformed);
            else
                return PeekType(routine, scriptContext, arg, indexTransformed);

        }
        /// <summary>
        /// This method binds rules for PhpMethod
        /// </summary>
        private void InvokePhpMethod(DynamicMetaObject/*!*/ target, DynamicMetaObject[]/*!!*/ args, /*object targetObj,*/ PhpRoutine/*!*/ routine, out BindingRestrictions restrictions, out Expression invokeMethodExpr)
        {
            Debug.Assert(target != null && target.Value != null);
            Debug.Assert(!(target.Value is IClrValue), "PhpRoutine should not be declared on CLR value type!");

            /*if (target.Value is PhpObject)
            {
                // Restriction: typeof(target) == |target.TypeDesc.RealType|
                var targetPhpObj = (PhpObject)target.Value;
                Debug.Assert(targetPhpObj.TypeDesc.RealType == target.LimitType);
                Debug.Assert(target.Value.GetType() == target.LimitType);
                restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, targetPhpObj.TypeDesc.RealType);
            }
            else*/
            Debug.Assert(typeof(ClrObject).IsSealed);   // just to ensure following condition is correct
            if (target.Value.GetType() == typeof(ClrObject))
            {
                target = new ClrDynamicMetaObject(target);  // unwrap the real object, get restrictions
                restrictions = target.Restrictions;
            }
            else
            {
                Debug.Assert(target.Value.GetType() == target.LimitType);   // just for sure
                Debug.Assert(!(target.Value is PhpObject) || ((PhpObject)target.Value).TypeDesc.RealType == target.LimitType);

                restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType);
            }

            BindingRestrictions argumentsRestrictions;
            Expression[] arguments;

            if (routine.Name != Name.SpecialMethodNames.Call)
            {
                args = GetArgumentsRange(args, 0, RealMethodArgumentCount);// This can't be done when _call method is invoked

                //Check if method has ArgAware attribute
                if ((routine.Properties & RoutineProperties.IsArgsAware) != 0 ||
                    routine.IsStatic)// this is because of hack in PHP.Library.XML library static methods that can be also called like instance methods
                {
                    DynamicMetaObject scriptContext = args[0];

                    //Select arguments without scriptContext
                    DynamicMetaObject[] realArgs = GetArgumentsRange(args, 1, RealMethodArgumentCount - 1);

                    InvokeArgLess(target, scriptContext, routine.RoutineDesc, realArgs, out argumentsRestrictions, out invokeMethodExpr);
                    restrictions = restrictions.Merge(argumentsRestrictions);
                    return;
                }

                arguments = routine.PrepareArguments(args, _genericParamsCount, _paramsCount, out argumentsRestrictions);
                restrictions = restrictions.Merge(argumentsRestrictions);
            }
            else
            {
                arguments = BinderHelper.PackToExpressions(args);
            }

            //((PhpObject)target))
            var realObjEx = Expression.Convert(target.Expression, routine.ArgFullInfo.DeclaringType);//targetObj.TypeDesc.RealType);

            //ArgFull( ((PhpObject)target), ScriptContext, args, ... )
            invokeMethodExpr = Expression.Call(BinderHelper.WrapInstanceMethodCall(routine.ArgFullInfo),
                                     BinderHelper.CombineArguments(realObjEx, arguments));

            invokeMethodExpr = ReturnArgumentHelpers.ReturnValueConversion(routine.ArgFullInfo, invokeMethodExpr);

            invokeMethodExpr = HandleResult(invokeMethodExpr, routine.ArgFullInfo.ReturnType, false);

        }
Example #3
0
        /// <summary>
        /// Stores late static binding type information if necessary.
        /// </summary>
        private void EmitArgfullLateStaticBindTypeInitialization(PhpRoutine/*!*/routine)
        {
            if (routine == null || !routine.UsesLateStaticBinding)
                return;

            if (routine.IsMethod)
            {
                if (routine.IsStatic)
                {
                    // static method,
                    // reads <context>.Stack.LateStaticBindType,
                    // saves it into a local variable:

                    // <context>.Stack.LateStaticBindType
                    this.EmitLoadScriptContext();
                    this.il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack);
                    this.il.Emit(OpCodes.Ldfld, Fields.PhpStack_LateStaticBindType);

                    // DTypeDesc <loc_lsb> =
                    this.LateStaticBindTypePlace = new IndexedPlace(il.DeclareLocal(Types.DTypeDesc[0]));
                    this.LateStaticBindTypePlace.EmitStore(il);
                }
                else
                {
                    // instance method,
                    // uses ((DObject)this).TypeDesc
                    
                    Debug.Assert(this.SelfPlace != null && this.SelfPlace != LiteralPlace.Null, "SelfPlace expected to be non-NULL");
                    this.LateStaticBindTypePlace = new MethodCallPlace(Properties.DObject_TypeDesc.GetGetMethod(), false, this.SelfPlace);
                }
            }
            else
            {
                this.LateStaticBindTypePlace = LiteralPlace.Null;
            }

            
        }
Example #4
0
		/// <summary>
		/// Declares all locals used in a function.
		/// </summary>
		private void EmitArgfullLocalsInitialization(PhpRoutine/*!*/ routine)
		{
			bool optimized = (routine.Properties & RoutineProperties.HasUnoptimizedLocals) == 0;
			bool rt_var_table = (routine.Properties & RoutineProperties.HasRTVariablesTable) != 0;

			// TODO: MarkSequencePoint(0xFeeFee, 0xFeeFee, 0xFeeFee, 0xFeeFee);

			// emits creation of a new table of variables if it will be used in a function:
			if (rt_var_table)
			{
				il.LdcI4(routine.Builder.LocalVariables.Count);
				il.Emit(OpCodes.Newobj, PhpVariable.RTVariablesTableCtor);
				RTVariablesTablePlace.EmitStore(il);
			}

			if (optimized)
			{
				// declares and initializes real locals (skips arguments):
				foreach (VariablesTable.Entry entry in routine.Builder.LocalVariables)
				{
					if (!entry.IsParameter)
					{
						LocalBuilder local;

						if (entry.IsPhpReference)
						{
							local = il.DeclareLocal(Types.PhpReference[0]);

							// local = new PhpReference();
							il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
							il.Stloc(local);
						}
						else
						{
							local = il.DeclareLocal(Types.Object[0]);
						}

						// stores local to table:
						entry.Variable = new Place(local);

						// gives locals names (if they are not parameters):
						if (sourceUnit.SymbolDocumentWriter != null)
							local.SetLocalSymInfo(entry.VariableName.Value);
					}
				}
			}
		}
Example #5
0
		/// <summary>
		/// Emits a body of an arg-full function or method overload.
		/// </summary>
        public void EmitArgfullOverloadBody(PhpRoutine/*!*/ routine, IEnumerable<Statement>/*!*/ body, Text.Span entirePosition, int declarationBodyPosition)
		{
			Debug.Assert(!routine.IsAbstract);

            if (context.Config.Compiler.Debug)
            {
                if (!routine.IsLambda)
                {
                    MarkSequencePoint(declarationBodyPosition);
                }
                il.Emit(OpCodes.Nop);

                EmitArgsAwareCheck(routine);
            }

			// declares and initializes real locals (should be before args init):
			EmitArgfullLocalsInitialization(routine);

			// initializes locals (from arguments or by empty value):
			EmitArgfullArgsInitialization(routine);

            // remember late static bind type from <stack>
            EmitArgfullLateStaticBindTypeInitialization(routine);

			// define user labels:
			DefineLabels(routine.Builder.Labels);

			// emits function's body:
            body.Emit(this);

			// marks ending "}" as the last sequence point of the routine:
			// (do not mark it in lambda functions as they are created from source code without braces);
			if (!routine.IsLambda)
			{
				MarkSequencePoint(entirePosition.End);
			}
            else if (context.Config.Compiler.Debug)
            {
                il.Emit(OpCodes.Nop);
            }

			EmitRoutineEpilogue(null, false);
		}
Example #6
0
            internal void EmitLoadArgsOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
            {
                ILEmitter il = codeGenerator.IL;

                int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryParamCount : 0;
                int formal_count = (routine.Signature != null) ? routine.Signature.ParamCount : 0;
                int actual_count = node.Parameters.Count;
                PhpTypeCode param_type;

                // loads all actual parameters which are not superfluous:
                for (int i = 0; i < Math.Min(actual_count, formal_count); i++)
                {
                    var p = node.Parameters[i];
                    codeGenerator.EmitBoxing(param_type = p.NodeCompiler<ActualParamCompiler>().Emit(p, codeGenerator));

                    // Actual param emitter should emit "boxing" to a reference if its access type is ReadRef.
                    // That's why no operation is needed here and references should match.
                    Debug.Assert((routine.Signature == null || routine.Signature.IsAlias(i)) == (param_type == PhpTypeCode.PhpReference));
                }

                // loads missing mandatory arguments:
                for (int i = actual_count; i < mandatory_count; i++)
                {
                    // CALL PhpException.MissingArgument(<i+1>,<name>);
                    il.LdcI4(i + 1);
                    il.Emit(OpCodes.Ldstr, routine.FullName);
                    codeGenerator.EmitPhpException(Methods.PhpException.MissingArgument);

                    // LOAD null;
                    if (routine.Signature.IsAlias(i))
                        il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
                    else
                        il.Emit(OpCodes.Ldnull);
                }

                // loads missing optional arguments:
                for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++)
                {
                    // LOAD Arg.Default;
                    il.Emit(OpCodes.Ldsfld, Fields.Arg_Default);
                }
            }
Example #7
0
 /// <summary>
 /// Emits IL instructions that load actual parameters on the evaluation stack.
 /// </summary>
 /// <param name="node">Instance.</param>
 /// <param name="codeGenerator">Code generator.</param>
 /// <param name="routine">PHP method being called.</param>
 /// <remarks>
 /// <para>
 /// The function has mandatory and optional formal arguments.
 /// Mandatory arguments are those formal arguments which are not preceded by 
 /// any formal argument with default value. The others are optional.
 /// If a formal argument without default value is declared beyond the last mandatory argument
 /// it is treated as optional one by the caller. The callee checks this and throws warning.
 /// </para>
 /// Missing arguments handling:
 /// <list type="bullet">
 ///   <item>missing mandatory argument - WARNING; LOAD(null);</item>
 ///   <item>missing optional argument - LOAD(Arg.Default);</item>
 ///   <item>superfluous arguments are ignored</item>
 /// </list>
 /// </remarks>
 public void EmitLoadOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
 {
     EmitLoadTypeArgsOnEvalStack(node, codeGenerator, routine);
     EmitLoadArgsOnEvalStack(node, codeGenerator, routine);
 }
Example #8
0
		/// <summary>
		/// Enumerates all export overloads for the given target PHP method.
		/// </summary>
		public static IEnumerable<StubInfo> DefineMethodExportStubs(
			PhpRoutine/*!*/ target, PhpType/*!*/ declaringType,
			MethodAttributes attributes,
			bool defineConstructors,
			StubSignatureFilter/*!*/ signatureFilter)
		{
            Debug.Assert(target.Builder != null);

            Type return_type = Types.Object[0];

            PhpRoutineSignature signature = target.Signature;
			AST.FormalParam[] formal_params = target.Builder.Signature.FormalParams;
			AST.FormalTypeParam[] formal_type_params = target.Builder.TypeSignature.TypeParams;

			int gen_sig_count = signature.GenericParamCount - signature.MandatoryGenericParamCount + 1;
			int arg_sig_count = signature.ParamCount - signature.MandatoryParamCount + 1;

			// TODO: return type hints
			// HACK: change return type to void for methods that are apparently event handlers
			if (signature.GenericParamCount == 0 && arg_sig_count == 1 && signature.ParamCount == 2 &&
				(signature.TypeHints[0] == null || signature.TypeHints[0].RealType == Types.Object[0]) &&
				(signature.TypeHints[1] != null && typeof(EventArgs).IsAssignableFrom(signature.TypeHints[1].RealType)))
			{
				return_type = Types.Void;
			}

			for (int gen_sig = 0; gen_sig < gen_sig_count; gen_sig++)
			{
				for (int arg_sig = 0; arg_sig < arg_sig_count; arg_sig++)
				{
					// determine parameter types (except for method mandatory generic parameters)
					object[] parameter_types = GetStubParameterTypes(
						arg_sig + signature.MandatoryParamCount,
						gen_sig + signature.MandatoryGenericParamCount,
						signature,
						formal_type_params);

					// determine generic parameter names
					string[] generic_param_names = new string[target.Signature.MandatoryGenericParamCount + gen_sig];
					for (int i = 0; i < generic_param_names.Length; i++)
					{
						generic_param_names[i] = formal_type_params[i].Name.ToString();
					}

					// are we allowed to generate this signature?
					if (!signatureFilter(generic_param_names, parameter_types, return_type)) continue;

					GenericTypeParameterBuilder[] generic_params = StubInfo.EmptyGenericParameters;
					MethodBase method_base = null;
					MethodBuilder method = null;

					if (!defineConstructors)
					{
                        method = declaringType.RealTypeBuilder.DefineMethod(target.FullName, attributes);

						// determine generic parameters
						if (generic_param_names.Length > 0) generic_params = method.DefineGenericParameters(generic_param_names);

						method_base = method;
					}

					ParameterInfo[] parameters = new ParameterInfo[parameter_types.Length];

					// fill in parameter infos
					Type[] real_parameter_types = new Type[parameters.Length];
					for (int i = 0; i < parameters.Length; i++)
					{
						Type type = parameter_types[i] as Type;

						// generic method parameter fixup
						if (type == null)
						{
							int index = (int)parameter_types[i];
							if (index < 0) type = generic_params[-(index + 1)].MakeByRefType();
							else type = generic_params[index];
						}

						string param_name;
						ParameterAttributes param_attrs;
						if (i < formal_params.Length)
						{
							param_name = formal_params[i].Name.ToString();
							param_attrs = (formal_params[i].IsOut ? ParameterAttributes.Out : ParameterAttributes.None);
						}
						else
						{
							param_name = "args" + (i + 1);
							param_attrs = ParameterAttributes.None;
						}

						parameters[i] = new StubParameterInfo(i, type, param_attrs, param_name);
						real_parameter_types[i] = type;
					}

					if (method != null)
					{
						method.SetParameters(real_parameter_types);
						method.SetReturnType(return_type);

						method.SetCustomAttribute(AttributeBuilders.DebuggerHidden);
					}
					else
					{
						// constructor is never a generic method
						attributes |= MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;
						attributes &= ~MethodAttributes.Virtual;

                        ConstructorBuilder constructor = declaringType.RealTypeBuilder.DefineConstructor(
							attributes, CallingConventions.Standard, real_parameter_types);
						constructor.SetCustomAttribute(AttributeBuilders.DebuggerHidden);

						method_base = constructor;
					}

					yield return new StubInfo(method_base, parameters, generic_params, return_type);
				}
			}
		}
Example #9
0
        /// <summary>
        /// Resolves a method of given <see cref="DType"/> by its name.
        /// </summary>
        /// <param name="type">The type of routine being resolved.</param>
        /// <param name="methodName">The name of routine to be resolved.</param>
        /// <param name="position">Position of method call used for error reporting.</param>
        /// <param name="referringType">The type where the seached routine is being called. Can be <c>null</c>.</param>
        /// <param name="referringRoutine">The routine where the searched routine is being called. Can be <c>null</c>.</param>
        /// <param name="calledStatically">True if the searched routine is called statically - if it uses static method call syntax.
        /// This affects the __call or __callStatic method lookup.
        /// It affects also the error reporting, where for instance method calls, the bad visibility error is
        /// ignored and falls back to return <see cref="UnknownMethod"/>.</param>
        /// <param name="checkVisibilityAtRuntime">Will determine if the routine call must be checked for visibility at runtime.</param>
        /// <param name="isCallMethod">Will determine if __call or __callStatic magic methods were found instead.</param>
        /// <returns>The resolved routine. Cannot return <c>null</c>.</returns>
		public DRoutine/*!*/ ResolveMethod(DType/*!*/ type, Name methodName, Position position,
			PhpType referringType, PhpRoutine referringRoutine, bool calledStatically,
            out bool checkVisibilityAtRuntime, out bool isCallMethod)
		{
			checkVisibilityAtRuntime = false;
            isCallMethod = false;

			// we cannot resolve a method unless we know the inherited members:
			if (type.IsDefinite)
			{
				KnownType known;

				// the method is a constructor:
				if (methodName.IsConstructName || (known = type as KnownType) != null && methodName.Equals(known.QualifiedName.Name))
					return ResolveConstructor(type, position, referringType, referringRoutine, out checkVisibilityAtRuntime);

				DRoutine routine;
				GetMemberResult member_result;

				member_result = type.GetMethod(methodName, referringType, out routine);

                // Look for __call or __callStatic magic methods if no method was found:
                // Note: __call when looking for instance method is disabled, since there can be the searched method in some future override.
                if (member_result == GetMemberResult.NotFound && calledStatically)
                {
                    // in PHP, it is possible to call instance methods statically if we are in instance method context.
                    // In such case we have to look for __call instead of __callStatic:
                    
                    // determine the proper call method:
                    // use __call for instance method invocation, including static method invocation within the current type (e.g. A::foo(), parent::foo(), ...)
                    // use __callStatic for static method invocation
                    Name callMethodName =
                        (!calledStatically ||   // just to have complete condition here, always false
                        (referringRoutine != null && referringType != null && !referringRoutine.IsStatic &&  // in non-static method
                        type.TypeDesc.IsAssignableFrom(referringType.TypeDesc)) // {CurrentType} is inherited from or equal {type}
                        ) ? DObject.SpecialMethodNames.Call : DObject.SpecialMethodNames.CallStatic;

                    member_result = type.GetMethod(callMethodName, referringType, out routine);

                    if (member_result != GetMemberResult.NotFound)
                        isCallMethod = true;
                }

				switch (member_result)
				{
					case GetMemberResult.OK:
						return routine;

					case GetMemberResult.NotFound:
                        if (calledStatically) // throw an error only in we are looking for static method, instance method can be defined in some future inherited class
                            ErrorSink.Add(Errors.UnknownMethodCalled, SourceUnit, position, type.FullName, methodName);
						return new UnknownMethod(type, methodName.Value);

					case GetMemberResult.BadVisibility:
						{
                            if (!calledStatically)    // instance method will check the routine dynamically, there can be some override later
                                return new UnknownMethod(type, methodName.Value);

							if (referringType == null && referringRoutine == null)
							{
								// visibility must be checked at run-time:
								checkVisibilityAtRuntime = true;
								return routine;
							}
							else
							{
								// definitive error:
								if (routine.IsPrivate)
								{
									ErrorSink.Add(Errors.PrivateMethodCalled, SourceUnit, position, type.FullName, methodName.Value,
										referringType.FullName);
								}
								else
								{
									ErrorSink.Add(Errors.ProtectedMethodCalled, SourceUnit, position, type.FullName, methodName.Value,
					  referringType.FullName);
								}

								return new UnknownMethod(type, methodName.Value);
							}
						}

					default:
						Debug.Fail();
						return null;
				}
			}
			else
			{
				// warning (if any) reported by the type resolver:
				return new UnknownMethod(type, methodName.Value);
			}
		}
Example #10
0
		public DType/*!*/ ResolveTypeName(GenericQualifiedName genericName, PhpType referringType,
			PhpRoutine referringRoutine, Position position, bool mustResolve)
		{
			DType type = ResolveTypeName(genericName.QualifiedName, referringType, referringRoutine, position, mustResolve);

			DTypeDesc[] arguments = (genericName.GenericParams.Length > 0) ? new DTypeDesc[genericName.GenericParams.Length] : DTypeDesc.EmptyArray;

			for (int i = 0; i < arguments.Length; i++)
			{
				arguments[i] = ResolveType(genericName.GenericParams[i], referringType, referringRoutine, position, mustResolve).TypeDesc;
			}

			return type.MakeConstructedType(this, arguments, position);
		}
Example #11
0
		private GenericParameter ResolveTypeParameterName(Name name, PhpType referringType, PhpRoutine referringRoutine)
		{
			GenericParameter result = null;

			if (referringRoutine != null)
			{
				result = referringRoutine.Signature.GetGenericParameter(name);
				if (result != null)
					return result;
			}

			if (referringType != null)
			{
				result = referringType.GetGenericParameter(name);
				if (result != null)
					return result;
			}

			return result;
		}
Example #12
0
		public DType/*!*/ ResolveTypeName(QualifiedName qualifiedName, PhpType referringType,
			PhpRoutine referringRoutine, Position position, bool mustResolve)
		{
			DType result;

			if (qualifiedName.IsSelfClassName)
			{
				if (referringType != null)
				{
					result = referringType;
				}
				else
				{
					// we are sure the self is used incorrectly in function:
					if (referringRoutine != null)
						ErrorSink.Add(Errors.SelfUsedOutOfClass, SourceUnit, position);

					// global code can be included to the method:
					result = UnknownType.UnknownSelf;
				}
			}
            else if (qualifiedName.IsStaticClassName)
            {
                if (referringType != null)
                {
                    if (referringType.IsFinal)
                    {
                        // we are sure the 'static' == 'self'
                        result = referringType;
                    }
                    else
                    {
                        if (referringRoutine != null)
                            referringRoutine.Properties |= RoutineProperties.LateStaticBinding;

                        result = StaticType.Singleton;
                    }
                }
                else
                {
                    // we are sure the static is used incorrectly in function:
                    //if (referringRoutine != null) // do not allow 'static' in global code:
                        ErrorSink.Add(Errors.StaticUsedOutOfClass, SourceUnit, position);

                    // global code can be included to the method:
                    result = UnknownType.UnknownStatic;
                }
            }
            else if (qualifiedName.IsParentClassName)
            {
                if (referringType != null)
                {
                    if (referringType.IsInterface)
                    {
                        ErrorSink.Add(Errors.ParentUsedOutOfClass, SourceUnit, position);
                        result = UnknownType.UnknownParent;
                    }
                    else
                    {
                        DType base_type = referringType.Base;
                        if (base_type == null)
                        {
                            ErrorSink.Add(Errors.ClassHasNoParent, SourceUnit, position, referringType.FullName);
                            result = UnknownType.UnknownParent;
                        }
                        else
                        {
                            result = base_type;
                        }
                    }
                }
                else
                {
                    // we are sure the self is used incorrectly when we are in a function:
                    if (referringRoutine != null)
                        ErrorSink.Add(Errors.ParentUsedOutOfClass, SourceUnit, position);

                    // global code can be included to the method:
                    result = UnknownType.UnknownParent;
                }
            }
            else
            {
                // try resolve the name as a type parameter name:
                if (qualifiedName.IsSimpleName)
                {
                    result = ResolveTypeParameterName(qualifiedName.Name, referringType, referringRoutine);
                    if (result != null)
                        return result;
                }

                Scope referring_scope = GetReferringScope(referringType, referringRoutine);
                QualifiedName? alias;
                result = sourceUnit.ResolveTypeName(qualifiedName, referring_scope, out alias, ErrorSink, position, mustResolve);

                ReportUnknownType(result, alias, position);
            }

			return result;
		}
Example #13
0
		public DType ResolveType(object typeNameOrPrimitiveType, PhpType referringType, PhpRoutine referringRoutine,
				Position position, bool mustResolve)
		{
			Debug.Assert(typeNameOrPrimitiveType == null || typeNameOrPrimitiveType is PrimitiveType
			  || typeNameOrPrimitiveType is GenericQualifiedName);

			DType result = typeNameOrPrimitiveType as PrimitiveType;
			if (result != null)
				return result;

			if (typeNameOrPrimitiveType != null)
			{
				return ResolveTypeName((GenericQualifiedName)typeNameOrPrimitiveType, referringType,
							referringRoutine, position, mustResolve);
			}

			return null;
		}
Example #14
0
		private Scope GetReferringScope(PhpType referringType, PhpRoutine referringRoutine)
		{
			if (referringType != null) return referringType.Declaration.Scope;
            if (referringRoutine is PhpFunction) return ((PhpFunction)referringRoutine).Declaration.Scope;
            //if (referringRoutine is PhpLambdaFunction) ...

			// used for global statements during full analysis:
			Debug.Assert(currentScope.IsValid, "Scope is available only during full analysis.");
			return currentScope;
		}
Example #15
0
        /// <summary>
        /// Resolves type based on provided <paramref name="typeName"/>.
        /// </summary>
        /// <param name="typeName">Either <see cref="GenericQualifiedName"/> or <see cref="PrimitiveTypeName"/> or <c>null</c> reference.</param>
        /// <param name="referringType"></param>
        /// <param name="referringRoutine"></param>
        /// <param name="position"></param>
        /// <param name="mustResolve"></param>
        /// <returns></returns>
        internal DType ResolveType(object typeName, PhpType referringType, PhpRoutine referringRoutine,
				Position position, bool mustResolve)
		{
			DType result = null;

            if (typeName != null)
            {
                if (typeName.GetType() == typeof(GenericQualifiedName))
                {
                    result = ResolveTypeName((GenericQualifiedName)typeName,
                        referringType, referringRoutine, position, mustResolve);
                }
                else if (typeName.GetType() == typeof(PrimitiveTypeName))
                {
                    result = PrimitiveType.GetByName((PrimitiveTypeName)typeName);
                }
                else
                {
                    throw new ArgumentException("typeName");
                }
            }

            return result;
		}
Example #16
0
		internal PhpRoutineBuilder(PhpRoutine/*!*/ routine, Signature signature, TypeSignature typeSignature)
		{
			this.routine = routine;
			this.signature = signature;
			this.typeSignature = typeSignature;
			this.localVariables = new VariablesTable(10);
			this.labels = new Dictionary<VariableName, Statement>(1);
		}
Example #17
0
		/// <summary>
		/// Returns a <see cref="PhpRoutineSignature"/> for the specified argfull <see cref="MethodInfo"/>.
		/// </summary>
		/// <exception cref="ReflectionException">Invalid argfull.</exception>
		public static PhpRoutineSignature/*!*/ FromArgfullInfo(PhpRoutine/*!*/ routine, MethodInfo/*!*/ argfull)
		{
			// determine aliasReturn
			bool alias_return = false;

			if (argfull.ReturnType != Types.Object[0])
			{
				if (argfull.ReturnType == Types.PhpReference[0]) alias_return = true;
				else throw new ReflectionException("TODO");
			}

			ParameterInfo[] parms = argfull.GetParameters();

			int parms_length = parms.Length;
			int parms_offset = 1;

			if (--parms_length < 0 || parms[0].ParameterType != Types.ScriptContext[0])
			{
				// TODO: resource
				throw new ReflectionException("Invalid static argfull signature of method " + routine.FullName);
			}

			// process pseudo-generic parameters:
			int j = parms_offset;
			while (j < parms.Length && parms[j].ParameterType == Types.DTypeDesc[0]) j++;
			int generic_param_count = j - parms_offset;

			int mandatory_generic_param_count = 0;
			GenericParameter[] generic_params = (generic_param_count > 0) ? new GenericParameter[generic_param_count] : GenericParameter.EmptyArray;

			for (int i = 0; i < generic_param_count; i++)
			{
				ParameterInfo pinfo = parms[i + parms_offset];
				generic_params[i] = new GenericParameter(new Name(pinfo.Name), i, routine);

				DTypeSpecAttribute default_type = DTypeSpecAttribute.Reflect(pinfo);
				if (default_type != null)
				{
					// TODO:
					// generic_params[i].WriteUp(default_type.TypeSpec.GetTypeDesc(null, null, null, null).Type);
				}
				else
				{
					generic_params[i].WriteUp(null);

					if (mandatory_generic_param_count < i)
					{
						// TODO: resource
						throw new ReflectionException("Invalid signature");
					}
					else
						mandatory_generic_param_count++;
				}
			}

			parms_offset += generic_param_count;
			parms_length -= generic_param_count;

			// set up genericParams, aliasMask, typeHints, and mandatoryParamCount:
			BitArray alias_mask = new BitArray(parms_length, false);
			DType[] type_hints = new DType[parms_length];
			int mandatory_param_count = 0;

			for (int i = 0; i < parms_length; i++)
			{
				ParameterInfo pinfo = parms[i + parms_offset];

				if (pinfo.ParameterType != Types.Object[0])
				{
					if (pinfo.ParameterType == Types.PhpReference[0])
						alias_mask[i] = true;
					else
						return null;
				}

				DTypeSpecAttribute type_hint = DTypeSpecAttribute.Reflect(pinfo);
				if (type_hint != null)
				{
					// TODO:
					// type_hints[i] = type_hint.TypeSpec.GetTypeDesc(null, null, null, null).Type;
				}

				if (!pinfo.IsOptional)
				{
					if (mandatory_param_count < i)
					{
						// invalid optional parameters
						throw new ReflectionException("Invalid signature");
					}
					else mandatory_param_count++;
				}
			}

			return new PhpRoutineSignature(generic_params, mandatory_generic_param_count).
			  WriteUp(alias_return, alias_mask, type_hints, mandatory_param_count);
		}
Example #18
0
		/// <summary>
		/// Resolves constructor of the specified type within the current context (location).
		/// </summary>
		public DRoutine/*!*/ ResolveConstructor(DType/*!*/ type, Position position, PhpType referringType,
			PhpRoutine referringRoutine, out bool checkVisibilityAtRuntime)
		{
			checkVisibilityAtRuntime = false;
			KnownRoutine ctor;

			// Do resolve ctor despite of the indefiniteness of the type to make error reporting consistent
			// when accessing the constructors thru the new operator.

			switch (type.GetConstructor(referringType, out ctor))
			{
				case GetMemberResult.OK:
					return ctor;

				case GetMemberResult.NotFound:
					// default ctor to be used:
					return new UnknownMethod(type);

				case GetMemberResult.BadVisibility:
					if (referringType == null && referringRoutine == null)
					{
						// visibility must be checked at run-time:
						checkVisibilityAtRuntime = true;
						return ctor;
					}
					else
					{
						// definitive error:
						if (ctor.IsPrivate)
						{
							ErrorSink.Add(Errors.PrivateCtorCalled, SourceUnit, position, type.FullName,
								ctor.FullName, referringType.FullName);
						}
						else
						{
							ErrorSink.Add(Errors.ProtectedCtorCalled, SourceUnit, position, type.FullName,
								ctor.FullName, referringType.FullName);
						}

						return new UnknownMethod(type);
					}

				default:
					Debug.Fail();
					return null;
			}
		}
Example #19
0
		/// <summary>
		/// Emits IL instructions that load actual parameters on the evaluation stack.
		/// </summary>
		/// <param name="codeGenerator">Code generator.</param>
		/// <param name="routine">PHP method being called.</param>
		/// <remarks>
		/// <para>
		/// The function has mandatory and optional formal arguments.
		/// Mandatory arguments are those formal arguments which are not preceded by 
		/// any formal argument with default value. The others are optional.
		/// If a formal argument without default value is declared beyond the last mandatory argument
		/// it is treated as optional one by the caller. The callee checks this and throws warning.
		/// </para>
		/// Missing arguments handling:
		/// <list type="bullet">
		///   <item>missing mandatory argument - WARNING; LOAD(null);</item>
		///   <item>missing optional argument - LOAD(Arg.Default);</item>
		///   <item>superfluous arguments are ignored</item>
		/// </list>
		/// </remarks>
		internal void EmitLoadOnEvalStack(CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
		{
			EmitLoadTypeArgsOnEvalStack(codeGenerator, routine);
			EmitLoadArgsOnEvalStack(codeGenerator, routine);
		}
Example #20
0
		/// <summary>
		/// Resolves static properties.
		/// </summary>
		public DProperty/*!*/ ResolveProperty(DType/*!*/ type, VariableName propertyName, Position position, bool staticOnly,
			PhpType referringType, PhpRoutine referringRoutine, out bool checkVisibilityAtRuntime)
		{
			Debug.Assert(type != null);

			checkVisibilityAtRuntime = false;

			// we cannot resolve a property unless we know the inherited members:
			if (type.IsDefinite)
			{
				DProperty property;
				GetMemberResult member_result = type.GetProperty(propertyName, referringType, out property);

				switch (member_result)
				{
					case GetMemberResult.OK:
						if (staticOnly && !property.IsStatic) goto case GetMemberResult.NotFound;
						return property;

					case GetMemberResult.NotFound:
						ErrorSink.Add(Errors.UnknownPropertyAccessed, SourceUnit, position, type.FullName, propertyName);
						return new UnknownProperty(type, propertyName.Value);

					case GetMemberResult.BadVisibility:
						if (referringType == null && referringRoutine == null)
						{
							// visibility must be checked at run-time:
							checkVisibilityAtRuntime = true;
							return property;
						}
						else
						{
							// definitive error:
							if (property.IsPrivate)
							{
								ErrorSink.Add(Errors.PrivatePropertyAccessed, SourceUnit, position, type.FullName, propertyName.Value,
									referringType.FullName);
							}
							else
							{
								ErrorSink.Add(Errors.ProtectedPropertyAccessed, SourceUnit, position, type.FullName, propertyName.Value,
									referringType.FullName);
							}

							return new UnknownProperty(type, propertyName.Value);
						}

					default:
						Debug.Fail();
						throw null;
				}
			}
			else
			{
				// warning (if any) reported by the type resolver:
				return new UnknownProperty(type, propertyName.Value);
			}
		}
Example #21
0
            internal void EmitLoadTypeArgsOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
            {
                ILEmitter il = codeGenerator.IL;

                int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryGenericParamCount : 0;
                int formal_count = (routine.Signature != null) ? routine.Signature.GenericParamCount : 0;
                int actual_count = node.GenericParams.Count;

                // loads all actual parameters which are not superfluous:
                for (int i = 0; i < Math.Min(actual_count, formal_count); i++)
                    node.GenericParams[i].EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);

                // loads missing mandatory arguments:
                for (int i = actual_count; i < mandatory_count; i++)
                {
                    // CALL PhpException.MissingTypeArgument(<i+1>,<name>);
                    il.LdcI4(i + 1);
                    il.Emit(OpCodes.Ldstr, routine.FullName);
                    codeGenerator.EmitPhpException(Methods.PhpException.MissingTypeArgument);

                    // LOAD DTypeDesc.ObjectTypeDesc;
                    il.Emit(OpCodes.Ldsfld, Fields.DTypeDesc.ObjectTypeDesc);
                }

                // loads missing optional arguments:
                for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++)
                {
                    // LOAD Arg.DefaultType;
                    il.Emit(OpCodes.Ldsfld, Fields.Arg_DefaultType);
                }
            }
Example #22
0
		internal DConstant ResolveClassConstantName(DType/*!*/ type, VariableName constantName,
			Position position, PhpType referringType, PhpRoutine referringRoutine, out bool checkVisibilityAtRuntime)
		{
			checkVisibilityAtRuntime = false;

			// we cannot resolve a class constant unless we know the inherited members:
			if (type.IsDefinite)
			{
				ClassConstant constant;
				GetMemberResult member_result = type.GetConstant(constantName, referringType, out constant);

				switch (member_result)
				{
					case GetMemberResult.OK:
						return constant;

					case GetMemberResult.NotFound:
						ErrorSink.Add(Errors.UnknownClassConstantAccessed, SourceUnit, position, type.FullName, constantName);
						return new UnknownClassConstant(type, constantName.Value);

					case GetMemberResult.BadVisibility:
						if (referringType == null && referringRoutine == null)
						{
							// visibility must be checked at run-time:
							checkVisibilityAtRuntime = true;
							return constant;
						}
						else
						{
							// definitive error:
							if (constant.IsPrivate)
							{
								ErrorSink.Add(Errors.PrivateConstantAccessed, SourceUnit, position, type.FullName, constantName.Value,
				  referringType.FullName);
							}
							else
							{
								ErrorSink.Add(Errors.ProtectedConstantAccessed, SourceUnit, position, type.FullName, constantName.Value,
				  referringType.FullName);
							}

							return new UnknownClassConstant(type, constantName.Value);
						}

					default:
						Debug.Fail();
						throw null;
				}
			}
			else
			{
				// warning (if any) reported by the type resolver:
				return new UnknownClassConstant(type, constantName.Value);
			}
		}
Example #23
0
 public static void EmitLoadOnEvalStack(this CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
 {
     node.NodeCompiler<ICallSignatureCompiler>().EmitLoadOnEvalStack(node, codeGenerator, routine);
 }
Example #24
0
		internal void SetEntryPoint(PhpRoutine/*!*/ routine, Position position)
		{
			// pure entry point is a static parameterless "Main" method/function:
			if (!sourceUnit.CompilationUnit.IsPure || !routine.Name.Equals(PureAssembly.EntryPointName)
			  || !routine.IsStatic || routine.Signature.ParamCount > 0)
				return;

			PureCompilationUnit pcu = (PureCompilationUnit)sourceUnit.CompilationUnit;

			if (pcu.EntryPoint != null)
			{
				ErrorSink.Add(Errors.EntryPointRedefined, SourceUnit, position);
				ErrorSink.Add(Errors.RelatedLocation, pcu.EntryPoint.SourceUnit, pcu.EntryPoint.Position);
			}
			else
			{
				pcu.SetEntryPoint(routine);
			}
		}
Example #25
0
 /// <summary>
 /// Emit check whether the argsaware routine was called properly with <see cref="PhpStack"/> initialized.
 /// </summary>
 /// <remarks>Emitted code is equivalent to <code>context.Stack.ThrowIfNotArgsaware(routine.Name.Value);</code></remarks>
 private void EmitArgsAwareCheck(PhpRoutine/*!*/ routine)
 {
     if (routine.IsArgsAware)
     {
         //  <context>.Stack.ThrowIfNotArgsaware(routine.Name.Value)
         this.EmitLoadScriptContext();   // <context>
         this.IL.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack);    // .Stack
         this.IL.Emit(OpCodes.Ldstr, routine.Name.Value);    // routine.Name.Value
         this.IL.Emit(OpCodes.Call, Methods.PhpStack.ThrowIfNotArgsaware);   // .call ThrowIfNotArgsaware
     }
 }
Example #26
0
		internal void SetEntryPoint(PhpRoutine/*!*/ routine, Position position)
		{
			// nothing to do here on silverlight..
		}
Example #27
0
		/// <summary>
		/// Emits initialization of arg-full argument variables.
		/// </summary>
		private void EmitArgfullArgsInitialization(PhpRoutine/*!*/ routine)
		{
			bool optimized = (routine.Properties & RoutineProperties.HasUnoptimizedLocals) == 0;
			bool indirect_local_access = (routine.Properties & RoutineProperties.IndirectLocalAccess) != 0;

			int real_index = routine.FirstPseudoGenericParameterIndex;
			int index = 0;

			foreach (GenericParameter param in routine.Signature.GenericParams)
			{
				if (param.DefaultType != null)
				{
					Label endif_label = il.DefineLabel();

					// IF ARG[real_index] == Arg.DefaultType) THEN
					il.Ldarg(real_index);
					il.Emit(OpCodes.Ldsfld, Fields.Arg_DefaultType);
					il.Emit(OpCodes.Bne_Un, endif_label);

					// ARG[real_index] = <typedesc(param.DefaultType)>;
					param.DefaultType.EmitLoadTypeDesc(this, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
					il.Starg(real_index);

					// ENDIF;
					il.MarkLabel(endif_label);
				}

                // add the DTypeDesc into locals
                /*{
                    EmitLoadRTVariablesTable();
                    il.Emit(OpCodes.Ldstr, "!" + param.Name.ToString().ToLower());

                    // LOAD ARG[arg_idx];
                    il.Ldarg(real_index);

                    // stores argument to table:
                    il.Emit(OpCodes.Callvirt, PhpVariable.RTVariablesTableAdder);
                }*/

				real_index++;
				index++;
			}

			real_index = routine.FirstPhpParameterIndex;
			index = 0;

			foreach (FormalParam param in routine.Builder.Signature.FormalParams)
			{
				// sets variables place in the table:
				VariablesTable.Entry entry = routine.Builder.LocalVariables[param.Name];

                bool optional = index >= routine.Signature.MandatoryParamCount;

				// only variables accessible by function's code are initialized;
				// these are 
				// - all if function has unoptimized locals or contains indirect access 
				//   (which doesn't imply unoptimized locals)
				// - those which are directly used 
				if (!optimized || indirect_local_access || entry.IsDirectlyUsed)
				{
					// if the argument is reference => the local should also be a reference:
					Debug.Assert(!param.PassedByRef || entry.IsPhpReference);

					// marks a sequence point if a parameter is initialized or type hinted:
					if (optional || param.TypeHint != null)
					{
						this.MarkSequencePoint(param.Span);
					}

					if (optional)
					{
						Label end_label = il.DefineLabel();
						Label else_label = il.DefineLabel();

						// IF (ARG[arg_idx]!=Arg.Default) THEN
						il.Ldarg(real_index);
						il.Emit(OpCodes.Ldsfld, Fields.Arg_Default);
						il.Emit(OpCodes.Beq_S, else_label);

						// emits deep copying (if not reference):
						EmitArgumentCopying(real_index, param);

						// ELSE;
						il.Emit(OpCodes.Br, end_label);
						il.MarkLabel(else_label);

						// ARG[arg_idx] = <default value>;
						EmitLoadArgumentDefaultValue(index, param, routine.FullName);
						il.Starg(real_index);

						// END IF;
						il.MarkLabel(end_label);
					}
					else
					{
						// emits deep copying (if not reference):
						EmitArgumentCopying(real_index, param);
					}

					// emits type hint test (if specified):
					param.EmitTypeHintTest(this);

					// stores argument value to the local variable or to the table //

					// prepares evaluation stack for call to <variables_table>.Add(<name>,ARG[arg_idx]):
					if (!optimized)
					{
						EmitLoadRTVariablesTable();
						il.Emit(OpCodes.Ldstr, param.Name.ToString());

						// LOAD ARG[arg_idx];
						il.Ldarg(real_index);

                        // "box" to reference (if the local is a reference and argument is not a reference):
						if (entry.IsPhpReference && !param.PassedByRef)
							il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);

						// stores argument to table:
						il.Emit(OpCodes.Callvirt, PhpVariable.RTVariablesTableAdder);
					}
					else if (entry.IsPhpReference && !param.PassedByRef)
					{
						// local variable is stored in a new reference local:
						LocalBuilder local = il.DeclareLocal(typeof(PhpReference));
						entry.Variable = new Place(local);

						// "box" to reference (if the local is a reference and argument is not a reference):
						il.Ldarg(real_index);
						il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
						il.Stloc(local);
					}
					else
					{
						// local variable is stored in the argument:
						entry.Variable = new IndexedPlace(PlaceHolder.Argument, real_index);
					}
				}
				else
				{
                    if (param.TypeHint != null)
                    {
                        if (optional)
                        {
                            // convert Arg.Default to proper default value (so TypeHint test will check the proper value):

                            Label is_default = il.DefineLabel();
                            Label end_if = il.DefineLabel();

                            // if (ARG[arg_idx] = Arg.Default) THEN
                            il.Ldarg(real_index);
                            il.Emit(OpCodes.Ldsfld, Fields.Arg_Default);
                            il.Emit(OpCodes.Beq_S, is_default);
                            il.Emit(OpCodes.Br_S, end_if);
                            {
                                // ARG[arg_idx] = <default value>;
                                il.MarkLabel(is_default);
                                EmitLoadArgumentDefaultValue(index, param, routine.FullName);
                                il.Starg(real_index);
                            }
                            il.MarkLabel(end_if);
                        }

                        // emits type hint test (if specified):
                        param.EmitTypeHintTest(this);
                    }
				}

				real_index++;
				index++;
			}
		}
Example #28
0
			internal RoutineDeclLoc(PhpRoutine/*!*/ routine, int nestingLevel)
				: base(nestingLevel)
			{
				this.routine = routine;
			}
Example #29
0
        private bool EnterFunctionDeclarationInternal(PhpRoutine/*!*/ function, QualifiedName qualifiedName)
		{
            Debug.Assert(function.IsFunction);

			bool is_optimized = (function.Properties & RoutineProperties.HasUnoptimizedLocals) == 0;
			bool indirect_local_access = (function.Properties & RoutineProperties.IndirectLocalAccess) != 0;

			CompilerLocationStack.FunctionDeclContext fd_context = new CompilerLocationStack.FunctionDeclContext();
            fd_context.Name = qualifiedName;

			// Set whether access to variables should be generated via locals or table
			fd_context.OptimizedLocals = this.OptimizedLocals;
			this.OptimizedLocals = is_optimized;

			// Set the valid method to emit the "return" statement
			fd_context.ReturnsPhpReference = this.ReturnsPhpReference;
			this.ReturnsPhpReference = function.Signature.AliasReturn;

            // CallSites
            fd_context.CallSites = null;//fd_context.CallSites = callSites;
            //this.callSites = new Compiler.CodeGenerator.CallSitesBuilder(
            //    sourceUnit.CompilationUnit.Module.GlobalType.RealModuleBuilder,
            //    fd_context.Name.ToString(),
            //    LiteralPlace.Null);
            // keep current site container, just change the class context (to avoid of creating and baking so many types)
            this.callSites.PushClassContext(LiteralPlace.Null, null);
            
            // Set ILEmitter to function's body
			fd_context.IL = this.il;
			this.il = new ILEmitter(function.ArgFullInfo);

			// Set current variables table (at codeGenerator)
			fd_context.CurrentVariablesTable = this.currentVariablesTable;
			this.currentVariablesTable = function.Builder.LocalVariables;

			// Set current variables table (at codeGenerator)
			fd_context.CurrentLabels = this.currentLabels;
			this.currentLabels = function.Builder.Labels;

			// Set place for loading hashtable with variables at runtime
			fd_context.RTVariablesTablePlace = this.RTVariablesTablePlace;

			if (indirect_local_access || !is_optimized)
			{
				LocalBuilder var_table_local = il.DeclareLocal(PhpVariable.RTVariablesTableType);
				if (sourceUnit.SymbolDocumentWriter != null)
					var_table_local.SetLocalSymInfo("<locals>");
				this.RTVariablesTablePlace = new Place(var_table_local);
			}
			else
				this.RTVariablesTablePlace = LiteralPlace.Null;

			// Set ScriptContext
			fd_context.ScriptContextPlace = this.ScriptContextPlace;
			this.ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, FunctionBuilder.ArgContext);

			// Set Class context
			fd_context.ClassContextPlace = this.TypeContextPlace;
			this.TypeContextPlace = LiteralPlace.Null;

			// Set Self
			fd_context.SelfPlace = this.SelfPlace;
			this.SelfPlace = LiteralPlace.Null;

            // Set Static
            fd_context.LateStaticBindTypePlace = this.LateStaticBindTypePlace;
            this.LateStaticBindTypePlace = null;

            // set Result place
			fd_context.ResultPlace = this.ResultPlace;
			fd_context.ReturnLabel = this.ReturnLabel;
			this.ResultPlace = null;
            
			// set exception block nesting:
			fd_context.ExceptionBlockNestingLevel = this.ExceptionBlockNestingLevel;
			this.ExceptionBlockNestingLevel = 0;

            // set current PhpRoutine
            fd_context.PhpRoutine = function;

            //
			locationStack.PushFunctionDecl(fd_context);
			return true;
		}
Example #30
0
		/// <summary>
		/// Notices the analyzer that function declaration is entered.
		/// </summary>
		internal void EnterFunctionDeclaration(PhpRoutine/*!*/ function)
		{
            Debug.Assert(function.IsFunction);

			RoutineDeclLoc f = new RoutineDeclLoc(function, locationStack.Count);
			routineDeclStack.Push(f);
			locationStack.Push(f);

			EnterConditionalCode();
		}