167 lines
5.1 KiB
C#

// Copyright (C) 2025 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Reflection;
using System.Text;
using MBS.Core.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Mocha.Core;
using Mocha.Core.Oop;
using Mocha.Modeling.CodeGeneration;
using Mocha.Modeling.CodeGeneration.Generators;
namespace Mocha.Modeling;
public class OmsObjectFactory<TOmsClass> : CSharpCodeGenerator where TOmsClass : IOmsItem
{
public TOmsClass CreateDatabase(Oms oms)
{
string script = BuildScript();
Assembly dynamicAssembly = CompileScript(script, [ typeof(TOmsClass).Assembly.Location ]);
Type t = typeof(TOmsClass);
foreach (Type t2 in t.GetNestedTypes())
{
CreateType(oms, t2);
}
Type?[] tis;
try
{
tis = dynamicAssembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
tis = ex.Types;
}
object? o = Activator.CreateInstance(tis[0]);
if ((o?.GetType().IsAssignableTo(typeof(TOmsClass))).GetValueOrDefault())
{
TOmsClass db = (TOmsClass)o;
return db;
}
throw new TypeInitializationException(typeof(TOmsClass).Name, null);
}
public TOmsClass CreateInstance(Oms oms, Guid globalIdentifier)
{
string script = BuildScript(globalIdentifier);
Assembly dynamicAssembly = CompileScript(script, [ typeof(TOmsClass).Assembly.Location ]);
Type?[] tis;
try
{
tis = dynamicAssembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
tis = ex.Types;
}
object? o = Activator.CreateInstance(tis[0]);
tis[0].GetProperty("Oms", BindingFlags.Instance | BindingFlags.Public).SetValue(o, oms);
if ((o?.GetType().IsAssignableTo(typeof(TOmsClass))).GetValueOrDefault())
{
TOmsClass db = (TOmsClass)o;
return db;
}
throw new TypeInitializationException(typeof(TOmsClass).Name, null);
}
private void CreateType(Oms oms, Type t)
{
if (t.IsInterface)
{
string name = OmsDatabase.GetNameForClass(t);
Guid id = OmsDatabase.GetGlobalIdentifierForClass(t);
oms.CreateClass(name, id);
}
}
private string BuildScript(Guid? globalIdentifier = null)
{
Type t = typeof(TOmsClass);
Namespace ns = new Namespace(new string[] { "Mocha", "Modeling", "Models", t.Name });
if (t.IsAssignableTo(typeof(IOmsDatabase)))
{
Mocha.Modeling.CodeGeneration.Class cl = GenerateDatabase(t);
ns.Items.Add(cl);
}
else
{
Mocha.Modeling.CodeGeneration.Class cl = GenerateClass(t, globalIdentifier);
ns.Items.Add(cl);
}
return GenerateCode(ns);
}
private Mocha.Modeling.CodeGeneration.Class GenerateDatabase(Type t)
{
Mocha.Modeling.CodeGeneration.Class cl = new CodeGeneration.Class();
cl.Name = t.Name;
cl.InheritsClass = ParseObjectReference(SafeTypeName(t));
Type[] nts = t.GetNestedTypes();
foreach (Type nt in nts)
{
cl.Items.Add(GenerateClass(nt));
}
foreach (PropertyInfo pi in t.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
cl.Items.Add(GenerateProperty(pi));
}
cl.Items.Add(new Property("Oms", new ObjectReference(new string[] { "Mocha", "Core", "Oms" }), null) { AccessModifier = CodeGeneration.AccessModifier.Public, UseAutoProperty = true, ReadOnly = false });
cl.Items.Add(new CodeGeneration.Method("Initialize", new MethodParameter[] { new MethodParameter("oms", new ObjectReference(["Mocha", "Core", "Oms"]))}, new IMethodMember[]
{
new PropertyAssignment(new ObjectReference(["this", "Oms"]), "oms")
}) { AccessModifier = CodeGeneration.AccessModifier.Public});
return cl;
}
private Mocha.Modeling.CodeGeneration.Class GenerateClass(Type t, Guid? globalIdentifier = null)
{
Mocha.Modeling.CodeGeneration.Class cl = new CodeGeneration.Class();
cl.Name = t.Name;
cl.InheritsClass = ParseObjectReference(SafeTypeName(t));
if (globalIdentifier == null)
{
globalIdentifier = OmsDatabase.GetGlobalIdentifierForClass(t);
}
cl.Items.Add(new Property("GlobalIdentifier", new ObjectReference(new string[] { "System", "Guid" }), new CreateInstance(["System", "Guid"], [globalIdentifier.ToString()])) { AccessModifier = CodeGeneration.AccessModifier.Public });
cl.Items.Add(new Property("Oms", new ObjectReference(new string[] { "Mocha", "Core", "Oms" }), null) { AccessModifier = CodeGeneration.AccessModifier.Public, UseAutoProperty = true, ReadOnly = false });
foreach (PropertyInfo pi in t.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
cl.Items.Add(GenerateProperty(pi));
}
return cl;
}
}