diff --git a/capnpc-csharp.tests/Properties/Resources.Designer.cs b/capnpc-csharp.tests/Properties/Resources.Designer.cs
index 7c7c2e9..5148dec 100644
--- a/capnpc-csharp.tests/Properties/Resources.Designer.cs
+++ b/capnpc-csharp.tests/Properties/Resources.Designer.cs
@@ -90,6 +90,16 @@ namespace capnpc_csharp.Tests.Properties {
}
}
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] UnitTest11_capnp {
+ get {
+ object obj = ResourceManager.GetObject("UnitTest11_capnp", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Byte[].
///
@@ -119,5 +129,15 @@ namespace capnpc_csharp.Tests.Properties {
return ((byte[])(obj));
}
}
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] UnitTest4_capnp {
+ get {
+ object obj = ResourceManager.GetObject("UnitTest4_capnp", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
}
}
diff --git a/capnpc-csharp.tests/Properties/Resources.resx b/capnpc-csharp.tests/Properties/Resources.resx
index 6d2bda3..b4ecfef 100644
--- a/capnpc-csharp.tests/Properties/Resources.resx
+++ b/capnpc-csharp.tests/Properties/Resources.resx
@@ -136,4 +136,10 @@
..\Resources\schema-with-offsets.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\Resources\UnitTest11.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\Resources\UnitTest4.capnp.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
\ No newline at end of file
diff --git a/capnpc-csharp.tests/Resources/UnitTest11.capnp.bin b/capnpc-csharp.tests/Resources/UnitTest11.capnp.bin
new file mode 100644
index 0000000..5363609
Binary files /dev/null and b/capnpc-csharp.tests/Resources/UnitTest11.capnp.bin differ
diff --git a/capnpc-csharp.tests/Resources/UnitTest4.capnp.bin b/capnpc-csharp.tests/Resources/UnitTest4.capnp.bin
new file mode 100644
index 0000000..f93feb2
Binary files /dev/null and b/capnpc-csharp.tests/Resources/UnitTest4.capnp.bin differ
diff --git a/capnpc-csharp.tests/UnitTest11.capnp b/capnpc-csharp.tests/UnitTest11.capnp
new file mode 100644
index 0000000..5fda369
--- /dev/null
+++ b/capnpc-csharp.tests/UnitTest11.capnp
@@ -0,0 +1,15 @@
+@0xe4369c441ab8df19;
+
+using Imported = import "UnitTest11b.capnp";
+
+struct OuterStruct {
+ innerStruct @0: Imported.InnerStruct;
+ innerInterface @1: Imported.InnerInterface;
+}
+
+interface OuterInterface {
+ struct Wrapper {
+ innerStruct @0: Imported.InnerStruct;
+ innerInterface @1: Imported.InnerInterface;
+ }
+}
diff --git a/capnpc-csharp.tests/UnitTest11b.capnp b/capnpc-csharp.tests/UnitTest11b.capnp
new file mode 100644
index 0000000..c5b1926
--- /dev/null
+++ b/capnpc-csharp.tests/UnitTest11b.capnp
@@ -0,0 +1,9 @@
+@0xabc4e69d23fe287e;
+
+struct InnerStruct {
+ const constantS: Bool = false;
+}
+
+interface InnerInterface {
+ const constantI: Bool = false;
+}
diff --git a/capnpc-csharp.tests/UnitTest4.capnp b/capnpc-csharp.tests/UnitTest4.capnp
new file mode 100644
index 0000000..edfb8c7
--- /dev/null
+++ b/capnpc-csharp.tests/UnitTest4.capnp
@@ -0,0 +1,16 @@
+@0xf463d204f5208b43;
+$import "/capnp/c++.capnp".namespace("UnitTest4");
+
+interface Node {
+ getInfo @0 () -> Info;
+}
+
+struct Info {
+ node @0 :Node;
+ classes @1 :Classes;
+}
+
+struct Classes {
+ i1 @0 :import "UnitTest4b.capnp".I1.Classes;
+ i2 @1: Void;
+}
\ No newline at end of file
diff --git a/capnpc-csharp.tests/UnitTest4b.capnp b/capnpc-csharp.tests/UnitTest4b.capnp
new file mode 100644
index 0000000..3bfe83a
--- /dev/null
+++ b/capnpc-csharp.tests/UnitTest4b.capnp
@@ -0,0 +1,15 @@
+@0x8151238e9f9884c8;
+$import "/capnp/c++.capnp".namespace("UnitTest4");
+
+using Base = import "UnitTest4.capnp";
+
+interface I1 {
+ interface Node extends (Base.Node) {}
+ struct Classes {
+ sub @0: Sub;
+ }
+ struct Sub {
+ const prototype :Base.Classes = ( i1 = (sub = ()) );
+ data @0: Bool;
+ }
+}
diff --git a/capnpc-csharp.tests/UnitTests.cs b/capnpc-csharp.tests/UnitTests.cs
index c009ddd..f7d59fd 100644
--- a/capnpc-csharp.tests/UnitTests.cs
+++ b/capnpc-csharp.tests/UnitTests.cs
@@ -11,6 +11,7 @@ namespace CapnpC
[TestClass]
public class UnitTests
{
+ static readonly Dictionary GeneratedCode = new Dictionary();
[TestMethod]
public void Test00Enumerant()
@@ -22,11 +23,9 @@ namespace CapnpC
[TestMethod]
public void Test01NestedClash()
{
- var model = Load(Resources.UnitTest1_capnp);
- var structFoo = GetTypeDef(0x93db6ba5509bac24, model);
- var codeGen = NewGeneratorFor(model);
- codeGen.Transform(model.FilesToGenerate.First());
- var names = codeGen.GetNames();
+ var run = LoadAndGenerate(Resources.UnitTest1_capnp, 1);
+ var structFoo = GetTypeDef(0x93db6ba5509bac24, run.Model);
+ var names = run.CodeGen.GetNames();
var fieldName = names.GetCodeIdentifier(structFoo.Fields[0]).ToString();
Assert.AreEqual("Foo", structFoo.Name);
Assert.AreNotEqual(structFoo.Name, fieldName);
@@ -35,30 +34,33 @@ namespace CapnpC
[TestMethod]
public void Test02ForwardInheritance()
{
- var model = Load(Resources.UnitTest2_capnp);
- var codeGen = NewGeneratorFor(model);
- codeGen.Transform(model.FilesToGenerate.First());
+ LoadAndGenerate(Resources.UnitTest2_capnp, 2);
// Should not throw
}
[TestMethod]
public void Test03NonGeneratedNodeSkip()
{
- var model = Load(Resources.UnitTest3_capnp);
+ LoadAndGenerate(Resources.UnitTest3_capnp, 3);
+ // Should not throw
+ }
+
+ [TestMethod]
+ public void Test04MutualDependencies()
+ {
+ LoadAndGenerate(Resources.UnitTest4_capnp, 4);
// Should not throw
}
[TestMethod]
public void Test10ImportedNamespaces()
{
- var model = Load(Resources.UnitTest10_capnp);
- var codeGen = NewGeneratorFor(model);
- var genFile = model.FilesToGenerate.First();
- var outerTypeDef = genFile.NestedTypes.First();
+ var run = LoadAndGenerate(Resources.UnitTest10_capnp, 10);
+ var outerTypeDef = run.FirstFile.NestedTypes.First();
var outerType = Model.Types.FromDefinition(outerTypeDef);
var innerType = outerTypeDef.Fields[0].Type;
var innerTypeDef = innerType.Definition;
- var names = codeGen.GetNames();
+ var names = run.CodeGen.GetNames();
var outerNameSyntax = names.GetQName(outerType, outerTypeDef);
var innerNameSyntax = names.GetQName(innerType, outerTypeDef);
string[] outerNamespace = { "Foo", "Bar", "Baz" };
@@ -71,27 +73,50 @@ namespace CapnpC
Assert.AreEqual($"{innerNSStr}.Inner", innerNameSyntax.ToString());
}
+ [TestMethod]
+ public void Test11ImportedConst()
+ {
+ LoadAndGenerate(Resources.UnitTest11_capnp, 11);
+ // Should not throw
+ }
+
[TestMethod]
public void Test20AnnotationAndConst()
{
- var model = Load(Resources.UnitTest20_capnp);
- var codeGen = NewGeneratorFor(model);
- codeGen.Transform(model.FilesToGenerate.First());
+ LoadAndGenerate(Resources.UnitTest20_capnp, 20);
// Should not throw
}
[TestMethod]
public void Test30SchemaCapnp()
{
- var model = Load(Resources.schema_with_offsets_capnp);
- var codeGen = NewGeneratorFor(model);
- codeGen.Transform(model.FilesToGenerate.First());
+ LoadAndGenerate(Resources.schema_with_offsets_capnp);
// Should not throw
}
+ struct Run
+ {
+ public Model.SchemaModel Model;
+ public Generator.CodeGenerator CodeGen;
+ public Model.GenFile FirstFile;
+ public string Code;
+ }
+
static Generator.CodeGenerator NewGeneratorFor(Model.SchemaModel model)
=> new Generator.CodeGenerator(model, new Generator.GeneratorOptions());
+ Run LoadAndGenerate(byte[] input, int? testNum = null)
+ {
+ var run = new Run();
+ run.Model = Load(input);
+ run.CodeGen = NewGeneratorFor(run.Model);
+ run.FirstFile = run.Model.FilesToGenerate.First();
+ run.Code = run.CodeGen.Transform(run.FirstFile);
+ if (testNum is int num)
+ GeneratedCode[num] = run.Code;
+ return run;
+ }
+
static Model.TypeDefinition GetTypeDef(ulong id, Model.SchemaModel model)
{
foreach (var defs in model.FilesToGenerate.Select(f => f.NestedTypes))
diff --git a/capnpc-csharp/Model/Annotation.cs b/capnpc-csharp/Model/Annotation.cs
index 6dbbd9a..36191b6 100644
--- a/capnpc-csharp/Model/Annotation.cs
+++ b/capnpc-csharp/Model/Annotation.cs
@@ -1,9 +1,11 @@
-
+using System.Diagnostics;
+
namespace CapnpC.Model
{
class Annotation : IDefinition
{
public ulong Id { get; }
+ public bool IsGenerated { get; }
public TypeTag Tag { get => TypeTag.Annotation; }
public IHasNestedDefinitions DeclaringElement { get; }
@@ -11,7 +13,9 @@ namespace CapnpC.Model
public Annotation(ulong id, IHasNestedDefinitions parent)
{
+ Trace.Assert(parent != null);
Id = id;
+ IsGenerated = (parent as IDefinition).IsGenerated;
DeclaringElement = parent;
parent.NestedDefinitions.Add(this);
}
diff --git a/capnpc-csharp/Model/Constant.cs b/capnpc-csharp/Model/Constant.cs
index a992ca0..5879100 100644
--- a/capnpc-csharp/Model/Constant.cs
+++ b/capnpc-csharp/Model/Constant.cs
@@ -1,9 +1,11 @@
-
+using System.Diagnostics;
+
namespace CapnpC.Model
{
class Constant : IDefinition
{
public ulong Id { get; }
+ public bool IsGenerated { get; }
public TypeTag Tag { get => TypeTag.Const; }
public IHasNestedDefinitions DeclaringElement { get; }
@@ -11,7 +13,9 @@ namespace CapnpC.Model
public Constant(ulong id, IHasNestedDefinitions parent)
{
+ Trace.Assert(parent != null);
Id = id;
+ IsGenerated = (parent as IDefinition).IsGenerated;
DeclaringElement = parent;
parent.NestedDefinitions.Add(this);
}
diff --git a/capnpc-csharp/Model/DefinitionManager.cs b/capnpc-csharp/Model/DefinitionManager.cs
index 4a88fc6..95b9183 100644
--- a/capnpc-csharp/Model/DefinitionManager.cs
+++ b/capnpc-csharp/Model/DefinitionManager.cs
@@ -8,12 +8,12 @@ namespace CapnpC.Model
{
readonly Dictionary _id2def = new Dictionary();
- public GenFile CreateFile(ulong id)
- => CreateId(id, () => new GenFile(id));
+ public GenFile CreateFile(ulong id, bool isGenerated)
+ => CreateId(id, () => new GenFile(id, isGenerated));
public GenFile GetExistingFile(ulong id)
=> GetId(id, TypeTag.File);
- public TypeDefinition CreateTypeDef(ulong id, TypeTag tag, IHasNestedDefinitions decl)
+ public TypeDefinition CreateTypeDef(ulong id, TypeTag tag, IHasNestedDefinitions decl)
=> CreateId(id, () => new TypeDefinition(tag, id, decl));
public TypeDefinition GetExistingTypeDef(ulong id, TypeTag tag)
{
diff --git a/capnpc-csharp/Model/GenFile.cs b/capnpc-csharp/Model/GenFile.cs
index f912303..f889fce 100644
--- a/capnpc-csharp/Model/GenFile.cs
+++ b/capnpc-csharp/Model/GenFile.cs
@@ -5,8 +5,9 @@ namespace CapnpC.Model
class GenFile: IDefinition, IHasNestedDefinitions
{
public ulong Id { get; }
+ public bool IsGenerated { get; }
public TypeTag Tag { get => TypeTag.File; }
- public IHasNestedDefinitions DeclaringElement { get; }
+ public IHasNestedDefinitions DeclaringElement { get => null; }
public string Name { get; set; }
public string[] Namespace { get; set; }
@@ -15,9 +16,10 @@ namespace CapnpC.Model
public ICollection NestedDefinitions { get; } = new List();
public ICollection Constants { get; } = new List();
- public GenFile(ulong id)
+ public GenFile(ulong id, bool isGenerated)
{
Id = id;
+ IsGenerated = isGenerated;
}
}
}
diff --git a/capnpc-csharp/Model/IDefinition.cs b/capnpc-csharp/Model/IDefinition.cs
index e226d40..9bd8572 100644
--- a/capnpc-csharp/Model/IDefinition.cs
+++ b/capnpc-csharp/Model/IDefinition.cs
@@ -4,6 +4,7 @@ namespace CapnpC.Model
interface IDefinition
{
ulong Id { get; }
+ bool IsGenerated { get; }
TypeTag Tag { get; }
IHasNestedDefinitions DeclaringElement { get; }
}
diff --git a/capnpc-csharp/Model/SchemaModel.cs b/capnpc-csharp/Model/SchemaModel.cs
index 4ebafec..bd758c6 100644
--- a/capnpc-csharp/Model/SchemaModel.cs
+++ b/capnpc-csharp/Model/SchemaModel.cs
@@ -61,7 +61,6 @@ namespace CapnpC.Model
struct Pass1State
{
public HashSet unprocessedNodes;
- public bool isGenerated;
public IHasNestedDefinitions parent;
}
@@ -74,17 +73,11 @@ namespace CapnpC.Model
foreach (var node in _id2node.Values.Where(n => n.IsFile))
{
GenFile file;
- state.isGenerated = requestedFiles.TryGetValue(node.Id, out var req);
- state.parent = null;
- if (state.isGenerated)
- {
- file = (GenFile)ProcessNodePass1(node.Id, req.Filename, state);
+ bool isGenerated = requestedFiles.TryGetValue(node.Id, out var req);
+ var filename = isGenerated ? req.Filename : node.DisplayName;
+ file = ProcessFilePass1(node.Id, filename, state, isGenerated);
+ if (isGenerated)
_generatedFiles.Add(file);
- }
- else
- {
- file = (GenFile)ProcessNodePass1(node.Id, node.DisplayName, state);
- }
}
if (state.unprocessedNodes.Count != 0)
{
@@ -92,9 +85,20 @@ namespace CapnpC.Model
}
}
+ GenFile ProcessFilePass1(ulong id, string name, Pass1State state, bool isGenerated)
+ {
+ var file = _typeDefMgr.CreateFile(id, isGenerated);
+ var node = IdToNode(id);
+ state.parent = null;
+ file.Namespace = GetNamespaceAnnotation(node);
+ file.Name = name;
+ return ProcessNodePass1(id, name, state) as GenFile;
+ }
+
IDefinition ProcessNodePass1(ulong id, string name, Pass1State state)
{
- if (!(IdToNode(id, state.isGenerated) is Schema.Node.Reader node))
+ bool mustExist = state.parent == null || (state.parent as IDefinition).IsGenerated;
+ if (!(IdToNode(id, mustExist) is Schema.Node.Reader node))
return null;
if (!state.unprocessedNodes.Remove(id))
return null;
@@ -112,10 +116,11 @@ namespace CapnpC.Model
return _typeDefMgr.CreateConstant(id, state.parent);
case NodeKind.File:
if (state.parent != null)
- throw new InvalidSchemaException("Did not expect file nodes to appear as nested nodes");
- var file = _typeDefMgr.CreateFile(id);
+ throw new InvalidSchemaException($"Did not expect a file node {node.StrId()} to be a nested node.");
+ var file = _typeDefMgr.GetExistingFile(id);
file.Namespace = GetNamespaceAnnotation(node);
file.Name = name;
+ state.parent = file;
def = file;
processNestedNodes = true;
break;
@@ -137,11 +142,12 @@ namespace CapnpC.Model
if (def == null)
{
+ Trace.Assert(state.parent != null, $"The {node.GetTypeTag().ToString()} node {node.StrId()} was expected to have a parent.");
var typeDef = _typeDefMgr.CreateTypeDef(id, node.GetTypeTag(), state.parent);
typeDef.Name = name;
+ state.parent = typeDef;
def = typeDef;
}
- state.parent = def as IHasNestedDefinitions;
if (processNestedNodes && node.NestedNodes != null)
foreach (var nested in node.NestedNodes)
@@ -186,7 +192,6 @@ namespace CapnpC.Model
struct Pass2State
{
public Method currentMethod;
- public bool isGenerated;
public HashSet processedNodes;
}
@@ -196,16 +201,15 @@ namespace CapnpC.Model
foreach (var file in _typeDefMgr.Files)
{
var node = IdToNode(file.Id);
- state.isGenerated = requestedFiles.ContainsKey(file.Id);
- ProcessNestedNodes(node.NestedNodes, state);
+ ProcessNestedNodes(node.NestedNodes, state, file.IsGenerated);
}
}
- void ProcessNestedNodes(IEnumerable nestedNodes, Pass2State state)
+ void ProcessNestedNodes(IEnumerable nestedNodes, Pass2State state, bool mustExist)
{
foreach (var nestedNode in nestedNodes)
{
- ProcessNode(nestedNode.Id, state);
+ ProcessNode(nestedNode.Id, state, mustExist);
}
}
@@ -533,7 +537,7 @@ namespace CapnpC.Model
}
}
- ProcessNestedNodes(reader.NestedNodes, state);
+ ProcessNestedNodes(reader.NestedNodes, state, def.File.IsGenerated);
ProcessFields(reader, def, def.Fields, state);
@@ -682,18 +686,18 @@ namespace CapnpC.Model
TypeDefinition ProcessTypeDef(ulong id, Pass2State state, TypeTag tag = default)
{
- var def = ProcessNode(id, state, tag);
+ var def = ProcessNode(id, state, true, tag);
var typeDef = def as TypeDefinition;
- if (def == null)
+ if (typeDef == null)
throw new ArgumentException(
$"Expected node {id.StrId()} to be a TypeDefinition but got {def.GetType().Name} instead.",
nameof(id));
return typeDef;
}
- IDefinition ProcessNode(ulong id, Pass2State state, TypeTag tag = default)
+ IDefinition ProcessNode(ulong id, Pass2State state, bool mustExist, TypeTag tag = default)
{
- if (!(IdToNode(id, state.isGenerated) is Schema.Node.Reader node)) return null;
+ if (!(IdToNode(id, mustExist) is Schema.Node.Reader node)) return null;
var kind = node.GetKind();
if (tag == TypeTag.Unknown) tag = kind.GetTypeTag();
var def = _typeDefMgr.GetExistingDef(id, tag);
@@ -744,10 +748,10 @@ namespace CapnpC.Model
=> node.DisplayName.Substring((int)node.DisplayNamePrefixLength);
public static string StrId(this Schema.Node.Reader node)
- => $"0x{node.Id.ToString("X")}";
+ => $"0x{node.Id:X}";
public static string StrId(this ulong nodeId)
- => $"0x{nodeId.ToString("X")}";
+ => $"0x{nodeId:X}";
public static NodeKind GetKind(this Schema.Node.Reader node)
{
diff --git a/capnpc-csharp/Model/Type.cs b/capnpc-csharp/Model/Type.cs
index c1017df..e6e4fc3 100644
--- a/capnpc-csharp/Model/Type.cs
+++ b/capnpc-csharp/Model/Type.cs
@@ -67,7 +67,7 @@ namespace CapnpC.Model
declaringType = (declaringType as TypeDefinition)?.DeclaringElement as IHasGenericParameters;
}
- ElementType?.InheritFreeParameters(declaringType);
+ ElementType?.InheritFreeParameters(declaringType); // BUG: this is always null
}
Type SubstituteGenerics(Type type)
diff --git a/capnpc-csharp/Model/TypeDefinition.cs b/capnpc-csharp/Model/TypeDefinition.cs
index 910d4bd..dcbe512 100644
--- a/capnpc-csharp/Model/TypeDefinition.cs
+++ b/capnpc-csharp/Model/TypeDefinition.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
namespace CapnpC.Model
{
@@ -18,8 +19,10 @@ namespace CapnpC.Model
public TypeDefinition(TypeTag tag, ulong id, IHasNestedDefinitions parent)
{
+ Trace.Assert(parent != null);
Tag = tag;
Id = id;
+ IsGenerated = (parent as IDefinition).IsGenerated;
DeclaringElement = parent;
if (tag == TypeTag.Group)
((TypeDefinition)parent).NestedGroups.Add(this);
@@ -28,6 +31,7 @@ namespace CapnpC.Model
}
public ulong Id { get; }
+ public bool IsGenerated { get; }
public IHasNestedDefinitions DeclaringElement { get; }
public Method UsingMethod { get; set; }