diff --git a/Directory.Build.props b/Directory.Build.props index d15ef0e..5f5b29b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -9,7 +9,7 @@ Simpra ALTA Software llc. Copyright © 2024 ALTA Software llc. - 1.0.12 + 1.0.13 diff --git a/src/AltaSoft.Simpra/Visitor/SimpraParserVisitor.cs b/src/AltaSoft.Simpra/Visitor/SimpraParserVisitor.cs index 989ccef..316616c 100644 --- a/src/AltaSoft.Simpra/Visitor/SimpraParserVisitor.cs +++ b/src/AltaSoft.Simpra/Visitor/SimpraParserVisitor.cs @@ -263,6 +263,14 @@ public Expression VisitIndexAccess(SimpraParser.IndexAccessContext context) objectType = left.Type; } + // Handle IDictionary (including Dictionary<,>) + var isDictionary = objectType.IsIReadOnlyDictionaryT(); + + if (isDictionary) + { + return HandleDictionaryIndexAccess(context, objectType, index, left); + } + // Handle indexable types (e.g., List) var defaultIndexer = objectType .GetProperties() @@ -552,4 +560,21 @@ public Expression VisitArray(SimpraParser.ArrayContext context) { return NewSimpraList(context.exp().Select(Visit), context); } + + private static Expression HandleDictionaryIndexAccess(SimpraParser.IndexAccessContext context, Type objectType, Expression index, Expression left) + { + var keyType = objectType.GetGenericArguments()[0]; + var valueType = objectType.GetGenericArguments()[1]; + var tryGetValueMethod = objectType.GetMethod("TryGetValue", [keyType, valueType.MakeByRefType()])!; + + var keyExpr = index.Type != keyType ? Expression.Convert(index, keyType) : index; + var valueVar = Expression.Variable(valueType, "dictValue"); + + var tryGetValueCall = Expression.Call(left, tryGetValueMethod, keyExpr, valueVar); + + var defaultValue = Expression.Default(valueType); + var block = Expression.Block([valueVar], Expression.Condition(tryGetValueCall, valueVar, defaultValue)); + + return ConvertToSimpraType(block, false, context); + } } diff --git a/tests/AltaSoft.Simpra.tests/Models/TestModel.cs b/tests/AltaSoft.Simpra.tests/Models/TestModel.cs index 3478df2..24f9f89 100644 --- a/tests/AltaSoft.Simpra.tests/Models/TestModel.cs +++ b/tests/AltaSoft.Simpra.tests/Models/TestModel.cs @@ -30,6 +30,9 @@ public class TestModel : BaseModel, ITransferModel public required Transfer? Transfer { get; set; } public required Customer Customer { get; set; } public required string Remittance { get; set; } + public Dictionary? Countries { get; set; } + + public Dictionary? DictionaryOfObjects { get; set; } public ColorX ColorX { get; set; } = ColorX.Green; public ColorM ColorM { get; set; } = ColorM.Green; diff --git a/tests/AltaSoft.Simpra.tests/SimpraExpressionTests.cs b/tests/AltaSoft.Simpra.tests/SimpraExpressionTests.cs index 695fc1b..7943ac6 100644 --- a/tests/AltaSoft.Simpra.tests/SimpraExpressionTests.cs +++ b/tests/AltaSoft.Simpra.tests/SimpraExpressionTests.cs @@ -4,6 +4,60 @@ namespace AltaSoft.Simpra.Tests; public class SimpraExpressionTests { + + [Fact] + public void DictionaryIndexer_MissingKey_ReturnsDefaultValueForProperty() + { + const string expressionCode = + """ + return DictionaryOfObjects['test'].Id + """; + + var simpra = new Simpra(); + var model = GetTestModel(); + model.DictionaryOfObjects = new Dictionary { { "Georgia", new Customer + { + Id = 1, + Status = 10 + }} }; + + var result = simpra.Execute(model, new TestFunctions(), expressionCode); + Assert.Equal(0, result); + + } + + [Fact] + public void CallGetValueFromDictionaryWhenKeyDoesNotExist_ShouldReturnDefault() + { + const string expressionCode = + """ + return Countries['test'] is 'Test' + """; + + var simpra = new Simpra(); + var model = GetTestModel(); + model.Countries = new Dictionary { { "Georgia", "Test" } }; + var result = simpra.Execute(model, new TestFunctions(), expressionCode); + Assert.False(result); + + } + + [Fact] + public void CallGetValueFromDictionaryWhenKeyExist_ShouldReturnValue() + { + const string expressionCode = + """ + return Countries['Georgia'] is 'Test' + """; + + var simpra = new Simpra(); + var model = GetTestModel(); + model.Countries = new Dictionary { { "Georgia", "Test" } }; + var result = simpra.Execute(model, new TestFunctions(), expressionCode); + Assert.True(result); + + } + [Fact] public void CallInterfaceFunctionFromSimpra_ShouldReturnCorrectValue() {