/// <summary> /// Emits the node/edge/internal class object attribute initialization code in graph exporting /// for an attribute of internal class object type with the given value into the stream writer. /// </summary> private static void EmitAttributeInitialization(MainGraphExportContext mainGraphContext, IAttributeBearer owner, AttributeType attrType, object value, INamedGraph graph, StreamWriter sw) { if (owner is IGraphElement) { String persistentName = graph.GetElementName((IGraphElement)owner); sw.Write("@(\"{0}\").{1} = ", persistentName, attrType.Name); } else { String persistentName = mainGraphContext.GetOrAssignPersistentName((IObject)owner); sw.Write("@@(\"{0}\").{1} = ", persistentName, attrType.Name); } StringBuilder deferredInits = new StringBuilder(); if (value == null) { sw.Write("null"); } else if (value is IObject) { IObject obj = (IObject)value; EmitObjectFetchingOrCreation(mainGraphContext, obj.Type, obj, graph, sw, deferredInits); } else // container { EmitAttribute(mainGraphContext, attrType, value, graph, sw, deferredInits); } sw.WriteLine(); sw.Write(deferredInits); }
public string ToString(object data, INamedGraph graph, params object[] additionalData) { StringBuilder sb = new StringBuilder(); sb.Append(ToString(debuggingEvent)); sb.Append(" "); switch (debuggingEvent) { case SubruleDebuggingEvent.Add: case SubruleDebuggingEvent.Rem: case SubruleDebuggingEvent.Emit: case SubruleDebuggingEvent.Halt: case SubruleDebuggingEvent.Highlight: { string message = (string)data; sb.Append("\""); sb.Append(message); sb.Append("\""); for (int i = 0; i < additionalData.Length; ++i) { sb.Append(" "); sb.Append(EmitHelper.Clip(EmitHelper.ToStringAutomatic(additionalData[i], graph, false, null, null), 120)); } break; } case SubruleDebuggingEvent.Match: { IMatches matches = (IMatches)data; sb.Append(matches.Producer.PackagePrefixedName); break; } case SubruleDebuggingEvent.New: case SubruleDebuggingEvent.Delete: case SubruleDebuggingEvent.Retype: case SubruleDebuggingEvent.SetAttributes: { IGraphElement elem = (IGraphElement)data; sb.Append(graph.GetElementName(elem)); sb.Append(":"); sb.Append(elem.Type.Name); if (additionalData.Length > 0) { sb.Append("."); // the attribute name sb.Append((string)additionalData[0]); } break; } default: return("INTERNAL FAILURE, unknown SubruleDebuggingConfigurationRule"); } sb.Append(" triggers "); sb.Append(ToString()); return(sb.ToString()); }
/// <summary> /// type needed for enum, otherwise null ok /// graph needed for node/edge in set/map, otherwise null ok /// </summary> public static String ToString(object value, AttributeType type, INamedGraph graph) { switch (type.Kind) { case AttributeKind.ByteAttr: return(((sbyte)value).ToString() + "Y"); case AttributeKind.ShortAttr: return(((short)value).ToString() + "S"); case AttributeKind.IntegerAttr: return(((int)value).ToString()); case AttributeKind.LongAttr: return(((long)value).ToString() + "L"); case AttributeKind.BooleanAttr: return(((bool)value).ToString()); case AttributeKind.StringAttr: if (value == null) { return("\"\""); } if (((string)value).IndexOf('\"') != -1) { return("\'" + ((string)value) + "\'"); } else { return("\"" + ((string)value) + "\""); } case AttributeKind.FloatAttr: return(((float)value).ToString(System.Globalization.CultureInfo.InvariantCulture) + "f"); case AttributeKind.DoubleAttr: return(((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture)); case AttributeKind.ObjectAttr: Console.WriteLine("Warning: Exporting non-null attribute of object type to null"); return("null"); case AttributeKind.GraphAttr: Console.WriteLine("Warning: Exporting non-null attribute of graph type to null"); return("null"); case AttributeKind.EnumAttr: return(type.EnumType.Name + "::" + type.EnumType[(int)value].Name); case AttributeKind.NodeAttr: case AttributeKind.EdgeAttr: return(graph.GetElementName((IGraphElement)value)); default: throw new Exception("Unsupported attribute kind in export"); } }
//////////////////////////////////////////////////////////////////////// /// <summary> /// Event handler for IGraph.OnNodeAdded. /// </summary> /// <param name="node">The added node.</param> void NodeAdded(INode node) { foreach (RecordingState recordingState in recordings.Values) { recordingState.writer.WriteLine("new :" + node.Type.Name + "($=\"" + graph.GetElementName(node) + "\")"); } }
public void AddNode(INode node) { if (dumpInfo.IsExcludedNodeType(node.Type)) { return; } String nrName = nodeRealizer ?? GetNodeRealizer(node.Type); String name = graph.GetElementName(node); ycompStream.Write("addNode \"-1\" \"n" + name + "\" \"" + nrName + "\" \"" + GetElemLabel(node) + "\"\n"); foreach (AttributeType attrType in node.Type.AttributeTypes) { if (attrType.Kind == AttributeKind.SetAttr || attrType.Kind == AttributeKind.MapAttr) { IDictionary setmap = (IDictionary)node.GetAttribute(attrType.Name); string attrTypeString; string attrValue; EmitHelper.ToString(setmap, out attrTypeString, out attrValue, attrType, graph); ycompStream.Write("changeNodeAttr \"n" + name + "\" \"" + attrType.OwnerType.Name + "::" + attrType.Name + " : " + attrTypeString + "\" \"" + Encode(attrValue) + "\"\n"); } else if (attrType.Kind == AttributeKind.ArrayAttr) { IList array = (IList)node.GetAttribute(attrType.Name); string attrTypeString; string attrValue; EmitHelper.ToString(array, out attrTypeString, out attrValue, attrType, graph); ycompStream.Write("changeNodeAttr \"n" + name + "\" \"" + attrType.OwnerType.Name + "::" + attrType.Name + " : " + attrTypeString + "\" \"" + Encode(attrValue) + "\"\n"); } else { object attr = node.GetAttribute(attrType.Name); ycompStream.Write("changeNodeAttr \"n" + name + "\" \"" + attrType.OwnerType.Name + "::" + attrType.Name + " : " + GetKindName(attrType) + "\" \"" + EncodeAttr(attr) + "\"\n"); } } isDirty = true; isLayoutDirty = true; }
/// <summary> /// Exports the given graph to the file given by the stream writer in grg format, i.e. as GrGen rule. /// Any errors will be reported by exception. /// </summary> /// <param name="graph">The graph to export. Must be a NamedGraph.</param> /// <param name="sw">The stream writer of the file to export into. The stream writer is not closed automatically.</param> public static void ExportYouMustCloseStreamWriter(INamedGraph graph, StreamWriter sw, string modelPathPrefix) { // we traverse the graph in one pass, directly writing a creating rule, // and writing a matching test to a helper stream which is appended at the end to the primary stream using (Stream stream = new MemoryStream()) { using (StreamWriter sw2 = new StreamWriter(stream)) { sw.WriteLine("// graph \"{0}\" saved by GrgExport, as creating rule and matching test", graph.Name); sw.WriteLine(); sw.WriteLine("using " + graph.Model.ModelName + ";"); sw.WriteLine(); sw.Write("rule createGraph\n"); sw.Write("{\n"); sw.Write("\treplace {\n"); sw2.Write("test matchGraph\n"); sw2.Write("{\n"); // emit nodes int numNodes = 0; foreach (INode node in graph.Nodes) { String nodeName = EscapeName(graph.GetElementName(node)); sw.Write("\t\t{0}:{1};\n", nodeName, node.Type.Name); sw2.Write("\t{0}:{1};\n", nodeName, node.Type.Name); numNodes++; } sw.WriteLine("\t\t// total number of nodes: {0}", numNodes); sw.WriteLine(); sw2.WriteLine("\t// total number of nodes: {0}", numNodes); sw2.WriteLine(); // emit node attributes sw.Write("\t\teval {\n"); sw.Write("\tif {\n"); foreach (INode node in graph.Nodes) { foreach (AttributeType attrType in node.Type.AttributeTypes) { object value = node.GetAttribute(attrType.Name); // TODO: Add support for null values, as the default initializers could assign non-null values! if (value != null) { EmitAttributeInitialization(node, attrType, value, graph, "=", sw); EmitAttributeInitialization(node, attrType, value, graph, "==", sw2); } } } sw.Write("\t\t}\n"); sw.WriteLine(); sw2.Write("\t}\n"); sw2.WriteLine(); // emit edges int numEdges = 0; foreach (INode node in graph.Nodes) { foreach (IEdge edge in node.Outgoing) { String sourceName = EscapeName(graph.GetElementName(edge.Source)); String edgeName = EscapeName(graph.GetElementName(edge)); String targetName = EscapeName(graph.GetElementName(edge.Target)); sw.Write("\t\t{0} -{1}:{2} -> {3};\n", sourceName, edgeName, edge.Type.Name, targetName); sw2.Write("\t{0} -{1}:{2} -> {3};\n", sourceName, edgeName, edge.Type.Name, targetName); numEdges++; } } sw.WriteLine("\t\t// total number of edges: {0}", numEdges); sw.WriteLine(); sw2.WriteLine("\t// total number of edges: {0}", numEdges); sw2.WriteLine(); // emit edge attributes sw.Write("\t\teval {\n"); sw2.Write("\teval {\n"); foreach (INode node in graph.Nodes) { foreach (IEdge edge in node.Outgoing) { foreach (AttributeType attrType in edge.Type.AttributeTypes) { object value = edge.GetAttribute(attrType.Name); // TODO: Add support for null values, as the default initializers could assign non-null values! if (value != null) { EmitAttributeInitialization(edge, attrType, value, graph, "=", sw); EmitAttributeInitialization(edge, attrType, value, graph, "==", sw2); } } } } sw.Write("\t\t}\n"); sw2.Write("\t}\n"); sw.Write("\t}\n"); sw.Write("}\n"); //sw2.WriteLine("\nnegative { pattern; .; -->; } // no additional node and no additional edge allowed"); sw2.Write("}\n"); sw.WriteLine(); sw2.WriteLine(); // I'm sure now that M$ gave the task of designing the .NET library // to the most incompetent of the incompetent it could find on its campus // while C# is better than Java, the class library is just annoying sw2.Flush(); stream.Seek(0, SeekOrigin.Begin); StreamReader reader = new StreamReader(stream); string str = reader.ReadToEnd(); sw.WriteLine(str); // sw already contains creating rule, now write matching test } } }
/// <summary> /// Emits the node/edge attribute initialization code in graph exporting /// for an attribute of the given type with the given value into the stream writer /// </summary> private static void EmitAttributeInitialization(IGraphElement elem, AttributeType attrType, object value, INamedGraph graph, String op, StreamWriter sw) { sw.Write("\t\t\t{0}.{1} {2} ", EscapeName(graph.GetElementName(elem)), attrType.Name, op); EmitAttribute(attrType, value, graph, sw); sw.WriteLine(";"); }
/// <summary> /// Type needed for enum, otherwise null ok. /// Graph needed for node/edge, otherwise null ok. /// Main graph context needed to get access to the graph -> env dictionary for subgraph. /// </summary> public static String ToString(MainGraphExportContext mainGraphContext, object value, AttributeType type, INamedGraph graph) { switch (type.Kind) { case AttributeKind.ByteAttr: return(((sbyte)value).ToString() + "Y"); case AttributeKind.ShortAttr: return(((short)value).ToString() + "S"); case AttributeKind.IntegerAttr: return(((int)value).ToString()); case AttributeKind.LongAttr: return(((long)value).ToString() + "L"); case AttributeKind.BooleanAttr: return(((bool)value).ToString()); case AttributeKind.StringAttr: if (value == null) { return("\"\""); } else { return("\"" + ((string)value).Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""); } case AttributeKind.FloatAttr: return(((float)value).ToString(System.Globalization.CultureInfo.InvariantCulture) + "f"); case AttributeKind.DoubleAttr: return(((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture)); case AttributeKind.ObjectAttr: return(graph.Model.Serialize(value, type, graph)); case AttributeKind.GraphAttr: if (value != null && mainGraphContext != null && mainGraphContext.graphToContext != null) { return("\"" + mainGraphContext.graphToContext[(INamedGraph)value].name + "\""); } else { return("null"); } case AttributeKind.EnumAttr: return(type.EnumType.PackagePrefixedName + "::" + type.EnumType[(int)value].Name); case AttributeKind.NodeAttr: case AttributeKind.EdgeAttr: if (value != null) { return("\"" + graph.GetElementName((IGraphElement)value) + "\""); } else { return("null"); } default: throw new Exception("Unsupported attribute kind in export"); } }
public string ToString(object data, INamedGraph graph, params object[] additionalData) { StringBuilder sb = new StringBuilder(); sb.Append(ToString(debuggingEvent)); sb.Append(" "); switch(debuggingEvent) { case SubruleDebuggingEvent.Add: case SubruleDebuggingEvent.Rem: case SubruleDebuggingEvent.Emit: case SubruleDebuggingEvent.Halt: case SubruleDebuggingEvent.Highlight: { string message = (string)data; sb.Append("\""); sb.Append(message); sb.Append("\""); for(int i = 0; i < additionalData.Length; ++i) { sb.Append(" "); sb.Append(EmitHelper.Clip(EmitHelper.ToStringAutomatic(additionalData[i], graph), 120)); } break; } case SubruleDebuggingEvent.Match: { IMatches matches = (IMatches)data; sb.Append(matches.Producer.PackagePrefixedName); break; } case SubruleDebuggingEvent.New: case SubruleDebuggingEvent.Delete: case SubruleDebuggingEvent.Retype: case SubruleDebuggingEvent.SetAttributes: { IGraphElement elem = (IGraphElement)data; sb.Append(graph.GetElementName(elem)); sb.Append(":"); sb.Append(elem.Type.Name); if(additionalData.Length > 0) { sb.Append("."); // the attribute name sb.Append((string)additionalData[0]); } break; } default: return "INTERNAL FAILURE, unknown SubruleDebuggingConfigurationRule"; } sb.Append(" triggers "); sb.Append(ToString()); return sb.ToString(); }
public void AddNode(INode node) { if (IsNodeExcluded(node)) { return; } String nrName = nodeRealizerOverride ?? realizers.GetNodeRealizer(node.Type, dumpInfo); String name = graph.GetElementName(node); if (dumpInfo.GetGroupNodeType(node.Type) != null) { ycompStream.Write("addSubgraphNode \"-1\" \"n" + name + "\" \"" + nrName + "\" \"" + GetElemLabel(node) + "\"\n"); } else { ycompStream.Write("addNode \"-1\" \"n" + name + "\" \"" + nrName + "\" \"" + GetElemLabel(node) + "\"\n"); } foreach (AttributeType attrType in node.Type.AttributeTypes) { string attrTypeString; string attrValueString; EncodeAttr(attrType, node, out attrTypeString, out attrValueString); ycompStream.Write("changeNodeAttr \"n" + name + "\" \"" + attrType.OwnerType.Name + "::" + attrType.Name + " : " + attrTypeString + "\" \"" + attrValueString + "\"\n"); } isDirty = true; isLayoutDirty = true; }
/// <summary> /// Type needed for enum, otherwise null ok. /// Graph needed for node/edge, otherwise null ok. /// Main graph context needed to get access to the graph -> env dictionary for subgraph. /// </summary> public static String ToString(MainGraphExportContext mainGraphContext, object value, AttributeType type, INamedGraph graph) { switch(type.Kind) { case AttributeKind.ByteAttr: return ((sbyte)value).ToString()+"Y"; case AttributeKind.ShortAttr: return ((short)value).ToString()+"S"; case AttributeKind.IntegerAttr: return ((int)value).ToString(); case AttributeKind.LongAttr: return ((long)value).ToString()+"L"; case AttributeKind.BooleanAttr: return ((bool)value).ToString(); case AttributeKind.StringAttr: if(value == null) return "\"\""; else return "\"" + ((string)value).Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; case AttributeKind.FloatAttr: return ((float)value).ToString(System.Globalization.CultureInfo.InvariantCulture)+"f"; case AttributeKind.DoubleAttr: return ((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture); case AttributeKind.ObjectAttr: return graph.Model.Serialize(value, type, graph); case AttributeKind.GraphAttr: if(value != null && mainGraphContext != null && mainGraphContext.graphToContext != null) return "\"" + mainGraphContext.graphToContext[(INamedGraph)value].name + "\""; else return "null"; case AttributeKind.EnumAttr: return type.EnumType.PackagePrefixedName + "::" + type.EnumType[(int)value].Name; case AttributeKind.NodeAttr: case AttributeKind.EdgeAttr: if(value != null) return "\"" + graph.GetElementName((IGraphElement)value) + "\""; else return "null"; default: throw new Exception("Unsupported attribute kind in export"); } }
/// <summary> /// Exports the given graph to the file given by the stream writer in grg format, i.e. as GrGen rule. /// Any errors will be reported by exception. /// </summary> /// <param name="graph">The graph to export. Must be a NamedGraph.</param> /// <param name="sw">The stream writer of the file to export into. The stream writer is not closed automatically.</param> public static void ExportYouMustCloseStreamWriter(INamedGraph graph, StreamWriter sw, string modelPathPrefix) { // we traverse the graph in one pass, directly writing a creating rule, // and writing a matching test to a helper stream which is appended at the end to the primary stream using(Stream stream = new MemoryStream()) { using(StreamWriter sw2 = new StreamWriter(stream)) { sw.WriteLine("// graph \"{0}\" saved by GrgExport, as creating rule and matching test", graph.Name); sw.WriteLine(); sw.WriteLine("using " + graph.Model.ModelName + ";"); sw.WriteLine(); sw.Write("rule createGraph\n"); sw.Write("{\n"); sw.Write("\treplace {\n"); sw2.Write("test matchGraph\n"); sw2.Write("{\n"); // emit nodes int numNodes = 0; foreach (INode node in graph.Nodes) { String nodeName = EscapeName(graph.GetElementName(node)); sw.Write("\t\t{0}:{1};\n", nodeName, node.Type.Name); sw2.Write("\t{0}:{1};\n", nodeName, node.Type.Name); numNodes++; } sw.WriteLine("\t\t// total number of nodes: {0}", numNodes); sw.WriteLine(); sw2.WriteLine("\t// total number of nodes: {0}", numNodes); sw2.WriteLine(); // emit node attributes sw.Write("\t\teval {\n"); sw.Write("\tif {\n"); foreach(INode node in graph.Nodes) { foreach(AttributeType attrType in node.Type.AttributeTypes) { object value = node.GetAttribute(attrType.Name); // TODO: Add support for null values, as the default initializers could assign non-null values! if(value != null) { EmitAttributeInitialization(node, attrType, value, graph, "=", sw); EmitAttributeInitialization(node, attrType, value, graph, "==", sw2); } } } sw.Write("\t\t}\n"); sw.WriteLine(); sw2.Write("\t}\n"); sw2.WriteLine(); // emit edges int numEdges = 0; foreach (INode node in graph.Nodes) { foreach (IEdge edge in node.Outgoing) { String sourceName = EscapeName(graph.GetElementName(edge.Source)); String edgeName = EscapeName(graph.GetElementName(edge)); String targetName = EscapeName(graph.GetElementName(edge.Target)); sw.Write("\t\t{0} -{1}:{2} -> {3};\n", sourceName, edgeName, edge.Type.Name, targetName); sw2.Write("\t{0} -{1}:{2} -> {3};\n", sourceName, edgeName, edge.Type.Name, targetName); numEdges++; } } sw.WriteLine("\t\t// total number of edges: {0}", numEdges); sw.WriteLine(); sw2.WriteLine("\t// total number of edges: {0}", numEdges); sw2.WriteLine(); // emit edge attributes sw.Write("\t\teval {\n"); sw2.Write("\teval {\n"); foreach(INode node in graph.Nodes) { foreach(IEdge edge in node.Outgoing) { foreach(AttributeType attrType in edge.Type.AttributeTypes) { object value = edge.GetAttribute(attrType.Name); // TODO: Add support for null values, as the default initializers could assign non-null values! if(value != null) { EmitAttributeInitialization(edge, attrType, value, graph, "=", sw); EmitAttributeInitialization(edge, attrType, value, graph, "==", sw2); } } } } sw.Write("\t\t}\n"); sw2.Write("\t}\n"); sw.Write("\t}\n"); sw.Write("}\n"); //sw2.WriteLine("\nnegative { pattern; .; -->; } // no additional node and no additional edge allowed"); sw2.Write("}\n"); sw.WriteLine(); sw2.WriteLine(); // I'm sure now that M$ gave the task of designing the .NET library // to the most incompetent of the incompetent it could find on its campus // while C# is better than Java, the class library is just annoying sw2.Flush(); stream.Seek(0, SeekOrigin.Begin); StreamReader reader = new StreamReader(stream); string str = reader.ReadToEnd(); sw.WriteLine(str); // sw already contains creating rule, now write matching test } } }
/// <summary> /// type needed for enum, otherwise null ok /// graph needed for node/edge in set/map, otherwise null ok /// </summary> public static String ToString(object value, AttributeType type, INamedGraph graph) { switch(type.Kind) { case AttributeKind.ByteAttr: return ((sbyte)value).ToString()+"Y"; case AttributeKind.ShortAttr: return ((short)value).ToString()+"S"; case AttributeKind.IntegerAttr: return ((int)value).ToString(); case AttributeKind.LongAttr: return ((long)value).ToString()+"L"; case AttributeKind.BooleanAttr: return ((bool)value).ToString(); case AttributeKind.StringAttr: if(value == null) return "\"\""; if(((string)value).IndexOf('\"') != -1) return "\'" + ((string)value) + "\'"; else return "\"" + ((string)value) + "\""; case AttributeKind.FloatAttr: return ((float)value).ToString(System.Globalization.CultureInfo.InvariantCulture)+"f"; case AttributeKind.DoubleAttr: return ((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture); case AttributeKind.ObjectAttr: Console.WriteLine("Warning: Exporting non-null attribute of object type to null"); return "null"; case AttributeKind.GraphAttr: Console.WriteLine("Warning: Exporting non-null attribute of graph type to null"); return "null"; case AttributeKind.EnumAttr: return type.EnumType.Name + "::" + type.EnumType[(int)value].Name; case AttributeKind.NodeAttr: case AttributeKind.EdgeAttr: return graph.GetElementName((IGraphElement)value); default: throw new Exception("Unsupported attribute kind in export"); } }
/// <summary> /// Type needed for enum, otherwise null ok. /// Graph needed for node/edge, otherwise null ok. /// Main graph context needed to get access to the graph -> env dictionary for subgraph. /// </summary> public static void EmitAttributeValue(MainGraphExportContext mainGraphContext, object value, AttributeType type, INamedGraph graph, StreamWriter sw, StringBuilder deferredInits) { switch (type.Kind) { case AttributeKind.ByteAttr: sw.Write(((sbyte)value).ToString() + "Y"); return; case AttributeKind.ShortAttr: sw.Write(((short)value).ToString() + "S"); return; case AttributeKind.IntegerAttr: sw.Write(((int)value).ToString()); return; case AttributeKind.LongAttr: sw.Write(((long)value).ToString() + "L"); return; case AttributeKind.BooleanAttr: sw.Write(((bool)value).ToString()); return; case AttributeKind.StringAttr: if (value == null) { sw.Write("\"\""); } else { sw.Write("\"" + ((string)value).Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""); } return; case AttributeKind.FloatAttr: sw.Write(((float)value).ToString(System.Globalization.CultureInfo.InvariantCulture) + "f"); return; case AttributeKind.DoubleAttr: sw.Write(((double)value).ToString(System.Globalization.CultureInfo.InvariantCulture)); return; case AttributeKind.ObjectAttr: sw.Write(graph.Model.Serialize(value, type, graph)); return; case AttributeKind.GraphAttr: if (value != null && mainGraphContext != null && mainGraphContext.graphToContext != null) { sw.Write("\"" + mainGraphContext.graphToContext[(INamedGraph)value].name + "\""); } else { sw.Write("null"); } return; case AttributeKind.EnumAttr: sw.Write(type.EnumType.PackagePrefixedName + "::" + type.EnumType[(int)value].Name); return; case AttributeKind.NodeAttr: case AttributeKind.EdgeAttr: if (value != null) { sw.Write("@(\"" + graph.GetElementName((IGraphElement)value) + "\")"); } else { sw.Write("null"); } return; case AttributeKind.InternalClassObjectAttr: if (value != null) { IObject obj = (IObject)value; EmitObjectFetchingOrCreation(mainGraphContext, obj.Type, obj, graph, sw, deferredInits); } else { sw.Write("null"); } return; default: throw new Exception("Unsupported attribute kind in export"); } }