private void SetAttribute(Method targetMethod, Type type, string val, string objName, string fieldName) { if (type == typeof(string)) targetMethod.AddLine(String.Format("{0}.{1} = \"{2}\";", objName, fieldName, val)); else if (type == typeof(bool)) targetMethod.AddLine(String.Format("{0}.{1} = {2};", objName, fieldName, val.ToLowerInvariant())); else if (type.IsPrimitive) // a cast might be necessary (e.g. float) targetMethod.AddLine(String.Format("{0}.{1} = ({2}){3};", objName, fieldName, GetPlainTypeName(type), val)); else if (type.IsEnum) targetMethod.AddLine(String.Format("{0}.{1} = {2}.{3};", objName, fieldName, type.Name, val)); else if (type.IsSubclassOf(typeof(ZComponent))) // simple assignment to a named component targetMethod.AddLine(String.Format("{0}.{1} = {2};", objName, fieldName, val)); else if (type == typeof(Vector3) || type == typeof(Vector2)) // cast all constuctor parameters to float { string commaList = string.Join(", ", val.Split(' ').Select(it => "(float)" + it).ToArray()); targetMethod.AddLine(String.Format("{0}.{1} = new {2}({3});", objName, fieldName, type.Name, commaList)); } else if (type == typeof(Color)) // make a Color4 instead with float parameters { string commaList = string.Join(", ", val.Split(' ').Select(it => "(float)" + it).ToArray()); targetMethod.AddLine(String.Format("{0}.{1} = new {2}({3});", objName, fieldName, "Color4", commaList)); } else { string commaList = string.Join(", ", val.Split(' ')); targetMethod.AddLine(String.Format("{0}.{1} = new {2}({3});", objName, fieldName, type.Name, commaList)); } }
private void ProcessNode(Class targetClass, Variable parent, string targetList, XmlNode xmlNode) { if (xmlNode == null) return; if (standalone == false) // generate GUID for each xmlnode if (nodeMap.ContainsKey(xmlNode) == false) nodeMap[xmlNode] = Guid.NewGuid().ToString(); //Console.WriteLine("Processing: {0}", xmlNode.Name); Variable obj = parent; string list = null; if (xmlNode.Name == "ZApplication") { if (fullBuild) ParseAttributes(ns.mainClass, parent, xmlNode); } else { // Check if this node is a List property of the parent //FieldInfo fi = parent.type.GetField(xmlNode.Name, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo fi = CodeGenerator.GetField(parent.type, xmlNode.Name); //if (pi != null) Console.WriteLine(" Parent property found: {0}", pi.PropertyType.Name); if (fi != null && typeof(IList).IsAssignableFrom(fi.FieldType)) { //Console.WriteLine("List found: {0}", xmlNode.Name); list = fi.Name; } // Check if this node is an event of the parent else if (fi != null && typeof(Delegate).IsAssignableFrom(fi.FieldType)) { Type type = fi.FieldType; string currentGuid = ""; if (standalone == false) nodeMap.TryGetValue(xmlNode, out currentGuid); string methodName = targetClass.GetNextMethodName(); //bool isStatic = targetClass.baseClass.StartsWith("Prototype"); string header = GetMethodHeader(methodName, type, false); Method met = new Method(header); targetClass.methods.Add(met); //if (isStatic) //{ //Automatically cast the caller to the type of the Model class //met.AddLine(String.Format("{0} model = caller as {0};", targetClass.name)); //} met.AddLine(xmlNode.InnerText); // BIND THE CALLBACK if (targetClass.type == typeof(Model)) targetClass.init.AddLine(String.Format("{0} += {1};", fi.Name, methodName)); // init method points to BindCallbacks() if (fullBuild) { // Add the generated method as an event handler if (targetClass.type == typeof(ZApplication)) ns.mainClass.init.AddLine(String.Format("{0}.{1} += {2};", parent.name, fi.Name, methodName)); if (standalone == false) // Create a ZEvent (always in CustomGame) { string varName = ns.mainClass.GetNextObjectName(); ns.mainClass.init.AddLine(""); ns.mainClass.init.AddLine(String.Format("var {0} = new ZEvent({1}, \"{2}\");", varName, parent.name, fi.Name)); // assign a GUID to the ZEvent ns.mainClass.init.AddLine(String.Format("{0}.GUID = \"{1}\";", varName, currentGuid)); // store the text of the method (for editing purposes) string escaped = xmlNode.InnerText.Replace("\"", "\"\""); // escape inner strings " -> "" ns.mainClass.init.AddLine(String.Format("{0}.Text = @\"{1}\";", varName, escaped)); } } else { if (targetClass.type != typeof(Model)) { string exprName = ns.mainClass.GetNextObjectName(); ns.mainClass.restore.AddLine(""); ns.mainClass.restore.AddLine(String.Format("ZEvent {0} = oldApp.FindEvent(\"{1}\");", exprName, currentGuid)); ns.mainClass.restore.AddLine(String.Format("CodeGenerator.RestoreEvent({0}, {1}, \"{2}\");", exprName, targetClass.variable, methodName)); } } return; //return here, so no TreeNode will be created for the CodeLike component } // Check if this node is a CodeLike property of the parent else if (fi != null && typeof(CodeLike).IsAssignableFrom(fi.FieldType)) { Type type = fi.FieldType; if (type == typeof(CustomCodeDefinition)) // handle custom code definitions { targetClass.definitions.Add(xmlNode.InnerText); } else if (type == typeof(VirtualMethod)) { string methodName = targetClass.GetNextMethodName(); object[] attributes = fi.GetCustomAttributes(typeof(MethodSignature), false); if (attributes.Length == 1 && attributes[0] is MethodSignature) { MethodSignature ms = attributes[0] as MethodSignature; Method met = new Method(ms.Signature); targetClass.methods.Add(met); met.AddLine(xmlNode.InnerText); } else { Console.WriteLine("Missing MethodSignature attribute on VirtualMethod: {0}.{0}", parent.name, xmlNode.Name); return; } } // if (standalone == false && fullBuild == true) // assign the GUIDs to the CodeLike components // { // ns.mainClass.init.AddLine(String.Format("{0}.{1}.GUID = \"{2}\";", parent.name, fi.Name, currentGuid)); // // } // if not shader if (standalone == false && fullBuild == true) // no need for the code text in a standalone build { string escaped = xmlNode.InnerText.Replace("\"", "\"\""); // escape inner strings " -> "" ns.mainClass.init.AddLine(String.Format("{0}.{1}.Text = @\"{2}\";", parent.name, fi.Name, escaped)); } //Console.WriteLine("Code Text:\n{0}", code.Text); return; //return here, so no TreeNode will be created for the CodeLike component } else { obj = InitComponent(ns.mainClass, xmlNode.Name, xmlNode, parent, targetList); if (obj == null) { Console.WriteLine("SKIPPING subtree - Cannot find type: {0}", xmlNode.Name); return; } if (xmlNode.Name == "Model") { string modelName = obj.name + "Model"; Class model = new Class(typeof(Model), modelName, "Model", obj.name, false); //String.Format("Prototype<{0}>", modelName) model.constructor = new Method("public " + modelName + "(ZComponent parent): base(parent)"); var staticApp = new StaticVariable(typeof(ZApplication), "CustomGame", "App", false); model.memberVars.Add(staticApp); ns.mainClass.staticRef.AddLine(String.Format("{0}.App = this;", modelName)); //model.constructor.AddLine("InitializeComponents();"); model.init = new Method("public override void BindCallbacks()"); //model.init.AddLine("CreateNamedComponents();"); //model.createNamed = new Method("public void CreateNamedComponents()"); ns.helperClasses.Add(model); targetClass = model; } } } foreach (XmlNode childNode in xmlNode.ChildNodes) { if (childNode.NodeType == XmlNodeType.Element) { ProcessNode(targetClass, obj, list, childNode); } } }
public string GenerateCodeFromXml(XmlDocument xml, bool standalone, bool fullBuild, Dictionary<XmlNode, string> nodeMap) { XmlNode rootElement = xml.DocumentElement; if (standalone && fullBuild == false) fullBuild = true; // no incremental build for standalone this.standalone = standalone; this.fullBuild = fullBuild; if (standalone == false) // no need for XmlNode->GUID mapping at standalone builds { if (nodeMap == null) this.nodeMap = new Dictionary<XmlNode, string>(); else this.nodeMap = nodeMap; } cu = new CompileUnit(); cu.AddUsing("using System;"); cu.AddUsing("using System.Collections;"); cu.AddUsing("using System.Collections.Generic;"); cu.AddUsing("using System.Text;"); cu.AddUsing("using System.Drawing;"); cu.AddUsing("using OpenTK;"); cu.AddUsing("using OpenTK.Graphics;"); cu.AddUsing("using OpenTK.Graphics.OpenGL;"); cu.AddUsing("using ZGE.Components;"); cu.AddUsing("using Gwen.Control;"); //if (standalone == false) // cu.AddUsing("using System.ComponentModel"); ns = new Namespace("ZGE"); cu.namespaces.Add(ns); Class main = new Class(typeof(ZApplication), "CustomGame", "ZApplication", "this", true); ns.mainClass = main; main.constructor = new Method("public CustomGame()"); main.staticRef = new Method("public override void SetStaticReferences()"); if (fullBuild) { //main.constructor.AddLine("if (createAll) InitializeComponents();"); main.init = new Method("public override void InitializeComponents()"); main.init.AddLine("CreateNamedComponents();"); main.createNamed = new Method("public override void CreateNamedComponents()"); } else { main.restore = new Method("public void RestoreComponents(ZApplication oldApp)"); main.restore.AddLine("CodeGenerator.Restore(this, oldApp);"); } types = Factory.GetTypesFromNamespace(Assembly.GetAssembly(typeof(ZApplication)), "ZGE.Components"); types.AddRange(Factory.GetTypesFromNamespace(Assembly.GetAssembly(typeof(ZApplication)), "Gwen.Control")); Variable dummy = new Variable(typeof(ZApplication), "CustomGame", "this", false); if (rootElement != null) ProcessNode(main, dummy, null, rootElement); if (standalone) { Method mm = new Method("[STAThread]\npublic static void Main()"); main.methods.Add(mm); mm.AddLine("ZApplication app = new CustomGame();"); mm.AddLine("using (Standalone game = new Standalone(app))"); mm.AddLine("{"); mm.AddLine(" game.Run(app.UpdateFrequency);"); mm.AddLine("}"); } string code = cu.GetFullCode(); // Save the file for debugging using (StreamWriter writer = new StreamWriter("DynamicGame.cs", false)) { writer.Write(code); } return code; }