Skip to content

Instantly share code, notes, and snippets.

@kevinmcmahon
Created August 7, 2010 02:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kevinmcmahon/512356 to your computer and use it in GitHub Desktop.
Save kevinmcmahon/512356 to your computer and use it in GitHub Desktop.
An Objective C brute force parser from #monotouch irc
// no claim or warranty is made on this code
// it is very brute force
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
namespace parseObjectiveC
{
public class SourceStream : Stream
{
Stream source;
public SourceStream(Stream source)
{
this.source = source;
}
public override bool CanRead { get { return true; } }
public override bool CanWrite { get { return false; } }
public override bool CanSeek { get { return false; } }
public override long Length { get { return source.Length; } }
public override long Position { get { throw new Exception(); } set { throw new Exception(); } }
public override void Flush() { throw new Exception(); }
public override int Read(byte[] buf, int offset, int count)
{
int n = 0;
for (int i = 0; i < count; i++)
{
int c = ReadByte();
if (c == -1)
return n;
buf[offset + n] = (byte)c;
n++;
}
return n;
}
public override long Seek(long p, SeekOrigin o)
{
throw new Exception();
}
public override void SetLength(long l)
{
throw new Exception();
}
public override void Write(byte[] b, int a, int c)
{
throw new Exception();
}
public override int ReadByte()
{
restart:
int n = source.ReadByte();
if (n == -1)
return -1;
if (n == '/')
{
int p = source.ReadByte();
if (p == '/')
{
while (true)
{
n = source.ReadByte();
if (n == -1)
return -1;
if (n == '\n')
return n;
}
}
else if (p == '*')
{
while (true)
{
n = source.ReadByte();
if (n == -1)
return -1;
while (n == '*')
{
n = source.ReadByte();
if (n == -1)
return -1;
if (n == '/')
goto restart;
}
}
}
source.Position = source.Position - 1;
return '/';
}
return n;
}
}
class TrivialParser
{
StreamWriter gencs;
StreamWriter enumcs;
StreamReader r;
ArrayList types = new ArrayList();
string currentInterface = "";
void ProcessProperty(string line)
{
bool ro = false;
string getter = null;
string assign = "";
line = CleanDeclaration(line);
if (line.Length == 0)
return;
int p = line.IndexOf(')');
var sub = line.Substring(0, p + 1);
if (sub.IndexOf("readonly") != -1)
{
ro = true;
}
int j = sub.IndexOf("getter=");
if (j != -1)
{
int k = sub.IndexOfAny(new char[] { ',', ')' }, j + 1);
//Console.WriteLine("j={0} k={1} str={2}", j, k, sub);
getter = sub.Substring(j + 7, k - (j + 7));
}
if (sub.IndexOf("assign") != -1)
assign = ", ArgumentSemantic.Assign";
if (sub.IndexOf("retain") != -1)
assign += ", ArgumentSemantic.Retain";
if (sub.IndexOf("copy") != -1)
assign += ", ArgumentSemantic.Copy";
if (sub.IndexOf("readonly") != -1)
assign += ", ArgumentSemantic.ReadOnly";
var type = new StringBuilder();
int i = p + 1;
for (; i < line.Length; i++)
{
char c = line[i];
if (!Char.IsWhiteSpace(c))
break;
}
for (; i < line.Length; i++)
{
char c = line[i];
if (Char.IsWhiteSpace(c))
break;
type.Append(c);
}
for (; i < line.Length; i++)
{
char c = line[i];
if (Char.IsWhiteSpace(c) || c == '*')
continue;
else
break;
}
var selector = new StringBuilder();
for (; i < line.Length; i++)
{
char c = line[i];
if (Char.IsWhiteSpace(c) || c == ';')
break;
selector.Append(c);
}
string retType = TranslateType(type.ToString()).Trim();
if (retType == "id")
retType = "IntPtr";
gencs.WriteLine("\t//{0}", line);
gencs.WriteLine("\t[Export (\"{0}\"{1})]", selector, assign);
gencs.WriteLine("\t{0} {1} {{ {2} {3} }}",
retType, selector.ToString().Substring(0, 1).ToUpper() + selector.ToString().Substring(1, selector.Length - 1),
getter != null ? "[Bind (\"" + getter + "\")] get;" : "get;",
ro ? "" : "set; ");
gencs.WriteLine();
}
string MakeSelector(string sig)
{
StringBuilder sb = new StringBuilder();
string[] split1 = sig.Split(':');
int numArguments = split1.Length - 1;
if (numArguments > 0)
{
string[] args = new string[numArguments];
//split[0] is the function name
//split[1] is the first argument plus the name of the 2nd argument if present
for (int a = 1; a < split1.Length; a++)
{
//(@"(?<=\().*?[nNsS].*?(?=\))",
string r = Regex.Replace(split1[a], "\\(.+\\)", "").Trim();
r = r.Replace(" ", " ").Replace("\t\t", " ").Replace(" ", " ").Replace(" ", " ");
string[] split11 = r.Split(new char[2] { ' ', '\t' });
if (split11.Length == 2)
{
if (string.IsNullOrEmpty(args[a - 1]) == true)
args[a - 1] = split11[0];
if (a >= numArguments)
continue;
args[a] = split11[1] + ":";
}
else if (split11.Length == 1 && a == 1)
args[a - 1] = split11[0] + ":";
}
string signature = split1[0] + ":";
for (int b = 1; b < args.Length; b++)
signature += args[b];
return signature.Replace(";", "").Trim();
}
else
return sig.Replace(";", "").Trim();
for (int i = 0; i < sig.Length; i++)
{
char c = sig[i];
if (c == ' ')
continue;
if (c == ';')
break;
else if (c == ':')
{
bool bSkipFirst = true;
sb.Append(c);
i++;
for (; i < sig.Length; i++)
{
c = sig[i];
if (c == ')')
{
if (bSkipFirst)
{
bSkipFirst = false;
continue;
}
for (++i; i < sig.Length; i++)
{
if (!Char.IsLetterOrDigit(sig[i]))
break;
}
break;
}
}
}
else
sb.Append(c);
}
return sb.ToString();
}
enum State
{
SkipToType,
EndOfType,
Parameter,
}
string MakeParameters(string sig)
{
//Console.WriteLine("[{0}]", sig);
int colon = sig.IndexOf(':');
if (colon == -1)
return "";
string line = "";
string[] s = sig.Replace(";", "").Split(':');
for (int x = 1; x < s.Length; x++)
{
int stringTextReplacement = 0;
string[] b = s[x].Split(')');
if (string.IsNullOrEmpty(line) == false)
line += ", ";
if (b.Length == 2)
{
string t = TranslateType(b[0].Replace("(", "").Replace(")", ""));
if (t == "id")
t = "IntPtr";
if (t == "void")
t = "IntPtr";
string[] c = b[1].Trim().Split(new char[2] { ' ', '\t' });
if (c[0] == "string" || c[0] == "event" || c[0] == "delegate" || c[0] == "object" || c[0] == "base")
c[0] = c[0] + (++stringTextReplacement).ToString();
line += t + " " + c[0];
}
else
line += b[0];
}
return line;
var sb = new StringBuilder();
State state = State.SkipToType;
for (int i = 0; i < sig.Length; i++)
{
char c = sig[i];
switch (state)
{
case State.SkipToType:
if (Char.IsWhiteSpace(c))
continue;
if (c == '(')
state = State.EndOfType;
break;
case State.EndOfType:
if (c == ')')
{
state = State.Parameter;
sb.Append(' ');
}
else
{
if (c != '*')
sb.Append(c);
}
break;
case State.Parameter:
if (Char.IsWhiteSpace(c))
{
state = State.SkipToType;
sb.Append(", ");
}
else
{
if (c != ';')
sb.Append(c);
}
break;
}
}
//Console.WriteLine ("{0}", sb);
return sb.ToString();
}
Regex rx = new Regex("__OSX_AVAILABLE_STARTING\\(.*\\)");
string CleanDeclaration(string line)
{
return rx.Replace(line, "");
}
string TranslateType(string retval)
{
bool bNeedsOut = false;
if (retval.Contains("**") == true)
bNeedsOut = true;
retval = retval.Replace("*", "");
retval = retval.Trim();
if (retval.Contains("<"))
{
string[] a = retval.Split('<');
retval = a[0].Trim();
}
switch (retval.Trim())
{
case "NSTextAlignment":
return "uint";
case "NSSize":
return "SizeF";
case "NSWindowDepth":
return "int";
case "IBAction":
return "void";
case "NSGlyph":
return "uint";
case "void *":
case "void*":
retval = "IntPtr";
break;
case "NSMutableArray*":
case "NSMutableArray *":
case "NSMutableArray":
case "NSArray*":
case "NSArray *":
case "NSArray":
retval = retval.Replace("*", "").Trim();
break;
case "NSMutableSet":
retval = "NSSet";
break;
case "NSMutableDictionary":
retval = "NSDictionary";
break;
case "NSString":
case "NSString*":
case "NSString *":
retval = "string";
break;
case "NSRect":
case "NSRect*":
case "NSRect *":
retval = "RectangleF";
break;
// case "id":
// retval = "NSObject";
// break;
case "BOOL":
retval = "bool";
break;
case "NSPoint":
case "NSPoint*":
case "NSPoint *":
retval = "PointF";
break;
case "NSURL":
retval = "NSUrl";
break;
case "CFTimeInterval":
retval = "double";
break;
case "CGRect":
retval = "System.Drawing.RectangleF";
break;
case "CGPoint":
retval = "System.Drawing.PointF";
break;
case "CGSize":
retval = "System.Drawing.SizeF";
break;
case "CGFloat":
case "GLfloat":
retval = "float";
break;
case "GLubyte":
retval = "byte";
break;
case "ccTime":
retval = "float";
break;
case "GLshort":
retval = "short";
break;
case "unsigned int":
case "NSUInteger":
case "GLenum":
case "GLuint":
retval = "uint";
break;
case "NSInteger":
retval = "int";
break;
case "unsigned char":
retval = "byte";
break;
case "SEL":
retval = "Selector";
break;
case "NSTimeInterval":
retval = "double";
break;
}
string typedefValue = "";
if (retval == "NSAnimationProgress")
Console.WriteLine("break");
if (typedefName.TryGetValue(retval.Replace("*", "").Trim(), out typedefValue))
return typedefValue;
if (bNeedsOut)
retval = "out " + retval;
return retval.Replace("*", "");
}
Dictionary<string, string> methodDefs = new Dictionary<string, string>();
Dictionary<string, string> csharpMethods = new Dictionary<string, string>();
int ifdefCount = 0;
void ProcessDeclaration(bool isProtocol, string line, bool is_optional)
{
//StringBuilder sb = interfaceDictionary[currentInterface];
StringBuilder sb = new StringBuilder();
line = CleanDeclaration(line);
if (line.Length == 0)
return;
if (line.Contains("deprecated") || line.Contains("NS_REQUIRES_NIL_TERMINATION"))
{
sb.AppendFormat("\t\t//{0}", line);
sb.AppendLine();
return;
}
if (isProtocol && !is_optional)
{
//sb.AppendFormat("\t\t[Abstract]");
//sb.AppendLine();
}
if (line.StartsWith("@property"))
{
ProcessProperty(line);
return;
}
if (line.StartsWith("typedef enum"))
{
ProcessEnum(line);
return;
}
//if (line.StartsWith("enum"))
//{
// ProcessEnum2(line);
// return;
//}
if (line.StartsWith("typedef struct"))
{
ProcessStruct(line);
return;
}
//Console.WriteLine("PROCESSING: {0}", line);
string addStatic = "";
if (line.StartsWith("+"))
addStatic = "Static, ";
int p, q;
p = line.IndexOf('(');
if (p == -1)
return;
q = line.IndexOf(')');
if (line.Contains("NSTableColumnNoResizing") == true)
q = q;
line = line.Replace(Environment.NewLine, " ");
//Console.WriteLine ("->{0}\np={1} q-p={2}", line, p, q-p);
string retval = line.Substring(p + 1, q - p - 1);
retval = TranslateType(retval);
string constructor = "";
if (retval == "id" || retval == currentInterface)
if (line.Contains("init"))
{
retval = "IntPtr";
constructor = "Constructor";
}
else
retval = currentInterface;
p = line.IndexOf(';');
string signature = line.Substring(q + 1, p - q);
string selector = MakeSelector(signature);
string parameters = MakeParameters(signature);
string unsupported = "";
if (parameters.Contains("const") || retval.Contains("const") || signature.Contains("...") ||
retval.Contains("unsigned short") || parameters.Contains("NSInteger (*") ||
parameters.Contains("NSComparisonResult (*") ||
retval.Contains("unsigned long long") ||
parameters.Contains("unsigned short") ||
currentCategory.Contains("Deprecated") ||
parameters.Contains("["))
unsupported = "//";
//Console.WriteLine("signature: {0}", signature);
//Console.WriteLine("selector: {0}", selector);
sb.AppendFormat("\t\t//{1}{2}{0}", line, unsupported,
(currentTarget != "" && currentInterface != currentTarget ? " from " + currentCategory : ""));
if (currentCategory.Contains("Deprecated"))
unsupported = "//";
sb.AppendLine();
selector = selector.Replace("DEPRECATED_IN_MAC_OS_X_VERSION_10_4_AND_LATER", "").Replace("AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED", "").Replace("AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER", "").Trim();
sb.AppendFormat("\t\t{2}[{1}{3}Export (\"{0}\")]", selector, addStatic, unsupported,
(isProtocol && !is_optional ? "Abstract, " : ""));
sb.AppendLine();
int f = selector.IndexOf(':');
string func = "";
if (f != -1)
func = selector.Substring(0, 1).ToUpper() + selector.Substring(1, f - 1);
else
func = selector.Substring(0, 1).ToUpper() + selector.Substring(1, selector.Length - 1);
if (func.Contains("URL"))
func = func.Replace("URL", "Url");
if (bInCategory)
{
//if (currentTarget != currentInterface)
{
string[] s1 = selector.Split(':');
if (s1.Length > 2)
func = s1[0].Substring(0, 1).ToUpper() + s1[0].Substring(1) +
s1[1].Substring(0, 1).ToUpper() + s1[1].Substring(1);
}
}
func = func.Replace("DEPRECATED_IN_MAC_OS_X_VERSION_10_4_AND_LATER", "").Replace("AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER","").Trim();
string[] p1 = parameters.Split(' ');
string p3 = "";
if (parameters != "")
{
for (int p2 = 0; p2 < p1.Length; p2 = p2 + 2)
p3 += p1[p2];
}
string csharpSig = currentInterface + func + p3;
if (csharpMethods.ContainsKey(csharpSig))
{
string[] s1 = selector.Split(':');
if (s1.Length > 2)
func = s1[0].Substring(0, 1).ToUpper() + s1[0].Substring(1) +
s1[1].Substring(0, 1).ToUpper() + s1[1].Substring(1);
else
Console.WriteLine("conflict");
}
else
csharpMethods.Add(csharpSig, "hi");
if (currentTarget != "")
{
string targetObj = currentCategory.Replace("NS", "");
targetObj = targetObj.Substring(0, 1).ToLower() + targetObj.Substring(1);
parameters = string.Format("[Target] {0} {2}{1}", currentTarget, parameters == "" ? "" : ", " + parameters,
targetObj);
}
if (parameters != "" || retval == "void")
sb.AppendFormat("\t\t{3}{0} {1} ({2});", retval, constructor == "" ? func : constructor, parameters, unsupported);
else
sb.AppendFormat("\t\t{4}{0} {1} {2} get; {3}", retval, func, "{", "}", unsupported);
sb.AppendLine();
sb.AppendLine();
string uniqueNmae = currentInterface + "-" + selector.ToLower() + "%$" + addStatic +
(string.IsNullOrEmpty(p3) ? "" : p3) + "$%" + retval;
if (methodDefs.ContainsKey(uniqueNmae) == false)
methodDefs.Add(uniqueNmae, sb.ToString());
else
Console.WriteLine("dup");
}
private struct ttt
{
int x;
}
private void ProcessStruct(string line)
{
string firstLine = "\tpublic struct {0}\n";
StringBuilder sb = new StringBuilder();
sb.Append("\t{\n");
while (true)
{
line = r.ReadLine();
if (line.Contains("}"))
{
line = line.Replace("}", "").Replace(";", "").Trim();
firstLine = string.Format(firstLine, line);
sb.Insert(0, firstLine);
sb.Append("\t}\n");
break;
}
else
{
line = line.Trim();
if (line == "" || line == "{")
continue;
sb.Append("\t\t" + line + "\n");
}
}
//enumcs.Write(sb);
}
int enumNotFoundCounter = 0;
private void ProcessEnum2(string line)
{
StringBuilder sb = new StringBuilder();
string enumName = "";
sb.AppendLine("\tpublic enum REPLACEME");
sb.AppendLine("\t{");
int endFound = 0;
List<string> enumArgs = new List<string>();
while (true)
{
if (line == null)
break;
if (line.Contains(";"))
endFound++;
if (endFound <= 1)
{
line = line.Replace("enum", "").Replace("{", "").Replace("}", "").Replace("}", "").Replace(";", "");
string[] args = line.Split(',');
foreach (string a in args)
{
string b = a.Trim();
if (b == "")
continue;
enumArgs.Add(b);
}
}
if (endFound == 1)
{
int peek = r.Peek();
if (peek == '@' || peek == 'e')
break;
if (peek == '#' || peek == '/')
{
line = r.ReadLine();
continue;
}
if (peek == 't')
{
line = r.ReadLine();
string[] args = line.Split(' ');
enumName = args[2].Replace(";", "").Trim();
break;
}
}
if (endFound > 1)
break;
line = r.ReadLine();
}
for (int i = 0; i < enumArgs.Count; i++)
{
string ar = enumArgs[i];
if (ar.StartsWith("#"))
sb.AppendLine("//" + ar);
else
sb.AppendLine("\t\t" + ar + (i < enumArgs.Count -1 ? "," : ""));
}
sb.AppendLine("\t}");
if (enumName == "")
enumName = string.Format("EnumNameNotFound{0}", enumNotFoundCounter++);
enumName += string.Format(" // in {0}", currentFileName);
sb = sb.Replace("REPLACEME", enumName);
enumcs.Write(sb);
}
private void ProcessEnum(string line)
{
string firstLine = "public enum {0}\n";
StringBuilder sb = new StringBuilder();
sb.Append("{\n");
while (true)
{
line = r.ReadLine();
if (line.Contains(";"))
{
line = line.Replace("}", "").Replace(";", "");
firstLine = string.Format(firstLine, line);
sb.Insert(0, firstLine);
sb.Append("}\n");
break;
}
else
{
line = line.Trim();
if (line == "")
continue;
sb.Append("\t" + line + "\n");
}
}
enumcs.Write(sb);
}
Dictionary<string, StringBuilder> interfaceDictionary = new Dictionary<string, StringBuilder>();
Dictionary<string, string> interfaceParent = new Dictionary<string, string>();
string lastClassName = "";
string currentCategory = "";
string currentTarget = "";
bool bInCategory = false;
void ProcessInterface(string iface)
{
var cols = iface.Split(':');
string line;
bInCategory = false;
currentCategory = "";
if (iface.Contains("NSWindow"))
Console.WriteLine("stop here");
string className = cols[0].Replace("@interface", "").Trim();
currentTarget = "";
if (className.Contains("("))
{
string[] t = className.Split('(');
//if (types.Contains(t[0].Trim()))
string maybeNewClassName = t[0];
// this code fixes delegate callbacks
//if (maybeNewClassName == "NSObject")
//{
// maybeNewClassName = t[1].Replace(")", "");
bInCategory = true;
//}
//else
{
className = maybeNewClassName;
currentTarget = maybeNewClassName.Trim();
currentCategory = t[1].Replace(")", "").Trim();
}
if (className == "")
className = currentFileName;
}
lastClassName = className;
types.Add(className);
currentInterface = className.Trim();
StringBuilder sb;
bool bNewInterface = false;
if (interfaceDictionary.TryGetValue(currentInterface, out sb) == false)
{
sb = new StringBuilder();
interfaceDictionary.Add(currentInterface, sb);
bNewInterface = true;
}
//Console.WriteLine("**** {0} ", iface);
if (cols.Length == 2)
{
string[] typeLine = cols[1].Trim().Split(new char[] { ' ', ',', '\t', '<' });
//sb.AppendFormat("\n\t[BaseType (typeof ({0}))]", typeLine[0]);
//sb.AppendLine();
if (string.IsNullOrEmpty(typeLine[0]) == false)
{
string curType = "";
if (interfaceParent.TryGetValue(currentInterface, out curType))
{
sb.AppendFormat("// {0} has multiple base types defined, '{1}' and '{2}'",
currentInterface, curType, typeLine[0]);
}
else
interfaceParent.Add(currentInterface, typeLine[0]);
}
}
//if (bNewInterface)
//{
// sb.AppendFormat("\tinterface {0} {{", className);
// sb.AppendLine();
// sb.AppendLine("APPKIT_EXTERN_ME");
//}
while ((line = r.ReadLine()) != null && !line.StartsWith("@end"))
{
string full = "";
//while ((line = r.ReadLine()) != null && !line.StartsWith("@end"))
{
if (line.Contains("#if") || line.Contains("#endif"))
{
methodDefs.Add(currentInterface + "-" + ifdefCount.ToString(), "//" + line + Environment.NewLine);
ifdefCount++;
continue;
}
full += line;
if (full.IndexOf(';') != -1 || full.IndexOf('}') != -1)
{
full = full.Replace('\n', ' ');
ProcessDeclaration(false, full, false);
full = "";
}
}
//break;
}
//sb.AppendLine("\t}");
}
void ProcessProtocol(string proto)
{
string[] d = proto.Split(new char[] { ' ', '<', '>' });
string line;
StringBuilder sb = new StringBuilder();
interfaceDictionary.Add(d[1], sb);
currentInterface = d[1];
types.Add(d[1]);
string curType = "";
if (interfaceParent.TryGetValue(currentInterface, out curType))
{
sb.AppendFormat("// {0} has multiple base types defined, '{1}' and '{2}'",
currentInterface, curType, d[3]);
}
else
interfaceParent.Add(currentInterface, d[3]);
//sb.AppendFormat("\t[BaseType (typeof ({0}))]", d[3]);
//sb.AppendLine();
sb.AppendLine("\t[Model]");
//sb.AppendFormat("\tinterface {0}", d[1]);
//sb.AppendLine();
//sb.AppendLine("\t{");
bool optional = false;
//while ((line = r.ReadLine()) != null && !line.StartsWith("@end"))
{
line = r.ReadLine();
if (line.StartsWith("@optional"))
optional = true;
string full = "";
while ((line = r.ReadLine()) != null && !line.StartsWith("@end"))
{
full += line;
if (full.IndexOf(';') != -1)
{
full = full.Replace('\n', ' ');
ProcessDeclaration(true, full, optional);
full = "";
}
}
}
}
internal TrivialParser() { }
internal string directoryName = "";
internal string currentFileName = "";
Dictionary<string, string> typedefName = new Dictionary<string, string>();
internal void Run(string[] args)
{
gencs = File.CreateText("gen.cs");
enumcs = File.CreateText("enum.cs");
gencs.WriteLine("using System;");
gencs.WriteLine("using MonoMac.ObjCRuntime;");
gencs.WriteLine("using MonoMac.CoreFoundation;");
gencs.WriteLine("\nnamespace {0}", "MonoMac.Foundation");
gencs.WriteLine("{");
enumcs.WriteLine("\nnamespace {0}", "MonoMac.Foundation");
enumcs.WriteLine("{");
if (args.Length == 1)
{
if (Directory.Exists(args[0]))
{
directoryName = args[0];
DirectoryInfo di = new DirectoryInfo(args[0]);
FileInfo[] files = di.GetFiles();
List<string> newArgs = new List<string>();
foreach (FileInfo f1 in files)
newArgs.Add(args[0] + System.IO.Path.DirectorySeparatorChar + f1.Name);
args = newArgs.ToArray();
}
}
foreach (string f in args)
{
using (var fs = File.OpenRead(f))
{
FileInfo fi = new FileInfo(f);
currentFileName = fi.Name.Replace("*.h", "");
r = new StreamReader(new SourceStream(fs));
interfaceDictionary.Add(f + "_externs", new StringBuilder());
string line;
while ((line = r.ReadLine()) != null)
{
if (line.StartsWith("#"))
continue;
if (line.Length == 0)
continue;
if (line.StartsWith("@class"))
continue;
if (line.StartsWith("@interface"))
ProcessInterface(line);
if (line.StartsWith("@protocol") && line.IndexOf("<") != -1)
ProcessProtocol(line);
if (line.StartsWith("typedef enum"))
{
ProcessEnum(line);
continue;
}
if (line.StartsWith("enum"))
{
ProcessEnum2(line);
continue;
}
if (line.StartsWith("typedef struct"))
{
if (line.Contains(";"))
{
string[] typeDefLine = line.Split(new char[2] { ' ', '\t' });
string t2 = typeDefLine[2].Trim();
string t3 = typeDefLine[3].Replace(";", "").Trim();
if (t3.Contains("*"))
t2 = "IntPtr";
t3 = t3.Replace("*", "").Trim();
typedefName.Add(t3, t2);
continue;
}
ProcessStruct(line);
continue;
}
if (line.StartsWith("typedef float"))
{
//not sure this should be done as most of these are enums
if (line.Contains(";"))
{
string[] typeDefLine = line.Split(new char[2] { ' ', '\t' });
typedefName.Add(typeDefLine[2].Replace(";","").Trim(), typeDefLine[1].Trim());
continue;
}
continue;
}
if (line.StartsWith("APPKIT_EXTERN") || line.StartsWith("FOUNDATION_EXPORT"))
{
ProcessAppKitExtern(line, f);
continue;
}
}
}
}
//foreach (string s in types)
//{
// Console.WriteLine("\t\ttypeof ({0}),", s);
//}
gencs.WriteLine("}");
enumcs.WriteLine("}");
gencs.Close();
enumcs.Close();
string fileName = "MonoMac";
if (directoryName != "")
fileName = directoryName + System.IO.Path.DirectorySeparatorChar + "MonoMac";
StreamWriter writeCS = File.CreateText(fileName + ".cs");
writeCS.WriteLine("using System;");
writeCS.WriteLine("using System.Drawing;");
writeCS.WriteLine("using MonoMac.Foundation;");
writeCS.WriteLine("using MonoMac.ObjCRuntime;");
writeCS.WriteLine("\nnamespace {0}", "MonoMac.AppKit");
writeCS.WriteLine("{");
foreach (string key in interfaceDictionary.Keys)
{
if (key.Contains("_externs"))
continue;
StringBuilder appKitExterns;
interfaceDictionary.TryGetValue(key + ".h_externs", out appKitExterns);
StringBuilder sb = interfaceDictionary[key];
string[] keys = new string[methodDefs.Keys.Count];
methodDefs.Keys.CopyTo(keys, 0);
for (int i = 0; i < keys.Length; i++)
{
string methodName = keys[i];
if (methodName.StartsWith(key + "-"))
{
string setMethod;
int pos = methodName.IndexOf("%$");
if (pos > 0)
{
string getMethodName = methodName.Substring(0, pos).Replace(key + "-", "");
getMethodName = "set" + getMethodName + ":";
int pos1 = methodName.IndexOf("$%") + 2; // start of retval
string retval = methodName.Substring(pos1);
getMethodName = key + "-" + getMethodName + "%$" + retval + "$%void";
if (methodDefs.TryGetValue(getMethodName, out setMethod))
{
string getMethod = methodDefs[methodName];
getMethod = getMethod.Replace("{ get; }", "{ get; set; }");
methodDefs[methodName] = getMethod;
methodDefs.Remove(getMethodName);
}
else
{
getMethodName = methodName.Substring(0, pos).Replace(key + "-", "");
string isMethodName = getMethodName;
getMethodName = "set" + getMethodName.Replace("is", "") + ":";
pos1 = methodName.IndexOf("$%") + 2; // start of retval
retval = methodName.Substring(pos1);
getMethodName = key + "-" + getMethodName + "%$" + retval + "$%void";
if (methodDefs.TryGetValue(getMethodName, out setMethod))
{
isMethodName = isMethodName.Replace("is", "");
isMethodName = isMethodName.Substring(0, 1).ToUpper() + isMethodName.Substring(1);
string getMethod = methodDefs[methodName];
getMethod = getMethod.Replace("{ get; }",
string.Format("{{ [Bind(\"{0}\")] get; set; }}", "is" + isMethodName));
getMethod = getMethod.Replace("Is" + isMethodName, isMethodName);
methodDefs[methodName] = getMethod;
methodDefs.Remove(getMethodName);
}
}
}
}
}
string parent = "";
if (key == "NSWindow")
Console.WriteLine("debug here");
if (interfaceParent.TryGetValue(key, out parent) == true)
{
sb.AppendFormat("\n\t[BaseType (typeof ({0}))]", parent);
sb.AppendLine();
}
sb.AppendFormat("\tinterface {0} {{", key.Replace(".h", ""));
sb.AppendLine();
sb.AppendLine("APPKIT_EXTERN_ME");
foreach (string methodName in methodDefs.Keys)
{
if (methodName.StartsWith(key + "-"))
{
sb.Append(methodDefs[methodName]);
}
}
sb.AppendLine("\t}");
//string fileName = key;
//if (key == "NSEntityMapping")
//{
// writeCS.WriteLine("using NSEntityMappingType = System.UInt32;");
//}
if (appKitExterns != null)
sb.Replace("APPKIT_EXTERN_ME", appKitExterns.ToString());
else
sb.Replace("APPKIT_EXTERN_ME", "");
writeCS.Write(sb.ToString());
}
writeCS.WriteLine("}");
writeCS.Close();
}
StringBuilder appKitExterns;
private void ProcessAppKitExtern(string line, string fileName)
{
StringBuilder appKitExterns = interfaceDictionary[fileName + "_externs"];
string[] words = line.Replace("*", "").Replace(";", "").Replace("\t", "").Replace(" ", " ").Replace(" ", " ").Replace(" ", " ").Split(' ');
if ((words[0] != "APPKIT_EXTERN" || words[0] != "FOUNDATION_EXPORT") && words[1] != "NSString")
{
appKitExterns.AppendFormat("\t\tTODO: {0}", line);
appKitExterns.AppendLine();
return;
}
string word = "";
if (words[0] == "APPKIT_EXTERN")
word = words[2];
else
word = words[3];
// format is [Field('objectCName')] TYPE NAME { get; }
string cSharpName = word.Substring(0, 1).ToUpper() + word.Substring(1);
appKitExterns.AppendFormat("\t\t[Field(\"{0}\")]", word);
appKitExterns.AppendLine();
appKitExterns.AppendFormat("\t\t{0} {1} {2} get; {3}", "NSString", cSharpName, "{", "}");
appKitExterns.AppendLine();
appKitExterns.AppendLine();
}
public static void Main(string[] args)
{
var tp = new TrivialParser();
tp.Run(args);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment