/* * [The "BSD licence"] * Copyright (c) 2013 Sam Harwell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ namespace Antlr4.Build.Tasks { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using RegistryHive = Microsoft.Win32.RegistryHive; using RegistryKey = Microsoft.Win32.RegistryKey; #if NET_4_0 using RegistryView = Microsoft.Win32.RegistryView; #else using Registry = Microsoft.Win32.Registry; #endif using StringBuilder = System.Text.StringBuilder; internal class AntlrClassGenerationTaskInternal : MarshalByRefObject { private List _generatedCodeFiles = new List(); private IList _sourceCodeFiles = new List(); private List _buildMessages = new List(); public IList GeneratedCodeFiles { get { return this._generatedCodeFiles; } } public string ToolPath { get; set; } public string TargetLanguage { get; set; } public string TargetFrameworkVersion { get; set; } public string OutputPath { get; set; } public string TargetNamespace { get; set; } public string[] LanguageSourceExtensions { get; set; } public bool GenerateListener { get; set; } public bool GenerateVisitor { get; set; } public bool ForceAtn { get; set; } public bool AbstractGrammar { get; set; } public string JavaVendor { get; set; } public string JavaInstallation { get; set; } public IList SourceCodeFiles { get { return this._sourceCodeFiles; } set { this._sourceCodeFiles = value; } } public IList BuildMessages { get { return _buildMessages; } } #if NET_4_0 private string JavaHome { get { string javaHome; if (TryGetJavaHome(RegistryView.Default, JavaVendor, JavaInstallation, out javaHome)) return javaHome; if (TryGetJavaHome(RegistryView.Registry64, JavaVendor, JavaInstallation, out javaHome)) return javaHome; if (TryGetJavaHome(RegistryView.Registry32, JavaVendor, JavaInstallation, out javaHome)) return javaHome; throw new NotSupportedException("Could not locate a Java installation."); } } private static bool TryGetJavaHome(RegistryView registryView, string vendor, string installation, out string javaHome) { javaHome = null; string javaKeyName = "SOFTWARE\\" + vendor + "\\" + installation; using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView)) { using (RegistryKey javaKey = baseKey.OpenSubKey(javaKeyName)) { if (javaKey == null) return false; object currentVersion = javaKey.GetValue("CurrentVersion"); if (currentVersion == null) return false; using (var homeKey = javaKey.OpenSubKey(currentVersion.ToString())) { if (homeKey == null || homeKey.GetValue("JavaHome") == null) return false; javaHome = homeKey.GetValue("JavaHome").ToString(); return !string.IsNullOrEmpty(javaHome); } } } } #else private string JavaHome { get { string javaHome; if (TryGetJavaHome(Registry.LocalMachine, JavaVendor, JavaInstallation, out javaHome)) return javaHome; throw new NotSupportedException("Could not locate a Java installation."); } } private static bool TryGetJavaHome(RegistryKey baseKey, string vendor, string installation, out string javaHome) { javaHome = null; string javaKeyName = "SOFTWARE\\" + vendor + "\\" + installation; using (RegistryKey javaKey = baseKey.OpenSubKey(javaKeyName)) { if (javaKey == null) return false; object currentVersion = javaKey.GetValue("CurrentVersion"); if (currentVersion == null) return false; using (var homeKey = javaKey.OpenSubKey(currentVersion.ToString())) { if (homeKey == null || homeKey.GetValue("JavaHome") == null) return false; javaHome = homeKey.GetValue("JavaHome").ToString(); return !string.IsNullOrEmpty(javaHome); } } } #endif public bool Execute() { try { string javaHome = JavaHome; string java = Path.Combine(Path.Combine(javaHome, "bin"), "java.exe"); List arguments = new List(); arguments.Add("-cp"); arguments.Add(ToolPath); arguments.Add("org.antlr.v4.CSharpTool"); arguments.Add("-o"); arguments.Add(OutputPath); if (GenerateListener) arguments.Add("-listener"); else arguments.Add("-no-listener"); if (GenerateVisitor) arguments.Add("-visitor"); else arguments.Add("-no-visitor"); if (ForceAtn) arguments.Add("-force-atn"); if (AbstractGrammar) arguments.Add("-Dabstract=true"); if (!string.IsNullOrEmpty(TargetLanguage)) { string framework = TargetFrameworkVersion; if (string.IsNullOrEmpty(framework)) framework = "v2.0"; string language; if (TargetLanguage.Equals("CSharp")) language = TargetLanguage + '_' + framework.Replace('.', '_'); else language = TargetLanguage; arguments.Add("-Dlanguage=" + language); } if (!string.IsNullOrEmpty(TargetNamespace)) { arguments.Add("-package"); arguments.Add(TargetNamespace); } arguments.AddRange(SourceCodeFiles); ProcessStartInfo startInfo = new ProcessStartInfo(java, JoinArguments(arguments)) { UseShellExecute = false, CreateNoWindow = true, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, }; this.BuildMessages.Add(new BuildMessage(TraceLevel.Info, "Executing command: \"" + startInfo.FileName + "\" " + startInfo.Arguments, "", 0, 0)); Process process = new Process(); process.StartInfo = startInfo; process.ErrorDataReceived += HandleErrorDataReceived; process.OutputDataReceived += HandleOutputDataReceived; process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); process.StandardInput.Close(); process.WaitForExit(); return process.ExitCode == 0; //using (LoggingTraceListener traceListener = new LoggingTraceListener(_buildMessages)) //{ // SetTraceListener(traceListener); // ProcessArgs(args.ToArray()); // process(); //} //_generatedCodeFiles.AddRange(GetGeneratedFiles().Where(file => LanguageSourceExtensions.Contains(Path.GetExtension(file), StringComparer.OrdinalIgnoreCase))); //int errorCount = GetNumErrors(); //return errorCount == 0; } catch (Exception e) { if (e is TargetInvocationException && e.InnerException != null) e = e.InnerException; _buildMessages.Add(new BuildMessage(e.Message)); throw; } } private static string JoinArguments(IEnumerable arguments) { if (arguments == null) throw new ArgumentNullException("arguments"); StringBuilder builder = new StringBuilder(); foreach (string argument in arguments) { if (builder.Length > 0) builder.Append(' '); if (argument.IndexOfAny(new[] { '"', ' ' }) < 0) { builder.Append(argument); continue; } // escape a backslash appearing before a quote string arg = argument.Replace("\\\"", "\\\\\""); // escape double quotes arg = arg.Replace("\"", "\\\""); // wrap the argument in outer quotes builder.Append('"').Append(arg).Append('"'); } return builder.ToString(); } private static readonly Regex GeneratedFileMessageFormat = new Regex(@"^Generating file '(?.*?)' for grammar '(?.*?)'$", RegexOptions.Compiled); private void HandleErrorDataReceived(object sender, DataReceivedEventArgs e) { if (string.IsNullOrEmpty(e.Data)) return; try { _buildMessages.Add(new BuildMessage(e.Data)); } catch (Exception ex) { if (Antlr4ClassGenerationTask.IsFatalException(ex)) throw; _buildMessages.Add(new BuildMessage(ex.Message)); } } private void HandleOutputDataReceived(object sender, DataReceivedEventArgs e) { if (string.IsNullOrEmpty(e.Data)) return; try { Match match = GeneratedFileMessageFormat.Match(e.Data); if (!match.Success) { _buildMessages.Add(new BuildMessage(e.Data)); return; } string fileName = match.Groups["OUTPUT"].Value; if (LanguageSourceExtensions.Contains(Path.GetExtension(fileName), StringComparer.OrdinalIgnoreCase)) GeneratedCodeFiles.Add(match.Groups["OUTPUT"].Value); } catch (Exception ex) { if (Antlr4ClassGenerationTask.IsFatalException(ex)) throw; _buildMessages.Add(new BuildMessage(ex.Message)); } } } }