Groups configuration related to the compiler. Includes ApplicationConfiguration.CompilerSection and ApplicationConfiguration.GlobalizationSection sections of global configuration record. Used for passing configuration for the purpose of compilation.
Пример #1
0
        /// <summary>
        /// Creates a compilation context.
        /// </summary>
        /// <param name="applicationContext">Application context.</param>
        /// <param name="manager">Manager.</param>
        /// <param name="config">Configuration.</param>
        /// <param name="errorSink">Error sink.</param>
        /// <param name="workingDirectory">Working directory.</param>
        internal CompilationContext(ApplicationContext /*!*/ applicationContext, ICompilerManager manager, CompilerConfiguration /*!*/ config, ErrorSink /*!*/ errorSink,
                                    string /*!*/ workingDirectory)
        {
            Debug.Assert(applicationContext != null);
            Debug.Assert(config != null && workingDirectory != null);

            this.applicationContext = applicationContext;
            this.manager            = manager;
            this.config             = config;
            this.errors             = errorSink;
            this.workingDirectory   = workingDirectory;
        }
Пример #2
0
		/// <summary>
		/// Creates a compilation context.
		/// </summary>
        /// <param name="applicationContext">Application context.</param>
		/// <param name="manager">Manager.</param>
		/// <param name="config">Configuration.</param>
		/// <param name="errorSink">Error sink.</param>
		/// <param name="workingDirectory">Working directory.</param>
        internal CompilationContext(ApplicationContext/*!*/ applicationContext, ICompilerManager manager, CompilerConfiguration/*!*/ config, ErrorSink/*!*/ errorSink,
			string/*!*/ workingDirectory)
		{
            Debug.Assert(applicationContext != null);
			Debug.Assert(config != null && workingDirectory != null);

            this.applicationContext = applicationContext;
			this.manager = manager;
			this.config = config;
			this.errors = errorSink;
			this.workingDirectory = workingDirectory;
		}
Пример #3
0
		/// <summary>
		/// Translates a source path to an assembly coded name.
		/// </summary>
		/// <param name="sourceFile">Source file.</param>
		/// <param name="config">The compiler configuration.</param>
		/// <returns>
		/// The code name consisting of significant configuration hashcode and source 
		/// path relative to the application source root.
		/// Format of the name: <code>{relativized path}(~{level_count})?#{config hash}#</code>
		/// Backslashes and colons are replaced with underscores, underscores are doubled.
		/// </returns>
		public static string GetAssemblyCodedName(PhpSourceFile/*!*/ sourceFile, CompilerConfiguration/*!*/ config)
		{
			RelativePath rp = sourceFile.RelativePath;
			StringBuilder sb = new StringBuilder(rp.Path);

			if (rp.Level >= 0)
			{
				sb.Append('~');
				sb.Append(rp.Level);
			}

			sb.Append('#');
			sb.Append(config.Compiler.HashCode.ToString("x"));
			sb.Append('#');

            return sb.Replace("_", "__").Replace('/', '_').Replace('\\', '_').Replace(':', '_').ToString();
		}
Пример #4
0
		public void ApplyToConfiguration(CompilerConfiguration/*!*/ compilerConfig)
		{
			if (compilerConfig == null)
				throw new ArgumentNullException("compilerConfig");

			if (languageFeatures.HasValue)
			{
				compilerConfig.Compiler.LanguageFeatures = languageFeatures.Value;
			}
			else
			{
				// sets the default language features for pure mode if not set yet:
				if (pure && !compilerConfig.Compiler.LanguageFeaturesSet)
					compilerConfig.Compiler.LanguageFeatures = Core.LanguageFeatures.PureModeDefault;
			}

			// cmd line:
			if (debuggable.HasValue)
				compilerConfig.Compiler.Debug = (bool)debuggable;

			if (staticInclusions.HasValue)
				compilerConfig.Compiler.EnableStaticInclusions = staticInclusions;

            // paths skipped during compilation are also forced dynamic inclusion paths (otherwise static inclusion could force compilation of these sources files)
            foreach (string path in skipPaths)
            {
                compilerConfig.Compiler.ForcedDynamicInclusionPaths.Add(path);
            }

			// static inclusion will be enabled for non-web applications if not set:
			if (!compilerConfig.Compiler.EnableStaticInclusions.HasValue && target != Targets.Web)
				compilerConfig.Compiler.EnableStaticInclusions = true;

			if (encoding != null)
				compilerConfig.Globalization.PageEncoding = encoding;

			// enable all warnings in pure mode by default:
			if (pure)
				compilerConfig.Compiler.DisabledWarnings = WarningGroups.None;

			// disableWarnings and enableWarnings sets are disjoint:
			compilerConfig.Compiler.DisabledWarnings |= disableWarnings;
			compilerConfig.Compiler.DisabledWarnings &= ~enableWarnings;
            compilerConfig.Compiler.DisabledWarningNumbers = compilerConfig.Compiler.DisabledWarningNumbers.Concat(disableWarningNumbers).Distinct().ToArray();

            // Treat Warnings as Errors
            compilerConfig.Compiler.TreatWarningsAsErrors = this.TreatWarningsAsErrors;

			// sets source root (overrides any config setting):
			compilerConfig.Compiler.SourceRoot = new FullPath(sourceRoot);
		}
