diff --git a/mocha-common b/mocha-common
index 569e302..52ad659 160000
--- a/mocha-common
+++ b/mocha-common
@@ -1 +1 @@
-Subproject commit 569e302f3000e236ba562f17bc83d9e70a54fbf5
+Subproject commit 52ad6594f3fc08a3cf77a1693ec0b254298720d2
diff --git a/mocha-dotnet.sln b/mocha-dotnet.sln
index a4ad55f..d7d2349 100644
--- a/mocha-dotnet.sln
+++ b/mocha-dotnet.sln
@@ -45,6 +45,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Oms.Server", "mocha-d
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Core.UI.Server", "mocha-dotnet\src\lib\Mocha.Core.UI.Server\Mocha.Core.UI.Server.csproj", "{4D1E2156-B1B5-4D15-B347-1F0E07C95891}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Zq", "mocha-dotnet\src\lib\Mocha.Zq\Mocha.Zq.csproj", "{04985CF7-45AA-4C67-9EEC-BDDF2DFC5C98}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Zq.Tests", "mocha-dotnet\tests\Mocha.Zq.Tests\Mocha.Zq.Tests.csproj", "{F5D1EF0F-B42F-4237-B08A-7A78143C3ECB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Zq.Integration", "mocha-dotnet\src\lib\Mocha.Zq.Integration\Mocha.Zq.Integration.csproj", "{ADD7359E-0E3B-4435-B812-EC961C52DA2A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -83,6 +89,18 @@ Global
{4D1E2156-B1B5-4D15-B347-1F0E07C95891}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D1E2156-B1B5-4D15-B347-1F0E07C95891}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D1E2156-B1B5-4D15-B347-1F0E07C95891}.Release|Any CPU.Build.0 = Release|Any CPU
+ {04985CF7-45AA-4C67-9EEC-BDDF2DFC5C98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {04985CF7-45AA-4C67-9EEC-BDDF2DFC5C98}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {04985CF7-45AA-4C67-9EEC-BDDF2DFC5C98}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {04985CF7-45AA-4C67-9EEC-BDDF2DFC5C98}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F5D1EF0F-B42F-4237-B08A-7A78143C3ECB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F5D1EF0F-B42F-4237-B08A-7A78143C3ECB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F5D1EF0F-B42F-4237-B08A-7A78143C3ECB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F5D1EF0F-B42F-4237-B08A-7A78143C3ECB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ADD7359E-0E3B-4435-B812-EC961C52DA2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ADD7359E-0E3B-4435-B812-EC961C52DA2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ADD7359E-0E3B-4435-B812-EC961C52DA2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ADD7359E-0E3B-4435-B812-EC961C52DA2A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -106,6 +124,9 @@ Global
{6005DB73-30D8-4398-8B1F-5E23C0F2FFBF} = {B024FD23-7084-4DDF-A185-D58BEE7A006F}
{EB83EE7A-AFFE-4068-B445-9139F2DEA0F6} = {11486802-8136-4958-8B32-FC34630B0306}
{4D1E2156-B1B5-4D15-B347-1F0E07C95891} = {A2C401E9-FED4-43BA-A928-566239894CEE}
+ {04985CF7-45AA-4C67-9EEC-BDDF2DFC5C98} = {A2C401E9-FED4-43BA-A928-566239894CEE}
+ {F5D1EF0F-B42F-4237-B08A-7A78143C3ECB} = {27C300F5-5172-4225-A6F7-3503B9007DD8}
+ {ADD7359E-0E3B-4435-B812-EC961C52DA2A} = {A2C401E9-FED4-43BA-A928-566239894CEE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D28A9CF8-0235-4F8F-865F-C460BDCAE16D}
diff --git a/mocha-dotnet/src/lib/Mocha.Core/KnownRelationshipGuids.cs b/mocha-dotnet/src/lib/Mocha.Core/KnownRelationshipGuids.cs
index ea47be5..a4442da 100755
--- a/mocha-dotnet/src/lib/Mocha.Core/KnownRelationshipGuids.cs
+++ b/mocha-dotnet/src/lib/Mocha.Core/KnownRelationshipGuids.cs
@@ -435,5 +435,6 @@ namespace Mocha.Core
public static Guid Get_Instances_Method__returns__Work_Set { get; } = new Guid("{7d0f93b1-8c93-464e-a44d-d674f910b589}");
public static Guid Get_Instances_Method__selects_instances_of__Class { get; } = new Guid("{c0b85d90-de8c-44c2-9420-c5e724ccdf2c}");
+ public static Guid Method_Binding__uses_super__Return_Instance_Set_Method_Binding { get; } = new Guid("{444279f1-3bf9-4d1f-848e-e7bf33fa0fd7}");
}
}
diff --git a/mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsClass.cs b/mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsClass.cs
index f92a4b2..8f8a658 100644
--- a/mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsClass.cs
+++ b/mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsClass.cs
@@ -15,6 +15,7 @@
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see .
+using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using MBS.Core.Reflection;
@@ -23,9 +24,15 @@ namespace Mocha.Core.Modeling;
public class OmsClass
{
- internal OmsDatabase omsdb { get; set; }
- public Guid GlobalIdentifier { get; internal set; } = Guid.Empty;
-
+ internal OmsDatabase omsdb { get; private set; }
+ private Guid _GlobalIdentifier = Guid.Empty;
+ public Guid GlobalIdentifier
+ {
+ get
+ {
+ return _GlobalIdentifier;
+ }
+ }
private Dictionary _attributeValuesTemp = new Dictionary();
protected object GetAttributeValue(object defaultValue = null)
@@ -99,4 +106,19 @@ public class OmsClass
}
throw new InvalidOperationException();
}
+
+ internal void Initialize(OmsDatabase omsdb, Guid localInstanceGuid)
+ {
+ this.omsdb = omsdb;
+ this._GlobalIdentifier = localInstanceGuid;
+
+ InstanceHandle inst = omsdb.Oms.GetInstance(_GlobalIdentifier);
+ if (inst != InstanceHandle.Empty)
+ {
+ foreach (KeyValuePair kvp in _attributeValuesTemp)
+ {
+ omsdb.Oms.SetAttributeValue(inst, omsdb.Oms.GetInstance(kvp.Key), kvp.Value);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsInstanceList.cs b/mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsInstanceList.cs
index 1a39492..eef5f29 100644
--- a/mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsInstanceList.cs
+++ b/mocha-dotnet/src/lib/Mocha.Core/Modeling/OmsInstanceList.cs
@@ -85,7 +85,28 @@ public class OmsInstanceList : OmsInstanceList, IList where T : OmsClass
this.classGuid = classGuid;
}
- public T this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ public T this[int index]
+ {
+ get
+ {
+ IEnumerable insts = omsdb.Oms.GetInstancesOf(omsdb.Oms.GetInstance(classGuid));
+
+ int i = 0;
+ foreach (InstanceHandle ih in insts)
+ {
+ if (i == index)
+ {
+ return (T)omsdb.GetClass(ih);
+ }
+ i++;
+ }
+ throw new IndexOutOfRangeException();
+ }
+ set
+ {
+
+ }
+ }
public int Count
{
@@ -104,10 +125,9 @@ public class OmsInstanceList : OmsInstanceList, IList where T : OmsClass
{
Guid localClassGuid = OmsDatabase.GetGlobalIdentifierForClass(item.GetType());
Guid localInstanceGuid = Guid.NewGuid();
- item.GlobalIdentifier = localInstanceGuid;
-
+
omsdb.CreateClass(item, localClassGuid, localInstanceGuid);
- item.omsdb = omsdb;
+ item.Initialize(omsdb, localInstanceGuid);
}
}
@@ -123,7 +143,13 @@ public class OmsInstanceList : OmsInstanceList, IList where T : OmsClass
public void CopyTo(T[] array, int arrayIndex)
{
- throw new NotImplementedException();
+ IEnumerable insts = omsdb.Oms.GetInstancesOf(omsdb.Oms.GetInstance(classGuid));
+ int i = 0;
+ foreach (InstanceHandle ih in insts)
+ {
+ array[i + arrayIndex] = (T)omsdb.GetClass(ih);
+ i++;
+ }
}
public IEnumerator GetEnumerator()
diff --git a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs
index e1edfa4..b6a5ee0 100644
--- a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs
+++ b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs
@@ -536,7 +536,13 @@ public abstract class Oms
}
protected abstract void SetInstanceKeyInternal(InstanceHandle target, InstanceKey instanceKey);
- protected void SetInstanceKey(InstanceHandle target, InstanceKey instanceKey)
+ ///
+ /// Sets the instance key for the given target instance. Instance Keys must conform to certain rules; namely, the
+ /// class index of the Instance Key must match the instance index of the instance's parent class.
+ ///
+ ///
+ ///
+ public void SetInstanceKey(InstanceHandle target, InstanceKey instanceKey)
{
SetInstanceKeyInternal(target, instanceKey);
}
@@ -1080,6 +1086,28 @@ public abstract class Oms
context.SetWorkData(assignsToParm, assignsFromWorkData);
}
retval = ExecuteMethodBinding(context, methodOrMethodBinding);
+
+ InstanceHandle ihSuperRSMB = GetRelatedInstance(methodOrMethodBinding, GetInstance(KnownRelationshipGuids.Method_Binding__uses_super__Return_Instance_Set_Method_Binding));
+ if (ihSuperRSMB != InstanceHandle.Empty)
+ {
+ if (retval != null)
+ {
+ object? insts = context.GetWorkData(retval.Value);
+ if (insts is IEnumerable ies)
+ {
+ InstanceHandle ws2 = Execute(context, ihSuperRSMB);
+ object? insts2 = context.GetWorkData(ws2);
+
+ if (insts2 is IEnumerable ies2)
+ {
+ List list = new List();
+ list.AddRange(ies2);
+ list.AddRange(ies);
+ context.SetWorkData(retval.Value, (IEnumerable)list);
+ }
+ }
+ }
+ }
}
else
{
@@ -1372,7 +1400,7 @@ public abstract class Oms
return value;
}
- public Method GetMethod(InstanceHandle forClass, string verb, string name, AccessModifier? accessModifier = null, bool? is_static = null)
+ public Method GetMethod(InstanceHandle forClass, string? verb, string name, AccessModifier? accessModifier = null, bool? is_static = null)
{
// this really needs to be super fast...
InstanceHandle a_Verb = GetInstance(KnownAttributeGuids.Text.Verb);
@@ -1383,7 +1411,7 @@ public abstract class Oms
{
string _verb = GetAttributeValue(method, a_Verb);
string _name = GetAttributeValue(method, a_Name);
- if (_verb.Equals(verb) && _name.Equals(name))
+ if ((verb == null || _verb.Equals(verb)) && _name.Equals(name))
{
return (Method)ConcreteInstanceWrapper.Wrap(this, method);
}
@@ -2051,4 +2079,18 @@ public abstract class Oms
}
return value;
}
+
+ public InstanceHandle GetInstanceByName(InstanceHandle parentClass, string name)
+ {
+ InstanceHandle a_Name = GetInstance(KnownAttributeGuids.Text.Name);
+ IEnumerable ihs = GetInstancesOf(parentClass);
+ foreach (InstanceHandle ih in ihs)
+ {
+ if ((GetAttributeValue(ih, a_Name)?.Equals(name)).GetValueOrDefault(false))
+ {
+ return ih;
+ }
+ }
+ return InstanceHandle.Empty;
+ }
}
diff --git a/mocha-dotnet/src/lib/Mocha.Core/OmsMethodBuilder.cs b/mocha-dotnet/src/lib/Mocha.Core/OmsMethodBuilder.cs
index 8051d7c..1b944d5 100644
--- a/mocha-dotnet/src/lib/Mocha.Core/OmsMethodBuilder.cs
+++ b/mocha-dotnet/src/lib/Mocha.Core/OmsMethodBuilder.cs
@@ -78,6 +78,17 @@ public class OmsMethodBuilder
return new GetAttributeMethod(method);
}
+
+ public GetSpecifiedInstancesMethod CreateGetSpecifiedInstancesMethod(InstanceHandle forClassInstance, string verb, string name, WorkSet returnsWorkSet, InstanceHandle specifiedInstance)
+ {
+ return CreateGetSpecifiedInstancesMethod(forClassInstance, verb, name, null, false, returnsWorkSet, specifiedInstance);
+ }
+ public GetSpecifiedInstancesMethod CreateGetSpecifiedInstancesMethod(InstanceHandle forClassInstance, string verb, string name, AccessModifier accessModifier, bool isStatic, WorkSet returnsWorkSet, InstanceHandle specifiedInstance)
+ {
+ GetSpecifiedInstancesMethod meth = CreateGetSpecifiedInstancesMethod(forClassInstance, verb, name, accessModifier, isStatic, returnsWorkSet, new InstanceHandle[] { specifiedInstance });
+ Oms.SetAttributeValue(meth.Handle, Oms.GetInstance(KnownAttributeGuids.Boolean.Singular), true);
+ return meth;
+ }
public GetSpecifiedInstancesMethod CreateGetSpecifiedInstancesMethod(InstanceHandle forClassInstance, string verb, string name, WorkSet returnsWorkSet, InstanceHandle[] specifiedInstances)
{
return CreateGetSpecifiedInstancesMethod(forClassInstance, verb, name, null, false, returnsWorkSet, specifiedInstances);
diff --git a/mocha-dotnet/src/lib/Mocha.Zq.Integration/Mocha.Zq.Integration.csproj b/mocha-dotnet/src/lib/Mocha.Zq.Integration/Mocha.Zq.Integration.csproj
new file mode 100644
index 0000000..dfa7ab9
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq.Integration/Mocha.Zq.Integration.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
diff --git a/mocha-dotnet/src/lib/Mocha.Zq.Integration/ZqIntegrator.cs b/mocha-dotnet/src/lib/Mocha.Zq.Integration/ZqIntegrator.cs
new file mode 100644
index 0000000..df2fefb
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq.Integration/ZqIntegrator.cs
@@ -0,0 +1,291 @@
+using System.Collections;
+using System.Runtime.InteropServices;
+using System.Text;
+using Microsoft.VisualBasic;
+using Mocha.Core;
+using Mocha.Zq.Expressions;
+using Mocha.Zq.Methods;
+
+namespace Mocha.Zq.Integration;
+
+public class ZqIntegrator
+{
+ private Oms OMS { get; }
+ public ZqParser Parser { get; }
+
+ public ZqIntegrator(Oms oms)
+ {
+ OMS = oms;
+ Parser = new ZqParser();
+ }
+
+ public object? Evaluate(string text)
+ {
+ return Evaluate(Parser.Parse(text));
+ }
+
+ public object? Evaluate(Stream stream)
+ {
+ return Evaluate(Parser.Parse(stream));
+ }
+ public object? Evaluate(ZqObject? obj)
+ {
+ if (obj is ZqClass zql)
+ {
+ InstanceHandle ih = OMS.CreateClass(zql.Name);
+ if (zql.InstanceKey != InstanceKey.Empty)
+ {
+ if (zql.InstanceKey.ClassIndex == 1)
+ {
+ OMS.SetInstanceKey(ih, zql.InstanceKey);
+ }
+ }
+
+ InstanceKey parentIK = OMS.GetInstanceKey(ih);
+ foreach (ZqInstance inst in zql.Instances)
+ {
+ InstanceHandle ih2 = OMS.CreateInstanceOf(ih);
+ if (inst.InstanceKey != InstanceKey.Empty && inst.InstanceKey.ClassIndex == parentIK.InstanceIndex)
+ {
+ OMS.SetInstanceKey(ih2, inst.InstanceKey);
+ }
+
+ InstanceHandle a_Name = OMS.GetInstance(KnownAttributeGuids.Text.Name);
+ if (a_Name != InstanceHandle.Empty)
+ {
+ if (inst.Name != null)
+ {
+ OMS.SetAttributeValue(ih2, a_Name, inst.Name);
+ }
+ }
+ }
+
+ foreach (ZqMethod meth in zql.Functions)
+ {
+ if (meth is ZqSimpleReturnMethod gsi)
+ {
+ Core.Oop.WorkSet ws = OMS.CreateWorkSet(meth.Name);
+ if (gsi.ReturnValue is ZqArray)
+ {
+ List list = new List();
+ foreach (ZqObject obj2 in ((ZqArray)gsi.ReturnValue))
+ {
+ if (obj2 is ZqVariableReference rr)
+ {
+ object r = ResolveVariable(ih, rr.Name);
+ if (r is InstanceHandle ihret)
+ {
+ list.Add(ihret);
+ }
+ }
+ }
+
+ OMS.MethodBuilder.CreateGetSpecifiedInstancesMethod(ih, null, meth.Name, ws, list.ToArray());
+ }
+ else if (gsi.ReturnValue is ZqVariableReference)
+ {
+ object r = ResolveVariable(ih, ((ZqVariableReference)gsi.ReturnValue).Name);
+ if (r is InstanceHandle ihret)
+ {
+ OMS.MethodBuilder.CreateGetSpecifiedInstancesMethod(ih, null, meth.Name, ws, ihret);
+ }
+ }
+ }
+ }
+ return ih;
+ }
+ return null;
+ }
+
+ private object ResolveVariable(InstanceHandle parentClassInstance, string name)
+ {
+ InstanceHandle ihret = OMS.GetInstanceByName(parentClassInstance, name);
+ if (ihret != InstanceHandle.Empty)
+ {
+ return ihret;
+ }
+ return null;
+ }
+
+ public InstanceHandle GetMethod(string fullyQualifiedName)
+ {
+ string[] namespacedName = fullyQualifiedName.Split(new char[] { '.' });
+ if (namespacedName.Length > 1)
+ {
+ if (namespacedName.Length == 2)
+ {
+ string className = namespacedName[0];
+ string methodName = namespacedName[1];
+
+ InstanceHandle c = OMS.GetInstanceByName(OMS.GetInstance(KnownInstanceGuids.Classes.Class), className);
+ IEnumerable ihMethods = OMS.GetRelatedInstances(c, OMS.GetInstance(KnownRelationshipGuids.Class__has__Method));
+ InstanceHandle a_Name = OMS.GetInstance(KnownAttributeGuids.Text.Name);
+
+ foreach (InstanceHandle ihMethod in ihMethods)
+ {
+ string name = OMS.GetAttributeValue(ihMethod, a_Name);
+ if (methodName == name)
+ {
+ return ihMethod;
+ }
+ }
+ }
+ }
+ else
+ {
+ // ??? test this
+ return OMS.GetInstanceByName(OMS.GetInstance(KnownInstanceGuids.Classes.Method), namespacedName[0]);
+ }
+ return InstanceHandle.Empty;
+ }
+
+ public ZqObject? Import(InstanceHandle inst)
+ {
+ if (OMS.IsInstanceOf(inst, OMS.GetInstance(KnownInstanceGuids.Classes.Class)))
+ {
+ string name = ZqNormalizeName(OMS.GetAttributeValue(inst, OMS.GetInstance(KnownAttributeGuids.Text.Name)));
+ ZqClass cls = new ZqClass(name);
+
+ IEnumerable insts = OMS.GetInstancesOf(inst);
+ foreach (InstanceHandle inst2 in insts)
+ {
+ cls.Instances.Add(new ZqInstance() { InstanceKey = OMS.GetInstanceKey(inst2), Name = ZqNormalizeName(OMS.GetInstanceText(inst2)) });
+ }
+
+ return cls;
+ }
+ else if (OMS.IsInstanceOf(inst, OMS.GetInstance(KnownInstanceGuids.Classes.Relationship)))
+ {
+ InstanceKey ik = OMS.GetInstanceKey(inst);
+ InstanceHandle destClass = OMS.GetRelatedInstance(inst, OMS.GetInstance(KnownRelationshipGuids.Relationship__has_destination__Class));
+ string relTypeName = OMS.GetAttributeValue(inst, OMS.GetInstance(KnownAttributeGuids.Text.RelationshipType));
+ string destClassName = ZqNormalizeName(OMS.GetInstanceText(destClass));
+ string name = ZqNormalizeName(relTypeName + destClassName);
+
+ bool singular = OMS.GetAttributeValue(inst, OMS.GetInstance(KnownAttributeGuids.Boolean.Singular));
+
+ ZqDataType dt = new ZqDataType(destClassName, !singular);
+ ZqRelationship rel = new ZqRelationship(name, relTypeName, dt, ik);
+ return rel;
+ }
+ else if (OMS.IsInstanceOf(inst, OMS.GetInstance(KnownInstanceGuids.MethodClasses.GetRelationshipMethod)))
+ {
+ string verb = OMS.GetAttributeValue(inst, OMS.GetInstance(KnownAttributeGuids.Text.Verb));
+ string name = OMS.GetAttributeValue(inst, OMS.GetInstance(KnownAttributeGuids.Text.Name));
+ string fullName = verb + name;
+ fullName = ZqNormalizeName(fullName);
+
+ InstanceHandle ihReturnsRelationship = OMS.GetRelatedInstance(inst, OMS.GetInstance(KnownRelationshipGuids.Get_Relationship_Method__returns__Relationship));
+ ZqRelationship rel = (ZqRelationship)Import(ihReturnsRelationship);
+ return new ZqGetRelationshipMethod(fullName, rel);
+ }
+ throw new NotImplementedException();
+ }
+
+ private string ZqNormalizeName(string fullName)
+ {
+ return fullName.Replace("-", "_").Replace(" ", "").Replace("(", "_").Replace(")", "_");
+ }
+
+ private string GetFunctionDefinition(ZqMethod method)
+ {
+ return String.Format("function {0}({1}) : {2}", method.Name, GenerateCode(method.Parameters), method.ReturnDataType);
+ }
+
+ public string GenerateCode(IEnumerable parms)
+ {
+ StringBuilder sb = new StringBuilder();
+ foreach (ZqParameter parm in parms)
+ {
+ sb.Append(parm.Name);
+ if (!parm.DataType.Equals(ZqDataType.None))
+ {
+ sb.Append(" : ");
+ sb.Append(parm.DataType);
+ }
+ sb.Append(", ");
+ }
+ if (sb.Length > 2)
+ {
+ sb.Remove(sb.Length - 2, 2);
+ }
+ return sb.ToString();
+ }
+
+ public string GenerateCode(ZqAccessModifier accessModifier)
+ {
+ switch (accessModifier)
+ {
+ case ZqAccessModifier.None: return String.Empty;
+ // case ZqAccessModifier.Internal: return "internal";
+ case ZqAccessModifier.Private: return "private";
+ case ZqAccessModifier.Protected: return "protected";
+ // case ZqAccessModifier.ProtectedInternal: return "protected internal";
+ case ZqAccessModifier.Public: return "public";
+ }
+ throw new NotImplementedException();
+ }
+ public string GenerateCode(ZqObject? obj)
+ {
+ StringBuilder sb = new StringBuilder();
+ if (obj is ZqClass cls)
+ {
+ if (cls.AccessModifier != ZqAccessModifier.None)
+ {
+ sb.Append(GenerateCode(cls.AccessModifier));
+ sb.Append(' ');
+ }
+ sb.Append("class ");
+ sb.Append(cls.Name);
+ if (cls.InstanceKey != InstanceKey.Empty)
+ {
+ sb.Append(", ");
+ sb.Append(cls.InstanceKey);
+ }
+ sb.AppendLine(" {");
+
+ if (cls.Attributes.Count > 0)
+ {
+ sb.AppendLine("attributes:");
+ sb.AppendLine();
+ }
+ if (cls.Relationships.Count > 0)
+ {
+ sb.AppendLine("relationships:");
+ sb.AppendLine();
+ }
+ if (cls.Functions.Count > 0)
+ {
+ sb.AppendLine("functions:");
+ sb.AppendLine();
+ }
+ if (cls.Instances.Count > 0)
+ {
+ sb.AppendLine("instances:");
+ foreach (ZqInstance inst in cls.Instances)
+ {
+ sb.AppendLine(String.Format("\t{0}, {1}", inst.Name, inst.InstanceKey));
+ }
+ }
+ sb.AppendLine();
+ sb.AppendLine("}");
+ }
+ else if (obj is ZqMethod m)
+ {
+ sb.Append(GetFunctionDefinition(m));
+ sb.Append(" = ");
+ if (obj is ZqGetRelationshipMethod gr)
+ {
+ sb.Append("this.");
+ sb.Append(gr.Relationship.Name);
+ }
+ else if (obj is ZqSimpleReturnMethod m2)
+ {
+ sb.Append(m2.ReturnValue);
+ }
+ // sb.Append("{");
+ // sb.Append("}");
+ }
+ return sb.ToString();
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/Expressions/ZqLiteral.cs b/mocha-dotnet/src/lib/Mocha.Zq/Expressions/ZqLiteral.cs
new file mode 100644
index 0000000..8142bb8
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/Expressions/ZqLiteral.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Mocha.Zq.Expressions;
+
+public class ZqLiteral : ZqExpression
+{
+ public object Value { get; }
+ public ZqLiteral(object value)
+ {
+ Value = value;
+ }
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/Expressions/ZqVariableReference.cs b/mocha-dotnet/src/lib/Mocha.Zq/Expressions/ZqVariableReference.cs
new file mode 100644
index 0000000..6e3b5be
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/Expressions/ZqVariableReference.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Text;
+
+namespace Mocha.Zq.Expressions;
+
+public class ZqVariableReference : ZqExpression
+{
+ public string Name { get; }
+
+ public string? ObjectName { get; }
+ public string PropertyName { get; }
+
+ public ZqVariableReference(string name)
+ {
+ Name = name;
+
+ if (Name.Contains("."))
+ {
+ ObjectName = Name.Substring(0, Name.LastIndexOf('.'));
+ PropertyName = Name.Substring(Name.LastIndexOf('.') + 1);
+ }
+ else
+ {
+ ObjectName = null;
+ PropertyName = Name;
+ }
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ if (ObjectName != null)
+ {
+ sb.Append(ObjectName);
+ sb.Append('.');
+ }
+ sb.Append(PropertyName);
+ return sb.ToString();
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/IZqMethod.cs b/mocha-dotnet/src/lib/Mocha.Zq/IZqMethod.cs
new file mode 100644
index 0000000..7aaec69
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/IZqMethod.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Mocha.Zq;
+
+public interface IZqMethod
+{
+ string Name { get; set; }
+ ZqDataType ReturnDataType { get; set; }
+ ZqMethodCall? Executable { get; }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqBuildAttributeMethod.cs b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqBuildAttributeMethod.cs
new file mode 100644
index 0000000..d3859e7
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqBuildAttributeMethod.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Mocha.Zq.Methods;
+
+public class ZqBuildAttributeMethod : ZqMethod
+{
+ public object? InitialValue { get; set; } = null;
+ public ZqBuildAttributeMethod(string name, object initialValue) : base(name)
+ {
+ InitialValue = initialValue;
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqConditionalSelectAttributeCase.cs b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqConditionalSelectAttributeCase.cs
new file mode 100644
index 0000000..35fca7c
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqConditionalSelectAttributeCase.cs
@@ -0,0 +1,28 @@
+using System;
+using MBS.Core.Collections.Generic;
+
+namespace Mocha.Zq.Methods;
+
+public class ZqConditionalSelectAttributeCase
+{
+ public class ZqConditionalSelectAttributeCaseCollection
+ : System.Collections.ObjectModel.Collection
+ {
+
+ }
+
+ public ZqCondition.ZqConditionCollection TrueConditions { get; } = new ZqCondition.ZqConditionCollection();
+ public ZqCondition.ZqConditionCollection FalseConditions { get; } = new ZqCondition.ZqConditionCollection();
+ public bool UseAnyCondition { get; set; } = false;
+ public ZqObject? Result { get; set; } = null;
+
+ public ZqConditionalSelectAttributeCase(IEnumerable trueConditions, IEnumerable falseConditions, bool useAnyCondition, ZqObject? result)
+ {
+ TrueConditions.AddRange(trueConditions);
+ FalseConditions.AddRange(falseConditions);
+ UseAnyCondition = useAnyCondition;
+ Result = result;
+ }
+
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqConditionalSelectAttributeMethod.cs b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqConditionalSelectAttributeMethod.cs
new file mode 100644
index 0000000..1bf36a5
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqConditionalSelectAttributeMethod.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Mocha.Zq.Methods;
+
+public class ZqConditionalSelectAttributeMethod : ZqMethod
+{
+ public ZqConditionalSelectAttributeMethod(string name = null) : base(name) { }
+
+ public ZqConditionalSelectAttributeCase.ZqConditionalSelectAttributeCaseCollection Cases { get; } = new ZqConditionalSelectAttributeCase.ZqConditionalSelectAttributeCaseCollection();
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqGetRelationshipMethod.cs b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqGetRelationshipMethod.cs
new file mode 100644
index 0000000..bb874eb
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqGetRelationshipMethod.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Mocha.Zq.Methods;
+
+public class ZqGetRelationshipMethod : ZqMethod
+{
+ public ZqRelationship Relationship { get; }
+
+ public ZqGetRelationshipMethod(string name, ZqRelationship rel) : base(name)
+ {
+ Relationship = rel;
+ }
+
+ public override ZqDataType ReturnDataType { get => Relationship.DataType; }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqSimpleReturnMethod.cs b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqSimpleReturnMethod.cs
new file mode 100644
index 0000000..52e5af1
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqSimpleReturnMethod.cs
@@ -0,0 +1,13 @@
+using System;
+using Mocha.Zq.Expressions;
+
+namespace Mocha.Zq.Methods;
+
+public class ZqSimpleReturnMethod : ZqMethod
+{
+ public object ReturnValue { get; }
+ public ZqSimpleReturnMethod(string name, object returnValue) : base(name)
+ {
+ ReturnValue = returnValue;
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/Mocha.Zq.csproj b/mocha-dotnet/src/lib/Mocha.Zq/Mocha.Zq.csproj
new file mode 100644
index 0000000..6731800
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/Mocha.Zq.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqAccessModifier.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqAccessModifier.cs
new file mode 100644
index 0000000..2a4197b
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqAccessModifier.cs
@@ -0,0 +1,11 @@
+namespace Mocha.Zq;
+
+public enum ZqAccessModifier
+{
+ None,
+ Public,
+ Protected,
+ Internal,
+ ProtectedInternal,
+ Private
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqArray.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqArray.cs
new file mode 100644
index 0000000..b752be0
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqArray.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections;
+
+namespace Mocha.Zq;
+
+public class ZqArray : ZqObject, IEnumerable
+{
+ public int Size { get; } = 0;
+ public ZqArray(int size)
+ {
+ Size = size;
+ _ary = new ZqObject[size];
+ }
+
+ private ZqObject[] _ary = new ZqObject[0];
+ public ZqObject this[int index]
+ {
+ get
+ {
+ return _ary[index];
+ }
+ set
+ {
+ _ary[index] = value;
+ }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return ((IEnumerable)_ary).GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return _ary.GetEnumerator();
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqAttribute.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqAttribute.cs
new file mode 100644
index 0000000..0ff86fe
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqAttribute.cs
@@ -0,0 +1,18 @@
+using System;
+using Mocha.Core;
+
+namespace Mocha.Zq;
+
+public class ZqAttribute : ZqObject
+{
+ public class ZqAttributeCollection
+ : System.Collections.ObjectModel.Collection
+ {
+
+ }
+
+ public string Name { get; set; }
+ public InstanceKey InstanceKey { get; set; }
+ public string DataType { get; set; }
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqClass.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqClass.cs
new file mode 100644
index 0000000..e831468
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqClass.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Text;
+using Mocha.Core;
+
+namespace Mocha.Zq;
+
+public class ZqClass : ZqObject
+{
+ public string Name { get; set; }
+ public InstanceKey InstanceKey { get; set; } = InstanceKey.Empty;
+
+ public ZqAccessModifier AccessModifier { get; set; } = ZqAccessModifier.None;
+ public ZqAttribute.ZqAttributeCollection Attributes { get; } = new ZqAttribute.ZqAttributeCollection();
+ public ZqMethod.ZqMethodCollection Functions { get; } = new ZqMethod.ZqMethodCollection();
+ public ZqInstance.ZqInstanceCollection Instances { get; } = new ZqInstance.ZqInstanceCollection();
+ public ZqRelationship.ZqRelationshipCollection Relationships { get; } = new ZqRelationship.ZqRelationshipCollection();
+
+ public ZqClass(string name)
+ {
+ Name = name;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append(Name);
+ if (InstanceKey != InstanceKey.Empty)
+ {
+ sb.Append(", ");
+ sb.Append(InstanceKey.ToString());
+ }
+ return sb.ToString();
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqClassDefinition.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqClassDefinition.cs
new file mode 100644
index 0000000..718bed7
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqClassDefinition.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Mocha.Zq;
+
+internal struct ZqDefParms
+{
+ public ZqAccessModifier accessModifier;
+ public bool isStatic;
+ public bool isPublished;
+ public bool isStub;
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqCondition.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqCondition.cs
new file mode 100644
index 0000000..e7fda4f
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqCondition.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqCondition
+{
+ public class ZqConditionCollection
+ : System.Collections.ObjectModel.Collection
+ {
+
+ }
+
+ public string Variable { get; set; }
+ public string Operator { get; set; }
+ public string Value { get; set; }
+
+ public ZqCondition(string variable, string op, string value)
+ {
+ Variable = variable;
+ Operator = op;
+ Value = value;
+ }
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqContext.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqContext.cs
new file mode 100644
index 0000000..18fd98e
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqContext.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqContext
+{
+ public Dictionary Variables { get; } = new Dictionary();
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqDataType.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqDataType.cs
new file mode 100644
index 0000000..eed2747
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqDataType.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Mocha.Zq;
+
+public struct ZqDataType
+{
+ public static ZqDataType None { get; } = new ZqDataType("(none)", false);
+ public static ZqDataType Text { get; } = new ZqDataType("text", false);
+ public static ZqDataType Integer { get; } = new ZqDataType("integer", false);
+ public static ZqDataType Relationship { get; } = new ZqDataType("Relationship", false);
+
+ public string Name { get; }
+ public bool IsArray { get; }
+
+ private static readonly string[] attributeTypeNames = new string[]
+ {
+ "text", "boolean", "integer", "date"
+ };
+
+ public bool IsAttribute
+ {
+ get
+ {
+ return attributeTypeNames.Contains(Name);
+ }
+ }
+
+ public ZqDataType(string name, bool isArray)
+ {
+ Name = name;
+ IsArray = isArray;
+ }
+
+ public static ZqDataType Parse(string value)
+ {
+ string name = value;
+ bool isArray = false;
+ if (value.EndsWith("*"))
+ {
+ name = value.Substring(0, value.Length - 1);
+ isArray = true;
+ }
+ return new ZqDataType(name, isArray);
+ }
+
+ public override string ToString()
+ {
+ string str = Name;
+ if (IsArray)
+ {
+ str += "*";
+ }
+ return str;
+ }
+
+ public override bool Equals([NotNullWhen(true)] object? obj)
+ {
+ if (obj is ZqDataType zqd)
+ {
+ return this.Name.Equals(zqd.Name) && this.IsArray == zqd.IsArray;
+ }
+ return false;
+ }
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqExpression.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqExpression.cs
new file mode 100644
index 0000000..ecaea61
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqExpression.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Mocha.Zq;
+
+public abstract class ZqExpression : ZqObject
+{
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqInstance.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqInstance.cs
new file mode 100644
index 0000000..81ded6d
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqInstance.cs
@@ -0,0 +1,16 @@
+using System;
+using Mocha.Core;
+
+namespace Mocha.Zq;
+
+public class ZqInstance : ZqObject
+{
+ public class ZqInstanceCollection
+ : System.Collections.ObjectModel.Collection
+ {
+
+ }
+
+ public string Name { get; set; }
+ public InstanceKey InstanceKey { get; set; }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqMethod.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqMethod.cs
new file mode 100644
index 0000000..45644e1
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqMethod.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace Mocha.Zq;
+
+public abstract class ZqMethod : ZqObject, IZqMethod
+{
+
+ public class ZqMethodCollection
+ : System.Collections.ObjectModel.Collection
+ {
+ private Dictionary _itemsByName = new Dictionary();
+ public IZqMethod? this[string name]
+ {
+ get
+ {
+ if (_itemsByName.ContainsKey(name))
+ {
+ return _itemsByName[name];
+ }
+ return null;
+ }
+ }
+
+ protected override void ClearItems()
+ {
+ base.ClearItems();
+ _itemsByName.Clear();
+ }
+ protected override void InsertItem(int index, IZqMethod item)
+ {
+ base.InsertItem(index, item);
+ _itemsByName[item.Name] = item;
+ }
+ protected override void RemoveItem(int index)
+ {
+ _itemsByName.Remove(this[index].Name);
+ base.RemoveItem(index);
+ }
+
+ }
+
+ public string Name { get; set; }
+ public ZqParameter.ZqParameterCollection Parameters { get; } = new ZqParameter.ZqParameterCollection();
+
+ public ZqMethodCall? Executable { get; internal set; } = null;
+ public virtual ZqDataType ReturnDataType { get; set; }
+
+ public ZqMethod(string name)
+ {
+ Name = name;
+ ReturnDataType = ZqDataType.None;
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqMethodCall.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqMethodCall.cs
new file mode 100644
index 0000000..eaa1db6
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqMethodCall.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqMethodCall : ZqMethod
+{
+ public ZqObject? Method { get; internal set; } = null;
+ public object[] ParmValues { get; }
+
+ public string Name { get; set; }
+ public ZqDataType ReturnDataType { get; set; }
+
+ public ZqMethodCall? Executable => throw new NotImplementedException();
+
+ public ZqMethodCall(ZqObject executesMethod, object[] parmValues = null) : base(null)
+ {
+ Method = executesMethod;
+ ParmValues = parmValues;
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqMethodReference.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqMethodReference.cs
new file mode 100644
index 0000000..a6ecf1a
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqMethodReference.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqMethodReference : ZqExpression, IZqMethod
+{
+ public string[] FullyQualifiedClassNameParts { get; }
+ public string Name { get; set; }
+ public ZqDataType ReturnDataType { get; set; }
+ public ZqMethodCall? Executable { get { return null; }}
+
+ public ZqMethodReference(string className, string methodName)
+ {
+ FullyQualifiedClassNameParts = className.Split(new char[] { '.' });
+ Name = methodName;
+ }
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqObject.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqObject.cs
new file mode 100644
index 0000000..9cb24c4
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqObject.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqObject
+{
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqOperation.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqOperation.cs
new file mode 100644
index 0000000..b722de0
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqOperation.cs
@@ -0,0 +1,7 @@
+namespace Mocha.Zq;
+
+public enum ZqOperation
+{
+ None = 0x00,
+ CreateClass
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqParameter.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqParameter.cs
new file mode 100644
index 0000000..fd2534d
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqParameter.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqParameter
+{
+ public class ZqParameterCollection
+ : System.Collections.ObjectModel.Collection
+ {
+
+
+ }
+
+ public string Name { get; set; }
+ public ZqDataType DataType { get; set; }
+
+ public ZqParameter(string name, ZqDataType dataType)
+ {
+ Name = name;
+ DataType = dataType;
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0} : {1}", Name, DataType);
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqParser.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqParser.cs
new file mode 100644
index 0000000..2fc21e9
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqParser.cs
@@ -0,0 +1,934 @@
+using System;
+using System.Dynamic;
+using System.Linq.Expressions;
+using System.Net.Http.Headers;
+using System.Reflection;
+using System.Security.Cryptography;
+using System.Security.Principal;
+using System.Text;
+using MBS.Core;
+
+using Mocha.Core;
+using Mocha.Zq.Expressions;
+using Mocha.Zq.Methods;
+
+namespace Mocha.Zq;
+
+public class ZqParser
+{
+ private char[] tokenTerminators = new char[] { ' ', '{', '\n', '\t', ',', ':', '(', ')' };
+
+ private bool IsTokenNameTerminator(char token)
+ {
+ return tokenTerminators.Contains(token);
+ }
+ private char[] tokenSignificants = new char[] { ',', ':', '(', ')', '{', '}' };
+
+ private bool IsSignificantTokenChar(char token)
+ {
+ return tokenSignificants.Contains(token);
+ }
+
+ private bool CheckComment(string text, ref int i)
+ {
+ if (i >= text.Length - 1)
+ {
+ return false;
+ }
+
+ char c1 = text[i];
+ char c2 = text[i + 1];
+ if (c1 == '/' && c2 == '/')
+ {
+ i += 2;
+
+ // handle single-line comments
+ // -- encountered "//"; read until next line --
+ while (true)
+ {
+ if (i >= text.Length) return false;
+
+ char c = text[i];
+ if (c == '\n')
+ break;
+
+ i++;
+ }
+ }
+ else if (c1 == '/' && c2 == '*')
+ {
+ i += 2;
+
+ // handle multi-line or inline comments
+ while (true)
+ {
+ if (i >= text.Length - 1)
+ return false;
+
+ char ac1 = text[i];
+ char ac2 = text[i + 1];
+
+ if (ac1 == '*' && ac2 == '/')
+ {
+ i += 3;
+ break;
+ }
+ i++;
+ }
+ }
+ return true;
+ }
+
+ private enum TokenType
+ {
+ None = 0,
+
+ Comment
+ }
+
+ private struct Token
+ {
+ public static readonly Token Empty = new Token(TokenType.None, null, null);
+
+ public TokenType TokenType { get; }
+ public string? StartingSequence { get; }
+ public string? EndingSequence { get; }
+
+ public Token(TokenType type, string? startingSequence, string? endingSequence)
+ {
+ TokenType = type;
+ StartingSequence = startingSequence;
+ EndingSequence = endingSequence;
+ }
+ }
+
+ private string StripComments(string text)
+ {
+ Token[] tokens = new Token[]
+ {
+ new Token(TokenType.Comment, "/*", "*/"),
+ new Token(TokenType.Comment, "//", "\n")
+ };
+
+ Token insideTok = Token.Empty;
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < text.Length; i++)
+ {
+ bool _continue = false;
+ foreach (Token tok in tokens)
+ {
+ if (i < text.Length - tok.StartingSequence.Length)
+ {
+ if (text.Substring(i, tok.StartingSequence.Length).Equals(tok.StartingSequence))
+ {
+ insideTok = tok;
+ string? contents = ReadUntil(text, ref i, tok.EndingSequence, false);
+ i--;
+ _continue = true;
+ break;
+ }
+ }
+ }
+ if (_continue)
+ continue;
+
+ sb.Append(text[i]);
+ }
+ return sb.ToString();
+ }
+
+ private string StripExtemporaneousWhitespace(string text)
+ {
+ StringBuilder sb = new StringBuilder();
+ bool hadWhitespace = false;
+ for (int i = 0; i < text.Length; i++)
+ {
+ if (i < text.Length - 1)
+ {
+ if (text[i] != '\n')
+ {
+ if (Char.IsWhiteSpace(text[i]) && Char.IsWhiteSpace(text[i + 1]))
+ {
+ hadWhitespace = true;
+ i++;
+ continue;
+ }
+ else if (Char.IsWhiteSpace(text[i]))
+ {
+ hadWhitespace = true;
+ continue;
+ }
+ }
+ }
+
+ if (hadWhitespace)
+ {
+ hadWhitespace = false;
+ sb.Append(' ');
+ }
+ sb.Append(text[i]);
+ }
+ return sb.ToString();
+ }
+
+ private Dictionary BuildSections(string text)
+ {
+ Dictionary sections = new Dictionary();
+ string[] lines = text.Split(new char[] { '\n' });
+ string? nextLabel = null;
+ for (int i = 0; i < lines.Length; i++)
+ {
+ if (lines[i].Trim() == "")
+ continue;
+
+ if (lines[i].Trim().EndsWith(":") && !lines[i].Contains(" "))
+ {
+ nextLabel = lines[i].Substring(0, lines[i].Length - 1);
+ }
+ else
+ {
+ if (nextLabel != null)
+ {
+ nextLabel = nextLabel.Trim();
+ if (!sections.ContainsKey(nextLabel))
+ {
+ sections[nextLabel] = "";
+ }
+ sections[nextLabel] += lines[i].Trim() + '\n';
+ }
+ }
+ }
+
+ Dictionary sections2 = new Dictionary();
+ foreach (KeyValuePair sect in sections)
+ {
+ sections2[sect.Key] = StripExtemporaneousWhitespace(sections[sect.Key]);
+ }
+ return sections2;
+ }
+
+ public ZqObject? Parse(string text)
+ {
+ text = StripComments(text);
+
+ ZqClass? thisClass = null;
+ ZqDefParms parms = new ZqDefParms();
+ int i = 0;
+ string currentLabel = "";
+
+ while (true)
+ {
+ if (!CheckComment(text, ref i))
+ break;
+
+ /*
+ if (!SkipWhitespace(text, ref i))
+ {
+ break;
+ }
+ */
+ string tok = ReadUntil(text, ref i, tokenTerminators, false);
+ if (!IsModifier(tok, ref parms))
+ {
+ if (tok.Equals("class"))
+ {
+ if (!CheckComment(text, ref i))
+ break;
+
+ ParseClass(text, ref i, ref thisClass, ref parms);
+ }
+ else if (tok.Equals("function"))
+ {
+ return ParseFunction(text, ref i, ref parms);
+ }
+ else if (tok.Equals("}"))
+ {
+ return thisClass;
+ }
+ }
+ }
+
+ return thisClass;
+ }
+
+ private ZqObject? ParseFunction2(string text, ref int i, ref ZqDefParms parms)
+ {
+ throw new NotImplementedException();
+ }
+
+ private bool IsModifier(string? tok, ref ZqDefParms parms)
+ {
+ if (tok == "published")
+ {
+ parms.isPublished = true;
+ return true;
+ }
+ else if (tok == "stub")
+ {
+ parms.isStub = true;
+ return true;
+ }
+ else if (tok == "static")
+ {
+ parms.isStatic = true;
+ return true;
+ }
+ else if (tok == "public")
+ {
+ parms.accessModifier = ZqAccessModifier.Public;
+ }
+ return false;
+ }
+
+ private void ParseClass(string text, ref int i, ref ZqClass thisClass, ref ZqDefParms parms)
+ {
+ string name = ReadUntil(text, ref i, '{', false).Trim();
+ i--;
+
+ InstanceKey ik = InstanceKey.Empty;
+ if (name.Contains(","))
+ {
+ string[] nameSplit = name.Split(new char[] { ',' }, 2);
+ name = nameSplit[0].Trim();
+
+ string strInstanceKey = nameSplit[1].Trim();
+ ik = InstanceKey.Parse(strInstanceKey);
+ }
+ thisClass = new ZqClass(name);
+ if (ik != InstanceKey.Empty)
+ {
+ thisClass.InstanceKey = ik;
+ }
+ knownClasses.Add(name, thisClass);
+
+ string body = ReadBetween(text, ref i, '{', '}');
+ Dictionary sections = BuildSections(body);
+
+ if (sections.ContainsKey("attributes"))
+ {
+ string pp = sections["attributes"];
+ StringBuilder sb = new StringBuilder();
+ string? instanceName = null;
+ string? instanceKey = null;
+ string? dataType = null;
+ for (int j = 0; j < pp.Length; j++)
+ {
+ if (pp[j] == ',')
+ {
+ instanceName = sb.ToString();
+ sb.Clear();
+ }
+ else if (pp[j] == ':')
+ {
+ instanceKey = sb.ToString();
+ sb.Clear();
+ }
+ else if (pp[j] == '\n')
+ {
+ if (instanceName != null)
+ {
+ if (sb.Length > 0)
+ {
+ dataType = sb.ToString();
+ sb.Clear();
+ }
+ }
+ if (instanceName != null && instanceKey != null && dataType != null)
+ {
+ ZqAttribute inst = new ZqAttribute();
+ inst.Name = instanceName.Trim();
+ inst.InstanceKey = InstanceKey.Parse(instanceKey.Trim());
+ inst.DataType = dataType.Trim();
+ thisClass.Attributes.Add(inst);
+
+ instanceName = null;
+ instanceKey = null;
+ dataType = null;
+ }
+ }
+ else
+ {
+ sb.Append(pp[j]);
+ }
+ }
+ }
+ if (sections.ContainsKey("instances"))
+ {
+ string pp = sections["instances"];
+ StringBuilder sb = new StringBuilder();
+ string? instanceName = null;
+ string? instanceKey = null;
+ for (int j = 0; j < pp.Length; j++)
+ {
+ if (pp[j] == ',')
+ {
+ instanceName = sb.ToString();
+ sb.Clear();
+ }
+ else if (pp[j] == '\n')
+ {
+ if (instanceName != null)
+ {
+ if (sb.Length > 0)
+ {
+ instanceKey = sb.ToString();
+ sb.Clear();
+ }
+ }
+ if (instanceName != null && instanceKey != null)
+ {
+ ZqInstance inst = new ZqInstance();
+ inst.Name = instanceName;
+ inst.InstanceKey = InstanceKey.Parse(instanceKey);
+ thisClass.Instances.Add(inst);
+
+ instanceName = null;
+ instanceKey = null;
+ }
+ }
+ else
+ {
+ sb.Append(pp[j]);
+ }
+ }
+ }
+ if (sections.ContainsKey("relationships"))
+ {
+ string pp = sections["relationships"];
+ string[] lines = pp.Split(new char[] { '\n' });
+ foreach (string line in lines)
+ {
+ int j = 0;
+ if (line.Contains(","))
+ {
+ string relName = ReadUntil(line, ref j, ',', false);
+ if (line.Contains("->"))
+ {
+ string relKey = ReadUntil(line, ref j, "->", false).Trim();
+
+ int k = line.LastIndexOf(' ');
+ string relationshipTypeName = line.Substring(j, k - j).Trim();
+
+ string dataType = line.Substring(k).Trim();
+ thisClass.Relationships.Add(new ZqRelationship(relName, relationshipTypeName, ZqDataType.Parse(dataType), InstanceKey.Parse(relKey)));
+ }
+ }
+ }
+ }
+ if (sections.ContainsKey("functions"))
+ {
+ string pp = sections["functions"];
+ int j = 0;
+ while (j < pp.Length)
+ {
+ string tok2 = ReadUntil(pp, ref j, ' ', false);
+ if (!IsModifier(tok2, ref parms))
+ {
+ if (tok2 == "function")
+ {
+ IZqMethod? m = ParseFunction(pp, ref j, ref parms);
+ if (m != null)
+ {
+ thisClass.Functions.Add(m);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private ZqMethod? ParseFunction(string pp, ref int j, ref ZqDefParms defparms)
+ {
+ string functionName = ReadUntil(pp, ref j, '(', false).Trim();
+ List parmListList = new List();
+ string parmlist = ReadUntil(pp, ref j, ')', false);
+ if (parmlist.Length > 0)
+ {
+ string[] parms = parmlist.Split(new char[] { ',' });
+ foreach (string parm in parms)
+ {
+ string[] parmstr = parm.Split(new char[] { ':' });
+ string parmName = parmstr[0].Trim();
+ string dataType = parmstr[1].Trim();
+ parmListList.Add(new ZqParameter(parmName, ZqDataType.Parse(dataType)));
+ }
+ }
+
+ int old_j = j;
+ string next = ReadUntil(pp, ref j, new char[] { '{', '\n' }).Trim();
+
+ int iEquals = next.IndexOf('=');
+ string nextAfterEq = "";
+ if (iEquals > -1)
+ {
+ nextAfterEq = next.Substring(iEquals + 1).Trim();
+ }
+
+ string funcBody = "";
+ if ((String.IsNullOrEmpty(nextAfterEq) && pp.Contains("{")) || next.EndsWith("{"))
+ {
+ funcBody = ReadUntil(pp, ref j, new char[] { '}' }, false).Trim();
+ }
+ if (funcBody.StartsWith("{"))
+ {
+ funcBody = funcBody.Substring(1).Trim();
+ }
+
+ string returnDataType = "";
+ int iColon = next.IndexOf(':');
+ if (iColon > -1)
+ {
+ if (iEquals == -1)
+ {
+ returnDataType = next.Substring(iColon + 1).Trim();
+ if (defparms.isStub)
+ {
+ ZqStubMethod func = new ZqStubMethod(functionName, parmListList.ToArray(), ZqDataType.Parse(returnDataType));
+ j -= funcBody.Length;
+ return func;
+ }
+ else
+ {
+
+ }
+ }
+ else
+ {
+ returnDataType = next.Substring(iColon + 1, iEquals - iColon - 1).Trim();
+ ZqDataType dataType = ZqDataType.Parse(returnDataType);
+
+ string value = next.Substring(iEquals + 1).Trim();
+
+ /*
+ if (String.IsNullOrEmpty(value))
+ {
+ j = old_j;
+ next = ReadUntil(pp, ref j, new char[] { '{' }).Trim();
+ continue;
+ }
+ */
+
+ // if (String.IsNullOrEmpty(funcBody) && !String.IsNullOrEmpty(value))
+ if (!String.IsNullOrEmpty(value) && value != "{")
+ {
+ object val = ParseValue(value);
+ ZqMethod func = new ZqSimpleReturnMethod(functionName, val);
+ func.ReturnDataType = ZqDataType.Parse(returnDataType);
+ return func;
+ }
+ else if (!funcBody.Contains("\n"))
+ {
+ if (!String.IsNullOrEmpty(funcBody))
+ {
+ value = funcBody;
+ }
+
+ object? val = ParseValue(value);
+ if (val is string)
+ {
+ return new ZqBuildAttributeMethod(functionName, val);
+ }
+ else if (val is ZqObject)
+ {
+ ZqMethod func = new ZqSimpleReturnMethod(functionName, (ZqObject)val);
+ func.ReturnDataType = ZqDataType.Parse(returnDataType);
+ return func;
+ }
+ }
+ else
+ {
+ /*
+ if (!SkipWhitespace(text, ref i))
+ {
+ break;
+ }
+ */
+ ZqContext context = new ZqContext();
+
+ int k = 0;
+ Queue exprs = new Queue();
+ ZqObject? expr = null;
+ while (k < funcBody.Length)
+ {
+ expr = ParseExpression(funcBody, ref k, context);
+ if (expr is IZqMethod mb)
+ {
+ ((IZqMethod)expr).Name = functionName;
+ ((IZqMethod)expr).ReturnDataType = ZqDataType.Parse(returnDataType);
+ return (ZqMethod)expr;
+ }
+ else if (expr == null)
+ {
+ funcBody += " ";
+ }
+ else
+ {
+ exprs.Enqueue(expr);
+ }
+ }
+
+ while (exprs.Count > 0)
+ {
+ ZqObject expr1 = exprs.Dequeue();
+ if (expr1 is ZqVariableAssignment assn)
+ {
+ context.Variables[assn.VariableName] = assn.VariableValue;
+ }
+ else if (expr1 is ZqVariableReference varr)
+ {
+ if (exprs.Count == 0)
+ {
+ /*
+ switch (context.Variables[varr.Name].DataType)
+ {
+ case ZqDataType.Relationship:
+ {
+ // this is a GR, Get Relationship Method
+ thisClass.Functions.Add(new ZqGetRelationshipMethod(functionName, context.Variables[varr.Name]));
+ break;
+ }
+ case ZqDataType.Text:
+ case ZqDataType.Boolean:
+ {
+ // this is a BA, Build Attribute Method
+ thisClass.Functions.Add(new ZqBuildAttributeMethod(functionName, context.Variables[varr.Name]));
+ break;
+ }
+ }
+ */
+
+ object rv = null;
+ if (context.Variables.ContainsKey(varr.Name))
+ {
+ return new ZqBuildAttributeMethod(functionName, context.Variables[varr.Name]);
+ }
+ else
+ {
+ /*
+ if (varr.ObjectName == "this")
+ {
+ if (thisClass.Relationships.Contains(varr.PropertyName))
+ {
+ thisClass.Functions.Add(new ZqGetRelationshipMethod(functionName, thisClass.Relationships[varr.PropertyName]));
+ }
+ }
+ */
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private object? ParseValue(string value)
+ {
+ if (value.Contains(",") || (!value.Contains(" ") && !value.Contains("{")))
+ {
+ // specify value
+ string[] values;
+ if (value.Contains(','))
+ {
+ values = value.Split(new char[] { ',' });
+ }
+ else
+ {
+ values = new string[] { value };
+ }
+
+ ZqObject val;
+ if (values.Length == 1)
+ {
+ if (values[0].Contains('(') && values[0].Contains(')'))
+ {
+ // is function call
+ string fullyQualifiedName = values[0].Substring(0, values[0].IndexOf('('));
+ string parmList = values[0].Substring(values[0].IndexOf('(') + 1, values[0].IndexOf(')') - values[0].IndexOf('(') - 1);
+ val = new ZqMethodCall(new ZqVariableReference(fullyQualifiedName), parmList.Split(new char[] { ',' }));
+ }
+ else
+ {
+ val = new ZqVariableReference(values[0].Trim());
+ }
+ }
+ else
+ {
+ val = new ZqArray(values.Length);
+ for (int k = 0; k < values.Length; k++)
+ {
+ ((ZqArray)val)[k] = new ZqVariableReference(values[k].Trim());
+ }
+ }
+ return val;
+ }
+ else if (value.StartsWith("\"") && value.EndsWith("\""))
+ {
+ return value.Substring(1, value.Length - 2);
+ }
+ return null;
+ }
+
+ private string ReadBetween(string text, ref int i, char beginChar, char endChar)
+ {
+ StringBuilder sb = new StringBuilder();
+ int k = 0;
+ while (i < text.Length)
+ {
+ if (text[i] == beginChar)
+ {
+ if (k > 0)
+ {
+ sb.Append(text[i]);
+ }
+ k++;
+ i++;
+ }
+ else if (text[i] == endChar)
+ {
+ k--;
+ if (k > 0)
+ {
+ sb.Append(text[i]);
+ }
+ i++;
+
+ if (k == 0)
+ {
+ break;
+ }
+ }
+ else
+ {
+ sb.Append(text[i]);
+ i++;
+ }
+ }
+ return sb.ToString();
+ }
+
+ private Dictionary knownClasses = new Dictionary();
+
+ private ZqObject? ParseExpression(string funcBody, ref int j, ZqContext context)
+ {
+ string next = null;
+ ZqObject? expr = null;
+ char[] whitespace = new char[] { ' ', '\n', '\t' };
+
+ string firstToken = ReadUntil(funcBody, ref j, new char[] { ' ', '\n' }, false);
+ if (firstToken.Equals("if"))
+ {
+ expr = new ZqConditionalSelectAttributeMethod();
+
+ // SkipWhitespace(funcBody, ref j);
+ string varr = ReadUntil(funcBody, ref j, whitespace, false);
+
+ // SkipWhitespace(funcBody, ref j);
+ string op = ReadUntil(funcBody, ref j, whitespace, false);
+
+ // SkipWhitespace(funcBody, ref j);
+ string val = ReadUntil(funcBody, ref j, whitespace, false);
+
+ // SkipWhitespace(funcBody, ref j);
+ string _then = ReadUntil(funcBody, ref j, whitespace, false);
+ if (_then != "then")
+ {
+ return null;
+ }
+
+ // SkipWhitespace(funcBody, ref j);
+ string strExpr2 = ReadUntil(funcBody, ref j, whitespace, false);
+
+ int l = 0;
+ ZqObject? expr2 = ParseExpression(strExpr2, ref l, context);
+
+ // SkipWhitespace(funcBody, ref j);
+ string _else = ReadUntil(funcBody, ref j, whitespace, false);
+ if (_else != "else")
+ {
+ throw new ZqParserException();
+ }
+
+ // SkipWhitespace(funcBody, ref j);
+ string strExpr3 = ReadUntil(funcBody, ref j, '\n', false);
+
+ l = 0;
+ ZqObject? expr3 = ParseExpression(strExpr3, ref l, context);
+
+ ((ZqConditionalSelectAttributeMethod)expr).Cases.Add(new ZqConditionalSelectAttributeCase
+ (
+ // true conditions
+ new ZqCondition[]
+ {
+ new ZqCondition(varr, op, val)
+ },
+ new ZqCondition[0], // false conditions,
+ true, // use any condition
+ expr2 // return value
+ ));
+ ((ZqConditionalSelectAttributeMethod)expr).Cases.Add(new ZqConditionalSelectAttributeCase
+ (
+ new ZqCondition[0], // true conditions,
+ new ZqCondition[]
+ {
+ // false conditions
+ new ZqCondition(varr, op, val)
+ },
+ true, // use any condition
+ expr3 // return value
+ ));
+ return expr;
+ }
+ else if (firstToken.Equals("let"))
+ {
+ string varName = ReadUntil(funcBody, ref j, '=', false).Trim();
+ string varValue = ReadUntil(funcBody, ref j, '\n', false).Trim();
+ if (Decimal.TryParse(varValue, out decimal mValue))
+ {
+ context.Variables[varName] = mValue;
+ return new ZqVariableAssignment(varName, mValue);
+ }
+
+ context.Variables[varName] = varValue;
+ return new ZqVariableAssignment(varName, varValue);
+ }
+ else if (firstToken.Contains("(") && firstToken.EndsWith(")"))
+ {
+ // method call?
+ j = 0;
+
+ string fullyQualifiedName = ReadUntil(funcBody, ref j, '(', false);
+ string actualParameterList = ReadUntil(funcBody, ref j, ')', false);
+
+ string[] nameParts = fullyQualifiedName.Split(new char[] { '.' });
+ string[] parmValues = actualParameterList.Split(new char[] { ',' });
+
+ // if (knownClasses.ContainsKey(nameParts[0]))
+ // {
+ // ZqMethod func = knownClasses[nameParts[0]].Functions[nameParts[nameParts.Length - 1]];
+ string className = fullyQualifiedName.Substring(0, fullyQualifiedName.LastIndexOf('.'));
+ string methodName = fullyQualifiedName.Substring(fullyQualifiedName.LastIndexOf('.') + 1);
+
+ return new ZqMethodCall(new ZqMethodReference(className, methodName), parmValues);
+ // }
+ // return null;
+ }
+ else
+ {
+ // is variable?
+ return new ZqVariableReference(firstToken);
+ }
+ return expr;
+ }
+
+ private bool IsReturnAttributeDataType(string returnDataType)
+ {
+ return returnDataType.Equals("text") || returnDataType.Equals("numeric") || returnDataType.Equals("integer") || returnDataType.Equals("boolean");
+ }
+
+ /*
+ private bool SkipWhitespace(string text, ref int i)
+ {
+ while (i < text.Length - 1 && Char.IsWhiteSpace(text[i]) && Char.IsWhiteSpace(text[i + 1]))
+ {
+ i++;
+ }
+ if (i >= text.Length)
+ {
+ return false;
+ }
+
+ if (Char.IsWhiteSpace(text[i]))
+ {
+ i++;
+ }
+
+ if (i < text.Length)
+ {
+ return true;
+ }
+ return false;
+ }
+ */
+
+ public ZqObject? Parse(Stream stream)
+ {
+ StreamReader reader = new StreamReader(stream);
+ string value = reader.ReadToEnd();
+ return Parse(value);
+ }
+
+ private string? ReadUntil(string text, ref int i, char v, bool includeLastChar = true)
+ {
+ return ReadUntil(text, ref i, new string[] { v.ToString() }, out char lastChar, includeLastChar);
+ }
+
+ private string? ReadUntil(string text, ref int i, char v, out char lastChar, bool includeLastChar = true)
+ {
+ return ReadUntil(text, ref i, new string[] { v.ToString() }, out lastChar, includeLastChar);
+ }
+ private string? ReadUntil(string text, ref int i, char[] vs, bool includeLastChar = true)
+ {
+ return ReadUntil(text, ref i, vs, out char c, includeLastChar);
+ }
+
+ private string? ReadUntil(string text, ref int i, char[] vs, out char lastChar, bool includeLastChar = true)
+ {
+ string[] svs = new string[vs.Length];
+ for (int k = 0; k < vs.Length; k++)
+ {
+ svs[k] = vs[k].ToString();
+ }
+ return ReadUntil(text, ref i, svs, out lastChar, includeLastChar);
+ }
+
+ private string? ReadUntil(string text, ref int i, string v, bool includeLastChar = true)
+ {
+ return ReadUntil(text, ref i, new string[] { v }, out char lastChar, includeLastChar);
+ }
+
+ private string? ReadUntil(string text, ref int i, string v, out char lastChar, bool includeLastChar = true)
+ {
+ return ReadUntil(text, ref i, new string[] { v }, out lastChar, includeLastChar);
+ }
+ private string? ReadUntil(string text, ref int i, string[] vs, bool includeLastChar = true)
+ {
+ return ReadUntil(text, ref i, vs, out char lastChar, includeLastChar);
+ }
+
+ private string? ReadUntil(string text, ref int i, string[] vs, out char lastChar, bool includeLastChar = true)
+ {
+ StringBuilder sb = new StringBuilder();
+ while (true)
+ {
+ if (i >= text.Length)
+ {
+ lastChar = '\0';
+ return sb.ToString();
+ }
+
+ bool _break = false;
+ foreach (string v in vs)
+ {
+ if (i + v.Length - 1 < text.Length && text.Substring(i, v.Length).Equals(v))
+ {
+ if (includeLastChar)
+ {
+ sb.Append(text.Substring(i, v.Length));
+ }
+ i += v.Length;
+ _break = true;
+ break;
+ }
+ }
+ if (_break)
+ break;
+
+ sb.Append(text[i]);
+ i++;
+ }
+ lastChar = text[i - 1];
+ return sb.ToString();
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqParserException.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqParserException.cs
new file mode 100644
index 0000000..a412f74
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqParserException.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqParserException : Exception
+{
+
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqRelationship.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqRelationship.cs
new file mode 100644
index 0000000..173e73b
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqRelationship.cs
@@ -0,0 +1,67 @@
+using System;
+using Mocha.Core;
+
+namespace Mocha.Zq;
+
+public class ZqRelationship : ZqExpression
+{
+
+ public class ZqRelationshipCollection
+ : System.Collections.ObjectModel.Collection
+ {
+
+ private Dictionary _itemsByKey = new Dictionary();
+
+ protected override void ClearItems()
+ {
+ base.ClearItems();
+ _itemsByKey.Clear();
+ }
+ protected override void InsertItem(int index, ZqRelationship item)
+ {
+ base.InsertItem(index, item);
+ _itemsByKey[item.Name] = item;
+ }
+ protected override void RemoveItem(int index)
+ {
+ _itemsByKey.Remove(this[index].Name);
+ base.RemoveItem(index);
+ }
+
+ public ZqRelationship? this[string name]
+ {
+ get
+ {
+ if (_itemsByKey.ContainsKey(name))
+ {
+ return _itemsByKey[name];
+ }
+ return null;
+ }
+ }
+ public bool Contains(string name)
+ {
+ return _itemsByKey.ContainsKey(name);
+ }
+
+ }
+
+
+ public string Name { get; }
+ public string RelationshipTypeName { get; }
+ public ZqDataType DataType { get; }
+ public InstanceKey InstanceKey { get; }
+
+ public ZqRelationship(string name, string relationshipTypeName, ZqDataType dataType, InstanceKey instanceKey)
+ {
+ Name = name;
+ RelationshipTypeName = relationshipTypeName;
+ DataType = dataType;
+ InstanceKey = instanceKey;
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0}, {1} -> {2} {3}", Name, InstanceKey, RelationshipTypeName);
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqStubMethod.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqStubMethod.cs
new file mode 100644
index 0000000..9f54c24
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqStubMethod.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqStubMethod : ZqMethod
+{
+ public ZqStubMethod(string name, IEnumerable parms, ZqDataType returnDataType) : base(name)
+ {
+ if (parms != null)
+ {
+ foreach (ZqParameter parm in parms)
+ {
+ Parameters.Add(parm);
+ }
+ }
+ ReturnDataType = returnDataType;
+ }
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqTokenType.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqTokenType.cs
new file mode 100644
index 0000000..7772174
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqTokenType.cs
@@ -0,0 +1,9 @@
+namespace Mocha.Zq;
+
+public enum ZqTokenType
+{
+ None,
+ EndOfStream,
+ Separator,
+ Token
+}
diff --git a/mocha-dotnet/src/lib/Mocha.Zq/ZqVariableAssignment.cs b/mocha-dotnet/src/lib/Mocha.Zq/ZqVariableAssignment.cs
new file mode 100644
index 0000000..a2e85dd
--- /dev/null
+++ b/mocha-dotnet/src/lib/Mocha.Zq/ZqVariableAssignment.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Mocha.Zq;
+
+public class ZqVariableAssignment : ZqExpression
+{
+ public string VariableName { get; set; }
+ public object VariableValue { get; set; }
+
+ public ZqVariableAssignment(string variableName, object variableValue)
+ {
+ VariableName = variableName;
+ VariableValue = variableValue;
+ }
+
+}
diff --git a/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/MethodBindingTests.cs b/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/MethodBindingTests.cs
index 9a61563..00e11bf 100644
--- a/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/MethodBindingTests.cs
+++ b/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/MethodBindingTests.cs
@@ -101,4 +101,39 @@ public class MethodBindingTests : MethodTestsBase
*/
Assert.Ignore();
}
+
+ [Test]
+ public void Method_Binding__uses_super__Return_Instance_Set_Method_Binding()
+ {
+ InstanceHandle c_OMS = Oms.GetInstance(KnownInstanceGuids.Classes.OMS);
+ InstanceHandle i_OMS = Oms.CreateInstanceOf(c_OMS);
+ InstanceHandle i_OMS2 = Oms.CreateInstanceOf(c_OMS);
+
+ WorkSet ws = Oms.CreateWorkSet("Singleton OMS");
+
+ Oop.Methods.GetSpecifiedInstancesMethod m1 = Oms.MethodBuilder.CreateGetSpecifiedInstancesMethod(c_OMS, "get", "Singleton", ws, new InstanceHandle[] { i_OMS });
+ ReturnInstanceSetMethodBinding rsmb1 = m1.CreateMethodBinding(Oms);
+
+ Oop.Methods.GetSpecifiedInstancesMethod m2 = Oms.MethodBuilder.CreateGetSpecifiedInstancesMethod(c_OMS, "get", "Singleton 2", ws, new InstanceHandle[] { i_OMS2 });
+ ReturnInstanceSetMethodBinding rsmb2 = m2.CreateMethodBinding(Oms);
+
+ ReturnInstanceSetMethodBinding rsmb3 = m2.CreateMethodBinding(Oms);
+ Oms.AssignRelationship(rsmb3.Handle, Oms.GetInstance(KnownRelationshipGuids.Method_Binding__uses_super__Return_Instance_Set_Method_Binding), rsmb1.Handle);
+
+ OmsContext context = Oms.CreateContext();
+ InstanceHandle valWS = Oms.Execute(context, rsmb3);
+
+ Assert.That(valWS, Is.Not.EqualTo(InstanceHandle.Empty));
+
+ object? val = context.GetWorkData(valWS);
+
+ Assert.That(val, Is.InstanceOf>());
+ if (val is IEnumerable ie)
+ {
+ InstanceHandle[] ihs = ie.ToArray();
+ Assert.That(ihs.Length, Is.EqualTo(2));
+ Assert.That(ihs[0], Is.EqualTo(i_OMS));
+ Assert.That(ihs[1], Is.EqualTo(i_OMS2));
+ }
+ }
}
diff --git a/mocha-dotnet/tests/Mocha.Core.Tests/SampleDatabases/VehicleForHireTests.cs b/mocha-dotnet/tests/Mocha.Core.Tests/SampleDatabases/VehicleForHireTests.cs
index 1203e73..27414a6 100644
--- a/mocha-dotnet/tests/Mocha.Core.Tests/SampleDatabases/VehicleForHireTests.cs
+++ b/mocha-dotnet/tests/Mocha.Core.Tests/SampleDatabases/VehicleForHireTests.cs
@@ -115,6 +115,9 @@ public class VehicleForHireTests : OmsModelingTestsBase
VehicleForHireDB.Business busn = new VehicleForHireDB.Business("Ryde Rentals Transportation");
db.Businesses.Add(busn);
+ var query1 = from b in db.Businesses select b;
+ Assert.That(query1.Count(), Is.EqualTo(1));
+
var query2 = from b in db.Businesses where b.Name == "test" select b;
Assert.That(query2.Count(), Is.EqualTo(0));
diff --git a/mocha-dotnet/tests/Mocha.Zq.Tests/ClassDefinitionTests.cs b/mocha-dotnet/tests/Mocha.Zq.Tests/ClassDefinitionTests.cs
new file mode 100644
index 0000000..607ccf3
--- /dev/null
+++ b/mocha-dotnet/tests/Mocha.Zq.Tests/ClassDefinitionTests.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Reflection;
+
+namespace Mocha.Zq.Tests;
+
+public class ClassDefinitionTests
+{
+
+ [Test]
+ public void Class_with_Multiple_Attributes()
+ {
+ ZqParser parser = new ZqParser();
+ ZqObject? obj = parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ attributes:
+ name, 4$1 : text
+ order, 4$7 : text
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Attributes.Count, Is.EqualTo(2));
+ Assert.That(((ZqClass)obj).Attributes[1].Name, Is.EqualTo("order"));
+ }
+
+}
diff --git a/mocha-dotnet/tests/Mocha.Zq.Tests/Comments.cs b/mocha-dotnet/tests/Mocha.Zq.Tests/Comments.cs
new file mode 100644
index 0000000..27f95ee
--- /dev/null
+++ b/mocha-dotnet/tests/Mocha.Zq.Tests/Comments.cs
@@ -0,0 +1,34 @@
+using Mocha.Core;
+
+namespace Mocha.Zq.Tests;
+
+public class CommentsTests
+{
+ [Test]
+ public void SinglelineComment()
+ {
+ ZqParser zq = new ZqParser();
+ ZqObject? obj = zq.Parse(@"// class ZqTestClass2 { }");
+
+ // InstanceHandle c_ZqTestClass = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass2");
+ // Assert.That(c_ZqTestClass, Is.EqualTo(InstanceHandle.Empty));
+ Assert.That(obj, Is.Null);
+ }
+
+ [Test]
+ public void MultilineComment()
+ {
+ ZqParser zq = new ZqParser();
+ ZqObject? obj = zq.Parse(@"class /* ZqTestClass2 */ ZqTestClass3 { }");
+
+ // InstanceHandle c_ZqTestClass2 = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass2");
+ // Assert.That(c_ZqTestClass2, Is.EqualTo(InstanceHandle.Empty));
+
+ // InstanceHandle c_ZqTestClass3 = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass3");
+ // Assert.That(c_ZqTestClass3, Is.Not.EqualTo(InstanceHandle.Empty));
+ Assert.That(obj, Is.Not.Null);
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Name, Is.EqualTo("ZqTestClass3"));
+ }
+
+}
\ No newline at end of file
diff --git a/mocha-dotnet/tests/Mocha.Zq.Tests/GlobalUsings.cs b/mocha-dotnet/tests/Mocha.Zq.Tests/GlobalUsings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/mocha-dotnet/tests/Mocha.Zq.Tests/GlobalUsings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file
diff --git a/mocha-dotnet/tests/Mocha.Zq.Tests/IntegrationTests.cs b/mocha-dotnet/tests/Mocha.Zq.Tests/IntegrationTests.cs
new file mode 100644
index 0000000..9d0aa5b
--- /dev/null
+++ b/mocha-dotnet/tests/Mocha.Zq.Tests/IntegrationTests.cs
@@ -0,0 +1,274 @@
+using System;
+using Mocha.Core;
+using Mocha.Zq.Integration;
+
+namespace Mocha.Zq.Tests;
+
+public class IntegrationTests : Mocha.Core.Tests.OmsTestsBase
+{
+
+ [Test]
+ public void Create_Class()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+ zq.Evaluate(@"class ZqTestClass { }");
+
+ InstanceHandle c_ZqTestClass = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass");
+ Assert.That(c_ZqTestClass, Is.Not.EqualTo(InstanceHandle.Empty));
+ }
+
+ [Test]
+ public void UnitTestGCD()
+ {
+ Assert.Ignore();
+ /*
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+ object? obj = zq.Evaluate(@"test GreatestCommonDivisorTests
+ {
+ case gcdTest {
+
+ assert GreatestCommonDivisor.gcd(16, 4) == 4 :: """"
+ assert GreatestCommonDivisor.gcd(4, 16) == 4 :: """"
+ assert GreatestCommonDivisor.gcd(15, 60) == 15 :: """"
+ assert GreatestCommonDivisor.gcd(15, 65) == 5 :: """"
+ assert GreatestCommonDivisor.gcd(1052, 52) == 4 :: """"
+
+ }
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+
+ ZqTest test = (ZqTest)obj;
+ Assert.That(test.Cases.Count, Is.EqualTo(1));
+ Assert.That(test.Cases[0].Assertions.Count, Is.EqualTo(5));
+
+ Assert.DoesNotThrow(delegate ()
+ {
+ ZqTestResult result = test.Run();
+ });
+ */
+ }
+
+ [Test]
+ public void Create_Class_with_explicit_InstanceKey()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+ InstanceKey ik = new InstanceKey(1, 411009);
+ zq.Evaluate("class ZqTestClass, " + ik.ToString() + " { }");
+
+ InstanceHandle c_ZqTestClass = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass");
+ Assert.That(c_ZqTestClass, Is.Not.EqualTo(InstanceHandle.Empty));
+ Assert.That(Oms.GetInstanceKey(c_ZqTestClass), Is.EqualTo(ik));
+ }
+
+ [Test]
+ public void Create_Class_with_Instances()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+ zq.Evaluate(@"class ZqTestClass, 1$411009
+ {
+ instances:
+
+ TestInstance, 411009$1
+ AnotherTest, 411009$2
+
+ }");
+
+ InstanceHandle c_ZqTestClass = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass");
+ Assert.That(c_ZqTestClass, Is.Not.EqualTo(InstanceHandle.Empty));
+
+ IEnumerable instances = Oms.GetInstancesOf(c_ZqTestClass);
+ Assert.That(instances.Count(), Is.EqualTo(2));
+
+ InstanceHandle i_1 = instances.First();
+ string name = Oms.GetAttributeValue(i_1, Oms.GetInstance(KnownAttributeGuids.Text.Name));
+ Assert.That(name, Is.EqualTo("TestInstance"));
+ }
+
+ [Test]
+ public void Create_Get_Specific_Instances_Method_Singular()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+ ZqObject? obj = zq.Parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ functions:
+
+ static function getInstance() : ZqTestClass = TestInstance
+
+ instances:
+
+ TestInstance, 411009$1
+ AnotherTest, 411009$2
+
+ }");
+ zq.Evaluate(obj);
+
+ InstanceHandle c_ZqTestClass = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass");
+ Assert.That(c_ZqTestClass, Is.Not.EqualTo(InstanceHandle.Empty));
+
+ InstanceHandle TestInstance = Oms.GetInstancesOf(c_ZqTestClass).First();
+
+ Core.Oop.Method method = Oms.GetMethod(c_ZqTestClass, null, "getInstance", null, true);
+ Assert.That(method, Is.Not.Null);
+
+ OmsContext context = Oms.CreateContext();
+ InstanceHandle ih = Oms.Execute(context, method);
+ object? val = context.GetWorkData(ih);
+
+ Assert.That(val, Is.Not.Null);
+ Assert.That(((IEnumerable)val).First(), Is.EqualTo(TestInstance));
+ }
+
+ [Test]
+ public void Create_Get_Specific_Instances_Method_Nonsingular()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+ ZqObject? obj = zq.Parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ functions:
+
+ static function getInstance() : ZqTestClass* = TestInstance, AnotherTest
+
+ instances:
+
+ TestInstance, 411009$1
+ AnotherTest, 411009$2
+
+ }");
+ zq.Evaluate(obj);
+
+ InstanceHandle c_ZqTestClass = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass");
+ Assert.That(c_ZqTestClass, Is.Not.EqualTo(InstanceHandle.Empty));
+
+ InstanceHandle[] insts = Oms.GetInstancesOf(c_ZqTestClass).ToArray();
+
+ Core.Oop.Method method = Oms.GetMethod(c_ZqTestClass, null, "getInstance", null, true);
+ Assert.That(method, Is.Not.Null);
+
+ OmsContext context = Oms.CreateContext();
+ InstanceHandle ih = Oms.Execute(context, method);
+ object? val = context.GetWorkData(ih);
+
+ Assert.That(val, Is.Not.Null);
+ Assert.That(((IEnumerable)val).First(), Is.EqualTo(insts[0]));
+ Assert.That(((IEnumerable)val).ElementAt(1), Is.EqualTo(insts[1]));
+ }
+
+ [Test]
+ public void Create_Multiple_Methods()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+ ZqObject? obj = zq.Parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ functions:
+
+ static function getInstance() : ZqTestClass = TestInstance
+ static function getAnother() : ZqTestClass = AnotherTest
+
+ instances:
+
+ TestInstance, 411009$1
+ AnotherTest, 411009$2
+
+ }");
+ zq.Evaluate(obj);
+
+ InstanceHandle c_ZqTestClass = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass");
+ Assert.That(c_ZqTestClass, Is.Not.EqualTo(InstanceHandle.Empty));
+
+ InstanceHandle TestInstance = Oms.GetInstancesOf(c_ZqTestClass).First();
+
+ Core.Oop.Method method = Oms.GetMethod(c_ZqTestClass, null, "getInstance", null, true);
+ Assert.That(method, Is.Not.Null);
+
+ OmsContext context = Oms.CreateContext();
+ InstanceHandle ih = Oms.Execute(context, method);
+ object? val = context.GetWorkData(ih);
+
+ Assert.That(val, Is.Not.Null);
+ Assert.That(((IEnumerable)val).First(), Is.EqualTo(TestInstance));
+ }
+
+
+ [Test]
+ public void Create_Multiple_Different_Methods()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+ ZqObject? obj = zq.Parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ functions:
+
+ static function getInstance() : ZqTestClass = TestInstance
+
+ static function gcd (p:integer, q : integer) : integer =
+ {
+
+ if q == 0
+ then p
+ else GreatestCommonDivisor.gcd(q, p % q)
+
+ }
+
+ static function getAnother() : ZqTestClass = AnotherTest
+ static function getAll() : ZqTestClass* = TestInstance, AnotherTest
+
+ instances:
+
+ TestInstance, 411009$1
+ AnotherTest, 411009$2
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Functions.Count, Is.EqualTo(4));
+
+ zq.Evaluate(obj);
+
+ InstanceHandle c_ZqTestClass = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "ZqTestClass");
+ Assert.That(c_ZqTestClass, Is.Not.EqualTo(InstanceHandle.Empty));
+
+ InstanceHandle TestInstance = Oms.GetInstancesOf(c_ZqTestClass).First();
+
+ Core.Oop.Method method = Oms.GetMethod(c_ZqTestClass, null, "getInstance", null, true);
+ Assert.That(method, Is.Not.Null);
+
+ OmsContext context = Oms.CreateContext();
+ InstanceHandle ih = Oms.Execute(context, method);
+ object? val = context.GetWorkData(ih);
+
+ Assert.That(val, Is.Not.Null);
+ Assert.That(((IEnumerable)val).First(), Is.EqualTo(TestInstance));
+ }
+
+ [Test]
+ public void Pull_Class_Definition_from_OMS()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+
+ ZqObject obj1 = zq.Import(Oms.GetInstance(KnownInstanceGuids.Classes.AccessModifier));
+ string code1 = zq.GenerateCode(obj1);
+
+
+ ZqObject obj2 = zq.Import(Oms.GetInstance(KnownInstanceGuids.Classes.Instance));
+ string code2 = zq.GenerateCode(obj2);
+
+ // ZqObject obj2 = zq.Parser.Parse(code);
+ // Assert.That(code, Is.EqualTo("function getParentClass() : Class* = this.forClass"));
+ }
+
+ [Test(Description = "Checks that a Get Relationship Method pulls from the OMS, converts to Zq, compiles, and converts back into Zq.")]
+ public void Pull_GR_Method_Definition_from_OMS()
+ {
+ ZqIntegrator zq = new ZqIntegrator(Oms);
+
+ ZqObject obj = zq.Import(Oms.GetInstance(KnownInstanceGuids.Methods.GetRelationship.Instance__get__Parent_Class));
+ string code = zq.GenerateCode(obj);
+
+ Assert.That(code, Is.EqualTo("function getParentClass() : Class* = this.forClass"));
+
+ ZqObject obj2 = zq.Parser.Parse(code);
+ string code2 = zq.GenerateCode(obj2);
+
+ Assert.That(code2, Is.EqualTo(code));
+ }
+}
diff --git a/mocha-dotnet/tests/Mocha.Zq.Tests/MathTests.cs b/mocha-dotnet/tests/Mocha.Zq.Tests/MathTests.cs
new file mode 100644
index 0000000..e75e38b
--- /dev/null
+++ b/mocha-dotnet/tests/Mocha.Zq.Tests/MathTests.cs
@@ -0,0 +1,88 @@
+using System;
+using Mocha.Zq.Methods;
+
+namespace Mocha.Zq.Tests;
+
+public class MathTests
+{
+
+ [Test]
+ public void Greatest_Common_Divisor()
+ {
+ ZqParser zq = new ZqParser();
+
+ ZqObject? obj = zq.Parse(@" class GreatestCommonDivisor {
+
+ functions:
+
+ static function gcd (p:integer, q : integer) : integer = {
+
+ if q == 0
+ then p
+ else GreatestCommonDivisor.gcd(q, p % q)
+
+ }
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+
+ if (obj is ZqClass zql)
+ {
+ Assert.That(zql.Name, Is.EqualTo("GreatestCommonDivisor"));
+ Assert.That(zql.Functions.Count, Is.EqualTo(1));
+ Assert.That(zql.Functions[0].Name, Is.EqualTo("gcd"));
+ Assert.That(zql.Functions[0], Is.TypeOf());
+
+ /*
+
+ InstanceHandle c_GCD = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "GreatestCommonDivisor");
+ Assert.That(c_GCD, Is.Not.EqualTo(InstanceHandle.Empty));
+
+ InstanceHandle i_GcdMethod = zq.GetMethod("GreatestCommonDivisor.gcd");
+ Assert.That(i_GcdMethod, Is.Not.EqualTo(InstanceHandle.Empty));
+ */
+ }
+ }
+
+ [Test]
+ public void Greatest_Common_Divisor_with_multiline_comment_in_the_middle_of_an_Expression()
+ {
+ ZqParser zq = new ZqParser();
+
+ ZqObject? obj = zq.Parse(@" class GreatestCommonDivisor {
+
+ functions:
+
+ static function gcd (p:integer, q : integer) : integer = {
+
+ if q == 0/* hey I'ma
+multiline comment*/
+ then p
+ else GreatestCommonDivisor.gcd(q, p % q)
+
+ }
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+
+ if (obj is ZqClass zql)
+ {
+ Assert.That(zql.Name, Is.EqualTo("GreatestCommonDivisor"));
+ Assert.That(zql.Functions.Count, Is.EqualTo(1));
+ Assert.That(zql.Functions[0].Name, Is.EqualTo("gcd"));
+ Assert.That(zql.Functions[0], Is.TypeOf());
+
+ /*
+
+ InstanceHandle c_GCD = Oms.GetInstanceByName(Oms.GetInstance(KnownInstanceGuids.Classes.Class), "GreatestCommonDivisor");
+ Assert.That(c_GCD, Is.Not.EqualTo(InstanceHandle.Empty));
+
+ InstanceHandle i_GcdMethod = zq.GetMethod("GreatestCommonDivisor.gcd");
+ Assert.That(i_GcdMethod, Is.Not.EqualTo(InstanceHandle.Empty));
+ */
+ }
+ }
+
+}
diff --git a/mocha-dotnet/tests/Mocha.Zq.Tests/MethodDefinitionTests.cs b/mocha-dotnet/tests/Mocha.Zq.Tests/MethodDefinitionTests.cs
new file mode 100644
index 0000000..9b4e1fe
--- /dev/null
+++ b/mocha-dotnet/tests/Mocha.Zq.Tests/MethodDefinitionTests.cs
@@ -0,0 +1,155 @@
+using System;
+using Mocha.Core;
+using Mocha.Zq.Methods;
+using NUnit.Framework.Interfaces;
+
+namespace Mocha.Zq.Tests;
+
+public class MethodDefinitionTests
+{
+ [Test]
+ public void Stub_Function_Call_Test()
+ {
+
+ ZqParser parser = new ZqParser();
+ ZqObject? obj = parser.Parse(@"class CommonInstanceSet, 1$770
+ {
+ functions:
+
+ // the actual method definition is in the MADI OMS
+ // we re-declare the function here only to use it within Zq
+ static stub function instanceByInstanceID(instanceID : text) : instance
+
+ static function testStubFunctionCall() : Class = {
+
+ CommonInstanceSet.instanceByInstanceID('1$770')
+
+ }
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Functions.Count, Is.EqualTo(2));
+ Assert.That(((ZqClass)obj).Functions[1], Is.TypeOf());
+ Assert.That(((ZqSimpleReturnMethod)((ZqClass)obj).Functions[1]).ReturnValue, Is.TypeOf());
+ Assert.That(((ZqMethodCall)((ZqSimpleReturnMethod)((ZqClass)obj).Functions[1]).ReturnValue).ParmValues.Length, Is.EqualTo(1));
+
+ // FIXME: the text literal, once parsed, should not have '' / "" quotes
+ Assert.That(((ZqMethodCall)((ZqSimpleReturnMethod)((ZqClass)obj).Functions[1]).ReturnValue).ParmValues[0], Is.EqualTo("'1$770'"));
+ }
+
+ [Test]
+ public void Stub_Function_Test()
+ {
+
+ ZqParser parser = new ZqParser();
+ ZqObject? obj = parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ functions:
+
+ // the actual method definition is in the MADI OMS
+ // we re-declare the function here only to use it within Zq
+ static stub function testStub() : integer
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Functions.Count, Is.EqualTo(1));
+ Assert.That(((ZqClass)obj).Functions[0], Is.TypeOf());
+ Assert.That(((ZqMethod)((ZqClass)obj).Functions[0]).ReturnDataType, Is.EqualTo(ZqDataType.Integer));
+ }
+
+ [Test]
+ public void BA_String_Inline_Test()
+ {
+
+ ZqParser parser = new ZqParser();
+ ZqObject? obj = parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ functions:
+
+ static function getAString() : text = ""Build Attribute Method""
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Functions.Count, Is.EqualTo(1));
+ Assert.That(((ZqClass)obj).Functions[0], Is.TypeOf());
+ Assert.That(((ZqBuildAttributeMethod)((ZqClass)obj).Functions[0]).InitialValue, Is.EqualTo("Build Attribute Method"));
+ }
+
+
+ [Test]
+ public void BA_String_Fullbody_Test()
+ {
+
+ ZqParser parser = new ZqParser();
+ ZqObject? obj = parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ functions:
+
+ static function getAString() : text = {
+ ""Build Attribute Method""
+ }
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Functions.Count, Is.EqualTo(1));
+ Assert.That(((ZqClass)obj).Functions[0], Is.TypeOf());
+ Assert.That(((ZqBuildAttributeMethod)((ZqClass)obj).Functions[0]).InitialValue, Is.EqualTo("Build Attribute Method"));
+ }
+
+
+ [Test]
+ public void Temporary_Variable_Test()
+ {
+
+ ZqParser parser = new ZqParser();
+ ZqObject? obj = parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ functions:
+
+ static function getSomeInteger() : integer =
+ {
+ let someInteger = 5
+ someInteger
+ }
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Functions.Count, Is.EqualTo(1));
+ Assert.That(((ZqClass)obj).Functions[0], Is.TypeOf());
+ Assert.That(((ZqBuildAttributeMethod)((ZqClass)obj).Functions[0]).InitialValue, Is.EqualTo(5));
+ }
+
+ [Test]
+ public void Get_Relationship_Method()
+ {
+ ZqParser parser = new ZqParser();
+ ZqObject? obj = parser.Parse(@"class ZqTestClass, 1$411009
+ {
+ attributes:
+ name, 4$1 : text
+ order, 4$7 : text
+
+ relationships:
+ hasAnotherTestClass, 3$410001 -> has another ZqTestClass*
+
+ functions:
+
+ public function getAnotherZqTestClass() : ZqTestClass = {
+ this.hasAnotherTestClass
+ }
+
+ }");
+
+ Assert.That(obj, Is.TypeOf());
+ Assert.That(((ZqClass)obj).Relationships.Count, Is.EqualTo(1));
+ Assert.That(((ZqClass)obj).Relationships[0].Name, Is.EqualTo("hasAnotherTestClass"));
+ Assert.That(((ZqClass)obj).Relationships[0].InstanceKey, Is.EqualTo(new InstanceKey(3, 410001)));
+ Assert.That(((ZqClass)obj).Relationships[0].DataType, Is.EqualTo(new ZqDataType("ZqTestClass", true)));
+ }
+
+}
diff --git a/mocha-dotnet/tests/Mocha.Zq.Tests/Mocha.Zq.Tests.csproj b/mocha-dotnet/tests/Mocha.Zq.Tests/Mocha.Zq.Tests.csproj
new file mode 100644
index 0000000..735fe46
--- /dev/null
+++ b/mocha-dotnet/tests/Mocha.Zq.Tests/Mocha.Zq.Tests.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+