private static string GetCopyCreationExpression(DataModelType memberType, string sourceVariable) { switch (memberType.Kind) { case DataModelTypeKind.Leaf: case DataModelTypeKind.BuiltInDictionary: return("new " + memberType.CSharpName + "(" + sourceVariable + ")"); case DataModelTypeKind.Base: return(sourceVariable + ".DeepClone()"); case DataModelTypeKind.BuiltInNumber: case DataModelTypeKind.BuiltInString: case DataModelTypeKind.BuiltInBoolean: return(sourceVariable); case DataModelTypeKind.BuiltInVersion: return("(global::System.Version)" + sourceVariable + ".Clone()"); case DataModelTypeKind.Enum: return(sourceVariable); case DataModelTypeKind.BuiltInUri: return("new global::System.Uri(" + sourceVariable + ".OriginalString, " + sourceVariable + ".IsAbsoluteUri ? global::System.UriKind.Absolute : global::System.UriKind.Relative)"); default: Debug.Fail("Unexpected DataModelTypeKind"); throw new InvalidOperationException(); } }
private static void WriteDefinition(CodeWriter codeWriter, DataModel model, DataModelType type, bool lastType) { codeWriter.WriteLine(@"""" + type.G4DeclaredName + @""": "); codeWriter.OpenBrace(); WriteTypeMembers(codeWriter, model, type, true); codeWriter.CloseBrace(lastType ? "" : ","); }
private ToStringGenerator(CodeWriter codeWriter, DataModel model, DataModelType writtenType) { _codeWriter = codeWriter; _model = model; _writtenType = writtenType; _indexNamer = new LocalVariableNamer("index"); _valueNamer = new LocalVariableNamer("value"); _labelNamer = new LocalVariableNamer("label"); }
/// <summary>Generates Equals(object), Equals(T), and GetHashCode members for the supplied type from the supplied model.</summary> /// <param name="codeWriter">The code writer into which generated code shall be written.</param> /// <param name="model">The model from which code is being generated.</param> /// <param name="writtenType">Data model type being written.</param> public static void Generate(CodeWriter codeWriter, DataModel model, DataModelType writtenType) { if (!model.MetaData.GenerateEquals || writtenType.Kind != DataModelTypeKind.Leaf) { return; } new EqualsGenerator(codeWriter, model, writtenType).Generate(); }
private static void WriteParameters(StringBuilder sb, DataModel model, DataModelType type) { WriteParameterForMember(sb, model, type.Members[0]); for (int idx = 1; idx < type.Members.Length; ++idx) { sb.Append(", "); WriteParameterForMember(sb, model, type.Members[idx]); } }
private EqualsGenerator(CodeWriter codeWriter, DataModel model, DataModelType writtenType) { _codeWriter = codeWriter; _model = model; _writtenType = writtenType; _valueNamer = new LocalVariableNamer("value"); _indexNamer = new LocalVariableNamer("index"); _maxNamer = new LocalVariableNamer("max"); _xorNamer = new LocalVariableNamer("xor"); }
private static void WriteVisitMember(CodeWriter codeWriter, DataModel model, DataModelMember member) { DataModelType memberType = model.GetTypeForMember(member); switch (memberType.Kind) { case DataModelTypeKind.BuiltInNumber: case DataModelTypeKind.BuiltInString: case DataModelTypeKind.BuiltInDictionary: case DataModelTypeKind.BuiltInBoolean: case DataModelTypeKind.BuiltInUri: case DataModelTypeKind.BuiltInVersion: case DataModelTypeKind.Enum: // Don't visit builtins; overrides would inspect those directly. return; case DataModelTypeKind.Leaf: case DataModelTypeKind.Base: // Visit this member break; case DataModelTypeKind.Default: default: Debug.Fail("Unexpected DataModelTypeKind"); return; } var valueNamer = new LocalVariableNamer("value"); string sourceVariable = "node." + member.CSharpName; for (int idx = 0; idx < member.Rank; ++idx) { string valueName = valueNamer.MakeName(); codeWriter.OpenBrace("if ({0} != null)", sourceVariable); codeWriter.OpenBrace("foreach (var {0} in {1})", valueName, sourceVariable); sourceVariable = valueName; } codeWriter.WriteLine("this.VisitNullChecked({0});", sourceVariable); if (member.Rank == 0) { return; } for (int idx = 0; idx < member.Rank; ++idx) { codeWriter.CloseBrace(); // if (source != null) codeWriter.CloseBrace(); // foreach } codeWriter.WriteLine(); }
private static void WriteMembers(CodeWriter codeWriter, DataModel model, DataModelType type) { foreach (DataModelMember member in type.Members) { if (model.MetaData.GenerateLocations && (member.CSharpName == "Length" || member.CSharpName == "Offset")) { continue; } codeWriter.WriteLine(); WriteProperty(codeWriter, model, member); } }
private static void WriteCopyConstructor(CodeWriter codeWriter, DataModelType type) { codeWriter.WriteLine(); codeWriter.WriteLine("/// <summary>Initializes a new instance of the <see cref=\"" + type.CSharpName + "\" /> class as a copy of another instance.</summary>"); codeWriter.WriteLine("/// <exception cref=\"ArgumentNullException\">Thrown if <paramref name=\"other\" /> is null.</exception>"); codeWriter.WriteLine("/// <param name=\"other\">The instance to copy.</param>"); codeWriter.OpenBrace("public {0}({0} other)", type.CSharpName); codeWriter.OpenBrace("if (other == null)"); codeWriter.WriteLine("throw new ArgumentNullException(\"other\");"); codeWriter.CloseBrace(); codeWriter.WriteLine(); WriteCallToInit(codeWriter, type.Members.Select(member => "other." + member.CSharpName)); codeWriter.CloseBrace(); }
public ImmutableArray <string> GetKnownTypesFor(DataModelType type) { string cSharpName = type.CSharpName; ImmutableArray <string> .Builder result = ImmutableArray.CreateBuilder <string>(); foreach (DataModelType thisType in _g4Lookup.Values) { if (thisType.Base == cSharpName) { result.Add(thisType.CSharpName); } } return(result.ToImmutable().Sort(StringComparer.Ordinal)); }
private static void WriteTypes(CodeWriter codeWriter, DataModel model) { DataModelType rootType = model.Types.Where((dmt) => dmt.RootObject == true).First(); DataModelType[] types = model.Types.ToArray(); WriteTypeMembers(codeWriter, model, rootType, false); codeWriter.WriteLine(@"""definitions"":"); codeWriter.OpenBrace(); for (int i = 0; i < types.Length; i++) { DataModelType type = types[i]; bool lastType = (i == types.Length - 1); if (type == rootType) { continue; } switch (type.Kind) { case DataModelTypeKind.Base: case DataModelTypeKind.Leaf: WriteDefinition(codeWriter, model, type, lastType); break; case DataModelTypeKind.BuiltInNumber: case DataModelTypeKind.BuiltInString: case DataModelTypeKind.BuiltInDictionary: case DataModelTypeKind.BuiltInBoolean: case DataModelTypeKind.BuiltInVersion: case DataModelTypeKind.BuiltInUri: case DataModelTypeKind.Enum: // Don't write builtin types break; case DataModelTypeKind.Default: default: Debug.Fail("Unexpected data model type kind in a data model " + type.Kind); break; } } codeWriter.CloseBrace(); }
private static void WriteEnum(CodeWriter codeWriter, DataModel model, DataModelType type) { WriteXmlDocCommentsFor(codeWriter, type); WriteCommonAttributes(codeWriter); codeWriter.WriteLine("public enum " + type.CSharpName); codeWriter.OpenBrace(); codeWriter.WriteLine("Unknown = 0,"); foreach (string member in type.SerializedValues) { codeWriter.WriteLine(member.Trim() + ","); } codeWriter.CloseBrace(); // enum codeWriter.WriteLine(); }
private static void WriteMembers(CodeWriter codeWriter, DataModel model, DataModelType type) { DataModelMember[] members = type.Members.ToArray(); for (int i = 0; i < members.Length; i++) { DataModelMember member = members[i]; bool lastMember = (i == members.Length - 1); if (model.MetaData.GenerateLocations && (member.CSharpName == "Length" || member.CSharpName == "Offset")) { continue; } if (i > 0) { codeWriter.WriteLine(); } WriteProperty(codeWriter, model, member, lastMember); } }
private static void WriteType(CodeWriter codeWriter, DataModel model, DataModelType type) { WriteXmlDocCommentsFor(codeWriter, type); WriteCommonAttributes(codeWriter); WriteClassDeclaration(codeWriter, model, type); WriteKindProperty(codeWriter, model, type); if (model.MetaData.GenerateLocations && !type.HasBase) { // (if the type has a base; these properties come from the base) WriteLocationProperties(codeWriter, "public "); } WriteMembers(codeWriter, model, type); WriteConstructors(codeWriter, model, type); WriteVirtualConstructor(codeWriter, type); ToStringGenerator.Generate(codeWriter, model, type); EqualsGenerator.Generate(codeWriter, model, type); codeWriter.CloseBrace(); // class codeWriter.WriteLine(); }
private static void WriteTypeMembers(CodeWriter codeWriter, DataModel model, DataModelType type, bool lastMember) { if (!string.IsNullOrEmpty(type.SummaryText)) { codeWriter.WriteLine(@"""description"": """ + BuildDescription(type.SummaryText) + @""","); } codeWriter.WriteLine(@"""additionalMembers"": false,"); codeWriter.WriteLine(@"""type"": ""object"","); codeWriter.WriteLine(@"""properties"": {"); codeWriter.IncrementIndentLevel(); WriteMembers(codeWriter, model, type); bool hasOneOrMoreRequiredMembers = false; foreach (DataModelMember member in type.Members) { if (member.Required) { hasOneOrMoreRequiredMembers = true; break; } } if (hasOneOrMoreRequiredMembers) { codeWriter.CloseBrace(","); } else { codeWriter.CloseBrace(); } WriteRequiredMember(codeWriter, model, type, lastMember); }
private static void WriteClassDeclaration(CodeWriter codeWriter, DataModel model, DataModelType type) { var decl = new StringBuilder("public "); switch (type.Kind) { case DataModelTypeKind.Base: decl.Append("abstract "); break; case DataModelTypeKind.Leaf: decl.Append("sealed "); break; default: throw new InvalidOperationException("Unexpected data model kind"); } decl.Append("class "); decl.Append(type.CSharpName); decl.Append(" : "); if (!string.IsNullOrEmpty(type.InterfaceName)) { decl.Append(type.InterfaceName); decl.Append(", "); } if (type.HasBase) { decl.Append(type.Base); decl.Append(", "); } decl.Append(CommonInterfaceName); if (model.MetaData.GenerateEquals && type.Kind == DataModelTypeKind.Leaf) { decl.Append(", IEquatable<"); decl.Append(type.CSharpName); decl.Append('>'); } codeWriter.OpenBraceConsume(decl); }
private static void WriteRequiredMember(CodeWriter codeWriter, DataModel model, DataModelType type, bool lastMember) { List <string> requiredMembers = new List <string>(); foreach (DataModelMember member in type.Members) { if (member.Required) { requiredMembers.Add(member.SerializedName); } } if (requiredMembers.Count > 0) { var sb = new StringBuilder(@"""required"": ["); for (int i = 0; i < requiredMembers.Count; i++) { string name = requiredMembers[i]; sb.Append(@"""" + name + @"""" + (i != requiredMembers.Count - 1 ? ", " : "")); } codeWriter.WriteLine(sb.ToString() + "]" + (lastMember ? "" : ",")); } }
private static void WriteConstructorDeclaration(CodeWriter codeWriter, DataModel model, DataModelType type) { var sb = new StringBuilder(); sb.Append("public "); sb.Append(type.CSharpName); sb.Append('('); WriteParameters(sb, model, type); sb.Append(')'); codeWriter.OpenBraceConsume(sb); }
private static void WriteProperty(CodeWriter codeWriter, DataModel model, DataModelMember member, bool lastMember) { string memberName = member.SerializedName; DataModelType memberType = model.GetTypeByG4Name(member.DeclaredName); string memberTypeName = memberType.G4DeclaredName; codeWriter.WriteLine(@"""" + memberName + @""": "); codeWriter.OpenBrace(); codeWriter.WriteLine(@"""description"": """ + BuildDescription(member.SummaryText) + @""","); string canonicalizedName, format; bool isPrimitive = CanonicalizeTypeName(memberTypeName, out canonicalizedName, out format); int rank = member.Rank; while (rank > 0) { WriteArrayStart(codeWriter, member); rank--; } string defaultValue = member.Default; bool hasDefault = !string.IsNullOrEmpty(defaultValue); if (isPrimitive) { string pattern = member.Pattern; string minimum = member.Minimum; bool hasMinimum = !(string.IsNullOrEmpty(minimum)); bool hasPattern = !string.IsNullOrEmpty(pattern); bool hasFormat = !string.IsNullOrEmpty(format); codeWriter.WriteLine(@"""type"": """ + canonicalizedName + @"""" + ((hasPattern || hasFormat || hasMinimum || hasDefault) ? "," : "")); if (hasFormat) { codeWriter.WriteLine(@"""format"": """ + format + @"""" + ((hasPattern || hasMinimum || hasDefault) ? "," : "")); } if (hasPattern) { codeWriter.WriteLine(@"""pattern"": """ + pattern + @"""" + ((hasMinimum || hasDefault) ? "," : "")); } if (hasMinimum) { codeWriter.WriteLine(@"""minimum"": " + minimum + (hasDefault ? "," : "")); } if (hasDefault) { codeWriter.WriteLine(@"""default"": " + defaultValue); } } else if (memberType.Kind == DataModelTypeKind.Enum) { var sb = new StringBuilder(); sb.Append(@"""enum"": [ "); if (hasDefault) { codeWriter.WriteLine(@"""default"": " + defaultValue + ","); } for (int i = 0; i < memberType.G4DeclaredValues.Length; i++) { bool isFinal = i == memberType.G4DeclaredValues.Length - 1; string name = memberType.G4DeclaredValues[i].Replace("'", ""); sb.Append(@"""" + name + @"""" + (isFinal ? "" : ",")); } codeWriter.WriteLine(sb.ToString() + "]"); } else { codeWriter.WriteLine(@"""$ref"": ""#/definitions/" + canonicalizedName + @""""); } rank = member.Rank; while (rank > 0) { WriteArrayEnd(codeWriter); rank--; } codeWriter.CloseBrace(lastMember ? "" : ","); }
private static void WriteInitForMember(CodeWriter codeWriter, DataModel model, DataModelMember member, LocalVariableNamer destNamer, LocalVariableNamer valueNamer) { DataModelType memberType = model.GetTypeForMember(member); if (memberType.IsNullable) { codeWriter.OpenBrace("if ({0} != null)", member.ArgumentName); } if (member.Rank == 0) { codeWriter.WriteLine("this." + member.CSharpName + " = " + GetCopyCreationExpression(memberType, member.ArgumentName) + ";"); } else { string[] destinations = new string[member.Rank]; string source = member.ArgumentName; for (int idx = 0; idx < destinations.Length; ++idx) { string currentDest = destNamer.MakeName(); destinations[idx] = currentDest; StringBuilder sb = new StringBuilder(); sb.Append("var ").Append(currentDest).Append(" = new List<"); AppendRankedTypeName(sb, "IList", memberType.CSharpName, member.Rank - idx - 1); sb.Append(">();"); codeWriter.WriteLineConsume(sb); codeWriter.OpenBrace("if ({0} != null)", source); string value = valueNamer.MakeName(); codeWriter.OpenBrace("foreach (var {0} in {1})", value, source); source = value; } string lastDestination = destinations[destinations.Length - 1]; if (memberType.IsNullable) { codeWriter.OpenBrace("if ({0} == null)", source); codeWriter.WriteLine(lastDestination + ".Add(null);"); codeWriter.CloseBrace(); codeWriter.OpenBrace("else"); } codeWriter.WriteLine(lastDestination + ".Add(" + GetCopyCreationExpression(memberType, source) + ");"); if (memberType.IsNullable) { codeWriter.CloseBrace(); } codeWriter.CloseBrace(); // foreach codeWriter.CloseBrace(); // if (source != null) codeWriter.WriteLine(); for (int idx = 1; idx < destinations.Length; ++idx) { codeWriter.WriteLine("{0}.Add({1});", destinations[member.Rank - idx - 1], destinations[member.Rank - idx]); codeWriter.CloseBrace(); // foreach codeWriter.CloseBrace(); // if (source != null) codeWriter.WriteLine(); } codeWriter.WriteLine("this.{0} = {1};", member.CSharpName, destinations[0]); } if (memberType.IsNullable) { codeWriter.CloseBrace(); } }
private static void WriteInitFunction(CodeWriter codeWriter, DataModel model, DataModelType type) { codeWriter.WriteLine(); var sb = new StringBuilder(); sb.Append("private void Init("); WriteParameters(sb, model, type); sb.Append(')'); codeWriter.OpenBraceConsume(sb); var valueNamer = new LocalVariableNamer("value"); var destNamer = new LocalVariableNamer("destination"); foreach (DataModelMember member in type.Members) { WriteInitForMember(codeWriter, model, member, destNamer, valueNamer); } codeWriter.CloseBrace(); // Init }
private static void WriteMemberConstructor(CodeWriter codeWriter, DataModel model, DataModelType type) { codeWriter.WriteLine(); codeWriter.WriteLine("/// <summary>Initializes a new instance of the <see cref=\"" + type.CSharpName + "\" /> class with the supplied data.</summary>"); foreach (DataModelMember member in type.Members) { codeWriter.WriteLine("/// <param name=\"" + member.ArgumentName + "\">An initialization value for the <see cref=\"P:" + member.CSharpName + "\" /> member.</param>"); } WriteConstructorDeclaration(codeWriter, model, type); WriteCallToInit(codeWriter, type.Members.Select(member => member.ArgumentName)); codeWriter.CloseBrace(); }
public static void WriteXmlDocCommentsFor(CodeWriter sourceCode, DataModelType type) { WriteXmlDocComment(sourceCode, "summary", type.SummaryText); WriteXmlDocComment(sourceCode, "remarks", type.RemarksText); }
private static void WriteVirtualConstructor(CodeWriter codeWriter, DataModelType type) { if (!type.HasBase) { // If the type has a base, this got emitted in the base. codeWriter.WriteLine(); codeWriter.OpenBrace(CommonInterfaceName + " " + CommonInterfaceName + ".DeepClone()"); codeWriter.WriteLine("return this.DeepCloneCore();"); codeWriter.CloseBrace(); } codeWriter.WriteLine(); codeWriter.WriteLine("/// <summary>Creates a deep copy of this instance.</summary>"); var sb = new StringBuilder("public "); if (type.HasBase) { sb.Append("new "); } sb.Append(type.CSharpName).Append(" DeepClone()"); codeWriter.OpenBraceConsume(sb); codeWriter.WriteLine("return ({0})this.DeepCloneCore();", type.CSharpName); codeWriter.CloseBrace(); if (type.Kind == DataModelTypeKind.Base) { if (type.HasBase) { // Already got emitted in the base class return; } codeWriter.WriteLine(); codeWriter.WriteLine("protected abstract " + CommonInterfaceName + " DeepCloneCore();"); return; } codeWriter.WriteLine(); if (type.HasBase) { sb.Append("protected override "); } else if (type.Kind == DataModelTypeKind.Base) { sb.Append("protected "); } else { sb.Append("private "); } sb.Append(CommonInterfaceName).Append(" DeepCloneCore()"); codeWriter.OpenBraceConsume(sb); string copyType; if (type.Members.Length == 0) { copyType = String.Empty; } else { copyType = "this"; } codeWriter.WriteLine("return new {0}({1});", type.CSharpName, copyType); codeWriter.CloseBrace(); }
private static void WriteConstructors(CodeWriter codeWriter, DataModel model, DataModelType type) { if (type.Members.Length == 0) { // No need for the constructor when there are no members; the implicit one is fine. return; } WriteInitFunction(codeWriter, model, type); WriteNoArgConstructor(codeWriter, type.CSharpName); WriteMemberConstructor(codeWriter, model, type); WriteCopyConstructor(codeWriter, type); }
private void WriteGetHashCodeMember(DataModelMember member) { DataModelType memberType = _model.GetTypeForMember(member); DataModelTypeKind typeKind = memberType.Kind; string sourceVariable = "this." + member.CSharpName; int additionalCloseBraces = 0; // (rank - 1) * 2 OpenBrace calls for (int idx = 1; idx < member.Rank; ++idx) { string nextVariable = _valueNamer.MakeName(); _codeWriter.OpenBrace("if ({0} != null)", sourceVariable); _codeWriter.OpenBrace("foreach (var {0} in {1})", nextVariable, sourceVariable); _codeWriter.WriteLine("result = result * {0};", MultiplicativeConstant); _codeWriter.OpenBrace("if ({0} != null)", nextVariable); sourceVariable = nextVariable; ++additionalCloseBraces; } // rank != 0 ? 1 : 0 OpenBrace calls if (member.Rank != 0) { string nextVariable = _valueNamer.MakeName(); _codeWriter.OpenBrace("if ({0} != null)", sourceVariable); _codeWriter.OpenBrace("foreach (var {0} in {1})", nextVariable, sourceVariable); _codeWriter.WriteLine("result = result * {0};", MultiplicativeConstant); sourceVariable = nextVariable; ++additionalCloseBraces; } // rank if (memberType.IsNullable) { _codeWriter.OpenBrace("if ({0} != null)", sourceVariable); } switch (typeKind) { case DataModelTypeKind.Base: case DataModelTypeKind.Leaf: case DataModelTypeKind.BuiltInString: case DataModelTypeKind.BuiltInUri: case DataModelTypeKind.BuiltInVersion: _codeWriter.WriteLine("result = (result * {1}) + {0}.GetHashCode();", sourceVariable, MultiplicativeConstant); break; case DataModelTypeKind.BuiltInNumber: case DataModelTypeKind.Enum: _codeWriter.WriteLine("result = (result * {1}) + (int){0};", sourceVariable, MultiplicativeConstant); break; case DataModelTypeKind.BuiltInBoolean: _codeWriter.OpenBrace("if (" + sourceVariable + ")"); _codeWriter.WriteLine("result = (result * " + MultiplicativeConstant + ") + 1;"); _codeWriter.CloseBrace(); break; case DataModelTypeKind.BuiltInDictionary: string xorTempVal = _xorNamer.MakeName(); string iterVal = _valueNamer.MakeName(); _codeWriter.WriteLine("// Use xor for dictionaries to be order-independent"); _codeWriter.WriteLine("int {0} = 0;", xorTempVal); _codeWriter.OpenBrace("foreach (var {0} in {1})", iterVal, sourceVariable); _codeWriter.WriteLine("{0} ^= ({1}.Key ?? String.Empty).GetHashCode();", xorTempVal, iterVal); _codeWriter.WriteLine("{0} ^= ({1}.Value ?? String.Empty).GetHashCode();", xorTempVal, iterVal); _codeWriter.CloseBrace(); // foreach _codeWriter.WriteLine(); _codeWriter.WriteLine("result = (result * {1}) + {0};", xorTempVal, MultiplicativeConstant); break; default: Debug.Fail("Unrecognized DataModelTypeKind"); break; } int closeBraces; if (member.Rank == 0) { closeBraces = 0; } else { closeBraces = (member.Rank - 1) * 2 + 1; } if (memberType.IsNullable) { ++closeBraces; } closeBraces += additionalCloseBraces; for (int idx = 0; idx < closeBraces; ++idx) { _codeWriter.CloseBrace(); } }
private static void WriteKindProperty(CodeWriter codeWriter, DataModel model, DataModelType type) { if (type.HasBase && type.Kind == DataModelTypeKind.Base) { // It came from the base return; } WriteKindXmlComments(codeWriter); var sb = new StringBuilder("public "); if (type.Kind == DataModelTypeKind.Base) { sb.Append("abstract "); } else if (type.HasBase) { sb.Append("override "); } sb.Append(model.Name); sb.Append("Kind SyntaxKind "); switch (type.Kind) { case DataModelTypeKind.Leaf: sb.Append("{ get { return " + model.Name + "Kind." + type.CSharpName + "; } }"); break; case DataModelTypeKind.Base: sb.Append("{ get; }"); break; default: Debug.Fail("Tried to write kind for class not implementing common interface"); break; } codeWriter.WriteLineConsume(sb); }
/// <summary> /// Generates a "ToString" override for the supplied type from the supplied model into the /// supplied <see cref="CodeWriter"/>. /// </summary> /// <param name="codeWriter">The code writer.</param> /// <param name="model">The model.</param> /// <param name="writtenType">Type of the written.</param> public static void Generate(CodeWriter codeWriter, DataModel model, DataModelType writtenType) { new ToStringGenerator(codeWriter, model, writtenType).Generate(); }