Пример #5
0
        /// <summary>
        /// Loads configuration from Machine.config, phpc.exe.config, from files specified by command line arguments,
        /// and from command line arguments themselves.
        /// </summary>
        /// <exception cref="ConfigurationErrorsException">An error occured while loading the configuration.</exception>
        public static CompilerConfiguration/*!*/ LoadConfiguration(
            ApplicationContext/*!*/ appContext, List<FullPath>/*!*/ paths, TextWriter output)
        {
            Configuration.IsBuildTime = true;

            Configuration.Reload(appContext, true);

            // Machine.config, phpc.exe.config:
            CompilerConfiguration result = new CompilerConfiguration(Configuration.Application);

            // explicitly specified or default configs:
            foreach (FullPath path in paths)
            {
                if (output != null) output.WriteLine(path);
                result.LoadFromFile(appContext, path);
            }

            // load libraries lazily
            result.LoadLibraries(appContext);

            //
            return result;
        }
Пример #6
0
        /// <summary>
		/// Compiles an application.
		/// </summary>
		/// <param name="applicationContext">Application context.</param>
		/// <param name="config">Compiler configuration record.</param>
		/// <param name="errorSink">Error sink.</param>
		/// <param name="ps">Parameters.</param>
		/// <exception cref="InvalidSourceException">Cannot read a source file/directory. See the inner exception for details.</exception>
		public void Compile(
			ApplicationContext/*!*/ applicationContext,
			CompilerConfiguration/*!*/ config,
			ErrorSink/*!*/ errorSink,
			CompilationParameters/*!*/ ps)
		{
			if (applicationContext == null) throw new ArgumentNullException("applicationContext");
			if (config == null) throw new ArgumentNullException("config");
			if (errorSink == null) throw new ArgumentNullException("errorSink");
			ps.Validate();

			PhpSourceFile entry_point_file = (ps.StartupFile != null) ? new PhpSourceFile(config.Compiler.SourceRoot, ps.StartupFile) : null;
			List<ResourceFileReference> resource_files = ResourceFileReference.FromFiles(ps.Resources);

			// creates directory if not exists:
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(ps.OutPath));
			}
			catch (Exception ex)
			{
				errorSink.Add(FatalErrors.ErrorCreatingFile, null, ErrorPosition.Invalid, ps.OutPath, ex.Message);
			}	
				
			AssemblyKinds kind;

			switch (ps.Target)
			{
				case Targets.Dll:
					kind = AssemblyKinds.Library;
					entry_point_file = null;
					break;

				case Targets.Console:
					kind = AssemblyKinds.ConsoleApplication;
					break;

				case Targets.WinApp:
					kind = AssemblyKinds.WindowApplication;
					break;

				case Targets.Web:
					kind = AssemblyKinds.WebPage;
					entry_point_file = null;
					break;

				default:
                    throw new ArgumentException();
			}

			PhpAssemblyBuilder assembly_builder = PhpAssemblyBuilder.Create(applicationContext, kind, ps.Pure, ps.OutPath,
				ps.DocPath, entry_point_file, ps.Version, ps.Key, ps.Icon, resource_files, config.Compiler.Debug, ps.Force32Bit);

			assembly_builder.IsMTA = ps.IsMTA;
			
			Statistics.CompilationStarted();

			ICompilerManager manager = (!ps.Pure) ? new ApplicationCompilerManager(applicationContext, assembly_builder) : null;

            try
            {
                CompilationContext context = new CompilationContext(applicationContext, manager, config, errorSink, config.Compiler.SourceRoot);

                assembly_builder.Build(EnumerateScripts(ps.SourcePaths, ps.SourceDirs, ps.FileExtensions, context), context);

                if (!context.Errors.AnyError && (ps.Target == Targets.Console || ps.Target == Targets.WinApp))
                    CopyApplicationConfigFile(config.Compiler.SourceRoot, ps.OutPath);
            }
            catch (CompilerException e)
            {
                errorSink.Add(e.ErrorInfo, null, ErrorPosition.Invalid, e.ErrorParams);
            }
            catch (InvalidSourceException e)
            {
                e.Report(errorSink);
            }
            catch (Exception e)
            {
#if DEBUG
                //Console.WriteLine("Unexpected error: {0}", e.ToString());// removed, exception added into the error sink, so it's displayed in the VS Integration too
#endif
                errorSink.AddInternalError(e);  // compilation will fail, error will be displayed in Errors by VS Integration               
            }
			finally
			{
#if DEBUG
				Console.WriteLine();
				Console.WriteLine("Statistics:");
				Statistics.Dump(Console.Out, Path.GetDirectoryName(ps.OutPath));
				Console.WriteLine();
#endif
			}
        }
