aboutsummaryrefslogtreecommitdiffstatsci
path: root/src/Interface.cs
diff options
context:
space:
mode:
authorjpbruyere <jp.bruyere@hotmail.com>2015-09-29 10:07:13 +0200
committerjpbruyere <jp.bruyere@hotmail.com>2015-09-29 10:07:13 +0200
commit8dcac53903c37878d54d59066eb7f80da1d62bc7 (patch)
tree577390ded6146578e0c8b0efae5da549c99c5cec /src/Interface.cs
parentbc12a8d14fd559918c1ed97ed8f2cc5c8c9043c7 (diff)
generate c# with codedom for GOML
MonoDevelop.GOLib addin
Diffstat (limited to 'src/Interface.cs')
-rw-r--r--src/Interface.cs378
1 files changed, 329 insertions, 49 deletions
diff --git a/src/Interface.cs b/src/Interface.cs
index f988a17a..7712b577 100644
--- a/src/Interface.cs
+++ b/src/Interface.cs
@@ -26,6 +26,10 @@ using System.Diagnostics;
using System.Collections.Generic;
using System.Xml;
using System.Linq;
+using System.Reflection.Emit;
+using System.CodeDom;
+using Microsoft.CSharp;
+using System.CodeDom.Compiler;
namespace go
{
@@ -43,25 +47,27 @@ namespace go
/// <summary>
/// Graphic objects References use in dynamic delegates for binding
/// </summary>
- public static List<object> References = new List<object>();
- public static Queue<int> FreeRefIndices = new Queue<int>();
- public static void Unreference(Object o)
+ public static List<object> References = new List<object> ();
+ public static Queue<int> FreeRefIndices = new Queue<int> ();
+
+ public static void Unreference (Object o)
{
int idxt = Interface.References.IndexOf (o);
if (idxt < 0)
return;
- References[idxt] = null;
+ References [idxt] = null;
FreeRefIndices.Enqueue (idxt);
}
+
/// <summary> register target object reference in an array for binding CIL </summary>
- public static int Reference(object o)
+ public static int Reference (object o)
{
- int dstIdx = Interface.References.IndexOf(o);
+ int dstIdx = Interface.References.IndexOf (o);
if (dstIdx < 0) {
if (FreeRefIndices.Count == 0) {
- dstIdx = Interface.References.Count();
+ dstIdx = Interface.References.Count ();
Interface.References.Add (o);
} else {
dstIdx = FreeRefIndices.Dequeue ();
@@ -70,40 +76,40 @@ namespace go
}
return dstIdx;
}
- public static LayoutingQueue LayoutingQueue = new LayoutingQueue();
+
+ public static LayoutingQueue LayoutingQueue = new LayoutingQueue ();
#region Load/Save
- internal static Stack<List<DynAttribute>> GOMLResolutionStack = new Stack<List<DynAttribute>>();
- internal static List<DynAttribute> GOMLResolver
- {
- get { return GOMLResolutionStack.Peek ();}
+ internal static Stack<List<DynAttribute>> GOMLResolutionStack = new Stack<List<DynAttribute>> ();
+
+ internal static List<DynAttribute> GOMLResolver {
+ get { return GOMLResolutionStack.Peek (); }
}
//internal static List<DynAttribute> Bindings;
- public static void Save<T>(string file, T graphicObject)
+ public static void Save<T> (string file, T graphicObject)
{
- XmlSerializerNamespaces xn = new XmlSerializerNamespaces();
- xn.Add("", "");
- XmlSerializer xs = new XmlSerializer(typeof(T));
+ XmlSerializerNamespaces xn = new XmlSerializerNamespaces ();
+ xn.Add ("", "");
+ XmlSerializer xs = new XmlSerializer (typeof(T));
- xs = new XmlSerializer(typeof(T));
- using (Stream s = new FileStream(file, FileMode.Create))
- {
- xs.Serialize(s, graphicObject, xn);
+ xs = new XmlSerializer (typeof(T));
+ using (Stream s = new FileStream (file, FileMode.Create)) {
+ xs.Serialize (s, graphicObject, xn);
}
}
- public static Stream GetStreamFromPath(string path)
+ public static Stream GetStreamFromPath (string path)
{
Stream stream = null;
if (path.StartsWith ("#")) {
string resId = path.Substring (1);
- stream = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream(resId);
+ stream = System.Reflection.Assembly.GetEntryAssembly ().GetManifestResourceStream (resId);
if (stream == null)//try to find ressource in golib assembly
- stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resId);
+ stream = System.Reflection.Assembly.GetExecutingAssembly ().GetManifestResourceStream (resId);
if (stream == null)
throw new Exception ("Resource not found: " + path);
} else {
@@ -113,38 +119,312 @@ namespace go
}
return stream;
}
+
/// <summary>
/// Pre-read first node to set GraphicObject class for loading
/// and reset stream position to 0
/// </summary>
- public static Type GetTopContainerOfGOMLStream(Stream stream){
+ public static Type GetTopContainerOfGOMLStream (Stream stream)
+ {
string root = "Object";
- stream.Seek(0,SeekOrigin.Begin);
+ string ClassName = "";
+ stream.Seek (0, SeekOrigin.Begin);
using (XmlReader reader = XmlReader.Create (stream)) {
- while (reader.Read()) {
+ while (reader.Read ()) {
// first element is the root element
if (reader.NodeType == XmlNodeType.Element) {
root = reader.Name;
+ ClassName = reader.GetAttribute ("Class");
+ if (!string.IsNullOrEmpty (ClassName))
+ break;
+ if (CurrentGOMLPath.StartsWith ("#"))
+ ClassName = Path.GetFileNameWithoutExtension (CurrentGOMLPath.Substring (1));
+ else
+ ClassName = Path.GetFileNameWithoutExtension (CurrentGOMLPath);
break;
}
}
}
- Type t = Type.GetType("go." + root);
- //var go = Activator.CreateInstance(t);
- stream.Seek(0,SeekOrigin.Begin);
+ Type t = Type.GetType ("go." + root);
+
+ //t = CreateDynamicType (ClassName, t);
+
+ stream.Seek (0, SeekOrigin.Begin);
return t;
}
+
+
+
+
+ static AssemblyBuilder assemblyBuilder;
+ static ModuleBuilder moduleBuilder;
+
+ public static void InitDynamicAssembly ()
+ {
+ AssemblyName an = new AssemblyName ("DynamicGraphicObjects");
+ assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.RunAndSave);
+ moduleBuilder = assemblyBuilder.DefineDynamicModule ("MainModule");
+ }
+
+ public static void TerminateDynamicAssembly ()
+ {
+ }
+
+ public static CodeCompileUnit CompileUnit;
+ public static CodeTypeDeclaration GOTypeDecl;
+
+ public static CodeTypeDeclaration GenCodeType (string newTypeName, Type baseType)
+ {
+ CompileUnit = new CodeCompileUnit ();
+ CodeNamespace cns = null;
+
+ int idxLastDot = newTypeName.LastIndexOf ('.');
+ string typeName = newTypeName;
+ if (idxLastDot < 0)
+ cns = new CodeNamespace ("go");
+ else {
+ typeName = newTypeName.Substring (idxLastDot + 1);
+ cns = new CodeNamespace (newTypeName.Substring (0, idxLastDot));
+ }
+ CompileUnit.Namespaces.Add (new CodeNamespace ());
+ CompileUnit.Namespaces.Add (cns);
+ CompileUnit.Namespaces [0].Imports.Add (new CodeNamespaceImport ("System"));
+ CodeTypeDeclaration GOTypeDecl = new CodeTypeDeclaration (typeName);
+ GOTypeDecl.IsClass = true;
+ GOTypeDecl.IsPartial = true;
+ GOTypeDecl.TypeAttributes |= TypeAttributes.Public;
+ GOTypeDecl.BaseTypes.Add (baseType.Name);
+ cns.Types.Add (GOTypeDecl);
+ return GOTypeDecl;
+ }
+
+ static void GenNewClassFromGOML (string path)
+ {
+ string root = null;
+ string newClassName = "";
+
+ using (Stream stream = GetStreamFromPath (path)) {
+ using (XmlReader reader = XmlReader.Create (stream)) {
+ CodeTypeDeclaration GOTypeDecl = null;
+ CodeConstructor constructor = null;
+
+ CodeExpression curRef = null;
+ Type curType = null;
+ Stack<CodeExpression> curRefStack = new Stack<CodeExpression> ();
+ Stack<Type> curTypeStack = new Stack<Type> ();
+
+ int arrayIndex = -1;
+ int localVarCpt = 0;
+
+ while (reader.Read ()) {
+ switch (reader.NodeType) {
+ case XmlNodeType.Element:
+ if (string.IsNullOrEmpty (root)) {
+ //create the new base class
+ // first element is the root element
+ root = reader.Name;
+ newClassName = reader.GetAttribute ("Class");
+ if (string.IsNullOrEmpty (newClassName)) {
+ if (path.StartsWith ("#"))
+ newClassName = Path.GetFileNameWithoutExtension (path.Substring (1));
+ else
+ newClassName = Path.GetFileNameWithoutExtension (path);
+ }
+ curType = Type.GetType ("go." + root);
+
+ GOTypeDecl = GenCodeType (newClassName, curType);
+ // Declares a constructor.
+ constructor = new CodeConstructor ();
+ constructor.Attributes = MemberAttributes.Public;
+ GOTypeDecl.Members.Add (constructor);
+
+ curRef = new CodeThisReferenceExpression ();
+ } else if (reader.Name == "Template") {
+ }else{
+ Type childType = Type.GetType ("go." + reader.Name);
+ localVarCpt++;
+ string localVarName = childType.Name + localVarCpt;
+ constructor.Statements.Add (
+ new CodeVariableDeclarationStatement (
+ childType,
+ localVarName,
+ new CodeObjectCreateExpression (childType)
+ )
+ );
+ if (curType == typeof(go.Container) || curType.IsSubclassOf (typeof(go.Container))) {
+ constructor.Statements.Add (
+ new CodeMethodInvokeExpression (
+ curRef,
+ "SetChild",
+ new CodeVariableReferenceExpression (localVarName)
+ )
+ );
+ } else if (curType == typeof(go.Group) || curType.IsSubclassOf (typeof(go.Group))) {
+ constructor.Statements.Add (
+ new CodeMethodInvokeExpression (curRef, "addChild",
+ new CodeVariableReferenceExpression (localVarName)
+ )
+ );
+ }
+ curTypeStack.Push (curType);
+ curRefStack.Push (curRef);
+ curRef = new CodeVariableReferenceExpression (localVarName);
+ curType = childType;
+ }
+ while (reader.MoveToNextAttribute ()) {
+ string attName = reader.Name;
+ string attValue = reader.Value;
+
+ if (string.IsNullOrEmpty (attValue))
+ continue;
+
+ MemberInfo mi = curType.GetMember (attName).FirstOrDefault ();
+ if (mi == null) {
+ Debug.WriteLine (Interface.CurrentGOMLPath + "=>GOML: Unknown attribute in " + curType.ToString () + " : " + attName);
+ continue;
+ }
+ if (mi.MemberType == MemberTypes.Event) {
+ //TODO: handle events
+ continue;
+ }
+ if (mi.MemberType == MemberTypes.Property) {
+ PropertyInfo pi = mi as PropertyInfo;
+
+ if (pi.GetSetMethod () == null) {
+ Debug.WriteLine (Interface.CurrentGOMLPath + "=>GOML: Read only property in " + curType.ToString () + " : " + attName);
+ continue;
+ }
+
+ if (attValue.StartsWith("{")) {
+ if (Interface.DontResoveGOML)
+ continue;
+ //binding
+ if (!attValue.EndsWith("}"))
+ throw new Exception (string.Format("GOML:Malformed binding: {0}", attValue));
+
+ string strBinding = attValue.Substring (1, attValue.Length - 2);
+
+ continue;
+ }
+
+ CodeExpression val = null;
+ if (pi.PropertyType == typeof(string)) {
+ val = new CodePrimitiveExpression (attValue);
+ } else if (pi.PropertyType.IsPrimitive) {
+ MethodInfo me = pi.PropertyType.GetMethod ("Parse", new Type[] { typeof(string) });
+ val = new CodePrimitiveExpression (
+ me.Invoke (null, new string[] { attValue }));
+ } else if (pi.PropertyType.IsEnum || (pi.PropertyType == typeof(go.Color) && Char.IsLetter (attValue [0]))) {
+ val = new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (pi.PropertyType), attValue);
+ }else if (pi.PropertyType == typeof(go.Color) || pi.PropertyType == typeof(go.Font)) {
+ val = new CodeCastExpression(pi.PropertyType,
+ new CodeMethodInvokeExpression (
+ new CodeTypeReferenceExpression (pi.PropertyType),
+ "Parse",
+ new CodePrimitiveExpression (attValue)
+ )
+ );
+ } else {
+ val = new CodeMethodInvokeExpression (new CodeTypeReferenceExpression (pi.PropertyType),
+ "Parse", new CodePrimitiveExpression (attValue));
+
+ }
+ constructor.Statements.Add (
+ new CodeAssignStatement (
+ new CodePropertyReferenceExpression (curRef, attName),
+ val
+ )
+ );
+ }
+ }
+ reader.MoveToElement ();
+ if (reader.IsEmptyElement) {
+ curType = curTypeStack.Pop ();
+ curRef = curRefStack.Pop ();
+ }
+ break;
+ case XmlNodeType.EndElement:
+ if (curTypeStack.Count < 1)//GOML last closing tag
+ break;
+ curType = curTypeStack.Pop ();
+ curRef = curRefStack.Pop ();
+ if (curType.IsSubclassOf (typeof(go.Container)))
+ arrayIndex = -1;
+ break;
+ }
+ }
+ }
+ }
+
+
+
+
+ GenerateCSharpCode (CompileUnit, path + ".cs");
+ }
+
+ static void GenerateCSharpCode (CodeCompileUnit codeBase, string file)
+ {
+ CodeDomProvider codeDomProvider = new CSharpCodeProvider ();
+ //On définit les options de génération de code
+ CodeGeneratorOptions options = new CodeGeneratorOptions ();
+ //On demande a ce que le code généré soit dans le même ordre que le code inséré
+ options.VerbatimOrder = false;
+ //options.BracingStyle = "C";
+ //options.BracingStyle = "C";
+ options.ElseOnClosing = true;
+ options.BlankLinesBetweenMembers = false;
+
+ using (IndentedTextWriter itw = new IndentedTextWriter (new StreamWriter (file, false), "\t")) {
+ //On demande la génération proprement dite
+ codeDomProvider.GenerateCodeFromCompileUnit (codeBase, itw, options);
+ itw.Flush ();
+ }
+ Console.WriteLine ("C# code generated: " + file);
+ }
+
+ public static Type CreateDynamicType (string newTypeName, Type baseType)
+ {
+ if (moduleBuilder == null)
+ InitDynamicAssembly ();
+ TypeBuilder tb = moduleBuilder.DefineType (newTypeName
+ , TypeAttributes.Public |
+ TypeAttributes.Class |
+ TypeAttributes.AutoClass |
+ TypeAttributes.AnsiClass |
+ TypeAttributes.BeforeFieldInit |
+ TypeAttributes.AutoLayout
+ , baseType);
+
+ ConstructorBuilder constructor = tb.DefineDefaultConstructor (MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
+
+ ConstructorInfo cn = typeof(XmlRootAttribute).GetConstructor (new Type[] { typeof(string) });
+ CustomAttributeBuilder cab = new CustomAttributeBuilder (cn, new object[] { baseType.Name });
+
+ tb.SetCustomAttribute (cab);
+
+
+
+
+ Type tmp = tb.CreateType ();
+ //assemblyBuilder.Save ("newAssembly.dll",PortableExecutableKinds.ILOnly,ImageFileMachine.I386);
+ return tmp;
+ }
+
public static string CurrentGOMLPath;
- public static GraphicObject Load(string path, object hostClass = null, bool resolveGOML = true)
- {
+
+ public static GraphicObject Load (string path, object hostClass = null, bool resolveGOML = true)
+ {
+// GenNewClassFromGOML (path);
+// return null;
CurrentGOMLPath = path;
using (Stream stream = GetStreamFromPath (path)) {
return Load(stream, GetTopContainerOfGOMLStream(stream), hostClass, resolveGOML);
}
CurrentGOMLPath = "";
}
- public static GraphicObject Load(Stream stream, Type type, object hostClass = null, bool resolve = true)
+
+ public static GraphicObject Load (Stream stream, Type type, object hostClass = null, bool resolve = true)
{
#if DEBUG_LOAD_TIME
Stopwatch loadingTime = new Stopwatch ();
@@ -154,16 +434,16 @@ namespace go
GraphicObject result;
- XmlSerializerNamespaces xn = new XmlSerializerNamespaces();
- xn.Add("", "");
+ XmlSerializerNamespaces xn = new XmlSerializerNamespaces ();
+ xn.Add ("", "");
//prevent unused ref in References created by xmlSerializer
Interface.DontResoveGOML = true;
- XmlSerializer xs = new XmlSerializer(type);
+ XmlSerializer xs = new XmlSerializer (type);
Interface.DontResoveGOML = false;
- GOMLResolutionStack.Push(new List<DynAttribute>());
+ GOMLResolutionStack.Push (new List<DynAttribute> ());
- result = (GraphicObject)xs.Deserialize(stream);
- result.DataSource = hostClass;
+ result = (GraphicObject)xs.Deserialize (stream);
+ //result.DataSource = hostClass;
if (hostClass == null) {
GOMLResolutionStack.Pop ();
@@ -175,24 +455,23 @@ namespace go
#if DEBUG_LOAD_TIME
loadingTime.Stop ();
- Debug.WriteLine("GOML Loading ({2}): {0} ticks \t, {1} ms",
- loadingTime.ElapsedTicks,
- loadingTime.ElapsedMilliseconds,
- CurrentGOMLPath);
+ Debug.WriteLine ("GOML Loading ({2}): {0} ticks \t, {1} ms",
+ loadingTime.ElapsedTicks,
+ loadingTime.ElapsedMilliseconds,
+ CurrentGOMLPath);
#endif
return result;
}
- public static void resolveGOML(object hostClass)
+ public static void resolveGOML (object hostClass)
{
- foreach (DynAttribute es in GOMLResolver)
- {
+ foreach (DynAttribute es in GOMLResolver) {
// if (string.IsNullOrEmpty(es.Value))
// continue;
Type dstType = es.Source.GetType ();
- MemberInfo miTarget = dstType.GetMember (es.MemberName).FirstOrDefault();
+ MemberInfo miTarget = dstType.GetMember (es.MemberName).FirstOrDefault ();
if (miTarget == null) {
Debug.WriteLine ("'{0}' Member not found in '{1}' type.", es.MemberName, dstType.ToString ());
@@ -210,7 +489,7 @@ namespace go
if (mi == null) {
//TODO: hack to have it work, hostClass and dataSource should be clearly separated
mi = OpenTKGameWindow.currentWindow.GetType ().GetMethod (es.Value, BindingFlags.NonPublic | BindingFlags.Public
- | BindingFlags.Instance);
+ | BindingFlags.Instance);
if (mi == null) {
Debug.WriteLine ("Handler Method not found: " + es.Value);
continue;
@@ -223,15 +502,16 @@ namespace go
Delegate del = Delegate.CreateDelegate (ei.EventHandlerType, effectiveHostClass, mi);
- addHandler.Invoke(es.Source, new object[] {del});
+ addHandler.Invoke (es.Source, new object[] { del });
}
} else {
CompilerServices.ResolveBinding (es, hostClass);
}
}
- GOMLResolutionStack.Pop();
+ GOMLResolutionStack.Pop ();
}
+
#endregion
}
}