Skip to content

Commit 72a2501

Browse files
authored
Bug/issue 231 (#240)
* chore(sln file): removed mention of tests/Directory.Packages.props * test(TypeDeclarationsResolver): add unit test for resolving type declarations Closes #231 * test(TypeDeclarationsResolver): fix test fix test to validate array type for 'result' property Closes #231 * fix(TypeDeclarationsResolver): type resolution process Method Resolve is split into two phases - type building and reference resolving Closes #231 * refactor(TypeDeclarationsResolver): simplify type build logic Replaced repeated indexing with a local variable for readability and maintainability.
1 parent 35e697e commit 72a2501

4 files changed

Lines changed: 111 additions & 15 deletions

File tree

ExtendedJavaScriptSubset.slnx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,5 @@
5151
<Project Path="tests/HydraScript.UnitTests/HydraScript.UnitTests.csproj" />
5252
<File Path="tests/coverage-exclude.xml" />
5353
<File Path="tests/Directory.Build.props" />
54-
<File Path="tests/Directory.Packages.props" />
5554
</Folder>
5655
</Solution>

src/Application/HydraScript.Application.StaticAnalysis/Impl/TypeDeclarationsResolver.cs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Declarations;
22
using HydraScript.Domain.IR.Impl.Symbols;
3+
using HydraScript.Domain.IR.Impl.Symbols.Ids;
34
using ZLinq;
45

56
namespace HydraScript.Application.StaticAnalysis.Impl;
@@ -9,39 +10,45 @@ internal class TypeDeclarationsResolver(
910
ISymbolTableStorage symbolTables,
1011
IVisitor<TypeValue, Type> typeBuilder) : ITypeDeclarationsResolver
1112
{
12-
private readonly Queue<TypeDeclaration> _declarationsToResolve = [];
13+
private readonly List<TypeDeclaration> _declarationsToResolve = [];
1314

1415
public void Store(TypeDeclaration declaration) =>
15-
_declarationsToResolve.Enqueue(declaration);
16+
_declarationsToResolve.Add(declaration);
1617

1718
public void Resolve()
1819
{
19-
var defaults = TypesService.GetDefaultTypes()
20-
.AsValueEnumerable()
21-
.Select(x => new TypeSymbol(x))
22-
.ToList();
23-
24-
while (_declarationsToResolve.Count != 0)
20+
// build phase
21+
for (var i = 0; i < _declarationsToResolve.Count; i++)
2522
{
26-
var declarationToResolve = _declarationsToResolve.Dequeue();
23+
var declarationToResolve = _declarationsToResolve[i];
2724
var typeSymbol = new TypeSymbol(
2825
declarationToResolve.TypeValue.Accept(typeBuilder),
2926
declarationToResolve.TypeId);
3027
symbolTables[declarationToResolve.Scope].AddSymbol(typeSymbol);
28+
}
3129

32-
var resolvingCandidates = symbolTables[declarationToResolve.Scope]
33-
.GetAvailableSymbols()
30+
var defaults = TypesService.GetDefaultTypes()
31+
.AsValueEnumerable()
32+
.Select(x => new TypeSymbol(x))
33+
.ToList();
34+
35+
// resolve phase
36+
for (var i = 0; i < _declarationsToResolve.Count; i++)
37+
{
38+
var symbolTable = symbolTables[_declarationsToResolve[i].Scope];
39+
var typeSymbol = symbolTable.FindSymbol(new TypeSymbolId(_declarationsToResolve[i].TypeId))!;
40+
var resolvingCandidates = symbolTable.GetAvailableSymbols()
3441
.AsValueEnumerable()
3542
.OfType<TypeSymbol>()
3643
.Except(defaults);
3744

3845
foreach (var referenceSymbol in resolvingCandidates)
3946
{
40-
typeSymbol.Type.ResolveReference(
41-
referenceSymbol.Type,
42-
referenceSymbol.Name);
47+
typeSymbol.Resolve(referenceSymbol);
4348
}
4449
}
50+
51+
_declarationsToResolve.Clear();
4552
}
4653

4754
public IHydraScriptTypesService TypesService { get; } = typesService;

src/Domain/HydraScript.Domain.IR/Impl/Symbols/TypeSymbol.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ public class TypeSymbol(Type type, string? name = null) :
77
{
88
public override TypeSymbolId Id { get; } = new(name ?? type.ToString());
99

10+
public void Resolve(TypeSymbol referenceSymbol) =>
11+
Type.ResolveReference(
12+
referenceSymbol.Type,
13+
referenceSymbol.Name);
14+
1015
public override bool Equals(object? obj) =>
1116
obj is TypeSymbol typeSymbol &&
1217
Name == typeSymbol.Name && Type.Equals(typeSymbol.Type);
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using HydraScript.Application.StaticAnalysis.Impl;
2+
using HydraScript.Application.StaticAnalysis.Visitors;
3+
using HydraScript.Domain.FrontEnd.Parser;
4+
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes;
5+
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Declarations;
6+
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Expressions.PrimaryExpressions;
7+
using HydraScript.Domain.IR.Impl;
8+
using HydraScript.Domain.IR.Impl.Symbols;
9+
using HydraScript.Domain.IR.Impl.Symbols.Ids;
10+
using HydraScript.Domain.IR.Types;
11+
12+
namespace HydraScript.UnitTests.Application;
13+
14+
/// <summary>
15+
/// Тесты <see cref="TypeDeclarationsResolver"/>
16+
/// </summary>
17+
public class TypeDeclarationsResolverTests
18+
{
19+
/// <summary>
20+
/// https://github.com/Stepami/hydrascript/issues/231
21+
/// </summary>
22+
[Fact]
23+
public void Resolve_Issue231_Success()
24+
{
25+
// Arrange
26+
const string itemTypeName = "QueryStringParseResultItem";
27+
const string resultTypeName = "QueryStringParseResult";
28+
29+
var scope = new Scope();
30+
var symbolTable = new SymbolTable();
31+
symbolTable.AddSymbol(new TypeSymbol(itemTypeName));
32+
symbolTable.AddSymbol(new TypeSymbol(resultTypeName));
33+
34+
var symbolTables = new SymbolTableStorage();
35+
symbolTables.Init(scope, symbolTable);
36+
37+
var resolver = new TypeDeclarationsResolver(
38+
new HydraScriptTypesService(),
39+
symbolTables,
40+
new TypeBuilder(symbolTables));
41+
42+
foreach (var defaultType in resolver.TypesService.GetDefaultTypes())
43+
{
44+
symbolTable.AddSymbol(new TypeSymbol(defaultType));
45+
}
46+
47+
var resultDeclaration = new TypeDeclaration(
48+
new IdentifierReference(resultTypeName),
49+
new ObjectTypeValue(
50+
[
51+
new PropertyTypeValue(
52+
"result",
53+
new ArrayTypeValue(
54+
new TypeIdentValue(
55+
new IdentifierReference(itemTypeName)))),
56+
]));
57+
58+
var itemDeclaration = new TypeDeclaration(
59+
new IdentifierReference(itemTypeName),
60+
new ObjectTypeValue(
61+
[
62+
new PropertyTypeValue("name", TypeIdentValue.String),
63+
new PropertyTypeValue("value", TypeIdentValue.String),
64+
]));
65+
66+
var root = new ScriptBody([resultDeclaration, itemDeclaration]);
67+
root.InitScope(scope);
68+
itemDeclaration.InitScope();
69+
resultDeclaration.InitScope();
70+
71+
// Act
72+
resolver.Store(resultDeclaration);
73+
resolver.Store(itemDeclaration);
74+
75+
resolver.Resolve();
76+
77+
// Assert
78+
var itemType = symbolTable.FindSymbol(new TypeSymbolId(itemTypeName))?.Type;
79+
var resultType = symbolTable.FindSymbol(new TypeSymbolId(resultTypeName))?.Type as ObjectType;
80+
81+
itemType.Should().NotBeNull();
82+
resultType.Should().NotBeNull();
83+
resultType["result"].Should().Be(new ArrayType(itemType));
84+
}
85+
}

0 commit comments

Comments
 (0)