Skip to content

Commit 7e5ba63

Browse files
committed
#54 - implement missing return statement check
1 parent d087b15 commit 7e5ba63

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using HydraScript.Domain.FrontEnd.Parser;
2+
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Declarations.AfterTypesAreLoaded;
3+
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Statements;
4+
5+
namespace HydraScript.Application.StaticAnalysis.Visitors;
6+
7+
internal class ReturnAnalyzer : VisitorBase<IAbstractSyntaxTreeNode, ReturnAnalyzerResult>,
8+
IVisitor<FunctionDeclaration, ReturnAnalyzerResult>,
9+
IVisitor<IfStatement, ReturnAnalyzerResult>,
10+
IVisitor<ReturnStatement, ReturnAnalyzerResult>
11+
{
12+
public ReturnAnalyzerResult Visit(FunctionDeclaration visitable)
13+
{
14+
IAbstractSyntaxTreeNode astNode = visitable;
15+
return Visit(astNode);
16+
}
17+
18+
public override ReturnAnalyzerResult Visit(IAbstractSyntaxTreeNode visitable)
19+
{
20+
var result = ReturnAnalyzerResult.AdditiveIdentity;
21+
for (var i = 0; i < visitable.Count; i++)
22+
{
23+
var visitableResult = visitable[i].Accept(This);
24+
if (visitableResult.CodePathEndedWithReturn)
25+
return visitableResult * result;
26+
result += visitableResult;
27+
}
28+
29+
return result;
30+
}
31+
32+
public ReturnAnalyzerResult Visit(IfStatement visitable)
33+
{
34+
var thenReturns = visitable.Then.Accept(This);
35+
36+
if (visitable.Else is null)
37+
return thenReturns + ReturnAnalyzerResult.AdditiveIdentity;
38+
var elseReturns = visitable.Else.Accept(This);
39+
40+
return thenReturns + elseReturns;
41+
}
42+
43+
public ReturnAnalyzerResult Visit(ReturnStatement visitable) =>
44+
new(CodePathEndedWithReturn: true, ReturnStatements: [visitable]);
45+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Numerics;
2+
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Statements;
3+
4+
namespace HydraScript.Application.StaticAnalysis.Visitors;
5+
6+
public sealed record ReturnAnalyzerResult(bool CodePathEndedWithReturn, IReadOnlyList<ReturnStatement> ReturnStatements) :
7+
IAdditiveIdentity<ReturnAnalyzerResult, ReturnAnalyzerResult>,
8+
IAdditionOperators<ReturnAnalyzerResult, ReturnAnalyzerResult, ReturnAnalyzerResult>,
9+
IMultiplyOperators<ReturnAnalyzerResult, ReturnAnalyzerResult, ReturnAnalyzerResult>
10+
{
11+
public static ReturnAnalyzerResult operator +(ReturnAnalyzerResult left, ReturnAnalyzerResult right) =>
12+
new(
13+
left.CodePathEndedWithReturn && right.CodePathEndedWithReturn,
14+
ReturnStatements: [..left.ReturnStatements, ..right.ReturnStatements]);
15+
16+
public static ReturnAnalyzerResult AdditiveIdentity { get; } = new(CodePathEndedWithReturn: false, ReturnStatements: []);
17+
18+
public static ReturnAnalyzerResult operator *(ReturnAnalyzerResult left, ReturnAnalyzerResult right) =>
19+
new(
20+
left.CodePathEndedWithReturn || right.CodePathEndedWithReturn,
21+
ReturnStatements: [..left.ReturnStatements, ..right.ReturnStatements]);
22+
}

0 commit comments

Comments
 (0)