@ -10,9 +10,12 @@ using System.Collections.Generic;
@@ -10,9 +10,12 @@ using System.Collections.Generic;
using System.Linq ;
using Mono.VisualC.Interop ;
using Mono.VisualC.Interop.Util ;
using Mono.VisualC.Code ;
using Mono.VisualC.Code.Atoms ;
using System.Reflection ;
using System.CodeDom ;
using System.CodeDom.Compiler ;
using Microsoft.CSharp ;
@ -22,12 +25,33 @@ namespace CPPInterop {
@@ -22,12 +25,33 @@ namespace CPPInterop {
public static readonly string [ ] genericTypeArgs = new string [ ] { "T" , "U" , "V" , "W" , "X" , "Y" , "Z" } ;
public string Source { get ; set ; }
private CodeUnit currentUnit ;
public Dictionary < string , string > Classes ;
private CodeUnit enumerations ;
public HashSet < string > Enumerations ;
private CodeUnit unions ;
public HashSet < string > Unions ;
public string Dir { get ; set ; }
string templateClass ;
string templateStruct ;
string templateInterface ;
private string nspace ;
public string Namespace {
get { return nspace ; }
set {
nspace = value ;
enumerations . ManagedNamespace = value ;
unions . ManagedNamespace = value ;
}
}
public string Library { get ; set ; }
public CodeDomProvider Provider { get ; set ; }
public CodeGeneratorOptions Options { get ; set ; }
private Dictionary < string , Property > properties ;
public static void Main ( string [ ] args )
{
@ -36,7 +60,10 @@ namespace CPPInterop {
@@ -36,7 +60,10 @@ namespace CPPInterop {
var p = new OptionSet ( ) {
{ "h|?|help" , v = > help = v ! = null } ,
{ "f=" , v = > gen . Source = v } ,
{ "o=" , v = > gen . Dir = v }
{ "o=" , v = > gen . Dir = v } ,
{ "ns=" , v = > gen . Namespace = v } ,
{ "lib=" , v = > gen . Library = v } ,
{ "lang=" , v = > gen . Provider = CodeDomProvider . CreateProvider ( v ) }
} ;
List < string > extra = null ;
@ -47,6 +74,11 @@ namespace CPPInterop {
@@ -47,6 +74,11 @@ namespace CPPInterop {
return ;
}
if ( help ) {
p . WriteOptionDescriptions ( Console . Error ) ;
return ;
}
if ( gen . Source = = null ) {
Console . Error . WriteLine ( "-f required" ) ;
return ;
@ -56,74 +88,53 @@ namespace CPPInterop {
@@ -56,74 +88,53 @@ namespace CPPInterop {
gen . Dir = "output" ;
Directory . CreateDirectory ( gen . Dir ) ;
if ( gen . Namespace = = null )
gen . Namespace = "Wrappers" ;
if ( gen . Library = = null )
gen . Library = "Lib" ;
if ( gen . Library . EndsWith ( ".dll" ) | | gen . Library . EndsWith ( ".so" ) | | gen . Library . EndsWith ( ".dylib" ) )
gen . Library = gen . Library . Substring ( 0 , gen . Library . LastIndexOf ( '.' ) ) ;
if ( gen . Provider = = null )
gen . Provider = new CSharpCodeProvider ( ) ;
gen . Options = new CodeGeneratorOptions ( ) {
BlankLinesBetweenMembers = false
} ;
gen . Run ( ) ;
}
public Generator ( )
{
Classes = new Dictionary < string , string > ( ) ;
templateClass = File . ReadAllText ( "class.template" ) ;
templateStruct = File . ReadAllText ( "struct.template" ) ;
templateInterface = File . ReadAllText ( "interface.template" ) ;
}
XmlNode find ( XmlNode root , XmlAttribute att )
{
if ( att ! = null )
return find ( root , att . Value ) ;
return null ;
}
Enumerations = new HashSet < string > ( ) ;
enumerations = new CodeUnit { ManagedNamespace = Namespace } ;
XmlNode find ( XmlNode root , string id )
{
XmlNode n = root . SelectSingleNode ( "/GCC_XML/*[@id='" + id + "']" ) ;
//if (n.Name == "Typedef")
// return n;
if ( n . Attributes [ "type" ] ! = null )
return find ( root , n . Attributes [ "type" ] . Value ) ;
return n ;
}
Unions = new HashSet < string > ( ) ;
unions = new CodeUnit { ManagedNamespace = Namespace } ;
CppType findType ( XmlNode root , string id )
{
return findType ( root , id , new CppType ( ) ) ;
properties = new Dictionary < string , Property > ( ) ;
}
CppType findType ( XmlNode root , string id , CppType modifiers )
public void Run ( )
{
XmlNode n = root . SelectSingleNode ( "/GCC_XML/*[@id='" + id + "']" ) ;
switch ( n . Name ) {
case "ArrayType" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers . Modify ( CppModifiers . Array ) ) ;
case "PointerType" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers . Modify ( CppModifiers . Pointer ) ) ;
case "ReferenceType" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers . Modify ( CppModifiers . Reference ) ) ;
case "CvQualifiedType" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers . Modify ( n . Attributes [ "const" ] . Value = = "1" ? CppModifiers . Const : CppModifiers . Volatile ) ) ;
case "Typedef" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers ) ;
case "FundamentalType" : return modifiers . ApplyTo ( new CppType ( n . Attributes [ "name" ] . Value ) ) ;
case "Class" : return modifiers . ApplyTo ( new CppType ( CppTypes . Class , n . Attributes [ "name" ] . Value ) ) ;
case "Struct" : return modifiers . ApplyTo ( new CppType ( CppTypes . Struct , n . Attributes [ "name" ] . Value ) ) ;
case "Enumeration" : return modifiers . ApplyTo ( new CppType ( CppTypes . Enum , n . Attributes [ "name" ] . Value ) ) ;
XmlDocument xmldoc = new XmlDocument ( ) ;
xmldoc . Load ( Source ) ;
//XmlNodeList namespaces = xmldoc.SelectNodes ("/GCC_XML/Namespace[@name != '::' and @name != '' and @name != 'std']");
// FIXME: support function pointers better
case "FunctionType" : return modifiers . ApplyTo ( CppTypes . Void ) ;
}
ProcessClasses ( xmldoc ) ;
GenerateStaticLibField ( ) ;
throw new NotImplementedException ( "Unknown type node: " + n . Name ) ;
SaveFile ( enumerations . WrapperToCodeDom ( ) , "Enums" ) ;
SaveFile ( unions . WrapperToCodeDom ( ) , "Unions" ) ;
}
public void Run ( )
void ProcessClasses ( XmlDocument xmldoc )
{
var csharp = new CSharpCodeProvider ( ) ;
var options = new CodeGeneratorOptions {
BlankLinesBetweenMembers = false
} ;
XmlDocument xmldoc = new XmlDocument ( ) ;
xmldoc . Load ( Source ) ;
XmlNodeList namespaces = xmldoc . SelectNodes ( "/GCC_XML/Namespace[@name != '::' and @name != '' and @name != 'std']" ) ;
XmlNodeList classes = xmldoc . SelectNodes ( "/GCC_XML/Class[not(@incomplete)]" ) ;
foreach ( XmlNode clas in classes ) {
var f = xmldoc . SelectSingleNode ( "/GCC_XML/File[@id='" + clas . Attributes [ "file" ] . Value + "']/@name" ) ;
if ( f ! = null & & f . Value . StartsWith ( "/" ) )
@ -149,62 +160,80 @@ namespace CPPInterop {
@@ -149,62 +160,80 @@ namespace CPPInterop {
ras [ i ] = string . Format ( "{0} with {1}" , replaceArgs [ i ] . ToString ( ) , letters [ i ] ) ;
}
Console . WriteLine ( "Warning: Creating generic type {0}<{1}> from the instantiated template {2} by replacing {3} (very buggy!!!)" , baseName , string . Join ( "," , letters ) , name , string . Join ( ", " , ras ) ) ;
Console . Error . WriteLine ( "Warning: Creating generic type {0}<{1}> from the instantiated template {2} by replacing {3} (very buggy!!!)" , baseName , string . Join ( "," , letters ) , name , string . Join ( ", " , ras ) ) ;
name = baseName ;
}
var cu = new CodeUnit { ManagedNamespace = "Qt.Core" } ;
var classAtom = new Class ( name ) { StaticCppLibrary = "Qt.Libs.QtCore" } ;
if ( replaceArgs ! = null )
currentUnit = new CodeUnit { ManagedNamespace = Namespace } ;
var classAtom = new Class ( name ) {
StaticCppLibrary = string . Format ( "{0}.Libs.{1}" , Namespace , Library )
} ;
if ( replaceArgs ! = null ) {
for ( int i = 0 ; i < replaceArgs . Length ; i + + )
classAtom . TemplateArguments . Add ( genericTypeArgs [ i ] ) ;
cu . Atoms . AddLast ( classAtom ) ;
}
currentUnit . Atoms . AddLast ( classAtom ) ;
foreach ( XmlNode baseNode in clas . SelectNodes ( "Base" ) ) {
classAtom . Bases . Add ( new Class . BaseClass {
Name = find ( xmldoc . DocumentElement , baseNode . Attributes [ "type" ] ) . Attributes [ "name" ] . Value ,
Access = baseNode . Attributes [ "access" ] . Value = = "public" ? Access . Public :
baseNode . Attributes [ "access" ] . Value = = "protected" ? Access . Protected :
Access . Private ,
IsVirtual = baseNode . Attributes [ "virtual" ] . Value = = "1"
} ) ;
}
string size = clas . Attributes [ "size" ] . Value ;
string members = clas . Attributes [ "members" ] . Value ;
//string size = clas.Attributes["size"].Value;
var members = clas . Attributes [ "members" ] . Value . Split ( ' ' ) . Where ( id = > ! id . Equals ( string . Empty ) ) ;
//StringBuilder str = new StringBuilder();
foreach ( string id in members . Split ( new char [ ] { ' ' } ) ) {
if ( id . Equals ( String . Empty ) )
continue ;
XmlNode n = find ( xmldoc . DocumentElement , id ) ;
foreach ( string id in members ) {
XmlNode n = xmldoc . SelectSingleNode ( "/GCC_XML/*[@id='" + id + "']" ) ;
bool ctor = false ;
bool dtor = false ;
int fieldCount = 0 ;
switch ( n . Name ) {
case "Method" :
case "Constructor" :
ctor = true ;
break ;
case "Destructor" :
dtor = true ;
break ;
default :
case "Method" :
break ;
case "Field" :
CppType fieldType = findType ( xmldoc . DocumentElement , n . Attributes [ "type" ] ) ;
string fname = "field" + fieldCount + + ;
if ( n . Attributes [ "name" ] ! = null & & n . Attributes [ "name" ] . Value ! = "" )
fname = n . Attributes [ "name" ] . Value ;
classAtom . Atoms . AddLast ( new Field ( fname , fieldType ) ) ;
continue ;
default :
continue ;
}
if ( n . Attributes [ "access" ] = = null | | n . Attributes [ "access" ] . Value ! = "public" )
if ( n . Attributes [ "access" ] = = null | | n . Attributes [ "access" ] . Value ! = "public" | |
( n . Attributes [ "overrides" ] ! = null & & n . Attributes [ "overrides" ] . Value ! = "" & & ! dtor ) | |
n . Attributes [ "extern" ] = = null | | n . Attributes [ "extern" ] . Value ! = "1" )
continue ;
//str.Append ("\t\t\t");
string mname = n . Attributes [ "name" ] . Value ;
CppType retType = findType ( xmldoc . DocumentElement , n . Attributes [ "returns" ] . Value ) ;
if ( replaceArgs ! = null )
CppType retType = findType ( xmldoc . DocumentElement , n . Attributes [ "returns" ] ) ;
if ( replaceArgs ! = null ) {
for ( int i = 0 ; i < replaceArgs . Length ; i + + )
if ( replaceArgs [ i ] . ElementTypeName = = retType . ElementTypeName ) {
retType . Subtract ( replaceArgs [ i ] ) ;
retType . ElementTypeName = genericTypeArgs [ i ] ;
}
bool virt = n . Attributes [ "virtual" ] ! = null & & n . Attributes [ "virtual" ] . Value = = "1" ;
bool stat = n . Attributes [ "static" ] ! = null & & n . Attributes [ "static" ] . Value = = "1" ;
//if (virt)
//str.Append ("[Virtual] ");
//str.Append (rett + " " + mname + " (CppInstancePtr @this");
retType = replaceType ( retType , replaceArgs [ i ] , genericTypeArgs [ i ] ) ;
}
List < Method . Parameter > args = new List < Method . Parameter > ( ) ;
var methodAtom = new Method ( mname ) {
var methodAtom = new Method ( dtor ? "Destruct" : mname ) {
RetType = retType ,
IsVirtual = virt ,
IsStatic = stat ,
Parameters = args
IsVirtual = n . Attributes [ "virtual" ] ! = null & & n . Attributes [ "virtual" ] . Value = = "1" ,
IsStatic = n . Attributes [ "static" ] ! = null & & n . Attributes [ "static" ] . Value = = "1" ,
IsConst = n . Attributes [ "const" ] ! = null & & n . Attributes [ "const" ] . Value = = "1" ,
IsConstructor = ctor ,
IsDestructor = dtor
} ;
int c = 0 ;
@ -216,50 +245,230 @@ namespace CPPInterop {
@@ -216,50 +245,230 @@ namespace CPPInterop {
argname = arg . Attributes [ "name" ] . Value ;
CppType argtype = findType ( xmldoc . DocumentElement , arg . Attributes [ "type" ] . Value ) ;
if ( replaceArgs ! = null )
if ( replaceArgs ! = null ) {
for ( int i = 0 ; i < replaceArgs . Length ; i + + )
if ( replaceArgs [ i ] . ElementTypeName = = argtype . ElementTypeName ) {
argtype . Subtract ( replaceArgs [ i ] ) ;
argtype . ElementTypeName = genericTypeArgs [ i ] ;
}
argtype = replaceType ( argtype , replaceArgs [ i ] , genericTypeArgs [ i ] ) ;
}
//str.Append (", " + argtype + " " + argname);
args . Add ( new Method . Parameter { Name = argname , Type = argtype } ) ;
methodAtom . Parameters . Add ( new Method . Parameter { Name = argname , Type = argtype } ) ;
// tee hee
c + + ;
}
//str.AppendLine (");");
// if it's const, returns a value, and has no parameters, assume it's a property getter (for now?)
if ( methodAtom . IsConst & & ! retType . Equals ( CppTypes . Void ) & & ! methodAtom . Parameters . Any ( ) ) {
var pname = methodAtom . FormattedName ;
Property propertyAtom ;
if ( properties . TryGetValue ( pname , out propertyAtom ) ) {
propertyAtom . Getter = methodAtom ;
} else {
propertyAtom = new Property ( pname ) { Getter = methodAtom } ;
properties . Add ( pname , propertyAtom ) ;
classAtom . Atoms . AddLast ( propertyAtom ) ;
}
continue ;
}
// if it's name starts with "set", does not return a value, and has one arg (besides this ptr)
// AND there is a corresponding getter method, then assume it's a property setter
if ( mname . ToLower ( ) . StartsWith ( "set" ) & & retType . Equals ( CppTypes . Void ) & & methodAtom . Parameters . Count = = 1 ) {
string getterName = "translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = '" +
mname . Substring ( 3 ) . TrimStart ( '_' ) . ToLower ( ) + "'" ;
string isMember = "@id = '" + string . Join ( "' or @id = '" , members . ToArray ( ) ) + "'" ;
string pname = methodAtom . FormattedName . Substring ( 3 ) ;
Property propertyAtom = null ;
// FIXME: This xpath is probably very slow if the class has many members
if ( properties . TryGetValue ( pname , out propertyAtom ) | |
xmldoc . SelectSingleNode ( string . Format ( "/GCC_XML/Method[{0} and ({1})]" , getterName , isMember ) ) ! = null ) {
if ( propertyAtom ! = null ) {
propertyAtom . Setter = methodAtom ;
} else {
propertyAtom = new Property ( pname ) { Setter = methodAtom } ;
properties . Add ( pname , propertyAtom ) ;
classAtom . Atoms . AddLast ( propertyAtom ) ;
}
// set the method's arg name to "value" so that the prop setter works right
Method . Parameter valueParam = methodAtom . Parameters [ 0 ] ;
valueParam . Name = "value" ;
methodAtom . Parameters [ 0 ] = valueParam ;
continue ;
}
}
classAtom . Atoms . AddLast ( methodAtom ) ;
}
Classes . Add ( name , sanitize ( name ) + ".cs" ) ;
FileStream fs = File . Create ( Path . Combine ( Dir , Classes [ name ] ) ) ;
StreamWriter sw = new StreamWriter ( fs ) ;
/ *
StringBuilder sb = new StringBuilder ( ) ;
string strstruct = String . Format ( templateStruct , name ) ;
string strinterface = String . Format ( templateInterface , name , "" , str . ToString ( ) ) ;
sb . Append ( string . Format ( templateClass ,
"Qt.Core" ,
name ,
"ICppObject" ,
strinterface ,
strstruct ,
size ) ) ;
sw . Write ( sb . ToString ( ) ) ;
* /
csharp . GenerateCodeFromCompileUnit ( cu . WrapperToCodeDom ( ) , sw , options ) ;
sw . Flush ( ) ;
sw . Close ( ) ;
Classes . Add ( name , sanitize ( name ) + "." + Provider . FileExtension ) ;
SaveFile ( currentUnit . WrapperToCodeDom ( ) , name ) ;
}
}
XmlNode find ( XmlNode root , XmlAttribute att )
{
if ( att ! = null )
return find ( root , att . Value ) ;
return null ;
}
XmlNode find ( XmlNode root , string id )
{
XmlNode n = root . SelectSingleNode ( "/GCC_XML/*[@id='" + id + "']" ) ;
//if (n.Name == "Typedef")
// return n;
if ( n . Attributes [ "type" ] ! = null )
return find ( root , n . Attributes [ "type" ] . Value ) ;
return n ;
}
CppType findType ( XmlNode root , XmlAttribute att )
{
if ( att ! = null )
return findType ( root , att . Value ) ;
return CppTypes . Void ;
}
CppType findType ( XmlNode root , string id )
{
return findType ( root , id , new CppType ( ) ) ;
}
CppType findType ( XmlNode root , string id , CppType modifiers )
{
XmlNode n = root . SelectSingleNode ( "/GCC_XML/*[@id='" + id + "']" ) ;
switch ( n . Name ) {
case "ArrayType" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers . Modify ( CppModifiers . Array ) ) ;
case "PointerType" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers . Modify ( CppModifiers . Pointer ) ) ;
case "ReferenceType" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers . Modify ( CppModifiers . Reference ) ) ;
case "CvQualifiedType" :
return findType ( root , n . Attributes [ "type" ] . Value ,
modifiers . Modify ( n . Attributes [ "const" ] ! = null & & n . Attributes [ "const" ] . Value = = "1" ? CppModifiers . Const : CppModifiers . Volatile ) ) ;
case "Typedef" : return findType ( root , n . Attributes [ "type" ] . Value , modifiers ) ;
case "FundamentalType" : return modifiers . ApplyTo ( new CppType ( n . Attributes [ "name" ] . Value ) ) ;
case "Class" : return modifiers . ApplyTo ( new CppType ( CppTypes . Class , n . Attributes [ "name" ] . Value ) ) ;
case "Struct" : return modifiers . ApplyTo ( new CppType ( CppTypes . Struct , n . Attributes [ "name" ] . Value ) ) ;
case "Union" : return modifiers . ApplyTo ( ProcessUnion ( root , n ) ) ;
case "Enumeration" : return modifiers . ApplyTo ( ProcessEnum ( n ) ) ;
// FIXME: support function pointers betters
case "FunctionType" : return modifiers . ApplyTo ( CppTypes . Void ) ;
}
throw new NotImplementedException ( "Unknown type node: " + n . Name ) ;
}
CppType ProcessEnum ( XmlNode enm )
{
bool hasName = false ;
string ename = "Enum" + Enumerations . Count ;
if ( enm . Attributes [ "name" ] ! = null & & enm . Attributes [ "name" ] . Value ! = "" ) {
hasName = true ;
ename = enm . Attributes [ "name" ] . Value ;
}
if ( ! hasName | | ! Enumerations . Contains ( ename ) ) {
Enumeration enumAtom = new Enumeration ( enm . Attributes [ "name" ] . Value ) ;
foreach ( XmlNode v in enm . SelectNodes ( "EnumValue" ) )
enumAtom . Items . Add ( new Enumeration . Item { Name = v . Attributes [ "name" ] . Value , Value = Convert . ToInt32 ( v . Attributes [ "init" ] . Value ) } ) ;
if ( hasName ) // assume it might be shared between classes
enumerations . Atoms . AddLast ( enumAtom ) ;
else
currentUnit . Atoms . AddLast ( enumAtom ) ;
Enumerations . Add ( ename ) ;
}
return new CppType ( CppTypes . Enum , ename ) ;
}
CppType ProcessUnion ( XmlNode root , XmlNode union )
{
bool hasName = false ;
string uname = "Union" + Unions . Count ;
if ( union . Attributes [ "name" ] ! = null & & union . Attributes [ "name" ] . Value ! = "" ) {
hasName = true ;
uname = union . Attributes [ "name" ] . Value ;
}
if ( ! hasName | | ! Unions . Contains ( uname ) ) {
Union unionAtom = new Union ( uname ) ;
foreach ( string id in union . Attributes [ "members" ] . Value . Split ( ' ' ) . Where ( id = > ! id . Equals ( string . Empty ) ) ) {
XmlNode n = root . SelectSingleNode ( "/GCC_XML/*[@id = '" + id + "']" ) ;
// FIXME: Support union constructors/destructors?
if ( n . Name ! = "Field" )
continue ;
Field field = new Field ( n . Attributes [ "name" ] . Value , findType ( root , n . Attributes [ "type" ] ) ) ;
unionAtom . Atoms . AddLast ( field ) ;
}
if ( hasName ) // assume it might be shared between classes
unions . Atoms . AddLast ( unionAtom ) ;
else
currentUnit . Atoms . AddLast ( unionAtom ) ;
Unions . Add ( uname ) ;
}
return new CppType ( CppTypes . Union , uname ) ;
}
void GenerateStaticLibField ( )
{
var ccu = new CodeCompileUnit ( ) ;
var ns = new CodeNamespace ( Namespace ) ;
var cls = new CodeTypeDeclaration ( "Libs" ) {
TypeAttributes = TypeAttributes . NotPublic | TypeAttributes . Sealed | TypeAttributes . Class ,
IsPartial = true ,
IsClass = true
} ;
var field = new CodeMemberField ( typeof ( CppLibrary ) , Library ) {
Attributes = MemberAttributes . Public | MemberAttributes . Static ,
InitExpression = new CodeObjectCreateExpression ( typeof ( CppLibrary ) , new CodePrimitiveExpression ( Library ) )
} ;
cls . Members . Add ( field ) ;
ns . Types . Add ( cls ) ;
ccu . Namespaces . Add ( ns ) ;
SaveFile ( ccu , "Lib_" + Library ) ;
}
void SaveFile ( CodeCompileUnit ccu , string baseName )
{
var sw = File . CreateText ( Path . Combine ( Dir , sanitize ( baseName ) + "." + Provider . FileExtension ) ) ;
Provider . GenerateCodeFromCompileUnit ( ccu , sw , Options ) ;
sw . Flush ( ) ;
sw . Close ( ) ;
sw . Dispose ( ) ;
}
static CppType replaceType ( CppType inType , CppType toReplace , string tn )
{
// FIXME: The order of some modifiers is not significant.. is this a problem?
if ( /* inType.ElementType == toReplace.ElementType && */
inType . ElementTypeName = = toReplace . ElementTypeName & &
inType . Modifiers . StartsWith ( toReplace . Modifiers ) )
return new CppType ( CppTypes . Typename , tn , inType . Modifiers . Skip ( toReplace . Modifiers . Count ) . ToArray ( ) ) ;
foreach ( var tempMod in inType . Modifiers . OfType < CppModifiers . TemplateModifier > ( ) )
for ( int i = 0 ; i < tempMod . Types . Length ; i + + )
tempMod . Types [ i ] = replaceType ( tempMod . Types [ i ] , toReplace , tn ) ;
return inType ;
}
static string sanitize ( string name )
{