For LeMP: an input file plus per-file options (input and output language) and output code.
Example #1
0
		protected override void WriteOutput(InputOutput io)
		{
			Results = io.Output;
			Output = new StringBuilder();
			foreach (LNode node in Results) {
				LNode.Printer(node, Output, Sink, null, IndentString, NewlineString);
				Output.Append(NewlineString);
			}
		}
Example #2
0
        protected virtual void WriteOutput(InputOutput io)
        {
            Debug.Assert(io.FileName != io.OutFileName);

            Sink.Write(Severity.Verbose, io, "Writing output file: {0}", io.OutFileName);

            using (var stream = File.Open(io.OutFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
                using (var writer = new StreamWriter(stream, Encoding.UTF8)) {
                    var options = new LNodePrinterOptions {
                        IndentString  = IndentString,
                        NewlineString = NewlineString
                    };
                    var str = io.OutPrinter.Print(io.Output, Sink, null, options);
                    writer.Write(str);
                }
        }
Example #3
0
        /// <summary>Opens a set of source files by file name, and creates an <see cref="InputOutput"/> object for each.</summary>
        /// <param name="sink">Any I/O errors that occur will be logged to this object.</param>
        /// <param name="fileNames">List of file names</param>
        /// <returns>a list of files that were opened, together with their settings.
        /// This method does not run the macro processor on these files.</returns>
        public static List <InputOutput> OpenSourceFiles(IMessageSink sink, IEnumerable <string> fileNames)
        {
            var openFiles = new List <InputOutput>();

            foreach (var filename in fileNames)
            {
                try {
                    var stream = File.OpenRead(filename);
                    var io     = new InputOutput(new StreamCharSource(stream), Path.GetFullPath(filename));
                    openFiles.Add(io);
                } catch (Exception ex) {
                    sink.Error(filename, ex.GetType().Name + ": " + ex.Message);
                }
            }
            return(openFiles);
        }
Example #4
0
        /// <summary>Opens a set of source files by file name, and creates a text file for each.</summary>
        /// <param name="sink"></param>
        /// <param name="fileNames"></param>
        /// <returns></returns>
        public static List <InputOutput> OpenSourceFiles(IMessageSink sink, IEnumerable <string> fileNames)
        {
            var openFiles = new List <InputOutput>();

            foreach (var filename in fileNames)
            {
                try {
                    var stream = File.OpenRead(filename);
                    var text   = File.ReadAllText(filename, Encoding.UTF8);
                    var io     = new InputOutput(new StreamCharSource(stream), filename);
                    openFiles.Add(io);
                } catch (Exception ex) {
                    sink.Write(Severity.Error, filename, ex.GetType().Name + ": " + ex.Message);
                }
            }
            return(openFiles);
        }
Example #5
0
        private void WriteOutput2(InputOutput io)
        {
            Debug.Assert(io.FileName != io.OutFileName);

            Sink.Write(Severity.Verbose, io, "Writing output file: {0}", io.OutFileName);

            using (var stream = File.Open(io.OutFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
                using (var writer = new StreamWriter(stream, Encoding.UTF8)) {
                    var sb = new StringBuilder();
                    foreach (LNode node in io.Output)
                    {
                        io.OutPrinter(node, sb, Sink, null, IndentString, NewlineString);
                        writer.Write(sb.ToString());
                        writer.Write(NewlineString);
                        sb.Length = 0;                 // Clear() is new in .NET 4
                    }
                }
        }
Example #6
0
 public void CompleteInputOutputOptions(InputOutput file)
 {
     if (file.InputLang == null)
     {
         var inLang = InLang ?? ParsingService.Current;
         if (!ForceInLang || InLang == null)
         {
             inLang = ParsingService.GetServiceForFileName(file.FileName) ?? inLang;
         }
         file.InputLang = inLang;
     }
     if (file.OutFileName == null)
     {
         string inputFN = file.FileName;
         if (OutExt == null)
         {
             file.OutFileName = inputFN;
         }
         else
         {
             int dot = IndexOfExtension(inputFN);
             file.OutFileName = inputFN.Left(dot) + OutExt;
         }
         if (file.OutFileName == inputFN)
         {
             // e.g. input.cs => input.out.cs
             int dot = IndexOfExtension(inputFN);
             file.OutFileName = file.OutFileName.Insert(dot, ".out");
         }
     }
     if (file.OutPrinter == null)
     {
         var outLang = OutLang;
         if (outLang == null && OutExt != null)
         {
             var lang = ParsingService.GetServiceForFileName(OutExt);
             if (lang != null)
             {
                 outLang = lang.Printer;
             }
         }
         file.OutPrinter = outLang ?? LNode.Printer;
     }
 }
Example #7
0
        /// <summary>Writes results from <see cref="InputOutput.Output"/> to
        /// <see cref="InputOutput.OutFileName"/> using <see cref="InputOutput.OutPrinter"/>
        /// according to <see cref="InputOutput.OutOptions"/>.</summary>
        /// <remarks>In case of --eval inputs, output is sent to the Console.
        /// Status, warning and error messages are sent to <see cref="Sink"/>.</remarks>
        protected virtual void WriteOutput(InputOutput io)
        {
            Debug.Assert(io.FileName != io.OutFileName);

            if (io.OutFileName == "" && io.FileName.StartsWith("--eval"))
            {
                // Print result of --eval to console
                var str = io.OutPrinter.Print(io.Output, Sink, null, io.OutOptions);
                Console.WriteLine(str);
            }
            else
            {
                Sink.Write(Severity.Verbose, io, "Writing output file: {0}", io.OutFileName);

                using (var stream = File.Open(io.OutFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
                    using (var writer = new StreamWriter(stream, Encoding.UTF8))
                    {
                        var str = io.OutPrinter.Print(io.Output, Sink, null, io.OutOptions);
                        writer.Write(str);
                    }
            }
        }
Example #8
0
        public VList <LNode> ProcessFile(InputOutput io, Action <InputOutput> onProcessed)
        {
            using (ParsingService.PushCurrent(io.InputLang ?? ParsingService.Current)) {
                try {
                    string dir = Path.GetDirectoryName(io.FileName);
                    if (!string.IsNullOrEmpty(dir))
                    {
                        _rootScopedProperties[(Symbol)"#inputFolder"] = dir;
                    }
                    _rootScopedProperties[(Symbol)"#inputFileName"] = Path.GetFileName(io.FileName);
                } catch (ArgumentException) { }                    // Path.* may throw
                catch (PathTooLongException) { }                   // Path.* may throw

                var input   = ParsingService.Current.Parse(io.Text, io.FileName, _sink);
                var inputRV = new VList <LNode>(input);

                io.Output = ProcessRoot(inputRV);
                if (onProcessed != null)
                {
                    onProcessed(io);
                }
                return(io.Output);
            }
        }
Example #9
0
		public void CompleteInputOutputOptions(InputOutput file)
		{
			if (file.InputLang == null) {
				var inLang = InLang ?? ParsingService.Default;
				if (!ForceInLang || InLang == null)
					inLang = ParsingService.GetServiceForFileName(file.FileName) ?? inLang;
				file.InputLang = inLang;
			}
			if (file.OutFileName == null) {
				string inputFN = file.FileName;
				if (OutExt == null)
					file.OutFileName = inputFN;
				else {
					int dot = IndexOfExtension(inputFN);
					file.OutFileName = inputFN.Left(dot) + OutExt;
				}
				if (file.OutFileName == inputFN) {
					// e.g. input.cs => input.out.cs
					int dot = IndexOfExtension(inputFN);
					file.OutFileName = file.OutFileName.Insert(dot, ".out");
				}
			}
			if (file.OutPrinter == null) {
				var outLang = OutLang;
				if (outLang == null && OutExt != null) {
					var lang = ParsingService.GetServiceForFileName(OutExt); 
					if (lang != null) outLang = lang as ILNodePrinter;
				}
				file.OutPrinter = outLang ?? LNode.Printer;
			}
			if (file.OutOptions == null)
                file.OutOptions = OutOptions;
			if (file.PreserveComments == null)
				file.PreserveComments = PreserveComments;
			if (file.ParsingMode == null)
				file.ParsingMode = ParsingMode;
		}
Example #10
0
			protected override void WriteOutput(InputOutput io)
			{
				RVList<LNode> results = io.Output;
				var printer = LNode.Printer;
				if (!NoOutHeader)
					Output.AppendFormat(
						"// Generated from {1} by LeMP custom tool. LLLPG version: {2}{0}"
						+ "// Note: you can give command-line arguments to the tool via 'Custom Tool Namespace':{0}"
						+ "// --no-out-header       Suppress this message{0}"
						+ "// --verbose             Allow verbose messages (shown by VS as 'warnings'){0}"
						+ "// --macros=FileName.dll Load macros from FileName.dll, path relative to this file {0}"
						+ "// Use #importMacros to use macros in a given namespace, e.g. #importMacros(Loyc.LLPG);{0}", NewlineString, 
						Path.GetFileName(io.FileName), typeof(Rule).Assembly.GetName().Version.ToString());
				foreach (LNode node in results)
				{
					printer(node, Output, Sink, null, IndentString, NewlineString);
					Output.Append(NewlineString);
				}
			}
Example #11
0
		protected override byte[] Generate(string inputFilePath, string inputFileContents, string defaultNamespace, IVsGeneratorProgress progressCallback)
		{
			string oldCurDir = Environment.CurrentDirectory;
			try {
				string inputFolder = Path.GetDirectoryName(inputFilePath);
 				Environment.CurrentDirectory = inputFolder; // --macros should be relative to file being processed

				var options = new BMultiMap<string, string>();
				var argList = G.SplitCommandLineArguments(defaultNamespace);
				UG.ProcessCommandLineArguments(argList, options, "", LeMP.Compiler.ShortOptions, LeMP.Compiler.TwoArgOptions);

				string _;
				var KnownOptions = LeMP.Compiler.KnownOptions;
				if (options.TryGetValue("help", out _) || options.TryGetValue("?", out _))
					LeMP.Compiler.ShowHelp(KnownOptions);
				
				// Originally I wrote a conversion from IVsGeneratorProgress to
 				// IMessageSink so that errors could be reported immediately and
				// directly to Visual Studio. This broke in a bizarre way when I
				// added processing on a separate thread (in order to be able to
				// abort the thread if it runs too long); I got the following
				// InvalidCastException: "Unable to cast COM object of type 'System.__ComObject' 
				// to interface type 'Microsoft.VisualStudio.Shell.Interop.IVsGeneratorProgress'.
				// This operation failed because the QueryInterface call on the COM component for 
				// the interface with IID '{BED89B98-6EC9-43CB-B0A8-41D6E2D6669D}' failed due to 
				// the following error: No such interface supported (Exception from HRESULT: 
				// 0x80004002 (E_NOINTERFACE))."
				// 
				// A simple solution is to store the messages rather than reporting
				// them immediately. I'll report the errors at the very end.
				MessageHolder sink = new MessageHolder();
				
				var sourceFile = new InputOutput((UString)inputFileContents, Path.GetFileName(inputFilePath));

				var c = new Compiler(sink, sourceFile) { 
					AbortTimeout = TimeSpan.FromSeconds(10),
					Parallel = false // only one file, parallel doesn't help
				};

				if (LeMP.Compiler.ProcessArguments(c, options))
				{
					if (options.ContainsKey("no-out-header"))
					{
						options.Remove("no-out-header", 1);
						c.NoOutHeader = true;
					}
					LeMP.Compiler.WarnAboutUnknownOptions(options, sink, KnownOptions);
					if (c != null)
					{
						if (inputFilePath.EndsWith(".les", StringComparison.OrdinalIgnoreCase))
							c.MacroProcessor.PreOpenedNamespaces.Add(GSymbol.Get("LeMP.Prelude.Les"));
						Configure(c);
						c.Run();

						// Report errors
						foreach (var msg in sink.List)
							ReportErrorToVS(progressCallback, msg.Severity, msg.Context, msg.Format, msg.Args);

						return Encoding.UTF8.GetBytes(c.Output.ToString());
					}
				}
				return null;
			} finally {
				Environment.CurrentDirectory = oldCurDir;
			}
		}
Example #12
0
		protected override void WriteOutput(InputOutput io)
		{
			Results = io.Output;
			Output = new StringBuilder();
			var opts = new LNodePrinterOptions { IndentString = IndentString, NewlineString = NewlineString };
			LNode.Printer.Print(Results, Output, Sink, null, opts);
		}
Example #13
0
		private void WriteOutput2(InputOutput io)
		{
			Debug.Assert(io.FileName != io.OutFileName);

			Sink.Write(Severity.Verbose, io, "Writing output file: {0}", io.OutFileName);

			using (var stream = File.Open(io.OutFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
			using (var writer = new StreamWriter(stream, Encoding.UTF8)) {
				var sb = new StringBuilder();
				foreach (LNode node in io.Output) {
					io.OutPrinter(node, sb, Sink, null, IndentString, NewlineString);
					writer.Write(sb.ToString());
					writer.Write(NewlineString);
					sb.Length = 0; // Clear() is new in .NET 4
				}
			}
		}
Example #14
0
		protected virtual void WriteOutput(InputOutput io)
		{
			#if !DotNet2 && !DotNet3
			if (Parallel) {
				// attach to parent so that ProcessParallel does not exit before the file is written
				Task.Factory.StartNew(() => WriteOutput2(io), TaskCreationOptions.AttachedToParent);
				return;
			}
			#endif
			WriteOutput2(io);
		}
Example #15
0
		public void CompleteInputOutputOptions(InputOutput file)
		{
			if (file.InputLang == null) {
				var inLang = InLang ?? ParsingService.Current;
				if (!ForceInLang || InLang == null)
					inLang = FileNameToLanguage(file.FileName) ?? inLang;
				file.InputLang = inLang;
			}
			if (file.OutFileName == null) {
				string inputFN = file.FileName;
				if (OutExt == null)
					file.OutFileName = inputFN;
				else {
					int dot = IndexOfExtension(inputFN);
					file.OutFileName = inputFN.Left(dot) + OutExt;
				}
				if (file.OutFileName == inputFN) {
					// e.g. input.cs => input.out.cs
					int dot = IndexOfExtension(inputFN);
					file.OutFileName = file.OutFileName.Insert(dot, ".out");
				}
			}
			if (file.OutPrinter == null) {
				var outLang = OutLang;
				if (outLang == null && OutExt != null) {
					var lang = FileNameToLanguage(OutExt); 
					if (lang != null) outLang = lang.Printer;
				}
				file.OutPrinter = outLang ?? LNode.Printer;
			}
		}
Example #16
0
		protected virtual void WriteOutput(InputOutput io)
		{
			Debug.Assert(io.FileName != io.OutFileName);

			Sink.Write(Severity.Verbose, io, "Writing output file: {0}", io.OutFileName);

			using (var stream = File.Open(io.OutFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
			using (var writer = new StreamWriter(stream, Encoding.UTF8)) {
				var options = new LNodePrinterOptions {
					IndentString = IndentString,
					NewlineString = NewlineString
				};
				var str = io.OutPrinter.Print(io.Output, Sink, null, options);
				writer.Write(str);
			}
		}
Example #17
0
		/// <summary>Opens a set of source files by file name, and creates a text file for each.</summary>
		/// <param name="sink"></param>
		/// <param name="fileNames"></param>
		/// <returns></returns>
		public static List<InputOutput> OpenSourceFiles(IMessageSink sink, IEnumerable<string> fileNames)
		{
			var openFiles = new List<InputOutput>();
			foreach (var filename in fileNames) {
				try {
					var stream = File.OpenRead(filename);
					var text = File.ReadAllText(filename, Encoding.UTF8);
					var io = new InputOutput(new StreamCharSource(stream), filename);
					openFiles.Add(io);
				} catch (Exception ex) {
					sink.Write(Severity.Error, filename, ex.GetType().Name + ": " + ex.Message);
				}
			}
			return openFiles;
		}
Example #18
0
 protected override void WriteOutput(InputOutput io)
 {
     Results = io.Output;
     Output  = new StringBuilder();
     io.OutPrinter.Print(Results, Output, Sink, null, io.OutOptions);
 }
Example #19
0
			public Compiler(IMessageSink sink, InputOutput file)
				: base(sink, typeof(global::LeMP.Prelude.BuiltinMacros), new [] { file }) { }
Example #20
0
		protected override byte[] Generate(string inputFilePath, string inputFileContents, string defaultNamespace, IVsGeneratorProgress progressCallback)
		{
			string oldCurDir = Environment.CurrentDirectory;
			try {
				string inputFolder = Path.GetDirectoryName(inputFilePath);
 				Environment.CurrentDirectory = inputFolder; // --macros should be relative to file being processed

				// Originally I wrote a conversion from IVsGeneratorProgress to
 				// IMessageSink so that errors could be reported immediately and
				// directly to Visual Studio. This broke in a bizarre way when I
				// added processing on a separate thread (in order to be able to
				// abort the thread if it runs too long); I got the following
				// InvalidCastException: "Unable to cast COM object of type 'System.__ComObject' 
				// to interface type 'Microsoft.VisualStudio.Shell.Interop.IVsGeneratorProgress'.
				// This operation failed because the QueryInterface call on the COM component for 
				// the interface with IID '{BED89B98-6EC9-43CB-B0A8-41D6E2D6669D}' failed due to 
				// the following error: No such interface supported (Exception from HRESULT: 
				// 0x80004002 (E_NOINTERFACE))."
				// 
				// A simple solution is to store the messages rather than reporting
				// them immediately. I'll report the errors at the very end.
				MessageHolder sink = new MessageHolder();
				
				var sourceFile = new InputOutput((UString)inputFileContents, inputFilePath);

				Compiler.KnownOptions["no-out-header"] = Pair.Create("", "Remove explanatory comment from output file");
				Compiler.KnownOptions.Remove("parallel");   // not applicable to single file
				Compiler.KnownOptions.Remove("noparallel"); // not applicable to single file

				var c = new Compiler(sink, sourceFile) { 
					AbortTimeout = TimeSpan.FromSeconds(10),
					Parallel = false // only one file, parallel doesn't help
				};

				var argList = G.SplitCommandLineArguments(defaultNamespace);
				var options = c.ProcessArguments(argList, true, false);
				// Note: if default namespace is left blank, VS uses the namespace 
				// from project settings. Don't show an error in that case.
				if (argList.Count > 1 || (argList.Count == 1 && options.Count > 0))
					sink.Write(Severity.Error, "Command line", "'{0}': expected options only (try --help).", argList[0]);

				string _;
				if (options.TryGetValue("help", out _) || options.TryGetValue("?", out _))
				{
					var ms = new MemoryStream();
					LeMP.Compiler.ShowHelp(LeMP.Compiler.KnownOptions, new StreamWriter(ms), false);
					return ms.GetBuffer();
				}

				LeMP.Compiler.WarnAboutUnknownOptions(options, sink, LeMP.Compiler.KnownOptions);
				
				if (options.ContainsKey("no-out-header"))
					c.NoOutHeader = true;
				
				if (c.InLang == LesLanguageService.Value || inputFilePath.EndsWith(".les", StringComparison.OrdinalIgnoreCase))
					c.MacroProcessor.PreOpenedNamespaces.Add(GSymbol.Get("LeMP.Prelude.Les"));
						
				Configure(c);
				_requestedExtension = c.OutExt;
				c.Run();

				// Report errors
				foreach (var msg in sink.List)
					ReportErrorToVS(progressCallback, msg.Severity, msg.Context, msg.Format, msg.Args);

				return Encoding.UTF8.GetBytes(c.Output.ToString());
			} finally {
				Environment.CurrentDirectory = oldCurDir;
			}
		}
Example #21
0
			protected override void WriteOutput(InputOutput io)
			{
				VList<LNode> results = io.Output;
				if (!NoOutHeader)
					Output.AppendFormat(
						"// Generated from {1} by LeMP custom tool. LeMP version: {2}{0}"
						+ "// Note: you can give command-line arguments to the tool via 'Custom Tool Namespace':{0}"
						+ "// --no-out-header       Suppress this message{0}"
						+ "// --verbose             Allow verbose messages (shown by VS as 'warnings'){0}"
						+ "// --timeout=X           Abort processing thread after X seconds (default: 10){0}"
						+ "// --macros=FileName.dll Load macros from FileName.dll, path relative to this file {0}"
						+ "// Use #importMacros to use macros in a given namespace, e.g. #importMacros(Loyc.LLPG);{0}", NewlineString, 
						Path.GetFileName(io.FileName), typeof(MacroProcessor).Assembly.GetName().Version.ToString());
				var options = new LNodePrinterOptions {
					IndentString = IndentString, NewlineString = NewlineString
				};
				LNode.Printer.Print(results, Output, Sink, ParsingMode.File, options);
			}