From d7ed78fba87d512a85e115e4292ebe15cdb8a8b7 Mon Sep 17 00:00:00 2001 From: Stepami Date: Sat, 25 Apr 2026 00:17:19 +0300 Subject: [PATCH 1/5] chore(sln file): removed mention of tests/Directory.Packages.props --- ExtendedJavaScriptSubset.slnx | 1 - 1 file changed, 1 deletion(-) diff --git a/ExtendedJavaScriptSubset.slnx b/ExtendedJavaScriptSubset.slnx index 4932071c..94a939ee 100644 --- a/ExtendedJavaScriptSubset.slnx +++ b/ExtendedJavaScriptSubset.slnx @@ -51,6 +51,5 @@ - \ No newline at end of file From c4632f9f6565b69dd688153ae2dc4df28fbcaabd Mon Sep 17 00:00:00 2001 From: Stepami Date: Sat, 25 Apr 2026 00:59:51 +0300 Subject: [PATCH 2/5] test(TypeDeclarationsResolver): add unit test for resolving type declarations Closes #231 --- .../TypeDeclarationsResolverTests.cs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs diff --git a/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs b/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs new file mode 100644 index 00000000..b5a51ede --- /dev/null +++ b/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs @@ -0,0 +1,84 @@ +using HydraScript.Application.StaticAnalysis.Impl; +using HydraScript.Application.StaticAnalysis.Visitors; +using HydraScript.Domain.FrontEnd.Parser; +using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes; +using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Declarations; +using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Domain.IR.Impl; +using HydraScript.Domain.IR.Impl.Symbols; +using HydraScript.Domain.IR.Impl.Symbols.Ids; +using HydraScript.Domain.IR.Types; + +namespace HydraScript.UnitTests.Application; + +/// +/// Тесты +/// +public class TypeDeclarationsResolverTests +{ + /// + /// https://github.com/Stepami/hydrascript/issues/231 + /// + [Fact] + public void Resolve_Issue231_Success() + { + // Arrange + const string itemTypeName = "QueryStringParseResultItem"; + const string resultTypeName = "QueryStringParseResult"; + + var scope = new Scope(); + var symbolTable = new SymbolTable(); + symbolTable.AddSymbol(new TypeSymbol(itemTypeName)); + symbolTable.AddSymbol(new TypeSymbol(resultTypeName)); + + var symbolTables = new SymbolTableStorage(); + symbolTables.Init(scope, symbolTable); + + var resolver = new TypeDeclarationsResolver( + new HydraScriptTypesService(), + symbolTables, + new TypeBuilder(symbolTables)); + + foreach (var defaultType in resolver.TypesService.GetDefaultTypes()) + { + symbolTable.AddSymbol(new TypeSymbol(defaultType)); + } + + var resultDeclaration = new TypeDeclaration( + new IdentifierReference(resultTypeName), + new ObjectTypeValue( + [ + new PropertyTypeValue( + "result", + new ArrayTypeValue( + new TypeIdentValue( + new IdentifierReference(itemTypeName)))), + ])); + + var itemDeclaration = new TypeDeclaration( + new IdentifierReference(itemTypeName), + new ObjectTypeValue( + [ + new PropertyTypeValue("name", TypeIdentValue.String), + new PropertyTypeValue("value", TypeIdentValue.String), + ])); + + var root = new ScriptBody([resultDeclaration, itemDeclaration]); + root.InitScope(scope); + itemDeclaration.InitScope(); + resultDeclaration.InitScope(); + + // Act + resolver.Store(resultDeclaration); + resolver.Store(itemDeclaration); + + resolver.Resolve(); + + // Assert + var itemType = symbolTable.FindSymbol(new TypeSymbolId(itemTypeName))?.Type; + var resultType = symbolTable.FindSymbol(new TypeSymbolId(resultTypeName))?.Type as ObjectType; + + resultType.Should().NotBeNull(); + resultType["result"].Should().Be(itemType); + } +} \ No newline at end of file From 8f4b8be59bbd510b98d176a1d5f2a4ebf358de0b Mon Sep 17 00:00:00 2001 From: Stepami Date: Sat, 25 Apr 2026 01:40:13 +0300 Subject: [PATCH 3/5] test(TypeDeclarationsResolver): fix test fix test to validate array type for 'result' property Closes #231 --- .../Application/TypeDeclarationsResolverTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs b/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs index b5a51ede..2e9b2d9d 100644 --- a/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs +++ b/tests/HydraScript.UnitTests/Application/TypeDeclarationsResolverTests.cs @@ -78,7 +78,8 @@ public void Resolve_Issue231_Success() var itemType = symbolTable.FindSymbol(new TypeSymbolId(itemTypeName))?.Type; var resultType = symbolTable.FindSymbol(new TypeSymbolId(resultTypeName))?.Type as ObjectType; + itemType.Should().NotBeNull(); resultType.Should().NotBeNull(); - resultType["result"].Should().Be(itemType); + resultType["result"].Should().Be(new ArrayType(itemType)); } } \ No newline at end of file From dd1fb167c061922aa12781836e380c8b1a1aed72 Mon Sep 17 00:00:00 2001 From: Stepami Date: Sat, 25 Apr 2026 01:41:20 +0300 Subject: [PATCH 4/5] fix(TypeDeclarationsResolver): type resolution process Method Resolve is split into two phases - type building and reference resolving Closes #231 --- .../Impl/TypeDeclarationsResolver.cs | 34 +++++++++++-------- .../Impl/Symbols/TypeSymbol.cs | 5 +++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs b/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs index 6c2e1bd0..02a23dcd 100644 --- a/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs +++ b/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs @@ -1,5 +1,6 @@ using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Declarations; using HydraScript.Domain.IR.Impl.Symbols; +using HydraScript.Domain.IR.Impl.Symbols.Ids; using ZLinq; namespace HydraScript.Application.StaticAnalysis.Impl; @@ -9,39 +10,44 @@ internal class TypeDeclarationsResolver( ISymbolTableStorage symbolTables, IVisitor typeBuilder) : ITypeDeclarationsResolver { - private readonly Queue _declarationsToResolve = []; + private readonly List _declarationsToResolve = []; public void Store(TypeDeclaration declaration) => - _declarationsToResolve.Enqueue(declaration); + _declarationsToResolve.Add(declaration); public void Resolve() { + // build phase + for (var i = 0; i < _declarationsToResolve.Count; i++) + { + var typeSymbol = new TypeSymbol( + _declarationsToResolve[i].TypeValue.Accept(typeBuilder), + _declarationsToResolve[i].TypeId); + symbolTables[_declarationsToResolve[i].Scope].AddSymbol(typeSymbol); + } + var defaults = TypesService.GetDefaultTypes() .AsValueEnumerable() .Select(x => new TypeSymbol(x)) .ToList(); - while (_declarationsToResolve.Count != 0) + // resolve phase + for (var i = 0; i < _declarationsToResolve.Count; i++) { - var declarationToResolve = _declarationsToResolve.Dequeue(); - var typeSymbol = new TypeSymbol( - declarationToResolve.TypeValue.Accept(typeBuilder), - declarationToResolve.TypeId); - symbolTables[declarationToResolve.Scope].AddSymbol(typeSymbol); - - var resolvingCandidates = symbolTables[declarationToResolve.Scope] - .GetAvailableSymbols() + var symbolTable = symbolTables[_declarationsToResolve[i].Scope]; + var typeSymbol = symbolTable.FindSymbol(new TypeSymbolId(_declarationsToResolve[i].TypeId))!; + var resolvingCandidates = symbolTable.GetAvailableSymbols() .AsValueEnumerable() .OfType() .Except(defaults); foreach (var referenceSymbol in resolvingCandidates) { - typeSymbol.Type.ResolveReference( - referenceSymbol.Type, - referenceSymbol.Name); + typeSymbol.Resolve(referenceSymbol); } } + + _declarationsToResolve.Clear(); } public IHydraScriptTypesService TypesService { get; } = typesService; diff --git a/src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs b/src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs index bf6a0818..ef6646f1 100644 --- a/src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs +++ b/src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs @@ -7,6 +7,11 @@ public class TypeSymbol(Type type, string? name = null) : { public override TypeSymbolId Id { get; } = new(name ?? type.ToString()); + public void Resolve(TypeSymbol referenceSymbol) => + Type.ResolveReference( + referenceSymbol.Type, + referenceSymbol.Name); + public override bool Equals(object? obj) => obj is TypeSymbol typeSymbol && Name == typeSymbol.Name && Type.Equals(typeSymbol.Type); From ee5c0c45b4dedce721ebd2e13a49d6f0f0f2e83e Mon Sep 17 00:00:00 2001 From: Stepami Date: Sat, 25 Apr 2026 01:43:10 +0300 Subject: [PATCH 5/5] refactor(TypeDeclarationsResolver): simplify type build logic Replaced repeated indexing with a local variable for readability and maintainability. --- .../Impl/TypeDeclarationsResolver.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs b/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs index 02a23dcd..73dc5b08 100644 --- a/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs +++ b/src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs @@ -20,10 +20,11 @@ public void Resolve() // build phase for (var i = 0; i < _declarationsToResolve.Count; i++) { + var declarationToResolve = _declarationsToResolve[i]; var typeSymbol = new TypeSymbol( - _declarationsToResolve[i].TypeValue.Accept(typeBuilder), - _declarationsToResolve[i].TypeId); - symbolTables[_declarationsToResolve[i].Scope].AddSymbol(typeSymbol); + declarationToResolve.TypeValue.Accept(typeBuilder), + declarationToResolve.TypeId); + symbolTables[declarationToResolve.Scope].AddSymbol(typeSymbol); } var defaults = TypesService.GetDefaultTypes()