Skip to content

Commit 0986864

Browse files
committed
fixed #1696 Разрешалось чередование режимов компиляции в одном модуле
1 parent da01dd3 commit 0986864

3 files changed

Lines changed: 133 additions & 1 deletion

File tree

src/OneScript.Language/SyntaxAnalysis/LocalizedErrors.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ public static CodeError InvalidRegionName(string name) =>
137137
public static CodeError DirectiveIsMissing(string directive) =>
138138
Create($"Пропущена директива #{directive}", $"Directive #{directive} is missing");
139139

140+
public static CodeError RuntimeDirectiveAlreadyDefined() =>
141+
Create("Директива режима выполнения (#native или #stack) может быть указана только один раз",
142+
"Runtime directive (#native or #stack) can be specified only once");
143+
140144
public static CodeError LibraryNameExpected() =>
141145
Create("Ожидается имя библиотеки", "Library name expected");
142146

src/OneScript.Native/Compiler/NativeRuntimeAnnotationHandler.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This Source Code Form is subject to the terms of the
77

88
using System.Collections.Generic;
99
using OneScript.Language;
10+
using OneScript.Language.LexicalAnalysis;
1011
using OneScript.Language.SyntaxAnalysis;
1112

1213
namespace OneScript.Native.Compiler
@@ -21,9 +22,47 @@ public class NativeRuntimeAnnotationHandler : SingleWordModuleAnnotationHandler
2122
NativeDirectiveName,
2223
StackRuntimeDirectiveName
2324
};
25+
26+
private bool _runtimeDirectiveDefined;
2427

2528
public NativeRuntimeAnnotationHandler(IErrorSink errorSink) : base(Directives, errorSink)
2629
{
2730
}
31+
32+
public override void OnModuleEnter()
33+
{
34+
_runtimeDirectiveDefined = false;
35+
base.OnModuleEnter();
36+
}
37+
38+
public override void OnModuleLeave()
39+
{
40+
_runtimeDirectiveDefined = false;
41+
base.OnModuleLeave();
42+
}
43+
44+
protected override void ParseAnnotationInternal(
45+
ref Lexem lastExtractedLexem,
46+
ILexer lexer,
47+
ParserContext parserContext)
48+
{
49+
if (_runtimeDirectiveDefined)
50+
{
51+
var err = LocalizedErrors.RuntimeDirectiveAlreadyDefined();
52+
err.Position = new ErrorPositionInfo
53+
{
54+
LineNumber = lastExtractedLexem.Location.LineNumber,
55+
ColumnNumber = lastExtractedLexem.Location.ColumnNumber,
56+
Code = lexer.Iterator.GetCodeLine(lastExtractedLexem.Location.LineNumber),
57+
ModuleName = lexer.Iterator.Source.Name
58+
};
59+
ErrorSink.AddError(err);
60+
lastExtractedLexem = lexer.NextLexem();
61+
return;
62+
}
63+
64+
_runtimeDirectiveDefined = true;
65+
base.ParseAnnotationInternal(ref lastExtractedLexem, lexer, parserContext);
66+
}
2867
}
29-
}
68+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*----------------------------------------------------------
2+
This Source Code Form is subject to the terms of the
3+
Mozilla Public License, v.2.0. If a copy of the MPL
4+
was not distributed with this file, You can obtain one
5+
at http://mozilla.org/MPL/2.0/.
6+
----------------------------------------------------------*/
7+
8+
using FluentAssertions;
9+
using OneScript.Compilation;
10+
using OneScript.Language;
11+
using OneScript.Language.LexicalAnalysis;
12+
using OneScript.Language.SyntaxAnalysis;
13+
using OneScript.Native.Compiler;
14+
using OneScript.Sources;
15+
using Xunit;
16+
17+
namespace OneScript.Dynamic.Tests
18+
{
19+
public class NativeRuntimeAnnotationHandlerTests
20+
{
21+
[Theory]
22+
[InlineData("#stack\n#native")]
23+
[InlineData("#native\n#stack")]
24+
[InlineData("#stack\n#stack")]
25+
[InlineData("#native\n#native")]
26+
public void Duplicate_Runtime_Directive_Should_Report_Error(string code)
27+
{
28+
var errors = ParseModule(code);
29+
30+
errors.Should().ContainSingle(e => e.ErrorId == "RuntimeDirectiveAlreadyDefined");
31+
}
32+
33+
[Theory]
34+
[InlineData("#native")]
35+
[InlineData("#stack")]
36+
public void Single_Runtime_Directive_Should_Parse(string code)
37+
{
38+
var errors = ParseModule(code);
39+
40+
errors.Should().BeEmpty();
41+
}
42+
43+
[Fact]
44+
public void Duplicate_Runtime_Directive_Should_Throw_CompilerException()
45+
{
46+
var code = "#stack\n#native";
47+
48+
var act = () => ParseModuleWithThrowingSink(code);
49+
50+
act.Should().Throw<CompilerException>()
51+
.Which.LineNumber.Should().Be(2);
52+
}
53+
54+
private static System.Collections.Generic.IEnumerable<CodeError> ParseModule(string code)
55+
{
56+
var errors = new ListErrorSink();
57+
Parse(code, errors);
58+
return errors.Errors;
59+
}
60+
61+
private static void ParseModuleWithThrowingSink(string code)
62+
{
63+
var errors = new ThrowingErrorSink(CompilerException.FromCodeError);
64+
Parse(code, errors);
65+
}
66+
67+
private static void Parse(string code, IErrorSink errors)
68+
{
69+
var lexer = new DefaultLexer
70+
{
71+
Iterator = SourceCodeBuilder.Create()
72+
.FromString(code)
73+
.WithName("<text>")
74+
.Build()
75+
.CreateIterator()
76+
};
77+
78+
var handlers = new PreprocessorHandlers(new[] { new NativeRuntimeAnnotationHandler(errors) });
79+
var preprocessingLexer = new PreprocessingLexer(lexer)
80+
{
81+
Handlers = handlers,
82+
ErrorSink = errors
83+
};
84+
85+
var parser = new DefaultBslParser(preprocessingLexer, errors, handlers);
86+
_ = parser.ParseStatefulModule();
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)