internal void EmitHelpers()
		{
			CompilationUnit unit = this.CompilationUnit;
			ILEmitter il = new ILEmitter(DeclareHelperBuilder);
			IndexedPlace script_context_place = new IndexedPlace(PlaceHolder.Argument, 0);

			foreach (PhpFunction function in unit.GetDeclaredFunctions())
			{
				if (function.IsDefinite)
				{
                    CodeGenerator.EmitDeclareFunction(il, script_context_place, function);
				}
			}

			foreach (PhpType type in unit.GetDeclaredTypes())
			{
				if (type.IsDefinite)
				{
					// CALL <context>.DeclareType(<type desc>, <name>);
					type.EmitAutoDeclareOnScriptContext(il, script_context_place);
				}
                else if (!type.IsComplete)
                {
                    if (type.IncompleteClassDeclareMethodInfo != null)
                    {
                        // check whether base class is known at this point of execution,
                        // if so, declare this incomplete class immediately. As PHP does.

                        type.EmitDeclareIncompleteOnScriptContext(il, script_context_place);
                    }
                }
			}

            foreach (GlobalConstant constant in unit.GetDeclaredConstants())
            {
                if (constant.IsDefinite)
                {
                    var field = constant.RealField;
                    Debug.Assert(field != null);
                    Debug.Assert(field.IsStatic);

                    // CALL <context>.DeclareConstant(<name>, <value>);
                    script_context_place.EmitLoad(il);

                    il.Emit(OpCodes.Ldstr, constant.FullName);
                    il.LoadLiteralBox(constant.Value);  //il.Emit(OpCodes.Ldsfld, field);   // const field cannot be referenced in IL
                    il.Emit(OpCodes.Call, Methods.ScriptContext.DeclareConstant);
                }
            }

			il.Emit(OpCodes.Ret);
		}
		/// <summary>
		/// Emits helper declaring all single-declared functions and classes in the script being built.
		/// </summary>
		/// <remarks>
		/// For each function and class emits a call to <see cref="ApplicationContext.DeclareFunction"/> and 
        /// <see cref="ApplicationContext.DeclareType"/>, respectively, which declares it.
		/// The helper is called as the first instruction of Main helper. 
		/// </remarks>		
		private void EmitDeclareHelper()
		{
			PureCompilationUnit unit = this.PureCompilationUnit;
			ILEmitter il = new ILEmitter(declareHelperBuilder);
			IndexedPlace app_context_place = new IndexedPlace(PlaceHolder.Argument, 0);
            TypeBuilder publicsContainer = null;    // container type for public stubs of global declarations (which are inaccessible from other assemblies)

			foreach (PhpFunction function in unit.GetDeclaredFunctions())
			{
				if (function.IsDefinite)
				{
					app_context_place.EmitLoad(il);

					// NEW RoutineDelegate(<static method>);
					il.Emit(OpCodes.Ldnull);
					il.Emit(OpCodes.Ldftn, function.ArgLessInfo);
					il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate);

					// LOAD <full name>;
					il.Emit(OpCodes.Ldstr, function.FullName);

					// LOAD <attributes>;
					il.LdcI4((int)function.MemberDesc.MemberAttributes);

                    // LOAD <argfull>
                    if (function.ArgFullInfo != null)
                        CodeGenerator.EmitLoadMethodInfo(
                            il,
                            (function.ArgFullInfo.DeclaringType != null)
                                ? function.ArgFullInfo
                                : EmitPhpFunctionPublicStub(ref publicsContainer, function) // function.ArgFullInfo is real global method not accessible from other assemblies, must be wrapped
                            /*, AssemblyBuilder.DelegateBuilder*/);
                    else
                        il.Emit(OpCodes.Ldnull);
                    
					// CALL <application context>.DeclareFunction(<stub>, <name>, <member attributes>, <argfull>)
					il.Emit(OpCodes.Call, Methods.ApplicationContext.DeclareFunction);
				}
			}

			foreach (PhpType type in unit.GetDeclaredTypes())
			{
				if (type.IsDefinite)
				{
					// CALL <application context>.DeclareType(<type desc>, <name>);
					type.EmitAutoDeclareOnApplicationContext(il, app_context_place);
				}
			}

			foreach (GlobalConstant constant in unit.GetDeclaredConstants())
			{
				if (constant.IsDefinite)
				{
					app_context_place.EmitLoad(il);

					// CALL <application context>.DeclareConstant(<name>, <value>);
					il.Emit(OpCodes.Ldstr, constant.FullName);
                    //il.Emit(OpCodes.Ldsfld, constant.RealField);
                    //if (constant.RealField.FieldType.IsValueType) il.Emit(OpCodes.Box, constant.RealField.FieldType);
                    il.LoadLiteralBox(constant.Value);
					il.Emit(OpCodes.Call, Methods.ApplicationContext.DeclareConstant);
				}
			}

			il.Emit(OpCodes.Ret);

            // complete the publicsContainer type, if created:
            if (publicsContainer != null)
                publicsContainer.CreateType();
		}
Exemple #3
0
		/// <summary>
		/// Called when a <see cref="PHP.Core.AST.ConstantDecl"/> AST node is visited during the emit phase.
		/// </summary>
		/// <param name="constant">The constant.</param>
		/// <remarks>
		/// Even interface constants are permitted in PHP. These are implemented by <B>static</B> <B>initonly</B>
		/// fields in the interface, which causes some complaints in the .NET Framework 1.1 verifier.
		/// However it is rather a verifier bug - .NET Framework 2.0 verifier is fixed and verifies it OK.
		/// </remarks>
		public void InitializeClassConstant(ClassConstant/*!*/ constant)
		{
			Debug.Assert(constant != null);

            // real constant definition
            if (constant.RealField.IsLiteral)
            {
                Debug.Assert(constant.RealFieldBuilder != null);
                constant.RealFieldBuilder.SetConstant(constant.Value);
                return;
            }

			// class constant initialization is emitted into the static constructor
			ILEmitter old_il = il;
			IPlace old_sc_emitter = ScriptContextPlace;
			try
			{
				// set il and SC-emitter appropriately
				
				if (constant.HasValue)
				{
					il = constant.DeclaringPhpType.Builder.StaticCtorEmitter;
                    il.LoadLiteralBox(constant.Value);
				}
				else
				{
                    il = new ILEmitter(constant.DeclaringPhpType.StaticFieldInitMethodBuilder);
                    ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgContext);

					// emit the expression evaluating code
					EmitBoxing(constant.Node.Initializer.Emit(this));
				}

				// store it in the field
				il.Emit(OpCodes.Stsfld, constant.RealField);
			}
			finally
			{
				// restore the saved il and SC-emitter
				il = old_il;
				ScriptContextPlace = old_sc_emitter;
			}
		}