diff --git a/src/generator/Class.cs b/src/generator/Class.cs index 1c8dc358..fa455cd8 100644 --- a/src/generator/Class.cs +++ b/src/generator/Class.cs @@ -12,6 +12,7 @@ class Class { public Class (Node n) { Node = n; + BaseClasses = new List (); Methods = new List (); Fields = new List (); } @@ -26,6 +27,10 @@ class Class } } + public List BaseClasses { + get; set; + } + public List Methods { get; set; } @@ -34,11 +39,19 @@ class Class get; set; } - public CodeTypeDeclaration GenerateClass (Generator g, CodeTypeDeclaration libDecl) { + public bool Disable { + get; set; + } + + public CodeTypeDeclaration GenerateClass (Generator g, CodeTypeDeclaration libDecl, string libFieldName) { var decl = new CodeTypeDeclaration (Name); decl.IsPartial = true; - // FIXME: Inheritance - decl.BaseTypes.Add (new CodeTypeReference ("ICppObject")); + if (BaseClasses.Count > 0) + decl.BaseTypes.Add (new CodeTypeReference (BaseClasses [0].Name)); + else + decl.BaseTypes.Add (new CodeTypeReference ("ICppObject")); + + bool hasBase = BaseClasses.Count > 0; var layout = new CodeTypeDeclaration ("_" + Name); layout.IsStruct = true; @@ -63,34 +76,47 @@ class Class var implField = new CodeMemberField (new CodeTypeReference (iface.Name), "impl"); implField.Attributes = MemberAttributes.Private|MemberAttributes.Static; - var getclass = new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (libDecl.Name), "Test"), "GetClass", new CodeTypeReference [] { new CodeTypeReference (iface.Name), new CodeTypeReference (layout.Name), new CodeTypeReference (decl.Name) }); + var getclass = new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (libDecl.Name), libFieldName), "GetClass", new CodeTypeReference [] { new CodeTypeReference (iface.Name), new CodeTypeReference (layout.Name), new CodeTypeReference (decl.Name) }); implField.InitExpression = new CodeMethodInvokeExpression (getclass, new CodeExpression [] { new CodePrimitiveExpression (Name) }); decl.Members.Add (implField); //private static IClass impl = global::CppTests.Libs.Test.GetClass ("Class"); - var ptrField = new CodeMemberField (new CodeTypeReference ("CppInstancePtr"), "native_ptr"); - ptrField.Attributes = MemberAttributes.Family; - decl.Members.Add (ptrField); + if (!hasBase) { + var ptrField = new CodeMemberField (new CodeTypeReference ("CppInstancePtr"), "native_ptr"); + ptrField.Attributes = MemberAttributes.Family; + decl.Members.Add (ptrField); + } var allocCtor = new CodeConstructor () { }; allocCtor.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppLibrary"), "dummy")); allocCtor.Statements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (null, "native_ptr"), new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), "Alloc"), new CodeExpression [] { new CodeThisReferenceExpression () }))); + if (hasBase) { + var implTypeInfo = new CodeFieldReferenceExpression (new CodeFieldReferenceExpression { FieldName = "impl" }, "TypeInfo"); + allocCtor.BaseConstructorArgs.Add (implTypeInfo); + } decl.Members.Add (allocCtor); var subclassCtor = new CodeConstructor () { + Attributes = MemberAttributes.Family }; subclassCtor.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppTypeInfo"), "subClass")); subclassCtor.Statements.Add (new CodeExpressionStatement (new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeArgumentReferenceExpression ("subClass"), "AddBase"), new CodeExpression [] { new CodeFieldReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), "TypeInfo") }))); + if (hasBase) { + var implTypeInfo = new CodeFieldReferenceExpression (new CodeFieldReferenceExpression { FieldName = "impl" }, "TypeInfo"); + subclassCtor.BaseConstructorArgs.Add (implTypeInfo); + } decl.Members.Add (subclassCtor); - var nativeProperty = new CodeMemberProperty () { - Name = "Native", - Type = new CodeTypeReference ("CppInstancePtr"), - Attributes = MemberAttributes.Public|MemberAttributes.Final - }; - nativeProperty.GetStatements.Add (new CodeMethodReturnStatement (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "native_ptr"))); - decl.Members.Add (nativeProperty); + if (!hasBase) { + var nativeProperty = new CodeMemberProperty () { + Name = "Native", + Type = new CodeTypeReference ("CppInstancePtr"), + Attributes = MemberAttributes.Public|MemberAttributes.Final + }; + nativeProperty.GetStatements.Add (new CodeMethodReturnStatement (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "native_ptr"))); + decl.Members.Add (nativeProperty); + } var disposeMethod = new CodeMemberMethod () { Name = "Dispose", @@ -103,7 +129,13 @@ class Class foreach (Method m in Methods) { iface.Members.Add (m.GenerateIFaceMethod (g)); - decl.Members.Add (m.GenerateWrapperMethod (g)); + + var cm = m.GenerateWrapperMethod (g); + if (m.IsConstructor && hasBase) { + var implTypeInfo = new CodeFieldReferenceExpression (new CodeFieldReferenceExpression { FieldName = "impl" }, "TypeInfo"); + (cm as CodeConstructor).BaseConstructorArgs.Add (implTypeInfo); + } + decl.Members.Add (cm); } return decl; diff --git a/src/generator/Generator.cs b/src/generator/Generator.cs index 55a13eed..1ce75ab0 100644 --- a/src/generator/Generator.cs +++ b/src/generator/Generator.cs @@ -171,9 +171,9 @@ public class Generator // Compute bases foreach (Class klass in classes) { - foreach (Node bn in klass.Node.Children.Where (o => o.Type == "Base")) { - //Class baseClass = nodeToClass [bn.NodeForAttr ("type")]; - throw new NotImplementedException (); + foreach (Node bn in klass.Node.Children.Where (o => o.Type == "Base")) { + Class baseClass = NodeToClass [bn.NodeForAttr ("type")]; + klass.BaseClasses.Add (baseClass); } } @@ -202,6 +202,9 @@ public class Generator fieldName = n.Name; else fieldName = "field" + fieldCount++; + if (CppTypeToCodeDomType (fieldType) == null) + // FIXME: Assume IntPtr + fieldType = ((CppType)CppTypes.Void).Modify (CppModifiers.Pointer); klass.Fields.Add (new Field (fieldName, fieldType)); break; case "Constructor": @@ -222,7 +225,6 @@ public class Generator if (!n.IsTrue ("extern") && !n.IsTrue ("inline")) continue; - // FIXME: Casing string name = dtor ? "Destruct" : n.Name; var method = new Method (n) { @@ -236,17 +238,22 @@ public class Generator IsDestructor = dtor }; + bool skip = false; + CppType retType; if (n.HasValue ("returns")) retType = GetType (n.NodeForAttr ("returns")); else retType = CppTypes.Void; if (retType.ElementType == CppTypes.Unknown) - throw new NotImplementedException (); + skip = true; + if (CppTypeToCodeDomType (retType) == null) { + Console.WriteLine ("\t\tS: " + retType); + skip = true; + } method.ReturnType = retType; - bool skip = false; int c = 0; List argTypes = new List (); foreach (Node arg in n.Children.Where (o => o.Type == "Argument")) { @@ -262,6 +269,11 @@ public class Generator skip = true; } + if (CppTypeToCodeDomType (argtype) == null) { + Console.WriteLine ("\t\tS: " + argtype); + skip = true; + } + method.Parameters.Add (new Tuple (argname, argtype)); argTypes.Add (argtype); @@ -278,6 +290,12 @@ public class Generator klass.Methods.Add (method); } + + Field f2 = klass.Fields.FirstOrDefault (f => f.Type.ElementType == CppTypes.Unknown); + if (f2 != null) { + Console.WriteLine ("Skipping " + klass.Name + " because field " + f2.Name + " has unknown type."); + klass.Disable = true; + } } } @@ -302,10 +320,17 @@ public class Generator else throw new NotImplementedException (); case "Class": - // FIXME: Missing classes + case "Struct": + if (!NodeToClass.ContainsKey (n)) { + if (modifiers.Modifiers.Count () == 1 && modifiers.Modifiers [0] == CppModifiers.Pointer) + // Map these to void* + return modifiers.CopyTypeFrom (CppTypes.Void); + else + return CppTypes.Unknown; + } return modifiers.CopyTypeFrom (new CppType (CppTypes.Class, NodeToClass [n].Name)); default: - throw new NotImplementedException (n.Type); + return CppTypes.Unknown; } } @@ -313,11 +338,32 @@ public class Generator return Node.IdToNode [n.Attributes ["type"]]; } - public CodeTypeReference CppTypeToCodeDomType (CppType t) { + // Return the CodeDom type reference corresponding to T, or null + public CodeTypeReference CppTypeToCodeDomType (CppType t, out bool byref) { CodeTypeReference rtype = null; - // FIXME: Modifiers + + byref = false; + Type mtype = t.ToManagedType (); + if (mtype != null) { + if (mtype.IsByRef) { + byref = true; + mtype = mtype.GetElementType (); + } + return new CodeTypeReference (mtype); + } + + if (t.Modifiers.Count > 0 && t.ElementType != CppTypes.Void && t.ElementType != CppTypes.Class) + return null; switch (t.ElementType) { case CppTypes.Void: + if (t.Modifiers.Count > 0) { + if (t.Modifiers.Count == 1 && t.Modifiers [0] == CppModifiers.Pointer) + rtype = new CodeTypeReference (typeof (IntPtr)); + else + return null; + } else { + rtype = new CodeTypeReference (typeof (void)); + } break; case CppTypes.Bool: rtype = new CodeTypeReference (typeof (bool)); @@ -325,16 +371,31 @@ public class Generator case CppTypes.Int: rtype = new CodeTypeReference (typeof (int)); break; + case CppTypes.Float: + rtype = new CodeTypeReference (typeof (float)); + break; + case CppTypes.Double: + rtype = new CodeTypeReference (typeof (double)); + break; + case CppTypes.Char: + rtype = new CodeTypeReference (typeof (char)); + break; case CppTypes.Class: // FIXME: Full name rtype = new CodeTypeReference (t.ElementTypeName); break; default: - throw new NotImplementedException (t.ToString ()); + return null; } return rtype; } + public CodeTypeReference CppTypeToCodeDomType (CppType t) { + bool byref; + + return CppTypeToCodeDomType (t, out byref); + } + void GenerateCode () { Directory.CreateDirectory (OutputDir); @@ -353,9 +414,9 @@ public class Generator var decl = new CodeTypeDeclaration ("Libs"); - var field = new CodeMemberField (new CodeTypeReference ("CppLibrary"), "Test"); + var field = new CodeMemberField (new CodeTypeReference ("CppLibrary"), LibBaseName); field.Attributes = MemberAttributes.Public|MemberAttributes.Static; - field.InitExpression = new CodeObjectCreateExpression (new CodeTypeReference ("CppLibrary"), new CodeExpression [] { new CodePrimitiveExpression ("Test") }); + field.InitExpression = new CodeObjectCreateExpression (new CodeTypeReference ("CppLibrary"), new CodeExpression [] { new CodePrimitiveExpression (LibBaseName) }); decl.Members.Add (field); ns.Types.Add (decl); @@ -370,13 +431,16 @@ public class Generator // Generate user classes foreach (Class klass in Classes) { + if (klass.Disable) + continue; + var cu = new CodeCompileUnit (); var ns = new CodeNamespace (Namespace); ns.Imports.Add(new CodeNamespaceImport("System")); ns.Imports.Add(new CodeNamespaceImport("Mono.VisualC.Interop")); cu.Namespaces.Add (ns); - ns.Types.Add (klass.GenerateClass (this, libDecl)); + ns.Types.Add (klass.GenerateClass (this, libDecl, LibBaseName)); //Provider.GenerateCodeFromCompileUnit(cu, Console.Out, CodeGenOptions); using (TextWriter w = File.CreateText (Path.Combine (OutputDir, klass.Name + ".cs"))) { diff --git a/src/generator/Method.cs b/src/generator/Method.cs index eb00c597..ed0fc542 100644 --- a/src/generator/Method.cs +++ b/src/generator/Method.cs @@ -64,6 +64,10 @@ class Method get; set; } + string GetCSharpMethodName (string name) { + return "" + Char.ToUpper (name [0]) + name.Substring (1); + } + public CodeMemberMethod GenerateIFaceMethod (Generator g) { var method = new CodeMemberMethod () { Name = Name @@ -73,12 +77,15 @@ class Method method.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference ("CppInstancePtr"), "this")); CodeTypeReference rtype = g.CppTypeToCodeDomType (ReturnType); - if (rtype != null) - method.ReturnType = rtype; + method.ReturnType = rtype; foreach (var p in Parameters) { CppType ptype = p.Item2; - var param = new CodeParameterDeclarationExpression (g.CppTypeToCodeDomType (ptype), p.Item1); + bool byref; + var ctype = g.CppTypeToCodeDomType (ptype, out byref); + var param = new CodeParameterDeclarationExpression (ctype, p.Item1); + if (byref) + param.Direction = FieldDirection.Ref; if (!IsVirtual && !ptype.ToString ().Equals (string.Empty)) param.CustomAttributes.Add (new CodeAttributeDeclaration ("MangleAsAttribute", new CodeAttributeArgument (new CodePrimitiveExpression (ptype.ToString ())))); // FIXME: Structs too @@ -114,22 +121,25 @@ class Method if (IsConstructor) method = new CodeConstructor () { - Name = Name + Name = GetCSharpMethodName (Name) }; else method = new CodeMemberMethod () { - Name = Name + Name = GetCSharpMethodName (Name) }; method.Attributes = MemberAttributes.Public; if (IsStatic) method.Attributes |= MemberAttributes.Static; CodeTypeReference rtype = g.CppTypeToCodeDomType (ReturnType); - if (rtype != null) - method.ReturnType = rtype; + method.ReturnType = rtype; foreach (var p in Parameters) { - var param = new CodeParameterDeclarationExpression (g.CppTypeToCodeDomType (p.Item2), p.Item1); + bool byref; + var ptype = g.CppTypeToCodeDomType (p.Item2, out byref); + var param = new CodeParameterDeclarationExpression (ptype, p.Item1); + if (byref) + param.Direction = FieldDirection.Ref; method.Parameters.Add (param); } @@ -142,11 +152,18 @@ class Method CodeExpression[] args = new CodeExpression [Parameters.Count + (IsStatic ? 0 : 1)]; if (!IsStatic) args [0] = new CodeFieldReferenceExpression (null, "Native"); - for (int i = 0; i < Parameters.Count; ++i) - args [i + (IsStatic ? 0 : 1)] = new CodeArgumentReferenceExpression (Parameters [i].Item1); + for (int i = 0; i < Parameters.Count; ++i) { + bool byref; + g.CppTypeToCodeDomType (Parameters [i].Item2, out byref); + CodeExpression arg = new CodeArgumentReferenceExpression (Parameters [i].Item1); + if (byref) + arg = new CodeDirectionExpression (FieldDirection.Ref, arg); + args [i + (IsStatic ? 0 : 1)] = arg; + } + var call = new CodeMethodInvokeExpression (new CodeMethodReferenceExpression (new CodeFieldReferenceExpression (null, "impl"), Name), args); - if (rtype == null || IsConstructor) + if (rtype.BaseType == "System.Void" || IsConstructor) method.Statements.Add (call); else method.Statements.Add (new CodeMethodReturnStatement (call));