Browse Source

Refactor file writing into the driver instead of duplicating it each generator.

pull/3/head
triton 13 years ago
parent
commit
70f76588aa
  1. 199
      src/Generator/Driver.cs
  2. 36
      src/Generator/Generators/CLI/CLIGenerator.cs
  3. 2
      src/Generator/Generators/CLI/CLITypePrinter.cs
  4. 20
      src/Generator/Generators/CSharp/CSharpGenerator.cs
  5. 50
      src/Generator/Generators/Generator.cs

199
src/Generator/Driver.cs

@ -12,118 +12,76 @@ namespace CppSharp
public class Driver public class Driver
{ {
public DriverOptions Options { get; private set; } public DriverOptions Options { get; private set; }
public ILibrary Transform { get; private set; }
public IDiagnosticConsumer Diagnostics { get; private set; } public IDiagnosticConsumer Diagnostics { get; private set; }
public Parser Parser { get; private set; }
public TypeMapDatabase TypeDatabase { 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 Library { get; private set; }
public Library LibrarySymbols { 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; Options = options;
Transform = transform; Diagnostics = diagnostics;
Diagnostics = new TextDiagnosticPrinter(); Parser = new Parser(Options);
TypeDatabase = new TypeMapDatabase(); TypeDatabase = new TypeMapDatabase();
Transform = transform;
} }
public void Setup() static void ValidateOptions(DriverOptions options)
{
if (Transform != null)
Transform.Setup(Options);
ValidateOptions();
Generator = CreateGenerator();
}
private void ValidateOptions()
{ {
if (string.IsNullOrWhiteSpace(Options.LibraryName)) if (string.IsNullOrWhiteSpace(options.LibraryName))
throw new InvalidDataException(); throw new InvalidDataException();
if (Options.OutputDir == null) if (options.OutputDir == null)
Options.OutputDir = Directory.GetCurrentDirectory(); 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)) if (string.IsNullOrWhiteSpace(options.OutputNamespace))
Options.OutputNamespace = Options.LibraryName; options.OutputNamespace = options.LibraryName;
} }
Generator CreateGenerator() public void Setup()
{ {
switch (Options.GeneratorKind) ValidateOptions(Options);
{
case LanguageGeneratorKind.CSharp:
return new CSharpGenerator(this);
case LanguageGeneratorKind.CPlusPlusCLI:
return new CLIGenerator(this);
default:
throw new NotImplementedException("Unknown language generator kind");
}
}
private void OnFileParsed(string file, ParserResult result) if (!Directory.Exists(Options.OutputDir))
{ Directory.CreateDirectory(Options.OutputDir);
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) if (!Generators.ContainsKey(Options.GeneratorKind))
{ throw new NotImplementedException("Unknown generator kind");
Console.WriteLine(string.Format("{0}({1},{2}): {3}: {4}",
diag.FileName, diag.LineNumber, diag.ColumnNumber, Generator = Generators[Options.GeneratorKind](this);
diag.Level.ToString().ToLower(), diag.Message));
}
} }
public bool ParseCode() public bool ParseCode()
{ {
Console.WriteLine("Parsing code..."); if (!Parser.ParseHeaders(Options.Headers))
var parser = new Parser(Options);
parser.OnHeaderParsed += OnFileParsed;
if( !parser.ParseHeaders(Options.Headers) )
return false; return false;
Library = parser.Library; Library = Parser.Library;
return true; return true;
} }
public bool ParseLibraries() public bool ParseLibraries()
{ {
Console.WriteLine("Parsing libraries..."); if (!Parser.ParseLibraries(Options.Libraries))
var parser = new Parser(Options);
parser.OnLibraryParsed += OnFileParsed;
if (!parser.ParseLibraries(Options.Libraries))
return false; return false;
LibrarySymbols = parser.Library; LibrarySymbols = Parser.Library;
Console.WriteLine("Indexing library symbols...");
LibrarySymbols.IndexSymbols();
return true; return true;
} }
@ -133,7 +91,7 @@ namespace CppSharp
TypeDatabase.SetupTypeMaps(); TypeDatabase.SetupTypeMaps();
if (Transform != null) if (Transform != null)
Transform.Preprocess(Library); Transform.Preprocess(this, Library);
var passes = new PassBuilder(this); var passes = new PassBuilder(this);
passes.CleanUnit(Options); passes.CleanUnit(Options);
@ -150,11 +108,7 @@ namespace CppSharp
passes.CheckFlagEnums(); passes.CheckFlagEnums();
passes.CheckAmbiguousOverloads(); passes.CheckAmbiguousOverloads();
if (Options.GeneratorKind == LanguageGeneratorKind.CSharp) Generator.SetupPasses(passes);
{
passes.CheckAbiParameters(Options);
passes.CheckOperatorOverloads();
}
passes.RunPasses(); passes.RunPasses();
@ -167,12 +121,6 @@ namespace CppSharp
if (Library.TranslationUnits.Count <= 0) if (Library.TranslationUnits.Count <= 0)
return; 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) foreach (var unit in Library.TranslationUnits)
{ {
if (unit.Ignore || !unit.HasDeclarations) if (unit.Ignore || !unit.HasDeclarations)
@ -181,22 +129,18 @@ namespace CppSharp
if (unit.IsSystemHeader) if (unit.IsSystemHeader)
continue; continue;
// Generate the target code. var outputs = new List<GeneratorOutput>();
Generator.Generate(unit); if (!Generator.Generate(unit, outputs))
} continue;
}
public static void Run(ILibrary library) foreach (var output in outputs)
{ {
var options = new DriverOptions(); Diagnostics.EmitMessage(DiagnosticId.FileGenerated,
"Generated '{0}'", Path.GetFileName(output.OutputPath));
var driver = new Driver(options, library); var text = output.Template.ToString();
driver.Setup(); File.WriteAllText(output.OutputPath, text);
}
if (driver.ParseLibraries() && driver.ParseCode())
{
driver.ProcessCode();
driver.GenerateCode();
} }
} }
} }
@ -263,4 +207,61 @@ namespace CppSharp
public bool WriteOnlyWhenChanged; public bool WriteOnlyWhenChanged;
public Func<TranslationUnit, string> GenerateName; public Func<TranslationUnit, string> 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();
}
}
} }

