Skip to content

Commit

Permalink
Various bug fixes (#96)
Browse files Browse the repository at this point in the history
* Use ::bebop (scope resolution) in C++ codegen

* Output bebop.hpp

* Update Laboratory example

* Report an invalid --config path

* Don't log

* Report unrecognized command-line flags

* Complain about using a discriminator twice

* Disallow "enum { A=1; A=2; }"

* Move documentation from union branches to the inner definitions

That is: treat "union U { /** doc */ 1 -> struct S {} }" as "union U { 1 -> /** doc */ struct S {} }".

* rm gen/*

* Ignore case when comparing enum member names

* Rename BebopWriter to Writer, etc

* Improve C# codegen

* Add missing keywords

* Add missing nullable appendix

* Fix benchmark

* Add missing warning

* Remove using directives

* Fix union references

* Writer holds a reference, rather than unique_ptr, to its buffer

* Fix writeFloat64 bug

* Swap decodeInto arg order; perf test

* Properly split up tests and time compilation

* Consistently align type sigils

* Make generated conrete types partial

* changes based on feedback

Co-authored-by: Andrew Sampson <[email protected]>
  • Loading branch information
lynn and Andrew Sampson authored Mar 2, 2021
1 parent 44809b2 commit 69cf934
Show file tree
Hide file tree
Showing 34 changed files with 6,014 additions and 2,907 deletions.
32 changes: 23 additions & 9 deletions Compiler/CommandLineFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static CommandLineFlag GetFlag(this List<CommandLineFlag> flags, string f

}
/// <summary>
/// Represents a parsed command-line flag and it's values.
/// Represents a parsed command-line flag and its values.
/// </summary>
public class CommandLineFlag
{
Expand Down Expand Up @@ -153,20 +153,20 @@ public class CommandLineFlags
"--config bebop.json")]
public string? ConfigFile { get; private set; }

[CommandLineFlag("cs", "Generate C# source code to the specified file", "--cs ./cowboy/bebop/HelloWorld.cs",
[CommandLineFlag("cs", "Generate C# source code to the specified file", "--cs ./my/output/HelloWorld.cs",
true)]
public string? CSharpOutput { get; private set; }

[CommandLineFlag("ts", "Generate TypeScript source code to the specified file",
"--ts ./cowboy/bebop/HelloWorld.ts", true)]
"--ts ./my/output/HelloWorld.ts", true)]
public string? TypeScriptOutput { get; private set; }

[CommandLineFlag("dart", "Generate Dart source code to the specified file",
"--dart ./cowboy/bebop/HelloWorld.dart", true)]
"--dart ./my/output/HelloWorld.dart", true)]
public string? DartOutput { get; private set; }

[CommandLineFlag("cpp", "Generate C++ source code to the specified file",
"--cpp ./cowboy/bebop/HelloWorld.cpp", true)]
"--cpp ./my/output/HelloWorld.hpp", true)]
public string? CPlusPlusOutput { get; private set; }

[CommandLineFlag("namespace", "When this option is specified generated code will use namespaces",
Expand Down Expand Up @@ -294,7 +294,7 @@ private static List<CommandLineFlag> GetFlags(string[] args)
}

/// <summary>
/// Attempts to find the <see cref="LogFormatter"/> flag and parse it's value.
/// Attempts to find the <see cref="LogFormatter"/> flag and parse its value.
/// </summary>
/// <param name="args">The command-line arguments to sort through</param>
/// <returns>
Expand Down Expand Up @@ -383,15 +383,29 @@ public static bool TryParse(string[] args, out CommandLineFlags flagStore, out s
? parsedFlags.GetFlag("config").GetValue()
: FindBebopConfig();
// if bebop.json exist load it. the values in the JSON file are written to the store.
if (!string.IsNullOrWhiteSpace(bebopConfig) && new FileInfo(bebopConfig).Exists)
if (!string.IsNullOrWhiteSpace(bebopConfig))
{
if (!TryParseConfig(flagStore, bebopConfig))
if (new FileInfo(bebopConfig).Exists)
{
errorMessage = $"Failed to parse bebop configuration file at '{bebopConfig}'";
if (!TryParseConfig(flagStore, bebopConfig))
{
errorMessage = $"Failed to parse bebop configuration file at '{bebopConfig}'";
return false;
}
}
else
{
errorMessage = $"Bebop configuration file not found at '{bebopConfig}'";
return false;
}
}

var validFlagNames = props.Select(p => p.Attribute.Name).ToHashSet();
if (parsedFlags.Find(x => !validFlagNames.Contains(x.Name)) is CommandLineFlag unrecognizedFlag)
{
errorMessage = $"Unrecognized flag: --{unrecognizedFlag.Name}";
return false;
}

// parse all present command-line flags
// any flag on the command-line that was also present in bebop.json will be overwritten.
Expand Down
3 changes: 3 additions & 0 deletions Compiler/Compiler.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,8 @@
<PackageReference Include="Microsoft.DotNet.ILCompiler" Version="6.0.0-*" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="..\Runtime\C++\src\bebop.hpp" />
</ItemGroup>

</Project>
12 changes: 10 additions & 2 deletions Core/Exceptions/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,22 @@ public InvalidMapKeyTypeException(TypeBase type)
class DuplicateFieldException : SpanException
{
public DuplicateFieldException(IField field, Definition definition)
: base($"The type '{definition.Name}' already contains a definition for '{field.Name}'", field.Span, 112) { }
: base($"The type '{definition.Name}' already contains a definition for '{field.Name}'.", field.Span, 112) { }
}

[Serializable]
class InvalidUnionBranchException : SpanException
{
public InvalidUnionBranchException(Definition definition)
: base($"The definition '{definition.Name}' cannot be used as a union branch. Valid union branches are messages, structs, or unions.", definition.Span, 108)
: base($"The definition '{definition.Name}' cannot be used as a union branch. Valid union branches are messages, structs, or unions.", definition.Span, 113)
{ }
}

[Serializable]
class DuplicateUnionDiscriminatorException : SpanException
{
public DuplicateUnionDiscriminatorException(Token discriminator, string unionName)
: base($"The discriminator index {discriminator.Lexeme} was used more than once in union '{unionName}'.", discriminator.Span, 114)
{ }
}

Expand Down
37 changes: 23 additions & 14 deletions Core/Generators/CPlusPlus/CPlusPlusGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ private string FormatDocumentation(string documentation, int spaces)
{
var builder = new IndentedStringBuilder();
builder.Indent(spaces);
foreach (var line in documentation.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None))
foreach (var line in documentation.GetLines())
{
builder.AppendLine($"/// {line}");
}
Expand Down Expand Up @@ -211,7 +211,7 @@ private string CompileDecodeUnion(UnionDefinition definition)
var i = branch.Discriminator - 1;
builder.AppendLine($" case {branch.Discriminator}:");
builder.AppendLine($" target.variant.emplace<{i}>();");
builder.AppendLine($" {branch.Definition.Name}::decodeInto(std::get<{i}>(target.variant), reader);");
builder.AppendLine($" {branch.Definition.Name}::decodeInto(reader, std::get<{i}>(target.variant));");
builder.AppendLine(" break;");
}
builder.AppendLine(" default:");
Expand Down Expand Up @@ -271,7 +271,7 @@ private string CompileDecodeField(TypeBase type, string target, int depth = 0, i
},
DefinedType dt when Schema.Definitions[dt.Name] is EnumDefinition =>
$"{target} = static_cast<{dt.Name}>(reader.readUint32());",
DefinedType dt => $"{dt.Name}::decodeInto({target}, reader);",
DefinedType dt => $"{dt.Name}::decodeInto(reader, {target});",
_ => throw new InvalidOperationException($"CompileDecodeField: {type}")
};
}
Expand Down Expand Up @@ -299,8 +299,8 @@ private string TypeName(in TypeBase type)
BaseType.Float32 => "float",
BaseType.Float64 => "double",
BaseType.String => "std::string",
BaseType.Guid => "bebop::Guid",
BaseType.Date => "bebop::TickDuration",
BaseType.Guid => "::bebop::Guid",
BaseType.Date => "::bebop::TickDuration",
_ => throw new ArgumentOutOfRangeException(st.BaseType.ToString())
};
// case ArrayType at when at.IsBytes():
Expand Down Expand Up @@ -407,24 +407,27 @@ public override string Compile()
throw new InvalidOperationException($"unsupported definition {td}");
}

builder.AppendLine($" static std::unique_ptr<std::vector<uint8_t>> encode(const {td.Name}& message) {{");
builder.AppendLine(" bebop::BebopWriter writer{};");
builder.AppendLine($" static void encodeInto(const {td.Name}& message, std::vector<uint8_t>& targetBuffer) {{");
builder.AppendLine(" ::bebop::Writer writer{targetBuffer};");
builder.AppendLine($" {td.Name}::encodeInto(message, writer);");
builder.AppendLine(" return writer.buffer();");
builder.AppendLine(" }");
builder.AppendLine("");
builder.AppendLine($" static void encodeInto(const {td.Name}& message, bebop::BebopWriter& writer) {{");
builder.AppendLine($" static void encodeInto(const {td.Name}& message, ::bebop::Writer& writer) {{");
builder.Append(CompileEncode(td));
builder.AppendLine(" }");
builder.AppendLine("");
builder.AppendLine($" static {td.Name} decode(const uint8_t *buffer) {{");
builder.AppendLine($" static {td.Name} decode(const uint8_t* sourceBuffer) {{");
builder.AppendLine($" {td.Name} result;");
builder.AppendLine(" bebop::BebopReader reader{buffer};");
builder.AppendLine($" {td.Name}::decodeInto(result, reader);");
builder.AppendLine($" {td.Name}::decodeInto(sourceBuffer, result);");
builder.AppendLine($" return result;");
builder.AppendLine(" }");
builder.AppendLine("");
builder.AppendLine($" static void decodeInto({td.Name}& target, bebop::BebopReader& reader) {{");
builder.AppendLine($" static void decodeInto(const uint8_t* sourceBuffer, {td.Name}& target) {{");
builder.AppendLine(" ::bebop::Reader reader{sourceBuffer};");
builder.AppendLine($" {td.Name}::decodeInto(reader, target);");
builder.AppendLine(" }");
builder.AppendLine("");
builder.AppendLine($" static void decodeInto(::bebop::Reader& reader, {td.Name}& target) {{");
builder.Append(CompileDecode(td));
builder.AppendLine(" }");
builder.AppendLine("};");
Expand All @@ -444,7 +447,13 @@ public override string Compile()

public override void WriteAuxiliaryFiles(string outputPath)
{
// There is nothing to do here.
var assembly = Assembly.GetEntryAssembly()!;
var runtime = assembly.GetManifestResourceNames()!.FirstOrDefault(n => n.Contains("bebop.hpp"))!;

using Stream stream = assembly.GetManifestResourceStream(runtime)!;
using StreamReader reader = new StreamReader(stream);
string result = reader.ReadToEnd();
File.WriteAllText(Path.Join(outputPath, "bebop.hpp"), result);
}
}
}
Loading

0 comments on commit 69cf934

Please sign in to comment.