From adf800febc915b371a524f01e8216556de284a71 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Fri, 27 Dec 2024 19:00:29 -0500 Subject: [PATCH 1/4] implement `Method Binding.uses super Return Instance Set Method Binding` --- mocha-common | 2 +- .../lib/Mocha.Core/KnownRelationshipGuids.cs | 1 + mocha-dotnet/src/lib/Mocha.Core/Oms.cs | 22 ++++++++++++ .../MethodTests/MethodBindingTests.cs | 35 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/mocha-common b/mocha-common index 569e302..6514615 160000 --- a/mocha-common +++ b/mocha-common @@ -1 +1 @@ -Subproject commit 569e302f3000e236ba562f17bc83d9e70a54fbf5 +Subproject commit 6514615b51e61aa43ef54f6a9bc4da048cc37e4e 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/Oms.cs b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs index e1edfa4..3ba6991 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs @@ -1080,6 +1080,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 { 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)); + } + } } From c268310f39099a9216ddc53d2764697456569143 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Mon, 30 Dec 2024 23:20:55 -0500 Subject: [PATCH 2/4] update mocha-common --- mocha-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mocha-common b/mocha-common index 6514615..52ad659 160000 --- a/mocha-common +++ b/mocha-common @@ -1 +1 @@ -Subproject commit 6514615b51e61aa43ef54f6a9bc4da048cc37e4e +Subproject commit 52ad6594f3fc08a3cf77a1693ec0b254298720d2 From 9b501f29f6ed0e250a82be0a7ada82a1025fedd4 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Mon, 30 Dec 2024 23:23:07 -0500 Subject: [PATCH 3/4] improve the .NET-to-Mocha object modeling system --- .../src/lib/Mocha.Core/Modeling/OmsClass.cs | 28 +++++++++++++-- .../Mocha.Core/Modeling/OmsInstanceList.cs | 36 ++++++++++++++++--- .../SampleDatabases/VehicleForHireTests.cs | 3 ++ 3 files changed, 59 insertions(+), 8 deletions(-) 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/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)); From f1d5768b982fab06fe8b2286b7a2042a92a18f6d Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Mon, 30 Dec 2024 23:23:49 -0500 Subject: [PATCH 4/4] preliminary implementation of Zq scripting language for MADI --- mocha-dotnet.sln | 21 + mocha-dotnet/src/lib/Mocha.Core/Oms.cs | 26 +- .../src/lib/Mocha.Core/OmsMethodBuilder.cs | 11 + .../Mocha.Zq.Integration.csproj | 15 + .../lib/Mocha.Zq.Integration/ZqIntegrator.cs | 291 ++++++ .../src/lib/Mocha.Zq/Expressions/ZqLiteral.cs | 13 + .../Expressions/ZqVariableReference.cs | 40 + mocha-dotnet/src/lib/Mocha.Zq/IZqMethod.cs | 10 + .../Methods/ZqBuildAttributeMethod.cs | 12 + .../ZqConditionalSelectAttributeCase.cs | 28 + .../ZqConditionalSelectAttributeMethod.cs | 11 + .../Methods/ZqGetRelationshipMethod.cs | 15 + .../Mocha.Zq/Methods/ZqSimpleReturnMethod.cs | 13 + mocha-dotnet/src/lib/Mocha.Zq/Mocha.Zq.csproj | 14 + .../src/lib/Mocha.Zq/ZqAccessModifier.cs | 11 + mocha-dotnet/src/lib/Mocha.Zq/ZqArray.cs | 37 + mocha-dotnet/src/lib/Mocha.Zq/ZqAttribute.cs | 18 + mocha-dotnet/src/lib/Mocha.Zq/ZqClass.cs | 34 + .../src/lib/Mocha.Zq/ZqClassDefinition.cs | 12 + mocha-dotnet/src/lib/Mocha.Zq/ZqCondition.cs | 24 + mocha-dotnet/src/lib/Mocha.Zq/ZqContext.cs | 8 + mocha-dotnet/src/lib/Mocha.Zq/ZqDataType.cs | 66 ++ mocha-dotnet/src/lib/Mocha.Zq/ZqExpression.cs | 8 + mocha-dotnet/src/lib/Mocha.Zq/ZqInstance.cs | 16 + mocha-dotnet/src/lib/Mocha.Zq/ZqMethod.cs | 53 + mocha-dotnet/src/lib/Mocha.Zq/ZqMethodCall.cs | 20 + .../src/lib/Mocha.Zq/ZqMethodReference.cs | 18 + mocha-dotnet/src/lib/Mocha.Zq/ZqObject.cs | 7 + mocha-dotnet/src/lib/Mocha.Zq/ZqOperation.cs | 7 + mocha-dotnet/src/lib/Mocha.Zq/ZqParameter.cs | 27 + mocha-dotnet/src/lib/Mocha.Zq/ZqParser.cs | 934 ++++++++++++++++++ .../src/lib/Mocha.Zq/ZqParserException.cs | 8 + .../src/lib/Mocha.Zq/ZqRelationship.cs | 67 ++ mocha-dotnet/src/lib/Mocha.Zq/ZqStubMethod.cs | 18 + mocha-dotnet/src/lib/Mocha.Zq/ZqTokenType.cs | 9 + .../src/lib/Mocha.Zq/ZqVariableAssignment.cs | 16 + .../Mocha.Zq.Tests/ClassDefinitionTests.cs | 26 + mocha-dotnet/tests/Mocha.Zq.Tests/Comments.cs | 34 + .../tests/Mocha.Zq.Tests/GlobalUsings.cs | 1 + .../tests/Mocha.Zq.Tests/IntegrationTests.cs | 274 +++++ .../tests/Mocha.Zq.Tests/MathTests.cs | 88 ++ .../Mocha.Zq.Tests/MethodDefinitionTests.cs | 155 +++ .../Mocha.Zq.Tests/Mocha.Zq.Tests.csproj | 28 + 43 files changed, 2541 insertions(+), 3 deletions(-) create mode 100644 mocha-dotnet/src/lib/Mocha.Zq.Integration/Mocha.Zq.Integration.csproj create mode 100644 mocha-dotnet/src/lib/Mocha.Zq.Integration/ZqIntegrator.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/Expressions/ZqLiteral.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/Expressions/ZqVariableReference.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/IZqMethod.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqBuildAttributeMethod.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqConditionalSelectAttributeCase.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqConditionalSelectAttributeMethod.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqGetRelationshipMethod.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/Methods/ZqSimpleReturnMethod.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/Mocha.Zq.csproj create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqAccessModifier.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqArray.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqAttribute.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqClass.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqClassDefinition.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqCondition.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqContext.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqDataType.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqExpression.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqInstance.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqMethod.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqMethodCall.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqMethodReference.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqObject.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqOperation.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqParameter.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqParser.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqParserException.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqRelationship.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqStubMethod.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqTokenType.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Zq/ZqVariableAssignment.cs create mode 100644 mocha-dotnet/tests/Mocha.Zq.Tests/ClassDefinitionTests.cs create mode 100644 mocha-dotnet/tests/Mocha.Zq.Tests/Comments.cs create mode 100644 mocha-dotnet/tests/Mocha.Zq.Tests/GlobalUsings.cs create mode 100644 mocha-dotnet/tests/Mocha.Zq.Tests/IntegrationTests.cs create mode 100644 mocha-dotnet/tests/Mocha.Zq.Tests/MathTests.cs create mode 100644 mocha-dotnet/tests/Mocha.Zq.Tests/MethodDefinitionTests.cs create mode 100644 mocha-dotnet/tests/Mocha.Zq.Tests/Mocha.Zq.Tests.csproj 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/Oms.cs b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs index 3ba6991..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); } @@ -1394,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); @@ -1405,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); } @@ -2073,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.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 + + + + + + + + + + + + + + + + + + +