diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 87b1f9e9..15c44aa8 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -12,118 +12,76 @@ namespace CppSharp public class Driver { public DriverOptions Options { get; private set; } - public ILibrary Transform { get; private set; } public IDiagnosticConsumer Diagnostics { get; private set; } + public Parser Parser { get; private set; } public TypeMapDatabase TypeDatabase { get; private set; } + public ILibrary Transform { get; private set; } + public Generator Generator { get; private set; } + public Library Library { get; private set; } public Library LibrarySymbols { get; private set; } - public Generator Generator { get; private set; } - public Driver(DriverOptions options, ILibrary transform) + public Driver(DriverOptions options, IDiagnosticConsumer diagnostics, + ILibrary transform) { Options = options; - Transform = transform; - Diagnostics = new TextDiagnosticPrinter(); + Diagnostics = diagnostics; + Parser = new Parser(Options); TypeDatabase = new TypeMapDatabase(); + Transform = transform; } - public void Setup() - { - if (Transform != null) - Transform.Setup(Options); - - ValidateOptions(); - - Generator = CreateGenerator(); - } - - private void ValidateOptions() + static void ValidateOptions(DriverOptions options) { - if (string.IsNullOrWhiteSpace(Options.LibraryName)) + if (string.IsNullOrWhiteSpace(options.LibraryName)) throw new InvalidDataException(); - if (Options.OutputDir == null) - Options.OutputDir = Directory.GetCurrentDirectory(); + if (options.OutputDir == null) + options.OutputDir = Directory.GetCurrentDirectory(); - for (var i = 0; i < Options.IncludeDirs.Count; i++) + for (var i = 0; i < options.IncludeDirs.Count; i++) { - Options.IncludeDirs[i] = Path.GetFullPath(Options.IncludeDirs[i]); + options.IncludeDirs[i] = Path.GetFullPath(options.IncludeDirs[i]); } - for (var i = 0; i < Options.LibraryDirs.Count; i++) + for (var i = 0; i < options.LibraryDirs.Count; i++) { - Options.LibraryDirs[i] = Path.GetFullPath(Options.LibraryDirs[i]); + options.LibraryDirs[i] = Path.GetFullPath(options.LibraryDirs[i]); } - if (string.IsNullOrWhiteSpace(Options.OutputNamespace)) - Options.OutputNamespace = Options.LibraryName; + if (string.IsNullOrWhiteSpace(options.OutputNamespace)) + options.OutputNamespace = options.LibraryName; } - Generator CreateGenerator() + public void Setup() { - switch (Options.GeneratorKind) - { - case LanguageGeneratorKind.CSharp: - return new CSharpGenerator(this); - case LanguageGeneratorKind.CPlusPlusCLI: - return new CLIGenerator(this); - default: - throw new NotImplementedException("Unknown language generator kind"); - } - } + ValidateOptions(Options); - private void OnFileParsed(string file, ParserResult result) - { - switch (result.Kind) - { - case ParserResultKind.Success: - Console.WriteLine(" Parsed '{0}'", file); - break; - case ParserResultKind.Error: - Console.WriteLine(" Error parsing '{0}'", file); - break; - case ParserResultKind.FileNotFound: - Console.WriteLine(" File '{0}' was not found", file); - break; - } + if (!Directory.Exists(Options.OutputDir)) + Directory.CreateDirectory(Options.OutputDir); - foreach (var diag in result.Diagnostics) - { - Console.WriteLine(string.Format("{0}({1},{2}): {3}: {4}", - diag.FileName, diag.LineNumber, diag.ColumnNumber, - diag.Level.ToString().ToLower(), diag.Message)); - } + if (!Generators.ContainsKey(Options.GeneratorKind)) + throw new NotImplementedException("Unknown generator kind"); + + Generator = Generators[Options.GeneratorKind](this); } public bool ParseCode() { - Console.WriteLine("Parsing code..."); - - var parser = new Parser(Options); - parser.OnHeaderParsed += OnFileParsed; - - if( !parser.ParseHeaders(Options.Headers) ) + if (!Parser.ParseHeaders(Options.Headers)) return false; - Library = parser.Library; + Library = Parser.Library; return true; } public bool ParseLibraries() { - Console.WriteLine("Parsing libraries..."); - - var parser = new Parser(Options); - parser.OnLibraryParsed += OnFileParsed; - - if (!parser.ParseLibraries(Options.Libraries)) + if (!Parser.ParseLibraries(Options.Libraries)) return false; - LibrarySymbols = parser.Library; - - Console.WriteLine("Indexing library symbols..."); - LibrarySymbols.IndexSymbols(); + LibrarySymbols = Parser.Library; return true; } @@ -133,7 +91,7 @@ namespace CppSharp TypeDatabase.SetupTypeMaps(); if (Transform != null) - Transform.Preprocess(Library); + Transform.Preprocess(this, Library); var passes = new PassBuilder(this); passes.CleanUnit(Options); @@ -150,11 +108,7 @@ namespace CppSharp passes.CheckFlagEnums(); passes.CheckAmbiguousOverloads(); - if (Options.GeneratorKind == LanguageGeneratorKind.CSharp) - { - passes.CheckAbiParameters(Options); - passes.CheckOperatorOverloads(); - } + Generator.SetupPasses(passes); passes.RunPasses(); @@ -167,12 +121,6 @@ namespace CppSharp if (Library.TranslationUnits.Count <= 0) return; - Console.WriteLine("Generating wrapper code..."); - - if (!Directory.Exists(Options.OutputDir)) - Directory.CreateDirectory(Options.OutputDir); - - // Process everything in the global namespace for now. foreach (var unit in Library.TranslationUnits) { if (unit.Ignore || !unit.HasDeclarations) @@ -181,22 +129,18 @@ namespace CppSharp if (unit.IsSystemHeader) continue; - // Generate the target code. - Generator.Generate(unit); - } - } + var outputs = new List(); + if (!Generator.Generate(unit, outputs)) + continue; - public static void Run(ILibrary library) - { - var options = new DriverOptions(); + foreach (var output in outputs) + { + Diagnostics.EmitMessage(DiagnosticId.FileGenerated, + "Generated '{0}'", Path.GetFileName(output.OutputPath)); - var driver = new Driver(options, library); - driver.Setup(); - - if (driver.ParseLibraries() && driver.ParseCode()) - { - driver.ProcessCode(); - driver.GenerateCode(); + var text = output.Template.ToString(); + File.WriteAllText(output.OutputPath, text); + } } } } @@ -263,4 +207,61 @@ namespace CppSharp public bool WriteOnlyWhenChanged; public Func GenerateName; } + + public static class ConsoleDriver + { + static void OnFileParsed(string file, ParserResult result) + { + switch (result.Kind) + { + case ParserResultKind.Success: + Console.WriteLine(" Parsed '{0}'", file); + break; + case ParserResultKind.Error: + Console.WriteLine(" Error parsing '{0}'", file); + break; + case ParserResultKind.FileNotFound: + Console.WriteLine(" File '{0}' was not found", file); + break; + } + + foreach (var diag in result.Diagnostics) + { + Console.WriteLine(string.Format("{0}({1},{2}): {3}: {4}", + diag.FileName, diag.LineNumber, diag.ColumnNumber, + diag.Level.ToString().ToLower(), diag.Message)); + } + } + + public static void Run(ILibrary library) + { + Console.BufferHeight = 1999; + + var options = new DriverOptions(); + var driver = new Driver(options, new TextDiagnosticPrinter(), + library); + library.Setup(driver); + driver.Setup(); + + driver.Parser.OnHeaderParsed += OnFileParsed; + driver.Parser.OnLibraryParsed += OnFileParsed; + + Console.WriteLine("Parsing libraries..."); + if (!driver.ParseLibraries()) + return; + + Console.WriteLine("Indexing library symbols..."); + driver.LibrarySymbols.IndexSymbols(); + + Console.WriteLine("Parsing code..."); + if (!driver.ParseCode()) + return; + + Console.WriteLine("Processing code..."); + driver.ProcessCode(); + + Console.WriteLine("Generating code..."); + driver.GenerateCode(); + } + } } \ No newline at end of file diff --git a/src/Generator/Generators/CLI/CLIGenerator.cs b/src/Generator/Generators/CLI/CLIGenerator.cs index 049e8cc9..6819acbc 100644 --- a/src/Generator/Generators/CLI/CLIGenerator.cs +++ b/src/Generator/Generators/CLI/CLIGenerator.cs @@ -1,47 +1,33 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; +using CppSharp.Types.Std; namespace CppSharp.Generators.CLI { public class CLIGenerator : Generator { private readonly CLITypePrinter typePrinter; - private readonly FileHashes fileHashes; public CLIGenerator(Driver driver) : base(driver) { typePrinter = new CLITypePrinter(driver); Type.TypePrinterDelegate += type => type.Visit(typePrinter); - fileHashes = FileHashes.Load("hashes.ser"); } - void WriteTemplate(TextTemplate template) + public override bool Generate(TranslationUnit unit, + List outputs) { - var path = GetOutputPath(template.TranslationUnit) - + "." + template.FileExtension; - - template.Generate(); - var text = template.ToString(); + var header = new CLIHeadersTemplate(Driver, unit); + outputs.Add(GenerateTemplateOutput(header)); - if(Driver.Options.WriteOnlyWhenChanged) - { - var updated = fileHashes.UpdateHash(path, text.GetHashCode()); - if (File.Exists(path) && !updated) - return; - } + var source = new CLISourcesTemplate(Driver, unit); + outputs.Add(GenerateTemplateOutput(source)); - Driver.Diagnostics.EmitMessage(DiagnosticId.FileGenerated, - " Generated '{0}'.", Path.GetFileName(path)); - File.WriteAllText(path, text); + return true; } - public override bool Generate(TranslationUnit unit) + public override bool SetupPasses(PassBuilder builder) { - var header = new CLIHeadersTemplate(Driver, unit); - WriteTemplate(header); - - var source = new CLISourcesTemplate(Driver, unit); - WriteTemplate(source); - return true; } } diff --git a/src/Generator/Generators/CLI/CLITypePrinter.cs b/src/Generator/Generators/CLI/CLITypePrinter.cs index 9ba1f69f..5fe9b8a6 100644 --- a/src/Generator/Generators/CLI/CLITypePrinter.cs +++ b/src/Generator/Generators/CLI/CLITypePrinter.cs @@ -248,7 +248,7 @@ namespace CppSharp.Generators.CLI var names = new List(); if (Options.GenerateLibraryNamespace) - names.Add(Driver.Library.Name); + names.Add(Driver.Options.OutputNamespace); if (!string.IsNullOrEmpty(decl.Namespace.QualifiedName)) names.Add(decl.Namespace.QualifiedName); diff --git a/src/Generator/Generators/CSharp/CSharpGenerator.cs b/src/Generator/Generators/CSharp/CSharpGenerator.cs index b8635b2f..c26eb83a 100644 --- a/src/Generator/Generators/CSharp/CSharpGenerator.cs +++ b/src/Generator/Generators/CSharp/CSharpGenerator.cs @@ -1,5 +1,6 @@ -using System; +using System.Collections.Generic; using System.IO; +using CppSharp.Passes; namespace CppSharp.Generators.CSharp { @@ -13,22 +14,11 @@ namespace CppSharp.Generators.CSharp Type.TypePrinterDelegate += type => type.Visit(typePrinter).Type; } - void WriteTemplate(TextTemplate template) - { - var path = GetOutputPath(template.TranslationUnit) - + "." + template.FileExtension; - - template.Generate(); - - File.WriteAllText(path, template.ToString()); - Driver.Diagnostics.EmitMessage(DiagnosticId.FileGenerated, - " Generated '{0}'.", Path.GetFileName(path)); - } - - public override bool Generate(TranslationUnit unit) + public override bool Generate(TranslationUnit unit, + List outputs) { var template = new CSharpTextTemplate(Driver, unit, typePrinter); - WriteTemplate(template); + outputs.Add(GenerateTemplateOutput(template)); return true; } diff --git a/src/Generator/Generators/Generator.cs b/src/Generator/Generators/Generator.cs index bd6747ca..786e1f01 100644 --- a/src/Generator/Generators/Generator.cs +++ b/src/Generator/Generators/Generator.cs @@ -1,19 +1,36 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; namespace CppSharp.Generators { public enum LanguageGeneratorKind { CPlusPlusCLI, - CSharp + CSharp, } - public interface IGenerator + /// + /// Output generated by each backend generator. + /// + public struct GeneratorOutput { - bool Generate(TranslationUnit unit); + /// + /// Translation unit associated with output. + /// + public TranslationUnit TranslationUnit; + + /// + /// Text template with generated output. + /// + public TextTemplate Template; + + /// + /// Output path of the generated output. + /// + public string OutputPath; } - public abstract class Generator : IGenerator + public abstract class Generator { public Driver Driver { get; private set; } @@ -22,9 +39,11 @@ namespace CppSharp.Generators Driver = driver; } - public abstract bool Generate(TranslationUnit unit); + public abstract bool Generate(TranslationUnit unit, + List outputs); + - public string GetOutputPath(TranslationUnit unit) + protected string GetOutputPath(TranslationUnit unit) { var file = unit.FileNameWithoutExtension; @@ -34,5 +53,22 @@ namespace CppSharp.Generators var path = Path.Combine(Driver.Options.OutputDir, file); return Path.GetFullPath(path); } + + protected GeneratorOutput GenerateTemplateOutput(TextTemplate template) + { + var path = GetOutputPath(template.TranslationUnit) + + "." + template.FileExtension; + + template.Generate(); + + var output = new GeneratorOutput() + { + OutputPath = path, + Template = template, + TranslationUnit = template.TranslationUnit + }; + + return output; + } } } \ No newline at end of file