mirror of https://github.com/mono/CppSharp.git
c-sharpdotnetmonobindingsbridgecclangcpluspluscppsharpglueinteropparserparsingpinvokeswigsyntax-treevisitorsxamarinxamarin-bindings
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
7.7 KiB
257 lines
7.7 KiB
// |
|
// Mono.VisualC.Interop.CppType.cs: Abstracts a C++ type declaration |
|
// |
|
// Author: |
|
// Alexander Corrado (alexander.corrado@gmail.com) |
|
// |
|
// Copyright (C) 2010 Alexander Corrado |
|
// |
|
|
|
using System; |
|
using System.Linq; |
|
using System.Text; |
|
using System.Text.RegularExpressions; |
|
using System.Reflection; |
|
using System.Collections.Generic; |
|
|
|
namespace Mono.VisualC.Interop { |
|
|
|
public enum CppModifiers { |
|
Const, |
|
Pointer, |
|
Array, |
|
Reference, |
|
Volatile, |
|
// --- |
|
Signed, |
|
Unsigned, |
|
Short, |
|
Long |
|
} |
|
public enum CppTypes { |
|
Unknown, |
|
Class, |
|
Struct, |
|
Enum, |
|
Union, |
|
Void, |
|
Bool, |
|
Char, |
|
Int, |
|
Float, |
|
Double |
|
} |
|
|
|
public struct CppType { |
|
|
|
public static Dictionary<string,CppModifiers> Tokenize = new Dictionary<string, CppModifiers> () { |
|
{ "\\*", CppModifiers.Pointer }, |
|
{ "\\[\\s*\\]", CppModifiers.Array }, |
|
{ "\\&", CppModifiers.Reference } |
|
}; |
|
|
|
/* |
|
public static Dictionary<CppModifiers,string> Stringify = new Dictionary<CppModifiers, string> () { |
|
{ CppModifiers.Pointer, "*" }, |
|
{ CppModifiers.Array, "[]" }, |
|
{ CppModifiers.Reference, "&" } |
|
}; |
|
*/ |
|
|
|
// FIXME: Passing these as delegates allows for the flexibility of doing processing on the |
|
// type (i.e. to correctly mangle the function pointer arguments if the managed type is a delegate), |
|
// however this does not make it very easy to override the default mappings at runtime. |
|
public static List<Func<Type,CppType>> ManagedTypeMap = new List<Func<Type,CppType>> () { |
|
(t) => { return typeof (void).Equals (t) ? CppTypes.Void : CppTypes.Unknown; }, |
|
(t) => { return typeof (bool).Equals (t) ? CppTypes.Bool : CppTypes.Unknown; }, |
|
(t) => { return typeof (char).Equals (t) ? CppTypes.Char : CppTypes.Unknown; }, |
|
(t) => { return typeof (int).Equals (t) ? CppTypes.Int : CppTypes.Unknown; }, |
|
(t) => { return typeof (float).Equals (t) ? CppTypes.Float : CppTypes.Unknown; }, |
|
(t) => { return typeof (double).Equals (t)? CppTypes.Double : CppTypes.Unknown; }, |
|
|
|
(t) => { return typeof (short).Equals (t) ? new CppType (CppModifiers.Short, CppTypes.Int) : CppTypes.Unknown; }, |
|
(t) => { return typeof (long).Equals (t) ? new CppType (CppModifiers.Long, CppTypes.Int) : CppTypes.Unknown; }, |
|
|
|
// strings mangle as "const char*" by default |
|
(t) => { return typeof (string).Equals (t)? new CppType (CppModifiers.Const, CppTypes.Char, CppModifiers.Pointer) : CppTypes.Unknown; }, |
|
// StringBuilder gets "char*" |
|
(t) => { return typeof (StringBuilder).Equals (t)? new CppType (CppTypes.Char, CppModifiers.Pointer) : CppTypes.Unknown; }, |
|
|
|
// delegate types get special treatment |
|
(t) => { return typeof (Delegate).IsAssignableFrom (t)? CppType.ForDelegate (t) : CppTypes.Unknown; }, |
|
|
|
// ... and of course ICppObjects do too! |
|
// FIXME: We assume c++ class not struct. There should probably be an attribute |
|
// we can apply to managed wrappers to indicate if the underlying C++ type is actually declared struct |
|
(t) => { return typeof (ICppObject).IsAssignableFrom (t)? new CppType (CppTypes.Class, t.Name, CppModifiers.Pointer) : CppTypes.Unknown; }, |
|
|
|
// convert managed type modifiers to C++ type modifiers like so: |
|
// ref types to C++ references |
|
// pointer types to C++ pointers |
|
// array types to C++ arrays |
|
(t) => { |
|
if (t.GetElementType () == null) return CppTypes.Unknown; |
|
CppType cppType = CppType.ForManagedType (t.GetElementType ()); |
|
if (t.IsByRef) cppType.Modifiers.Add (CppModifiers.Reference); |
|
if (t.IsPointer) cppType.Modifiers.Add (CppModifiers.Pointer); |
|
if (t.IsArray) cppType.Modifiers.Add (CppModifiers.Array); |
|
return cppType; |
|
} |
|
}; |
|
|
|
public CppTypes ElementType { get; set; } |
|
|
|
// if the ElementType is Union, Struct, Class, or Enum |
|
// this will contain the name of said type |
|
public string ElementTypeName { get; set; } |
|
|
|
public List<CppModifiers> Modifiers { get; private set; } |
|
|
|
// here, you can pass in things like "const char*" or "const Foo * const" |
|
// DISCLAIMER: this is really just for convenience for now, and is not meant to be able |
|
// to parse even moderately complex C++ type declarations. |
|
public CppType (string type) : this (Regex.Split (type, "\\s+(?!\\])")) |
|
{ |
|
} |
|
|
|
public CppType (params object[] cppTypeSpec) |
|
{ |
|
ElementType = CppTypes.Unknown; |
|
ElementTypeName = null; |
|
|
|
Modifiers = new List<CppModifiers> (); |
|
|
|
Parse (cppTypeSpec); |
|
} |
|
|
|
private void Parse (object [] modifiers) |
|
{ |
|
for (int i = 0; i < modifiers.Length; i++) { |
|
|
|
if (modifiers [i] is CppModifiers) { |
|
Modifiers.Add ((CppModifiers)modifiers [i]); |
|
continue; |
|
} |
|
|
|
string strModifier = modifiers [i] as string; |
|
if (strModifier != null) { |
|
// FIXME: Use Enum.TryParse here if we decide to make this NET_4_0 only |
|
try { |
|
Modifiers.Add ((CppModifiers)Enum.Parse (typeof (CppModifiers), strModifier, true)); |
|
continue; |
|
} catch { } |
|
} |
|
|
|
// must be a type name |
|
ParseType (modifiers [i]); |
|
} |
|
} |
|
|
|
private void ParseType (object type) |
|
{ |
|
if (type is CppTypes) { |
|
ElementType = (CppTypes)type; |
|
ElementTypeName = null; |
|
return; |
|
} |
|
|
|
string strType = type as string; |
|
if (strType != null) { |
|
// strip tokens off type name |
|
foreach (var token in Tokenize) { |
|
foreach (var match in Regex.Matches (strType, token.Key)) |
|
Modifiers.Add (token.Value); |
|
|
|
strType = Regex.Replace (strType, token.Key, string.Empty); |
|
} |
|
|
|
// FIXME: Use Enum.TryParse here if we decide to make this NET_4_0 only |
|
try { |
|
CppTypes parsed = (CppTypes)Enum.Parse (typeof (CppTypes), strType, true); |
|
ElementType = parsed; |
|
ElementTypeName = null; |
|
return; |
|
} catch { } |
|
|
|
// it's the element type name |
|
strType = strType.Trim (); |
|
if (!strType.Equals (string.Empty)) |
|
ElementTypeName = strType; |
|
return; |
|
} |
|
|
|
|
|
Type managedType = type as Type; |
|
if (managedType != null) { |
|
CppType mapped = CppType.ForManagedType (managedType); |
|
Apply (mapped); |
|
return; |
|
} |
|
} |
|
|
|
// Applies the element type of the passed instance |
|
// and combines its modifiers into this instance. |
|
// Use when THIS instance may have attributes you want, |
|
// but want the element type of the passed instance. |
|
public void Apply (CppType type) |
|
{ |
|
ElementType = type.ElementType; |
|
ElementTypeName = type.ElementTypeName; |
|
if (Modifiers == null) Modifiers = new List<CppModifiers> (); |
|
|
|
List<CppModifiers> oldModifiers = Modifiers; |
|
Modifiers = type.Modifiers; |
|
Modifiers.AddRange (oldModifiers); |
|
} |
|
|
|
/* |
|
public override string ToString () |
|
{ |
|
StringBuilder cppTypeString = new StringBuilder (); |
|
|
|
cppTypeString.Append (Enum.GetName (typeof (CppTypes), ElementType).ToLower ()); |
|
|
|
if (ElementTypeName != null) |
|
cppTypeString.Append (" ").Append (ElementTypeName); |
|
|
|
foreach (var modifier in Modifiers) { |
|
string stringified; |
|
if (!Stringify.TryGetValue (modifier, out stringified)) |
|
stringified = Enum.GetName (typeof (CppModifiers), modifier).ToLower (); |
|
|
|
cppTypeString.Append (" ").Append (stringified); |
|
} |
|
|
|
return cppTypeString.ToString (); |
|
} |
|
*/ |
|
|
|
public static CppType ForManagedType (Type type) |
|
{ |
|
|
|
var mappedType = (from checkType in ManagedTypeMap |
|
where checkType (type).ElementType != CppTypes.Unknown |
|
select checkType (type)).FirstOrDefault (); |
|
|
|
if (mappedType.Modifiers == null) |
|
mappedType.Modifiers = new List<CppModifiers> (); |
|
|
|
return mappedType; |
|
} |
|
|
|
public static CppType ForDelegate (Type delType) |
|
{ |
|
if (!typeof (Delegate).IsAssignableFrom (delType)) |
|
throw new ArgumentException ("Argument must be a delegate type"); |
|
|
|
throw new NotImplementedException (); |
|
} |
|
|
|
|
|
|
|
public static implicit operator CppType (CppTypes type) { |
|
return new CppType (type); |
|
} |
|
} |
|
} |
|
|
|
|