Skip to content

Commit 411a3f6

Browse files
authored
#142 - параметры функций по умолчанию (#167) +semver:feature
* #142 - обновление грамматики * #142 - новая модель аргумента функции * #142 - новая модель 2 * #142 - новая грамматика скобочек * #142 - реализация новой грамматики в парсере * #142 - проверка порядка аргументов функции * #142 - регистрация по заданному ключу в таблице символов * #142 - регистрация перегрузок функции с параметрами по умолчанию * #167 - добавлен тест * #167 - удаление ненужной проверки * #167 - доработка кодогенерации * #167 - fix code cov * #167 - fix * #167 - fix cov 2 * #167 - доработка теста и статического анализа * fix * #167 - error test * change event develop workflow * fix * fix docs * #167 - after merge * #167 - update nuget * #167 - доработка статического анализа на проверку неоднозначных вызовов * #167 - не зависим от порядка объявления функции * #167 - ещё один фикс про порядок
1 parent 49955fb commit 411a3f6

File tree

35 files changed

+344
-93
lines changed

35 files changed

+344
-93
lines changed

CONTRIBUTING.md

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@ Contributions are welcomed! Here's a few things to know:
88
- [Do not point fingers](#do-not-point-fingers)
99
- [Provide code feedback based on evidence](#provide-code-feedback-based-on-evidence)
1010
- [Ask questions do not give answers](#ask-questions-do-not-give-answers)
11-
- [HydraScript Contributor License Agreement](#hydrascript-contributor-license-agreement)
1211

1312
## Steps to Contributing
1413

1514
Here are the basic steps to get started with your first contribution. Please reach out with any questions.
1615
1. Use [open issues](https://github.com/stepami/hydrascript/issues) to discuss the proposed changes. Create an issue describing changes if necessary to collect feedback. Also, please use provided labels to tag issues so everyone can easily sort issues of interest.
17-
1. [Fork the repo](https://help.github.com/articles/fork-a-repo/) in order if you want to make and test local changes.
18-
1. Create a new branch **from master** for the issue. We suggest prefixing the branch with type of contribution (`bugfix`/`feature`), your username and then a descriptive title: (e.g. `bugfix/user1/object-comparision` or `feature/user2/variable-initialization-check`)
19-
1. Make code changes.
20-
1. Ensure unit tests pass and code coverage minimum is satisfied.
21-
1. Create a pull request against **master** branch.
16+
2. [Fork the repo](https://help.github.com/articles/fork-a-repo/) in order if you want to make and test local changes.
17+
3. Create a new branch **from master** for the issue. We suggest prefixing the branch with type of contribution (`bugfix`/`feature`), your username and then a descriptive title: (e.g. `bugfix/user1/object-comparision` or `feature/user2/variable-initialization-check`)
18+
4. Make code changes.
19+
5. Ensure unit tests pass and code coverage minimum is satisfied.
20+
6. Create a pull request against **master** branch.
2221

2322
## Code of conduct
2423

@@ -54,10 +53,4 @@ Try to be empathic.
5453
* Would it make more sense if ...?
5554
* Have you considered this ... ?
5655

57-
</details>
58-
59-
## HydraScript Contributor License Agreement
60-
61-
Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution.
62-
63-
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once in this repo.
56+
</details>

Directory.Packages.props

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
66
</PackageVersion>
77
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
8-
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.3" />
9-
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.3" />
10-
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.3" />
11-
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.3" />
8+
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.4" />
9+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.4" />
10+
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.4" />
11+
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.4" />
1212
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.24126.1" />
13-
<PackageVersion Include="System.IO.Abstractions" Version="22.0.12" />
14-
<PackageVersion Include="Visitor.NET" Version="4.1.2" />
15-
<PackageVersion Include="Visitor.NET.AutoVisitableGen" Version="1.3.0" />
13+
<PackageVersion Include="System.IO.Abstractions" Version="22.0.14" />
14+
<PackageVersion Include="Visitor.NET" Version="4.2.0" />
15+
<PackageVersion Include="Visitor.NET.AutoVisitableGen" Version="1.5.2" />
1616
</ItemGroup>
1717
</Project>

SECURITY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
## Supported Versions
44

55
| Version | Supported |
6-
| ------- | ------------------ |
6+
|---------|--------------------|
77
| > 1.0 | :white_check_mark: |
88

99
## Reporting a Vulnerability
@@ -15,4 +15,4 @@ Security issues and bugs should be reported privately via email to stepami@mail.
1515
## When Should I Report a Vulnerability?
1616

1717
- You think you discovered a potential security vulnerability
18-
- You are unsure how a vulnerability affects YTsaurus
18+
- You are unsure how a vulnerability affects HydraScript

src/Application/HydraScript.Application.CodeGeneration/Visitors/InstructionProvider.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public InstructionProvider(
3838
_expressionVisitor = expressionVisitor;
3939
}
4040

41+
public override AddressedInstructions Visit(IAbstractSyntaxTreeNode visitable) => [];
42+
4143
public AddressedInstructions Visit(ScriptBody visitable)
4244
{
4345
var result = new AddressedInstructions();
@@ -52,8 +54,6 @@ public AddressedInstructions Visit(ScriptBody visitable)
5254
return result;
5355
}
5456

55-
public override AddressedInstructions DefaultVisit { get; } = [];
56-
5757
public AddressedInstructions Visit(LexicalDeclaration visitable)
5858
{
5959
var result = new AddressedInstructions();
@@ -129,8 +129,14 @@ public AddressedInstructions Visit(FunctionDeclaration visitable)
129129
}
130130
};
131131

132-
foreach (var (id, _) in visitable.Arguments)
133-
result.Add(new PopParameter(id));
132+
for (var i = 0; i < visitable.Arguments.Count; i++)
133+
{
134+
var arg = visitable.Arguments[i];
135+
if (arg is DefaultValueArgument @default)
136+
result.Add(new PopParameter(arg.Name, @default.Info.Value));
137+
else
138+
result.Add(new PopParameter(arg.Name));
139+
}
134140

135141
result.AddRange(visitable.Statements.Accept(This));
136142
if (!visitable.HasReturnStatement())
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using HydraScript.Domain.IR.Impl.Symbols.Ids;
3+
4+
namespace HydraScript.Application.StaticAnalysis.Exceptions;
5+
6+
[ExcludeFromCodeCoverage]
7+
public class AmbiguousInvocation(
8+
string segment,
9+
IReadOnlyCollection<FunctionSymbolId> candidates) :
10+
SemanticException(
11+
segment,
12+
$"Ambiguous Invocation - Candidates are:\n{string.Join('\n', candidates)}");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Declarations.AfterTypesAreLoaded;
3+
4+
namespace HydraScript.Application.StaticAnalysis.Exceptions;
5+
6+
[ExcludeFromCodeCoverage]
7+
public class NamedArgumentAfterDefaultValueArgument(string segment, string function, IFunctionArgument argument) :
8+
SemanticException(segment, $"The argument {argument} of function {function} is placed after default value argument");

src/Application/HydraScript.Application.StaticAnalysis/Exceptions/WrongNumberOfArguments.cs

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using HydraScript.Domain.IR.Impl.Symbols.Ids;
2+
3+
namespace HydraScript.Application.StaticAnalysis;
4+
5+
public interface IAmbiguousInvocationStorage
6+
{
7+
void WriteCandidate(FunctionSymbolId invocation, FunctionSymbolId candidate);
8+
9+
void CheckCandidatesAndThrow(string segment, FunctionSymbolId invocation);
10+
11+
void Clear(FunctionSymbolId invocation);
12+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using HydraScript.Application.StaticAnalysis.Exceptions;
2+
using HydraScript.Domain.IR.Impl.Symbols.Ids;
3+
4+
namespace HydraScript.Application.StaticAnalysis.Impl;
5+
6+
internal class AmbiguousInvocationStorage : IAmbiguousInvocationStorage
7+
{
8+
private readonly Dictionary<FunctionSymbolId, HashSet<FunctionSymbolId>> _invocations = [];
9+
10+
public void WriteCandidate(FunctionSymbolId invocation, FunctionSymbolId candidate)
11+
{
12+
if (!_invocations.ContainsKey(invocation))
13+
_invocations[invocation] = [];
14+
_invocations[invocation].Add(candidate);
15+
}
16+
17+
public void CheckCandidatesAndThrow(string segment, FunctionSymbolId invocation)
18+
{
19+
var candidates = _invocations.GetValueOrDefault(invocation, []);
20+
if (candidates.Count > 0)
21+
throw new AmbiguousInvocation(segment, candidates);
22+
}
23+
24+
public void Clear(FunctionSymbolId invocation) => _invocations.Remove(invocation);
25+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ internal class DefaultValueForTypeCalculator : IDefaultValueForTypeCalculator
1212

1313
public object? GetDefaultValueForType(Type type)
1414
{
15+
if (type is NullableType)
16+
return null;
1517
if (type.Equals(_boolean))
1618
return false;
1719
if (type.Equals(_number))

src/Application/HydraScript.Application.StaticAnalysis/ServiceCollectionExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public static IServiceCollection AddStaticAnalysis(this IServiceCollection servi
2121
services.AddSingleton<IJavaScriptTypesProvider, JavaScriptTypesProvider>();
2222
services.AddSingleton<IDefaultValueForTypeCalculator, DefaultValueForTypeCalculator>();
2323

24+
services.AddSingleton<IAmbiguousInvocationStorage, AmbiguousInvocationStorage>();
25+
2426
services.AddSingleton<IVisitor<TypeValue, Type>, TypeBuilder>();
2527

2628
services.AddSingleton<IVisitor<IAbstractSyntaxTreeNode>, SymbolTableInitializer>();

src/Application/HydraScript.Application.StaticAnalysis/Visitors/DeclarationVisitor.cs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,20 @@ internal class DeclarationVisitor : VisitorNoReturnBase<IAbstractSyntaxTreeNode>
1717
private readonly IFunctionWithUndefinedReturnStorage _functionStorage;
1818
private readonly IMethodStorage _methodStorage;
1919
private readonly ISymbolTableStorage _symbolTables;
20+
private readonly IAmbiguousInvocationStorage _ambiguousInvocations;
2021
private readonly IVisitor<TypeValue, Type> _typeBuilder;
2122

2223
public DeclarationVisitor(
2324
IFunctionWithUndefinedReturnStorage functionStorage,
2425
IMethodStorage methodStorage,
2526
ISymbolTableStorage symbolTables,
27+
IAmbiguousInvocationStorage ambiguousInvocations,
2628
IVisitor<TypeValue, Type> typeBuilder)
2729
{
2830
_functionStorage = functionStorage;
2931
_methodStorage = methodStorage;
3032
_symbolTables = symbolTables;
33+
_ambiguousInvocations = ambiguousInvocations;
3134
_typeBuilder = typeBuilder;
3235
}
3336

@@ -67,14 +70,28 @@ public VisitUnit Visit(LexicalDeclaration visitable)
6770

6871
public VisitUnit Visit(FunctionDeclaration visitable)
6972
{
73+
var parentTable = _symbolTables[visitable.Parent.Scope];
74+
var indexOfFirstDefaultArgument = visitable.Arguments
75+
.Select((x, i) => new { Argument = x, Index = i })
76+
.FirstOrDefault(pair => pair.Argument is DefaultValueArgument)?.Index ?? -1;
77+
7078
var parameters = visitable.Arguments.Select(x =>
7179
new VariableSymbol(
72-
name: x.Key,
80+
x.Name,
7381
x.TypeValue.Accept(_typeBuilder))).ToList();
7482
var functionSymbolId = new FunctionSymbolId(visitable.Name, parameters.Select(x => x.Type));
83+
_ambiguousInvocations.Clear(functionSymbolId);
7584
visitable.ComputedFunctionAddress = functionSymbolId.ToString();
76-
if (_symbolTables[visitable.Parent.Scope].ContainsSymbol(functionSymbolId))
77-
throw new OverloadAlreadyExists(visitable.Name, functionSymbolId);
85+
var functionSymbol = new FunctionSymbol(
86+
visitable.Name,
87+
parameters,
88+
visitable.ReturnTypeValue.Accept(_typeBuilder),
89+
visitable.IsEmpty);
90+
if (parentTable.ContainsSymbol(functionSymbolId))
91+
{
92+
if (!(parentTable.FindSymbol(functionSymbolId)! > functionSymbol))
93+
throw new OverloadAlreadyExists(visitable.Name, functionSymbolId);
94+
}
7895

7996
for (var i = 0; i < parameters.Count; i++)
8097
{
@@ -83,11 +100,6 @@ public VisitUnit Visit(FunctionDeclaration visitable)
83100
_symbolTables[visitable.Scope].AddSymbol(arg);
84101
}
85102

86-
var functionSymbol = new FunctionSymbol(
87-
visitable.Name,
88-
parameters,
89-
visitable.ReturnTypeValue.Accept(_typeBuilder),
90-
visitable.IsEmpty);
91103
if (parameters is [{ Type: ObjectType objectType }, ..] &&
92104
visitable.Arguments is [{ TypeValue: TypeIdentValue }, ..])
93105
{
@@ -103,7 +115,31 @@ public VisitUnit Visit(FunctionDeclaration visitable)
103115
functionSymbol.DefineReturnType("void");
104116
}
105117

106-
_symbolTables[visitable.Parent.Scope].AddSymbol(functionSymbol);
118+
parentTable.AddSymbol(functionSymbol);
119+
for (var i = indexOfFirstDefaultArgument; i < visitable.Arguments.Count; i++)
120+
{
121+
if (i is -1) break;
122+
if (visitable.Arguments[i] is not DefaultValueArgument)
123+
throw new NamedArgumentAfterDefaultValueArgument(
124+
visitable.Segment,
125+
function: visitable.Name,
126+
visitable.Arguments[i]);
127+
128+
var overload = new FunctionSymbolId(visitable.Name, parameters[..i].Select(x => x.Type));
129+
var existing = parentTable.FindSymbol(overload);
130+
parentTable.AddSymbol(functionSymbol, overload);
131+
if (existing is not null && existing < functionSymbol)
132+
{
133+
parentTable.AddSymbol(existing, overload);
134+
}
135+
136+
if (existing is not null && !existing.Id.Equals(overload))
137+
{
138+
_ambiguousInvocations.WriteCandidate(overload, existing.Id);
139+
_ambiguousInvocations.WriteCandidate(overload, functionSymbolId);
140+
}
141+
}
142+
107143
return visitable.Statements.Accept(This);
108144
}
109145
}

src/Application/HydraScript.Application.StaticAnalysis/Visitors/SemanticChecker.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ internal class SemanticChecker : VisitorBase<IAbstractSyntaxTreeNode, Type>,
4646
private readonly IMethodStorage _methodStorage;
4747
private readonly ISymbolTableStorage _symbolTables;
4848
private readonly IComputedTypesStorage _computedTypes;
49+
private readonly IAmbiguousInvocationStorage _ambiguousInvocations;
4950
private readonly IVisitor<TypeValue, Type> _typeBuilder;
5051

5152
public SemanticChecker(
@@ -54,17 +55,19 @@ public SemanticChecker(
5455
IMethodStorage methodStorage,
5556
ISymbolTableStorage symbolTables,
5657
IComputedTypesStorage computedTypes,
58+
IAmbiguousInvocationStorage ambiguousInvocations,
5759
IVisitor<TypeValue, Type> typeBuilder)
5860
{
5961
_calculator = calculator;
6062
_functionStorage = functionStorage;
6163
_methodStorage = methodStorage;
6264
_symbolTables = symbolTables;
6365
_computedTypes = computedTypes;
66+
_ambiguousInvocations = ambiguousInvocations;
6467
_typeBuilder = typeBuilder;
6568
}
6669

67-
public override Type DefaultVisit => "undefined";
70+
public override Type Visit(IAbstractSyntaxTreeNode visitable) => "undefined";
6871

6972
public Type Visit(ScriptBody visitable)
7073
{
@@ -411,13 +414,15 @@ public Type Visit(CallExpression visitable)
411414
var objectType = (ObjectType)visitable.Member.Accept(This);
412415
var availableMethods = _methodStorage.GetAvailableMethods(objectType);
413416
var methodKey = new FunctionSymbolId(objectType.LastAccessedMethodName, [objectType, ..parameters]);
417+
_ambiguousInvocations.CheckCandidatesAndThrow(visitable.Segment, methodKey);
414418
functionSymbol =
415419
availableMethods.GetValueOrDefault(methodKey)
416420
?? throw new UnknownFunctionOverload(visitable.Id, methodKey);
417421
}
418422
else
419423
{
420424
var functionKey = new FunctionSymbolId(visitable.Id, parameters);
425+
_ambiguousInvocations.CheckCandidatesAndThrow(visitable.Segment, functionKey);
421426
functionSymbol =
422427
_symbolTables[visitable.Scope].FindSymbol(functionKey)
423428
?? throw new UnknownFunctionOverload(visitable.Id, functionKey);
@@ -427,12 +432,6 @@ public Type Visit(CallExpression visitable)
427432
visitable.IsEmptyCall = functionSymbol.IsEmpty;
428433
var functionReturnType = functionSymbol.Type;
429434

430-
if (functionSymbol.Parameters.Count != visitable.Parameters.Count + (methodCall ? 1 : 0))
431-
throw new WrongNumberOfArguments(
432-
visitable.Segment,
433-
expected: functionSymbol.Parameters.Count,
434-
actual: visitable.Parameters.Count);
435-
436435
visitable.Parameters.Zip(parameters).Zip(functionSymbol.Parameters.ToArray()[(methodCall ? 1 : 0)..])
437436
.ToList().ForEach(pair =>
438437
{
@@ -481,7 +480,7 @@ public Type Visit(FunctionDeclaration visitable)
481480
else
482481
{
483482
var wrongReturn = returnStatements
484-
.FirstOrDefault(x => !x.Type.Equals(symbol.Type));
483+
.FirstOrDefault(x => !symbol.Type.Equals(x.Type));
485484
if (wrongReturn is not null)
486485
throw new WrongReturnType(
487486
wrongReturn.Statement.Segment,
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
namespace HydraScript.Domain.BackEnd.Impl.Instructions;
22

3-
public class PopParameter(string parameter) : Instruction
3+
public class PopParameter(string parameter, object? defaultValue = null) : Instruction
44
{
55
public override IAddress Execute(IExecuteParams executeParams)
66
{
7-
var argument = executeParams.Arguments.Dequeue();
8-
executeParams.Frames.Peek()[parameter] = argument;
7+
var frame = executeParams.Frames.Peek();
8+
if (executeParams.Arguments.TryDequeue(out var argument))
9+
frame[parameter] = argument;
10+
else
11+
frame[parameter] = defaultValue;
912
return Address.Next;
1013
}
1114

1215
protected override string ToStringInternal() =>
13-
$"PopParameter {parameter}";
16+
defaultValue is null
17+
? $"PopParameter {parameter}"
18+
: $"PopParameter {parameter} {defaultValue}";
1419
}

0 commit comments

Comments
 (0)