Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MessageGeneration from ros-sharp #56

Merged
merged 11 commits into from
Feb 9, 2022
37 changes: 18 additions & 19 deletions MessageGeneration/ActionCodeGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Text;
using Microsoft.Extensions.Logging;
using static RosNet.MessageGeneration.Utilities;

namespace RosNet.MessageGeneration;

Expand All @@ -8,21 +10,22 @@ public class ActionCodeGenerator : CodeGenerator
public static new readonly string FileExtension = ".action";
public static new readonly string FileName = "action";

protected override List<string> GenerateSingle(string inPath, string outPath, string? rosPackageName, bool? verbose = false)
public ActionCodeGenerator(ILogger<ActionCodeGenerator> logger) : base(logger)
{
}

protected override List<string> GenerateSingle(string inPath, string? outPath, string? rosPackageName)
{
verbose ??= false;
// If no ROS package name is provided, extract from path
rosPackageName ??= inPath.Split(Path.PathSeparator)[^3];
rosPackageName ??= inPath.Split(Path.DirectorySeparatorChar)[^3];

outPath = Path.Combine(outPath, Utilities.ResolvePackageName(rosPackageName));
outPath = Path.Combine(outPath ?? "", Utilities.ResolvePackageName(rosPackageName));

var inFileName = Path.GetFileNameWithoutExtension(inPath);

if ((bool)verbose)
{
Console.WriteLine("Parsing: " + inPath);
Console.WriteLine("Output Location: " + outPath);
}
_logger.LogDebug("Parsing: {file}", inPath);
_logger.LogDebug("Output Location: {file}", outPath);


using var tokenizer = new MessageTokenizer(inPath, new HashSet<string>(Utilities.BuiltInTypesMapping.Keys));
var listsOfTokens = tokenizer.Tokenize();
Expand Down Expand Up @@ -60,10 +63,6 @@ protected override List<string> GenerateSingle(string inPath, string outPath, st

public class ActionWrapper
{

private const string ONE_TAB = " ";
private const string TWO_TABS = " ";

private readonly string _inPath;
private readonly string _inFileName;

Expand Down Expand Up @@ -107,12 +106,12 @@ private string GenerateParameterizedConstructor(string className, string msgType
var paramsOut = new StringBuilder();
var assignments = new StringBuilder();

if (msgType.Equals("Goal", StringComparison.Ordinal))
if (msgType == "Goal")
{
paramsIn.Append("Header header, GoalID goal_id, ");
paramsOut.Append("header, goal_id");
}
else if (msgType.Equals("Result", StringComparison.Ordinal) || msgType.Equals("Feedback", StringComparison.Ordinal))
else if (msgType is "Result" or "Feedback")
{
paramsIn.Append("Header header, GoalStatus status, ");
paramsOut.Append("header, status");
Expand Down Expand Up @@ -156,7 +155,7 @@ public void WrapActionSections(string type)
writer.Write(imports);

// Write namespace
writer.Write($"namespace RosSharp.RosBridgeClient.MessageTypes.{Utilities.ResolvePackageName(_rosPackageName)}\n{{\n");
writer.Write($"namespace RosSharp.RosBridgeClient.MessageTypes.{ResolvePackageName(_rosPackageName)}\n{{\n");

// Write class declaration
writer.Write($"{ONE_TAB}public class {wrapperName} : Action{type}<{_inFileName}{type}>\n{ONE_TAB}{{\n");
Expand All @@ -165,7 +164,7 @@ public void WrapActionSections(string type)
writer.WriteLine($"{TWO_TABS}public const string RosMessageName = \"{_rosPackageName}/{wrapperName}\";");
henrikhorluck marked this conversation as resolved.
Show resolved Hide resolved

// Record goal/result/feedback declaration
_symbolTable.Add(Utilities.LowerFirstLetter(type), msgName);
_symbolTable.Add(char.ToLower(type[0]) + type[1..], msgName);

writer.WriteLine("");

Expand Down Expand Up @@ -193,13 +192,13 @@ public void WrapAction()

using StreamWriter writer = new(outPath, false);
// Write block comment
writer.WriteLine(Utilities.BLOCK_COMMENT);
writer.WriteLine(BLOCK_COMMENT);

// Write imports
writer.Write(imports);

// Write namespace
writer.Write($"namespace RosSharp.RosBridgeClient.MessageTypes.{Utilities.ResolvePackageName(_rosPackageName)}\n{{\n");
writer.Write($"namespace RosSharp.RosBridgeClient.MessageTypes.{ResolvePackageName(_rosPackageName)}\n{{\n");

// Write class declaration
var genericParams = new string[] {
Expand Down
37 changes: 21 additions & 16 deletions MessageGeneration/CodeGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,45 +1,50 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;

using Microsoft.Extensions.Logging;

namespace RosNet.MessageGeneration;

public abstract class CodeGenerator
{
protected readonly ILogger<CodeGenerator> _logger;

public CodeGenerator(ILogger<CodeGenerator> logger)
{
_logger = logger;
}
public static string FileExtension => throw new InvalidOperationException("Accessing fileextension of abstract class");

public static string FileName => throw new InvalidOperationException("Accessing filename of abstract class");
protected abstract List<string> GenerateSingle(string inputPath, string outputPath, string? rosPackageName = "", bool? verbose = false);
public List<string> Generate(string inputPath, string outputPath, string? rosPackageName, bool? verbose)
protected abstract List<string> GenerateSingle(string inputPath, string? outputPath, string? rosPackageName = "");
public List<string> Generate(string inputPath, string? outputPath, string? rosPackageName)
{
var fileName = (string)this.GetType().GetProperty("FileName", BindingFlags.Public | BindingFlags.Static)?.GetValue(null)!;
var fileExtension = (string)this.GetType().GetProperty("FileExtension", BindingFlags.Public | BindingFlags.Static)?.GetValue(null)!;

var fileName = (string)this.GetType().GetField("FileName")?.GetValue(null)!;
var fileExtension = (string)this.GetType().GetField("FileExtension")?.GetValue(null)!;
var warnings = new List<string>();

if (Directory.Exists(inputPath))
{
// TODO: make this flexible depending on
string[] files = Directory.GetFiles(inputPath, fileExtension, SearchOption.AllDirectories);
string[] files = Directory.GetFiles(inputPath, "*" + fileExtension, SearchOption.AllDirectories);

if (files.Length == 0)
{
Console.Error.WriteLine($"No {fileName} files found!");
_logger.LogError("No files found in {fileName}!", fileName);
return warnings;
}
else
{
if (verbose ?? false)
{
Console.WriteLine($"Found {files.Length} {fileName} files.");
}
_logger.LogDebug("Found {count} files in {directory}.", files.Length, fileName);
foreach (string file in files)
{
warnings.AddRange(GenerateSingle(file, outputPath, rosPackageName, verbose ?? false));
warnings.AddRange(GenerateSingle(file, outputPath, rosPackageName));
}
}
}
else if (File.Exists(inputPath))
{
_logger.LogDebug("Generating code for {File}", inputPath);
warnings.AddRange(GenerateSingle(Path.GetFullPath(inputPath), outputPath, rosPackageName));
}

return warnings;
}

}
33 changes: 17 additions & 16 deletions MessageGeneration/MessageCodeGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
namespace RosNet.MessageGeneration;
using Microsoft.Extensions.Logging;

namespace RosNet.MessageGeneration;

public class MessageCodeGenerator : CodeGenerator
{
public static new readonly string FileExtension = ".msg";
public static new readonly string FileName = "message";
protected override List<string> GenerateSingle(string inPath, string outPath, string? rosPackageName = "", bool? verbose = false)

public MessageCodeGenerator(ILogger<MessageCodeGenerator> logger) : base(logger)
{
}

protected override List<string> GenerateSingle(string inPath, string? outPath, string? rosPackageName = "")
{
// If no ROS package name is provided, extract from path
rosPackageName ??= inPath.Split(Path.PathSeparator)[^3];
rosPackageName ??= inPath.Split(Path.DirectorySeparatorChar)[^3];

outPath = Path.Combine(outPath, Utilities.ResolvePackageName(rosPackageName));
outPath = Path.Combine(outPath ?? "", Utilities.ResolvePackageName(rosPackageName));

string inFileName = Path.GetFileNameWithoutExtension(inPath);

if (!(rosPackageName.Equals("std_msgs", StringComparison.Ordinal)
&& (inFileName.Equals("Time", StringComparison.Ordinal)
|| inFileName.Equals("Duration", StringComparison.Ordinal))))
if (rosPackageName != "std_msgs" && inFileName.ToLower() is "time" or "duration")
{
if (verbose ?? false)
{
Console.WriteLine("Parsing: " + inPath);
Console.WriteLine("Output Location: " + outPath);
}

_logger.LogDebug("Parsing: {file}", inPath);
_logger.LogDebug("Output Location: {file}", outPath);

using var tokenizer = new MessageTokenizer(inPath, new HashSet<string>(Utilities.BuiltInTypesMapping.Keys));
List<List<MessageToken>> listOfTokens = tokenizer.Tokenize();
Expand All @@ -37,10 +40,8 @@ protected override List<string> GenerateSingle(string inPath, string outPath, st
}
else
{
if (verbose ?? false)
{
Console.WriteLine(inFileName + " will not be generated");
}
_logger.LogInformation("{file} will not be generated", inFileName);

return new List<string>();
}
}
Expand Down
1 change: 1 addition & 0 deletions MessageGeneration/MessageGeneration.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
</ItemGroup>
</Project>
14 changes: 8 additions & 6 deletions MessageGeneration/MessageParser.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Microsoft.CodeAnalysis.CSharp;

using static RosNet.MessageGeneration.Utilities;

namespace RosNet.MessageGeneration;

public class MessageParser
Expand Down Expand Up @@ -41,9 +43,9 @@ public MessageParser(List<MessageToken> tokens, string outPath, string rosPackag

this._rosPackageName = rosPackageName;

this._className = className.Length == 0 ? Utilities.CapitalizeFirstLetter(_inFileName) : className;
this._className = className.Length == 0 ? CapitalizeFirstLetter(_inFileName) : className;

this._rosMsgName = rosMsgName.Length == 0 ? Utilities.CapitalizeFirstLetter(_inFileName) : rosMsgName;
this._rosMsgName = rosMsgName.Length == 0 ? CapitalizeFirstLetter(_inFileName) : rosMsgName;


this._outPath = outPath;
Expand Down Expand Up @@ -195,7 +197,7 @@ private void Declaration()
{
Warn($"By convention, there is only one header for each message. ({_inFilePath}:{_lineNum})");
}
if (peeked.Type == MessageTokenType.Identifier && !peeked.Content.Equals("header", StringComparison.Ordinal))
if (peeked.Type == MessageTokenType.Identifier && peeked.Content != "header")
{
Warn($"By convention, a ros message Header will be named 'header'. '{peeked.Content}'. ({_inFilePath}:{_lineNum})");
}
Expand Down Expand Up @@ -248,18 +250,18 @@ private void Declaration()
}

// Constant Declaration
if (peeked?.Type == MessageTokenType.ConstantDeclaration)
if (peeked.Type == MessageTokenType.ConstantDeclaration)
{
if (!canHaveConstDecl)
{
throw new MessageParserException($"Type {type}' at {_inFilePath}:{_lineNum} cannot have constant declaration");
throw new MessageParserException($"Type {type}' cannot have constant declaration", _inFilePath, _lineNum);
}
declaration += $"const {type} {identifier} = {ConstantDeclaration(type)}";
_constants.Add(identifier);
}
else
{
declaration += $"{type} {identifier}{Utilities.PROPERTY_EXTENSION}\n";
declaration += $"{type} {identifier} {{ get; set; }}\n";
}
_body += declaration;
}
Expand Down
Loading