Пример #7
0
        /// <summary>
        /// Tries to load script from ASP.NET Temporary files - this is useful when 
        /// web is not precompiled (so it is compiled into SSAs) and appdomain is reloaded
        /// (which means that we loose the cache)
        /// </summary>
        private bool TryLoadTemporaryCompiledNoLock(string ns, PhpSourceFile/*!*/ sourceFile, out CacheEntry cache_entry)
        {
            CompilerConfiguration config = new CompilerConfiguration(Configuration.Application);
            string name = WebCompilationContext.GetAssemblyCodedName(sourceFile, config);

            string sourcePath = sourceFile.FullPath.ToString();
            bool sourceExists = File.Exists(sourcePath);
            DateTime sourceTime = sourceExists ? File.GetLastWriteTime(sourcePath) : DateTime.UtcNow.AddYears(1);   // If file does not exist, fake the sourceTime to NOT load any SSA DLL. Delete them instead.
            DateTime configTime = Configuration.LastConfigurationModificationTime;

            // here find the max modification of all dependant files (configuration, script itself, other DLLs):
            long sourceStamp = Math.Max(Math.Max(sourceTime.Ticks, configTime.Ticks), appCodeAssemblyCreated.Ticks);

            // Find specified file in temporary files

            if (Directory.Exists(outDir))

            foreach (string file in Directory.GetFiles(outDir, name + "*.dll"))
            {
                Match match = reFileStamp.Match(file);
                if (!match.Success) continue;

                long fileStamp;
                if (!Int64.TryParse((string)match.Groups["Stamp"].Value, NumberStyles.AllowHexSpecifier,
                    CultureInfo.InvariantCulture, out fileStamp)) continue;

                // File is up-to-date
                if (sourceStamp < fileStamp)
                {
                    Debug.WriteLine("WSSM", "Loading from ASP.NET Temporary files.");

                    return LoadSSA(ns, file, out cache_entry);
                }
                else
                {
                    // do "some" cleanup:
                    try
                    {
                        File.Delete(file);
                        File.Delete(Path.ChangeExtension(file, ".pdb"));
                    }
                    catch{ /*nop*/ }
                }
            }
            cache_entry = default(CacheEntry);
            return false;
        }
Пример #8
0
        public WebCompilationContext(ApplicationContext applicationContext, ICompilerManager/*!*/ manager, CompilerConfiguration/*!*/ config, string/*!*/ workingDirectory,
		  DateTime requestTimestamp)
			: base(applicationContext, manager, config, new WebErrorSink(config.Compiler.DisabledWarnings, config.Compiler.DisabledWarningNumbers), workingDirectory)
		{
			this.requestTimestamp = requestTimestamp;
		}
Пример #9
0
		/// <summary>
		/// Compiles a script.
		/// Called when the script cannot be loaded from pre-compiled assembly and it should be compiled.
		/// </summary>
		/// <returns>The compiled script type.</returns>
        private ScriptInfo CompileScriptNoLock(string ns, PhpSourceFile/*!*/ sourceFile, RequestContext requestContext)
		{
            Debug.Assert(sourceFile != null);

			CompilerConfiguration config = new CompilerConfiguration(Configuration.Application);
			WebCompilationContext context = new WebCompilationContext(applicationContext, this, config, sourceFile.Directory, 
				(requestContext != null) ? requestContext.HttpContext.Timestamp : DateTime.UtcNow);

			try
			{
				CacheEntry cache_entry;
                if (ScriptAssemblyBuilder.CompileScripts(new PhpSourceFile[] { sourceFile }, context))
                {
                    // assembly should be already added into the cache by Persist() method
                    if (TryGetCachedEntry(ns, out cache_entry))
                        return cache_entry.ScriptInfo;
                }

                return null;
			}
			catch (CompilerException)
			{
				return null;
			}
			catch (Exception)
			{
				// record stack info to the message if the manager resides in a dedicated domain:
				throw;
			}
		}
