public MessageParser(List <MessageToken> tokens, string outPath, string rosPackageName, string type, Dictionary <string, string> builtInTypeMapping, Dictionary <string, string> builtInTypesDefaultInitialValues, string className = "", string rosMsgName = "") { this.tokens = tokens; this.inFilePath = tokens[0].content; this.inFileName = Path.GetFileNameWithoutExtension(inFilePath); this.rosPackageName = rosPackageName; if (className.Equals("")) { this.className = MsgAutoGenUtilities.CapitalizeFirstLetter(inFileName); } else { this.className = className; } if (rosMsgName.Equals("")) { this.rosMsgName = MsgAutoGenUtilities.CapitalizeFirstLetter(inFileName); } else { this.rosMsgName = rosMsgName; } this.outPath = outPath; this.outFilePath = Path.Combine(outPath, type); this.tokens.RemoveAt(0); this.builtInTypeMapping = builtInTypeMapping; this.builtInTypesDefaultInitialValues = builtInTypesDefaultInitialValues; }
// Declaration -> BuiltInType Identifier | BuiltInType Identifier ConstantDeclaration | BuiltInType ArrayDeclaration Identifier // Declaration -> DefinedType Identifier | DefinedType ArrayDeclaration Identifier // Declaration -> Header Identifier private void Declaration() { string declaration = ""; // Type MessageToken peeked = Peek(); string type = ""; bool canHaveConstDecl = false; declaration += MsgAutoGenUtilities.TWO_TABS + "public "; if (PeekType(MessageTokenType.BuiltInType)) { type = builtInTypeMapping[MatchByType(MessageTokenType.BuiltInType)]; if (!type.Equals("Time") && !type.Equals("Duration")) { // Time and Duration can't have constant declaration // See <wiki.ros.org/msg> canHaveConstDecl = true; } else { // Need to import Standard imports.Add("Std"); } } else if (PeekType(MessageTokenType.DefinedType)) { type = MatchByType(MessageTokenType.DefinedType); string[] hierarchy = type.Split(new char[] { '/', '\\' }); // Assume type can only be either: // Type // package/Type switch (hierarchy.Length) { case 1: break; case 2: if (hierarchy[0].Equals("") || hierarchy[1].Equals("")) { throw new MessageParserException( "Invalid field type '" + type + "'. + " + "(" + inFilePath + ":" + lineNum + ")"); } string package = MsgAutoGenUtilities.ResolvePackageName(hierarchy[0]); imports.Add(package); type = hierarchy[1]; break; default: throw new MessageParserException( "Invalid field type '" + type + "'. + " + "(" + inFilePath + ":" + lineNum + ")"); } } else { type = MatchByType(MessageTokenType.Header); if (PeekType(MessageTokenType.FixedSizeArray) || PeekType(MessageTokenType.VariableSizeArray)) { Warn( "By convention, there is only one header for each message." + "(" + inFilePath + ":" + lineNum + ")"); } if (PeekType(MessageTokenType.Identifier) && !Peek().content.Equals("header")) { Warn( "By convention, a ros message Header will be named 'header'. '" + Peek().content + "'. (" + inFilePath + ":" + lineNum + ")"); } imports.Add("Std"); } // Array Declaration int arraySize = -1; if (PeekType(MessageTokenType.FixedSizeArray)) { type += "[]"; canHaveConstDecl = false; arraySize = int.Parse(MatchByType(MessageTokenType.FixedSizeArray)); } if (PeekType(MessageTokenType.VariableSizeArray)) { type += "[]"; canHaveConstDecl = false; MatchByType(MessageTokenType.VariableSizeArray); arraySize = 0; } // Identifier string identifier = MatchByType(MessageTokenType.Identifier); // Check for duplicate declaration if (symbolTable.ContainsKey(identifier)) { throw new MessageParserException( "Field '" + identifier + "' at " + inFilePath + ":" + lineNum + " already declared!"); } // Check if identifier is a ROS message built-in type if (builtInTypeMapping.ContainsKey(identifier) && identifier.Equals("time") && identifier.Equals("duration")) { throw new MessageParserException( "Invalid field identifier '" + identifier + "' at " + inFilePath + ":" + lineNum + ". '" + identifier + "' is a ROS message built-in type."); } #if NETFRAMEWORK CodeDomProvider provider = CodeDomProvider.CreateProvider("C#"); // Check if identifier is a C# keyword if (!provider.IsValidIdentifier(identifier)) { Warn( "'" + identifier + "' is a C# keyword. We have appended \"_\" at the front to avoid C# compile-time issues." + "(" + inFilePath + ":" + lineNum + ")"); declaration = MsgAutoGenUtilities.TWO_TABS + "[JsonProperty(\"" + identifier + "\")]\n" + declaration; identifier = "_" + identifier; } #else Warn( "'CodeDomProvider class might not exist on your platform. We did not check whether " + identifier + "' is a C# keyword." + "(" + inFilePath + ":" + lineNum + ")"); #endif symbolTable.Add(identifier, type); // Array declaration table if (arraySize > -1) { arraySizes.Add(identifier, arraySize); } // Constant Declaration if (PeekType(MessageTokenType.ConstantDeclaration)) { if (canHaveConstDecl) { declaration += "const " + type + " " + identifier + " = "; declaration += ConstantDeclaration(type); constants.Add(identifier); } else { throw new MessageParserException( "Type " + type + "' at " + inFilePath + ":" + lineNum + " cannot have constant declaration"); } } else { declaration += type + " " + identifier + MsgAutoGenUtilities.PROPERTY_EXTENSION + "\n"; } body += declaration; }
public void WrapAction() { string wrapperName = inFileName + "Action"; string outPath = Path.Combine(this.outPath, wrapperName + ".cs"); string imports = "using Newtonsoft.Json;\n\n"; symbolTable = new Dictionary <string, string>(); using (StreamWriter writer = new StreamWriter(outPath, false)) { // Write block comment writer.Write(MsgAutoGenUtilities.BLOCK_COMMENT + "\n"); // Write imports writer.Write(imports); // Write namespace writer.Write( "namespace RosSharp.RosBridgeClient.MessageTypes." + MsgAutoGenUtilities.ResolvePackageName(rosPackageName) + "\n" + "{\n" ); // Write class declaration string[] genericParams = new string[] { inFileName + "ActionGoal", inFileName + "ActionResult", inFileName + "ActionFeedback", inFileName + "Goal", inFileName + "Result", inFileName + "Feedback" }; writer.Write( ONE_TAB + "public class " + wrapperName + " : Action<" + string.Join(", ", genericParams) + ">\n" + ONE_TAB + "{\n" ); // Write ROS package name writer.Write( TWO_TABS + "[JsonIgnore]\n" + TWO_TABS + "public const string RosMessageName = \"" + rosPackageName + "/" + wrapperName + "\";\n" ); // Record variables // Action Goal symbolTable.Add("action_goal", wrapperName + "Goal"); // Action Result symbolTable.Add("action_result", wrapperName + "Result"); //Action Feedback symbolTable.Add("action_feedback", wrapperName + "Feedback"); // Write default value constructor writer.Write("\n" + GenerateDefaultValueConstructor(wrapperName) + "\n"); // Close class writer.Write(ONE_TAB + "}\n"); // Close namespace writer.Write("}\n"); } }
public void Parse() { // If outpath doesn't exist, mkdir if (!Directory.Exists(outFilePath)) { Directory.CreateDirectory(outFilePath); } // Append filename this.outFilePath = Path.Combine(this.outFilePath, this.className + ".cs"); using (StreamWriter writer = new StreamWriter(outFilePath, false)) { writer.Write(MsgAutoGenUtilities.BLOCK_COMMENT + "\n"); // Message -> Lines // Lines -> Line Lines | e while (!IsEmpty()) { Line(); } // Write imports writer.Write(GenerateImports()); // Write namespace writer.Write( "namespace RosSharp.RosBridgeClient.MessageTypes." + MsgAutoGenUtilities.ResolvePackageName(rosPackageName) + "\n" + "{\n" ); // Write class declaration writer.Write( MsgAutoGenUtilities.ONE_TAB + "public class " + className + " : Message\n" + MsgAutoGenUtilities.ONE_TAB + "{\n" ); // Write ROS package name writer.Write(MsgAutoGenUtilities.TWO_TABS + "[JsonIgnore]\n"); writer.Write(MsgAutoGenUtilities.TWO_TABS + "public const string RosMessageName = \"" + rosPackageName + "/" + rosMsgName + "\";\n\n"); // Write body writer.Write(body); writer.Write("\n"); // Write constructors writer.Write(GenerateDefaultValueConstructor()); if (symbolTable.Count != 0 && !new HashSet <string>(symbolTable.Keys).SetEquals(constants)) { writer.Write("\n"); writer.Write(GenerateParameterizedConstructor()); } // Close class writer.Write(MsgAutoGenUtilities.ONE_TAB + "}\n"); // Close namespace writer.Write("}\n"); writer.Flush(); writer.Close(); } }