Skip to content

Commit de4e279

Browse files
authored
Проверка инициализации переменной +semver:feature (#98)
* fix * Контракт exit codes * изменение области видимости * #84 - подготовил интеграционники для скриптов с семантическими ошибками * #84 - реализация фичи * #84 - подправил тесты
1 parent 4ca963b commit de4e279

File tree

16 files changed

+137
-23
lines changed

16 files changed

+137
-23
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using HydraScript.Domain.FrontEnd.Parser.Impl.Ast.Nodes.Expressions.PrimaryExpressions;
3+
4+
namespace HydraScript.Application.StaticAnalysis.Exceptions;
5+
6+
[ExcludeFromCodeCoverage]
7+
public class AccessBeforeInitialization(IdentifierReference variable) : SemanticException(
8+
variable.Segment,
9+
$"Cannot access '{variable.Name}' before initialization");

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public VisitUnit Visit(FunctionDeclaration visitable)
7474
var arg = new VariableSymbol(
7575
id: x.Key,
7676
x.TypeValue.Accept(_typeBuilder));
77+
arg.Initialize();
7778
_symbolTables[visitable.Scope].AddSymbol(arg);
7879
return arg;
7980
}).ToList();

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ public Type Visit(ExpressionStatement visitable) =>
137137
public Type Visit(IdentifierReference visitable)
138138
{
139139
var symbol = _symbolTables[visitable.Scope].FindSymbol<ISymbol>(visitable.Name);
140+
if (symbol is { Initialized: false })
141+
throw new AccessBeforeInitialization(visitable);
140142
return symbol?.Type ?? throw new UnknownIdentifierReference(visitable);
141143
}
142144

@@ -167,11 +169,13 @@ public Type Visit(ObjectLiteral visitable)
167169
var properties = visitable.Properties.Select(prop =>
168170
{
169171
var propType = prop.Expression.Accept(This);
170-
_symbolTables[visitable.Scope].AddSymbol(propType switch
172+
var propSymbol = propType switch
171173
{
172174
ObjectType objectType => new ObjectSymbol(prop.Id, objectType),
173175
_ => new VariableSymbol(prop.Id, propType)
174-
});
176+
};
177+
propSymbol.Initialize();
178+
_symbolTables[visitable.Scope].AddSymbol(propSymbol);
175179
return new PropertyType(prop.Id, propType);
176180
});
177181
var objectLiteralType = new ObjectType(properties);
@@ -282,6 +286,7 @@ public Type Visit(LexicalDeclaration visitable)
282286
ObjectType objectType => new ObjectSymbol(registeredSymbol.Id, objectType, visitable.ReadOnly),
283287
_ => new VariableSymbol(registeredSymbol.Id, actualType, visitable.ReadOnly)
284288
};
289+
actualSymbol.Initialize();
285290
_symbolTables[visitable.Scope].AddSymbol(actualSymbol);
286291
}
287292

src/Domain/HydraScript.Domain.FrontEnd/Parser/Impl/Ast/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public partial class ImplicitLiteral(TypeValue type) : AbstractLiteral(type)
88
public object? ComputedDefaultValue { private get; set; }
99

1010
protected override string NodeRepresentation() =>
11-
Type.ToString();
11+
$"Implicit {Type}";
1212

1313
public override ValueDto ToValueDto() =>
1414
ValueDto.ConstantDto(

src/Domain/HydraScript.Domain.IR/ISymbol.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ public interface ISymbol
44
{
55
public string Id { get; }
66
public Type Type { get; }
7+
public bool Initialized { get; }
78
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ public abstract class Symbol(string id, Type type) : ISymbol
44
{
55
public virtual string Id { get; } = id;
66
public virtual Type Type { get; } = type;
7+
public virtual bool Initialized => true;
78
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ public class VariableSymbol(
55
Type type,
66
bool readOnly = false) : Symbol(id, type)
77
{
8+
private bool _initialized = readOnly;
9+
810
public bool ReadOnly { get; } = readOnly;
11+
public override bool Initialized => _initialized;
12+
13+
public void Initialize() => _initialized = true;
914

1015
public override string ToString() =>
1116
$"{(ReadOnly ? "const " : "")}{Id}: {Type}";

src/HydraScript/ExecuteCommand.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
namespace HydraScript;
44

5-
public class ExecuteCommand : RootCommand
5+
internal class ExecuteCommand : RootCommand
66
{
7-
public ExecuteCommand() : base("HydraScript interpreter")
7+
internal ExecuteCommand() : base("HydraScript interpreter")
88
{
99
PathArgument = new Argument<FileInfo>(
1010
name: "path",
@@ -18,6 +18,6 @@ public ExecuteCommand() : base("HydraScript interpreter")
1818
AddOption(DumpOption);
1919
}
2020

21-
public Argument<FileInfo> PathArgument { get; }
22-
public Option<bool> DumpOption { get; }
21+
internal Argument<FileInfo> PathArgument { get; }
22+
internal Option<bool> DumpOption { get; }
2323
}

src/HydraScript/ExecuteCommandHandler.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,19 @@ public int Invoke(InvocationContext context)
2424
var ast = parser.Parse(sourceCode);
2525
var instructions = codeGenerator.GetInstructions(ast);
2626
virtualMachine.Run(instructions);
27-
return 0;
27+
return ExitCodes.Success;
2828
}
2929
catch (Exception ex)
3030
when (ex is LexerException or ParserException or SemanticException)
3131
{
3232
writer.WriteLine(ex.Message);
33-
return 1;
33+
return ExitCodes.HydraScriptError;
3434
}
3535
catch (Exception ex)
3636
{
3737
writer.WriteLine("Internal HydraScript Error");
3838
writer.WriteLine(ex);
39-
return 2;
39+
return ExitCodes.DotnetRuntimeError;
4040
}
4141
}
4242

src/HydraScript/ExitCodes.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace HydraScript;
2+
3+
internal static class ExitCodes
4+
{
5+
public const int Success = 0;
6+
7+
public const int HydraScriptError = 1;
8+
9+
public const int DotnetRuntimeError = 2;
10+
}

0 commit comments

Comments
 (0)