public void CreateDatabaseFromDirectory() { // cannot really create a database from nothing. var dir = Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath); ClangService.CreateDatabaseFromDirectory(dir); }
public void OptionFlags() { using (var idx = ClangService.CreateIndex()) { Assert.AreEqual(GlobalOptionFlags.None, idx.GlobalOptions, "default flags"); idx.GlobalOptions = GlobalOptionFlags.ThreadBackgroundPriorityForAll; Assert.AreEqual(GlobalOptionFlags.ThreadBackgroundPriorityForAll, idx.GlobalOptions, "setter results"); } }
Tuple <ClangIndex, ClangTranslationUnit> CreateTranslationUnit(string filename, string content = null) { content = content ?? @"#include <stdio.h> void main () { printf (""hello world""); }"; File.WriteAllText(filename, content); var idx = ClangService.CreateIndex(); return(new Tuple <ClangIndex, ClangTranslationUnit> (idx, idx.CreateTranslationUnitFromSourceFile(filename, new string [0], new ClangUnsavedFile [0]))); }
public void ParseTranslationUnitFromSourceFile() { string file = "ClangIndexTest.CreateTranslationUnit.c"; File.WriteAllText(file, @"#include <stdio.h> void main () { printf (""hello world""); }"); try { using (var idx = ClangService.CreateIndex()) { var tu = idx.ParseTranslationUnit(file, new string [0], new ClangUnsavedFile [0], TranslationUnitFlags.None); tu.Dispose(); } } finally { File.Delete(file); } }
public void NullCursorType() { var c = ClangService.GetNullCursor(); Assert.AreEqual(-1, c.ArgumentCount, "ArgumentCount"); Assert.AreEqual(AvailabilityKind.Available, c.AvailabilityKind, "AvailabilityKind"); var t = c.CursorType; Assert.IsNull(t, "IsNull"); /* * Assert.AreEqual (-1, t.AlignOf, "AlignOf"); * Assert.AreEqual (-1, t.ArgumentTypeCount, "ArgumentTypeCount"); * var tt = t.ArrayElementType; * Assert.IsNotNull (tt, "ArrayElementType"); * Assert.AreEqual (-1, t.ArraySize, "ArraySize"); * tt = t.CanonicalType; * Assert.IsNotNull (tt, "CanonicalType"); * tt = t.ClassType; * Assert.IsNotNull (tt, "ClassType"); * Assert.AreEqual (-1, t.ElementCount, "ElementCount"); * tt = t.ElementType; * Assert.IsNotNull (tt, "ElementType"); * Assert.AreEqual (CallingConvention.Invalid, t.FunctionTypeCallingConvention, "FunctionTypeCallingConvention"); * Assert.AreEqual (false, t.IsConstQualifiedType, "IsConstQualifiedType"); * Assert.AreEqual (false, t.IsFunctionTypeVariadic, "IsFunctionTypeVariadic"); * Assert.AreEqual (false, t.IsPODType, "IsPODType"); * Assert.AreEqual (false, t.IsRestrictQualifiedType, "IsRestrictQualifiedType"); * Assert.AreEqual (false, t.IsVolatileQualifiedType, "IsVolatileQualifiedType"); * Assert.AreEqual (TypeKind.Invalid, t.Kind, "Kind"); * tt = t.PointeeType; * Assert.IsNotNull (tt, "PointeeType"); * Assert.AreEqual (RefQualifierKind.None, t.RefQualifier, "RefQualifier"); * tt = t.ResultType; * Assert.IsNotNull (tt, "ResultType"); * Assert.AreEqual (-1, t.SizeOf, "SizeOf"); * Assert.AreEqual (string.Empty, t.Spelling, "Spelling"); * // not in libclang 3.5 * // Assert.AreEqual (-1, t.TemplateArgumentCount, "TemplateArgumentCount"); * var cc = t.TypeDeclaration; * Assert.IsNotNull (cc, "TypeDeclaration"); */ }
public void NullCursor() { var c = ClangService.GetNullCursor(); Assert.AreEqual(-1, c.ArgumentCount, "ArgumentCount"); Assert.AreEqual(AvailabilityKind.Available, c.AvailabilityKind, "AvailabilityKind"); var t = c.CursorType; Assert.IsNull(t, "CursorType"); Assert.AreEqual(CXXAccessSpecifier.Invalid, c.CxxAccessSpecifier, "CxxAccessSpecifier"); Assert.AreEqual(string.Empty, c.DeclObjCTypeEncoding, "DeclObjCTypeEncoding"); Assert.AreEqual(18446744073709551615m, c.EnumConstantDeclUnsignedValue, "EnumConstantDeclUnsignedValue"); Assert.AreEqual(-9223372036854775808m, c.EnumConstantDeclValue, "EnumConstantDeclValue"); t = c.EnumDeclIntegerType; Assert.IsNull(t, "EnumDeclIntegerType"); Assert.AreEqual(-1, c.FieldDeclBitWidth, "FieldDeclBitWidth"); Assert.AreEqual(null, c.IncludedFile, "IncludedFile"); Assert.AreEqual(false, c.IsBitField, "IsBitField"); Assert.AreEqual(false, c.IsVirtualBase, "IsVirtualBase"); Assert.AreEqual(CursorKind.FirstInvalid, c.Kind, "Kind"); Assert.AreEqual(LanguageKind.Invalid, c.Language, "Language"); var cc = c.LexicalParent; Assert.IsNotNull(cc, "LexicalParent"); Assert.AreEqual(LinkageKind.Invalid, c.Linkage, "Linkage"); Assert.AreEqual(0, c.OverloadedDeclarationCount, "OverloadedDeclarationCount"); t = c.ResultType; Assert.IsNull(t, "ResultType"); cc = c.SemanticParent; Assert.IsNotNull(cc, "SemanticParent"); Assert.IsNull(c.TranslationUnit, "TranslationUnit"); t = c.TypeDefDeclUnderlyingType; Assert.IsNull(t, "TypeDefDeclUnderlyingType"); }
public void NodeTraversalWithVisitor() { string source = @" bool foo() { return true; } void bar() { foo(); for (int i = 0; i < 10; ++i) foo(); } int main() { bar(); if (foo()) bar(); }"; string filename = "ClangCursorTest.NodeTraversalWithVisitor.c"; var file = new ClangUnsavedFile(filename, source); using (var idx = ClangService.CreateIndex()) { using (var tu = idx.ParseTranslationUnit(filename, new string [0], new ClangUnsavedFile [] { file }, TranslationUnitFlags.None)) { Func <ClangCursor, ClangCursor, IntPtr, ChildVisitResult> func = (cursor, parent, clientData) => { if (cursor.Kind == CursorKind.CallExpression) { Console.Error.WriteLine("Found {0} [line:{1}, column:{2}]", cursor.DisplayName, cursor.Location.FileLocation.Line, cursor.Location.FileLocation.Column); } else { Console.Error.WriteLine("different kind {0} ({1}, {2})", cursor.Kind, cursor.Location.FileLocation.Line, cursor.Location.FileLocation.Column); } return(ChildVisitResult.Recurse); }; tu.GetCursor().VisitChildren(func, IntPtr.Zero); } } }
public static void WithTranslationUnit(Action <ClangIndex, ClangTranslationUnit> test, string testFullName, string content = null) { string filename = testFullName; content = content ?? @" #include <stdio.h> void main () { printf (""hello world""); } "; File.WriteAllText(filename, content); var idx = ClangService.CreateIndex(); var tu = idx.CreateTranslationUnitFromSourceFile(filename, new string [0], new ClangUnsavedFile [0]); try { test(idx, tu); } finally { File.Delete(filename); tu.Dispose(); idx.Dispose(); } }
public void NewIndex() { ClangService.CreateIndex().Dispose(); }
void Run(string [] args) { var idx = ClangService.CreateIndex(); var tus = new List <ClangTranslationUnit> (); TextWriter output = Console.Out; var opts = new CApiGeneratorOptions(); // We are going to parse C++ sources. opts.ClangArgs.Add("-x"); opts.ClangArgs.Add("c++"); opts.ClangArgs.Add("-std=c++1y"); foreach (var arg in args) { if (arg == "--help" || arg == "-?") { Console.Error.WriteLine($"[USAGE] {GetType ().Assembly.GetName ().CodeBase} [options] [inputs]"); Console.Error.WriteLine(@"options: --out:[filename] output source file name. --lib:[library] library name specified on [DllImport]. --match:[regex] process only matching files to [regex]. --arg:[namespace] compiler arguments to parse the sources." ); return; } else if (arg.StartsWith("--out:", StringComparison.Ordinal)) { output = File.CreateText(arg.Substring(6)); } else if (arg.StartsWith("--lib:", StringComparison.Ordinal)) { opts.LibraryName = arg.Substring(6); } else if (arg.StartsWith("--arg:", StringComparison.Ordinal)) { opts.ClangArgs.Add(arg.Substring(6)); } else if (arg == "--only-explicit") { opts.OnlyExplicit = true; } else if (arg.StartsWith("--match:", StringComparison.Ordinal)) { opts.FileMatches.Add(arg.Substring(8)); } else if (arg.Contains(Path.DirectorySeparatorChar) || arg.Contains(Path.AltDirectorySeparatorChar)) { foreach (var file in Directory.GetFiles(Path.GetDirectoryName(arg), Path.GetFileName(arg))) { opts.Sources.Add(file); } } else { opts.Sources.Add(arg); } } foreach (var source in opts.Sources) { if (!File.Exists(source)) { throw new ArgumentException("File not found: " + source); } tus.Add(idx.ParseTranslationUnit(source, opts.ClangArgs.ToArray(), null, TranslationUnitFlags.None)); } var members = new HeaderParser().Run(opts, tus); new CCodeWriter().Write(output, members, opts); output.Close(); }
void Run(string [] args) { var idx = ClangService.CreateIndex(); var tus = new List <ClangTranslationUnit> (); TextWriter output = Console.Out; List <Regex> fileMatches = new List <Regex> (); bool onlyExplicit = false; bool skipStandardCTypes = false; string type_scope = "internal"; Args.Add("-x"); Args.Add("c++"); Args.Add("--std=c++1y"); foreach (var arg in args) { if (arg == "--help" || arg == "-?") { Console.Error.WriteLine($"[USAGE] {GetType ().Assembly.GetName ().CodeBase} [options] [inputs]"); Console.Error.WriteLine(@"options: --out:[filename] output source file name. --lib:[library] library name specified on [DllImport]. --ns:[namespace] namespace name that wraps the entire code. --match:[regex] when specified, process only matching files. --arg:[namespace] compiler arguments to parse the sources." ); return; } else if (arg.StartsWith("--out:", StringComparison.Ordinal)) { output = File.CreateText(arg.Substring(6)); } else if (arg.StartsWith("--lib:", StringComparison.Ordinal)) { LibraryName = arg.Substring(6); } else if (arg.StartsWith("--ns:", StringComparison.Ordinal)) { Namespace = arg.Substring(5); } else if (arg.StartsWith("--arg:", StringComparison.Ordinal)) { Args.Add(arg.Substring(6)); } else if (arg.StartsWith("--match:", StringComparison.Ordinal)) { fileMatches.Add(new Regex(arg.Substring(8))); } else if (arg == "--only-explicit") { onlyExplicit = true; } else if (arg == "--skip-standard-c-types") { skipStandardCTypes = true; } else if (arg == "--expose-types") { type_scope = "public"; } else if (arg == "--prefer-string-over-byte-array") { PreferStringOverByteArray = true; } else { sources.Add(arg); } } foreach (var source in sources) { ClangTranslationUnit tu; var err = idx.ParseTranslationUnit(source, Args.ToArray(), null, TranslationUnitFlags.SkipFunctionBodies, out tu); if (err == ErrorCode.Success) { tus.Add(tu); } } var members = new List <Named> (); Struct current = null; string current_typedef_name = null; int anonymous_type_count = 0; Action <ClangCursor> removeDuplicates = c => { var dups = members.Where(m => m.Name == c.Spelling || m.Line == c.Location.FileLocation.Line && m.Column == c.Location.FileLocation.Column && m.SourceFile == c.Location.FileLocation.File.FileName).ToArray(); foreach (var d in dups) { members.Remove(d); } }; foreach (var tu in tus) { for (int i = 0; i < tu.DiagnosticCount; i++) { Console.Error.WriteLine($"[diag] {tu.GetDiagnostic (i).Location}: {tu.GetDiagnostic (i).Spelling}"); } Func <ClangCursor, ClangCursor, IntPtr, ChildVisitResult> func = null; func = (cursor, parent, clientData) => { // skip ignored file. if (onlyExplicit && !sources.Contains(cursor.Location.FileLocation.File.FileName)) { return(ChildVisitResult.Continue); } if (fileMatches.Any() && !fileMatches.Any(fm => fm.IsMatch(cursor.Location.FileLocation.File.FileName))) { return(ChildVisitResult.Continue); } // FIXME: this doesn't work. if (cursor.Kind == CursorKind.InclusionDirective) { Console.Error.WriteLine("[diag] Include File " + cursor.IncludedFile); idx.ParseTranslationUnit(cursor.IncludedFile.FileName, null, null, TranslationUnitFlags.None).GetCursor().VisitChildren(func, IntPtr.Zero); } else if (cursor.Kind == CursorKind.TypedefDeclaration) { if (cursor.Location.FileLocation.File != null) { var alias = ToTypeName(cursor.CursorType); InsideUsingDeclaration = true; if (usings.All(u => u.Alias != alias)) { var actual = ToTypeName(cursor.TypeDefDeclUnderlyingType); var td = new TypeDef { Alias = alias, ActualInC = cursor.TypeDefDeclUnderlyingType.Spelling, Managed = cursor.TypeDefDeclUnderlyingType.ArraySize < 0 ? actual : $"System.IntPtr/*{actual}[]*/", Location = cursor.Location, }; usings.Add(td); } InsideUsingDeclaration = false; current_typedef_name = alias; foreach (var child in cursor.GetChildren()) { func(child, cursor, clientData); } current_typedef_name = null; return(ChildVisitResult.Continue); } } else if (cursor.Kind == CursorKind.EnumConstantDeclaration) { removeDuplicates(cursor); current.Fields.Add(new Variable() { Type = ToTypeName(cursor.CursorType), Name = cursor.Spelling, // FIXME: this is HACK. Value = (cursor.EnumConstantDeclValue != 0 ? (decimal)cursor.EnumConstantDeclValue : (decimal)cursor.EnumConstantDeclUnsignedValue).ToString(), }); return(ChildVisitResult.Continue); } else if (cursor.Kind == CursorKind.FieldDeclaration) { removeDuplicates(cursor); var typeCursor = cursor.CursorType.TypeDeclaration; var type = !string.IsNullOrEmpty(typeCursor.DisplayName) ? ToTypeName(cursor.CursorType) : members.FirstOrDefault(m => m.Line == typeCursor.Location.FileLocation.Line && m.Column == typeCursor.Location.FileLocation.Column && m.SourceFile == typeCursor.Location.FileLocation.File.FileName)?.Name ?? ToTypeName(cursor.CursorType); var variable = new Variable() { Type = type, TypeDetails = GetTypeDetails(cursor.CursorType), ArraySize = cursor.CursorType.ArraySize, SizeOf = cursor.CursorType.SizeOf, Name = cursor.Spelling }; if (current == null) { Console.Error.WriteLine($"[warn] {cursor.Spelling}: globally declared fields are ignored"); } else { current.Fields.Add(variable); } return(ChildVisitResult.Continue); } else if (cursor.Kind == CursorKind.StructDeclaration || cursor.Kind == CursorKind.UnionDeclaration || cursor.Kind == CursorKind.EnumDeclaration) { removeDuplicates(cursor); var parentType = current; current = new Struct() { Name = current_typedef_name != null && parentType == null ? current_typedef_name : string.IsNullOrEmpty(cursor.DisplayName) ? "anonymous_type_" + (anonymous_type_count++) : cursor.DisplayName, Location = cursor.Location, IsUnion = cursor.Kind == CursorKind.UnionDeclaration, IsEnum = cursor.Kind == CursorKind.EnumDeclaration, }; members.Add(current); foreach (var child in cursor.GetChildren()) { func(child, cursor, clientData); } current = parentType; return(ChildVisitResult.Continue); } else if (cursor.Kind == CursorKind.FunctionDeclaration) { removeDuplicates(cursor); var fargs = Enumerable.Range(0, cursor.ArgumentCount) .Select(i => cursor.GetArgument(i)); // function with va_list isn't supported in P/Invoke. if (fargs.Any(a => a.CursorType.Spelling == "va_list")) { Console.Error.WriteLine($"Cannot bind {cursor.DisplayName} because it contains va_list."); return(ChildVisitResult.Continue); } members.Add(new Function() { Name = cursor.Spelling, Return = ToTypeName(cursor.ResultType), Location = cursor.Location, Args = fargs.Select(a => new Variable() { Name = a.Spelling, Type = ToTypeName(a.CursorType), TypeDetails = GetTypeDetails(a.CursorType) }) .ToArray() }); return(ChildVisitResult.Continue); } return(ChildVisitResult.Recurse); }; tu.GetCursor().VisitChildren(func, IntPtr.Zero); } output.WriteLine("// This source file is generated by nclang PInvokeGenerator."); output.WriteLine("using System;"); output.WriteLine("using System.Runtime.InteropServices;"); if (!skipStandardCTypes) { output.WriteLine("using time_t = System.IntPtr;"); output.WriteLine("using size_t = System.IntPtr;"); } foreach (var u in usings.Distinct(new KeyComparer())) { if (u.Managed == "System.IntPtr" || u.Managed.StartsWith(Namespace + ".Pointer<")) { // FIXME: maybe it's hacky, but do no further existence checks. output.WriteLine($"using {u.Alias} = {u.Managed};"); continue; } // FIXME: hacky matching var mbr = members.FirstOrDefault(m => u.Managed.EndsWith(m.Name, StringComparison.Ordinal)); if (mbr != null) { mbr.Name = u.Alias; } else { // FIXME: this does not seem to work var del = delegates.FirstOrDefault(d => u.Managed.EndsWith(d.TypeNameForDeclaration, StringComparison.Ordinal)); if (del != null) { del.TypeNameForDeclaration = u.Alias; del.TypeNameForReference = "Delegates." + u.Alias; output.WriteLine("using {0} = {1}; // {2} ({3},{4})", u.Managed.Substring(Namespace.Length + 1), WithNamespace(del.TypeNameForReference), u.SourceFileName, u.Line, u.Column); } else { Console.Error.WriteLine($"[warn] typedef \"{u.Alias}\" is being missed. It should be mapped to \"{u.ActualInC}\", but \"{u.Managed}\" did not match anything. (Declared at {u.SourceFile}({u.Line}, {u.Column}).)"); } } } // some code references function pointer types without "Delegates.", so workaround that with hacky "Delegates." addition. foreach (var del in delegates) { output.WriteLine("using {0} = {1};", del.TypeNameForDeclaration, WithNamespace(del.TypeNameForReference)); } output.WriteLine(); if (Namespace != null) { output.WriteLine("namespace {0} {{", Namespace); } foreach (var o in members.OfType <Struct> ()) { o.Write(output, type_scope); output.WriteLine(); } output.WriteLine($"{type_scope} partial class Natives"); output.WriteLine("{"); output.WriteLine("\tconst string LibraryName = \"{0}\";", LibraryName); foreach (var o in members.OfType <Function> ()) { o.Write(output, type_scope); output.WriteLine(); } output.WriteLine("}"); output.WriteLine(); if (delegates.Any()) { output.WriteLine($"{type_scope} class Delegates"); output.WriteLine("{"); foreach (var s in delegates) { output.WriteLine("public " + s.DelegateDefinition + ";"); } output.WriteLine("}"); } output.WriteLine($@" {type_scope} struct Pointer<T> {{ public IntPtr Handle; public static implicit operator IntPtr (Pointer<T> value) {{ return value.Handle; }} public static implicit operator Pointer<T> (IntPtr value) {{ return new Pointer<T> (value); }} public Pointer (IntPtr handle) {{ Handle = handle; }} public override bool Equals (object obj) {{ return obj is Pointer<T> && this == (Pointer<T>) obj; }} public override int GetHashCode () {{ return (int) Handle; }} public static bool operator == (Pointer<T> p1, Pointer<T> p2) {{ return p1.Handle == p2.Handle; }} public static bool operator != (Pointer<T> p1, Pointer<T> p2) {{ return p1.Handle != p2.Handle; }} }} {type_scope} struct ArrayOf<T> {{}} {type_scope} struct ConstArrayOf<T> {{}} {type_scope} class CTypeDetailsAttribute : Attribute {{ public CTypeDetailsAttribute (string value) {{ Value = value; }} public string Value {{ get; set; }} }} "); if (Namespace != null) { output.WriteLine("}"); } output.Close(); }
void Run(string[] args) { var idx = ClangService.CreateIndex(); var tus = new List <ClangTranslationUnit> (); TextWriter output = Console.Out; foreach (var arg in args) { if (arg.StartsWith("--out:", StringComparison.Ordinal)) { output = File.CreateText(arg.Substring(6)); } else if (arg.StartsWith("--lib:", StringComparison.Ordinal)) { LibraryName = arg.Substring(6); } else if (arg.StartsWith("--ns:", StringComparison.Ordinal)) { Namespace = arg.Substring(5); } else { tus.Add(idx.ParseTranslationUnit(arg, null, null, TranslationUnitFlags.None)); } } var members = new List <Locatable> (); Struct current = null; foreach (var tu in tus) { Func <ClangCursor, ClangCursor, IntPtr, ChildVisitResult> func = null; func = (cursor, parent, clientData) => { // FIXME: this doesn't work. if (cursor.Kind == CursorKind.InclusionDirective) { Console.Error.WriteLine("Include File " + cursor.IncludedFile); idx.ParseTranslationUnit(cursor.IncludedFile.FileName, null, null, TranslationUnitFlags.None).GetCursor().VisitChildren(func, IntPtr.Zero); } if (cursor.Kind == CursorKind.TypedefDeclaration) { if (cursor.Location.FileLocation.File != null) { var alias = ToTypeName(cursor.CursorType); InsideUsingDeclaration = true; if (usings.All(u => u.Alias != alias)) { var actual = ToTypeName(cursor.TypeDefDeclUnderlyingType); usings.Add(new TypeDef() { Alias = alias, Actual = actual }); } InsideUsingDeclaration = false; } } if (cursor.Kind == CursorKind.EnumConstantDeclaration) { current.Fields.Add(new Variable() { Type = ToTypeName(cursor.CursorType), Name = cursor.Spelling, // FIXME: this is HACK. Value = (cursor.EnumConstantDeclValue != 0 ? (decimal)cursor.EnumConstantDeclValue : (decimal)cursor.EnumConstantDeclUnsignedValue).ToString(), }); } if (cursor.Kind == CursorKind.FieldDeclaration) { current.Fields.Add(new Variable() { Type = ToTypeName(cursor.CursorType), Name = cursor.Spelling }); } if (cursor.Kind == CursorKind.StructDeclaration || cursor.Kind == CursorKind.UnionDeclaration || cursor.Kind == CursorKind.EnumDeclaration) { current = new Struct() { Name = cursor.DisplayName, SourceFile = cursor.Location.FileLocation.File.FileName, Line = cursor.Location.FileLocation.Line, Column = cursor.Location.FileLocation.Column, IsUnion = cursor.Kind == CursorKind.UnionDeclaration, IsEnum = cursor.Kind == CursorKind.EnumDeclaration, }; if (members.All(m => m.Line != current.Line || m.Column != current.Column)) { var dup = members.OfType <Struct> ().Where(m => m.Name == current.Name).ToArray(); foreach (var d in dup) { members.Remove(d); } members.Add(current); } } if (cursor.Kind == CursorKind.FunctionDeclaration) { members.Add(new Function() { Name = cursor.Spelling, Return = ToTypeName(cursor.ResultType), SourceFile = cursor.Location.FileLocation.File.FileName, Line = cursor.Location.FileLocation.Line, Column = cursor.Location.FileLocation.Column, Args = Enumerable.Range(0, cursor.ArgumentCount).Select(i => cursor.GetArgument(i)).Select(a => new Variable() { Name = a.Spelling, Type = ToTypeName(a.CursorType) }).ToArray() }); } return(ChildVisitResult.Recurse); }; tu.GetCursor().VisitChildren(func, IntPtr.Zero); } output.WriteLine("// This source file is generated by nclang PInvokeGenerator."); output.WriteLine("using System;"); output.WriteLine("using System.Runtime.InteropServices;"); foreach (var u in usings.Distinct(new KeyComparer())) { if (u.Alias != u.Actual) { output.WriteLine("using {0} = {1};", u.Alias, u.Actual); } } output.WriteLine(); if (Namespace != null) { output.WriteLine("namespace {0} {{", Namespace); } foreach (var o in members.OfType <Struct> ()) { o.Write(output); output.WriteLine(); } output.WriteLine("class Natives"); output.WriteLine("{"); foreach (var o in members.OfType <Function> ()) { o.Write(output); output.WriteLine(); } output.WriteLine("}"); output.WriteLine(); output.WriteLine(@" public struct Pointer<T> { public IntPtr Handle; public static implicit operator IntPtr (Pointer<T> value) { return value.Handle; } public static implicit operator Pointer<T> (IntPtr value) { return new Pointer<T> (value); } public Pointer (IntPtr handle) { Handle = handle; } } public struct ArrayOf<T> {} public struct ConstArrayOf<T> {} "); if (Namespace != null) { output.WriteLine("}"); } output.Close(); }