36
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 namespace CppSharp.Generators.CLI
{ {
public class CLIGenerator : Generator public class CLIGenerator : Generator
{ {
private readonly CLITypePrinter typePrinter; private readonly CLITypePrinter typePrinter;
private readonly FileHashes fileHashes;
public CLIGenerator(Driver driver) : base(driver) public CLIGenerator(Driver driver) : base(driver)
{ {
typePrinter = new CLITypePrinter(driver); typePrinter = new CLITypePrinter(driver);
Type.TypePrinterDelegate += type => type.Visit(typePrinter); Type.TypePrinterDelegate += type => type.Visit(typePrinter);
fileHashes = FileHashes.Load("hashes.ser");
} }
void WriteTemplate(TextTemplate template) public override bool Generate(TranslationUnit unit,
List<GeneratorOutput> outputs)
{ {
var path = GetOutputPath(template.TranslationUnit) var header = new CLIHeadersTemplate(Driver, unit);
+ "." + template.FileExtension; outputs.Add(GenerateTemplateOutput(header));
template.Generate();
var text = template.ToString();
if(Driver.Options.WriteOnlyWhenChanged) var source = new CLISourcesTemplate(Driver, unit);
{ outputs.Add(GenerateTemplateOutput(source));
var updated = fileHashes.UpdateHash(path, text.GetHashCode());
if (File.Exists(path) && !updated)
return;
}
Driver.Diagnostics.EmitMessage(DiagnosticId.FileGenerated, return true;
" Generated '{0}'.", Path.GetFileName(path));
File.WriteAllText(path, text);
} }
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; return true;
} }
} }

2
src/Generator/Generators/CLI/CLITypePrinter.cs

@ -248,7 +248,7 @@ namespace CppSharp.Generators.CLI
var names = new List<string>(); var names = new List<string>();
if (Options.GenerateLibraryNamespace) if (Options.GenerateLibraryNamespace)
names.Add(Driver.Library.Name); names.Add(Driver.Options.OutputNamespace);
if (!string.IsNullOrEmpty(decl.Namespace.QualifiedName)) if (!string.IsNullOrEmpty(decl.Namespace.QualifiedName))
names.Add(decl.Namespace.QualifiedName); names.Add(decl.Namespace.QualifiedName);

20
src/Generator/Generators/CSharp/CSharpGenerator.cs

@ -1,5 +1,6 @@
using System; using System.Collections.Generic;
using System.IO; using System.IO;
using CppSharp.Passes;
namespace CppSharp.Generators.CSharp namespace CppSharp.Generators.CSharp
{ {
@ -13,22 +14,11 @@ namespace CppSharp.Generators.CSharp
Type.TypePrinterDelegate += type => type.Visit(typePrinter).Type; Type.TypePrinterDelegate += type => type.Visit(typePrinter).Type;
} }
void WriteTemplate(TextTemplate template) public override bool Generate(TranslationUnit unit,
{ List<GeneratorOutput> outputs)
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)
{ {
var template = new CSharpTextTemplate(Driver, unit, typePrinter); var template = new CSharpTextTemplate(Driver, unit, typePrinter);
WriteTemplate(template); outputs.Add(GenerateTemplateOutput(template));
return true; return true;
} }

50
src/Generator/Generators/Generator.cs

@ -1,19 +1,36 @@
using System.IO; using System.Collections.Generic;
using System.IO;
namespace CppSharp.Generators namespace CppSharp.Generators
{ {
public enum LanguageGeneratorKind public enum LanguageGeneratorKind
{ {
CPlusPlusCLI, CPlusPlusCLI,
CSharp CSharp,
} }
public interface IGenerator /// <summary>
/// Output generated by each backend generator.
/// </summary>
public struct GeneratorOutput
{ {
bool Generate(TranslationUnit unit); /// <summary>
/// Translation unit associated with output.
/// </summary>
public TranslationUnit TranslationUnit;
/// <summary>
/// Text template with generated output.
/// </summary>
public TextTemplate Template;
/// <summary>
/// Output path of the generated output.
/// </summary>
public string OutputPath;
} }
public abstract class Generator : IGenerator public abstract class Generator
{ {
public Driver Driver { get; private set; } public Driver Driver { get; private set; }
@ -22,9 +39,11 @@ namespace CppSharp.Generators
Driver = driver; Driver = driver;
} }
public abstract bool Generate(TranslationUnit unit); public abstract bool Generate(TranslationUnit unit,
List<GeneratorOutput> outputs);
public string GetOutputPath(TranslationUnit unit) protected string GetOutputPath(TranslationUnit unit)
{ {
var file = unit.FileNameWithoutExtension; var file = unit.FileNameWithoutExtension;
@ -34,5 +53,22 @@ namespace CppSharp.Generators
var path = Path.Combine(Driver.Options.OutputDir, file); var path = Path.Combine(Driver.Options.OutputDir, file);
return Path.GetFullPath(path); 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;
}
} }
} }
Loading…
Cancel
Save