Пример #10
0
		/// <summary>
		/// Implements PHP <c>eval</c> construct with given code prefix and suffix. 
		/// A result of concatanation prefix + code + suffix is compiled.
		/// Prefix should contain no new line characters.
		/// </summary>
		internal static object EvalInternal(
			string prefix,
			string code,
			string suffix,
			EvalKinds kind,
			ScriptContext/*!*/ scriptContext,
			Dictionary<string, object> localVariables,
			DObject self,
			DTypeDesc referringType,
			SourceCodeDescriptor descriptor,
			bool entireFile, 
			NamingContext namingContext)
		{
			Debug.Assert(prefix != null && suffix != null);

			// composes code to be compiled:
			code = String.Concat(prefix, code, suffix);

			TransientAssemblyBuilder assembly_builder = scriptContext.ApplicationContext.TransientAssemblyBuilder;

			// looks up the cache:
			TransientModule module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

            if (module == null)
                // double checked lock,
                // if module != null, it is definitely completed
                // since module is added into TransientAssembly at the end
                // of assembly_builder.Build
                lock (assembly_builder.TransientAssembly)
                {
                    // lookup again, since it could be added into TransientAssembly while lock
                    module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

                    if (module == null)
                    {
                        if (kind == EvalKinds.SyntheticEval)
                            Debug.WriteLine("SYN EVAL", "Eval cache missed: '{0}'", code.Substring(0, Math.Max(code.IndexOf('{'), 0)).TrimEnd());
                        else
                            Debug.WriteLine("EVAL", "Eval cache missed: '{0}'({1},{2})", descriptor.ContainingSourcePath, descriptor.Line, descriptor.Column);

                        CompilerConfiguration config = new CompilerConfiguration(Configuration.Application);

                        CompilationContext context = new CompilationContext(scriptContext.ApplicationContext, null, config,
                            new EvalErrorSink(-prefix.Length, config.Compiler.DisabledWarnings, config.Compiler.DisabledWarningNumbers),
                            scriptContext.WorkingDirectory);

                        TransientCompilationUnit unit = assembly_builder.Build(code, descriptor, kind, context,
                            scriptContext, referringType, namingContext, entireFile);

                        // compilation failed:
                        if (unit == null) return false;
                        module = unit.TransientModule;
                    }
                }
			
			// activates unconditionally declared types, functions and constants: 
            module.TransientCompilationUnit.Declare(scriptContext);

			return module.Main(scriptContext, localVariables, self, referringType, true);
		}
Пример #11
0
        /// <summary>
        /// Implements PHP <c>eval</c> construct with given code prefix and suffix.
        /// A result of concatanation prefix + code + suffix is compiled.
        /// Prefix should contain no new line characters.
        /// </summary>
        internal static object EvalInternal(
            string prefix,
            string code,
            string suffix,
            EvalKinds kind,
            ScriptContext /*!*/ scriptContext,
            Dictionary <string, object> localVariables,
            DObject self,
            DTypeDesc referringType,
            SourceCodeDescriptor descriptor,
            bool entireFile,
            NamingContext namingContext)
        {
            Debug.Assert(prefix != null && suffix != null);

            // composes code to be compiled:
            code = String.Concat(prefix, code, suffix);

            TransientAssemblyBuilder assembly_builder = scriptContext.ApplicationContext.TransientAssemblyBuilder;

            // looks up the cache:
            TransientModule module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

            if (module == null)
            {
                // double checked lock,
                // if module != null, it is definitely completed
                // since module is added into TransientAssembly at the end
                // of assembly_builder.Build
                lock (assembly_builder.TransientAssembly)
                {
                    // lookup again, since it could be added into TransientAssembly while lock
                    module = assembly_builder.TransientAssembly.GetModule(scriptContext, referringType, code, descriptor);

                    if (module == null)
                    {
                        if (kind == EvalKinds.SyntheticEval)
                        {
                            Debug.WriteLine("SYN EVAL", "Eval cache missed: '{0}'", code.Substring(0, Math.Max(code.IndexOf('{'), 0)).TrimEnd());
                        }
                        else
                        {
                            Debug.WriteLine("EVAL", "Eval cache missed: '{0}'({1},{2})", descriptor.ContainingSourcePath, descriptor.Line, descriptor.Column);
                        }

                        CompilerConfiguration config = new CompilerConfiguration(Configuration.Application);

                        CompilationContext context = new CompilationContext(scriptContext.ApplicationContext, null, config,
                                                                            new EvalErrorSink(-prefix.Length, config.Compiler.DisabledWarnings, config.Compiler.DisabledWarningNumbers),
                                                                            scriptContext.WorkingDirectory);

                        TransientCompilationUnit unit = assembly_builder.Build(code, descriptor, kind, context,
                                                                               scriptContext, referringType, namingContext, entireFile);

                        // compilation failed:
                        if (unit == null)
                        {
                            return(false);
                        }
                        module = unit.TransientModule;
                    }
                }
            }

            // activates unconditionally declared types, functions and constants:
            module.TransientCompilationUnit.Declare(scriptContext);

            return(module.Main(scriptContext, localVariables, self, referringType, true));
        }