Skip to content

Commit 349270f

Browse files
committed
Merge remote-tracking branch 'origin/main' into webbju/refactor-parsing
2 parents 26db68e + 6785aed commit 349270f

File tree

10 files changed

+157
-91
lines changed

10 files changed

+157
-91
lines changed

ServerCodeExciser/Properties/AssemblyInfo.cs renamed to ServerCodeExciser/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515

1616
// The following GUID is for the ID of the typelib if this project is exposed to COM.
1717

18-
[assembly: Guid("f2a9e88b-71e2-43d8-8627-59199a0ff9ea")]
18+
[assembly: Guid("23858a33-edb8-4a1a-81c6-6a7347386704")]
1919

2020
[assembly: InternalsVisibleTo("ServerCodeExciserTest")]

ServerCodeExciser/ServerCodeExcisionProcessor.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,12 @@ internal EExciserReturnValues ProcessCodeFile(string script, string outputFile,
242242
}
243243

244244
// Determine if there are any existing preprocessor server-code exclusions in the source file.
245-
var preprocessorNodes = PreprocessorParser.Parse(commonTokenStream);
246-
var detectedPreprocessorServerOnlyScopes = FindScopesForSymbol(preprocessorNodes, scope => scope.Directive.Contains(excisionLanguage.ServerScopeStartString, StringComparison.Ordinal));
245+
var preprocessorScopes = PreprocessorParser.Parse(commonTokenStream);
246+
var detectedPreprocessorServerOnlyScopes = new List<PreprocessorScope>();
247+
FindPreprocessorScopesForSymbolRecursive(
248+
preprocessorScopes,
249+
scope => scope.Directive.Contains(excisionLanguage.ServerScopeStartString, StringComparison.Ordinal),
250+
detectedPreprocessorServerOnlyScopes);
247251

248252
// Process scopes we've evaluated must be server only.
249253
foreach (ServerOnlyScopeData currentScope in visitor.DetectedServerOnlyScopes)
@@ -316,7 +320,13 @@ internal EExciserReturnValues ProcessCodeFile(string script, string outputFile,
316320
// Next we must add dummy reference variables if they exist.
317321
// If there is already a block of dummy reference variables we skip adding new ones, there is no guarantee we are adding the right code.
318322
var dummyVarScope = "#ifndef " + excisionLanguage.ServerPrecompilerSymbol;
319-
if (!FindScopesForSymbol(preprocessorNodes, scope => scope.Directive.Contains(dummyVarScope, StringComparison.Ordinal)).Any())
323+
var detectedIfndefScopes = new List<PreprocessorScope>();
324+
FindPreprocessorScopesForSymbolRecursive(
325+
preprocessorScopes,
326+
scope => scope.Directive.Contains(dummyVarScope, StringComparison.Ordinal),
327+
detectedIfndefScopes);
328+
329+
if (!detectedIfndefScopes.Any())
320330
{
321331
foreach (KeyValuePair<int, HashSet<string>> dummyRefDataPair in visitor.ClassStartIdxDummyReferenceData)
322332
{
@@ -433,22 +443,15 @@ private static (int StartIndex, int StopIndex) TrimWhitespace(ReadOnlySpan<char>
433443
return (startIndex, stopIndex);
434444
}
435445

436-
public static List<PreprocessorScope> FindScopesForSymbol(List<PreprocessorScope> scopes, Predicate<PreprocessorScope> predicate)
437-
{
438-
var result = new List<PreprocessorScope>();
439-
FindScopesForSymbolRecursive(scopes, predicate, result);
440-
return result;
441-
}
442-
443-
private static void FindScopesForSymbolRecursive(List<PreprocessorScope> scopes, Predicate<PreprocessorScope> predicate, List<PreprocessorScope> result)
446+
private static void FindPreprocessorScopesForSymbolRecursive(List<PreprocessorScope> scopes, Predicate<PreprocessorScope> predicate, List<PreprocessorScope> result)
444447
{
445448
foreach (var scope in scopes)
446449
{
447450
if (predicate(scope))
448451
{
449452
result.Add(scope);
450453
}
451-
FindScopesForSymbolRecursive(scope.Children, predicate, result);
454+
FindPreprocessorScopesForSymbolRecursive(scope.Children, predicate, result);
452455
}
453456
}
454457
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using System;
2+
using System.IO;
3+
using Antlr4.Runtime;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using UnrealAngelscriptServerCodeExcision;
6+
7+
namespace ServerCodeExciser.Tests
8+
{
9+
[TestClass]
10+
public class AngelscriptSyntaxTests
11+
{
12+
private sealed class ThrowingErrorListener : BaseErrorListener
13+
{
14+
public override void SyntaxError(TextWriter output, IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, string msg, RecognitionException e)
15+
{
16+
throw new InvalidOperationException($"line {line}:{charPositionInLine} {msg}");
17+
}
18+
}
19+
20+
[TestMethod]
21+
[DataRow("mynamespace")]
22+
[DataRow("Nested::mynamespace")]
23+
public void Namespace(string @namespace)
24+
{
25+
ParseScript($"namespace {@namespace}\r\n{{\r\n}}\r\n");
26+
}
27+
28+
[TestMethod]
29+
public void NamedArgumentsFunctionCall()
30+
{
31+
ParseScript("void Func(bool Arg1 = false, int Arg2 = 0) {}\r\nvoid main() { Func(Arg2: 1, Arg1: true); }\r\n");
32+
}
33+
34+
[TestMethod]
35+
[DataRow("")]
36+
[DataRow("final")]
37+
[DataRow("override")]
38+
[DataRow("no_discard")] // UnrealAngelscript
39+
[DataRow("allow_discard")] // UnrealAngelscript
40+
[DataRow("accept_temporary_this")] // UnrealAngelscript
41+
[DataRow("const allow_discard")] // UnrealAngelscript
42+
public void FunctionModifier(string modifier)
43+
{
44+
ParseScript($"bool Func() {modifier}\r\n{{\r\nreturn true;\r\n}}");
45+
}
46+
47+
[TestMethod]
48+
[DataRow("int", "0")]
49+
[DataRow("int8", "0")]
50+
[DataRow("int16", "0")]
51+
[DataRow("int32", "0")]
52+
[DataRow("int64", "0")]
53+
[DataRow("uint", "0")]
54+
[DataRow("uint8", "0")]
55+
[DataRow("uint16", "0")]
56+
[DataRow("uint32", "0")]
57+
[DataRow("uint64", "0")]
58+
[DataRow("float", "0.0f")]
59+
[DataRow("float32", "0.0f")]
60+
[DataRow("float64", "0.0")]
61+
[DataRow("doublt", "0.0")]
62+
[DataRow("bool", "false")]
63+
[DataRow("string", "\"\\0\"")]
64+
[DataRow("string", "\"\\xFFFF\"")]
65+
[DataRow("string", "\"\\uFFFF\"")]
66+
[DataRow("string", "\"\\uFFFFFFFF\"")]
67+
[DataRow("string", "\"\"\"\r\nheredoc string\r\n\"\"\"")] // heredoc: https://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_strings.html
68+
[DataRow("FName", "n\"MyName\"")] // FName Literals: https://angelscript.hazelight.se/scripting/fname-literals/
69+
[DataRow("string", "f\"Formatted String: {L:0.1f}\"")] // Formatted Strings: https://angelscript.hazelight.se/scripting/format-strings/
70+
public void DataType(string type, string value)
71+
{
72+
ParseScript($"{type} VAR = {value};");
73+
}
74+
75+
[TestMethod]
76+
[DataRow("")]
77+
[DataRow("UCLASS()")]
78+
[DataRow("UCLASS(Abstract)")]
79+
public void UClass(string annotation)
80+
{
81+
ParseScript($"{annotation} class ClassName : BaseClass {{}};");
82+
}
83+
84+
[TestMethod]
85+
[DataRow("")]
86+
[DataRow("UPROPERTY()")]
87+
[DataRow("UPROPERTY(DefaultComponent)")]
88+
[DataRow("UPROPERTY(DefaultComponent,)")]
89+
[DataRow("UPROPERTY(DefaultComponent, RootComponent)")]
90+
public void UProperty(string annotation)
91+
{
92+
ParseScript($"class ClassName : BaseClass\r\n{{\r\n\t{annotation}\r\nDummyType DummyProperty;\r\n}};");
93+
}
94+
95+
private static void ParseScript(string script)
96+
{
97+
var lexer = new UnrealAngelscriptLexer(new AntlrInputStream(script));
98+
var tokenStream = new CommonTokenStream(lexer);
99+
var parser = new UnrealAngelscriptParser(tokenStream);
100+
parser.RemoveErrorListeners();
101+
parser.AddErrorListener(new ThrowingErrorListener());
102+
new UnrealAngelscriptSimpleVisitor(script).VisitChildren(parser.script());
103+
}
104+
}
105+
}

ServerCodeExciserTest/ExcisionIntegrationTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.IO;
33
using Microsoft.VisualStudio.TestTools.UnitTesting;
4-
using ServerCodeExciser;
54
using ServerCodeExcisionCommon;
65
using UnrealAngelscriptServerCodeExcision;
76

ServerCodeExciserTest/PreprocessorTests.cs renamed to ServerCodeExciserTest/PreprocessorParserTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
using Antlr4.Runtime;
1+
using Antlr4.Runtime;
22
using Microsoft.VisualStudio.TestTools.UnitTesting;
33

44
namespace ServerCodeExciser.Tests
55
{
66
[TestClass]
7-
public class PreprocessorTests
7+
public class PreprocessorParserTests
88
{
99
[TestMethod]
1010
public void ConditionalBranchTest()

ServerCodeExciserTest/Problems/Angelscript/DatatypesTest.as

Lines changed: 0 additions & 27 deletions
This file was deleted.

ServerCodeExciserTest/Problems/Angelscript/DatatypesTest.as.solution

Lines changed: 0 additions & 27 deletions
This file was deleted.

ServerCodeExcisionCommon/SourcePosition.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using Antlr4.Runtime;
2-
31
namespace ServerCodeExcisionCommon
42
{
53
/// <summary>

UnrealAngelscriptParser/Grammar/UnrealAngelscriptLexer.g4

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ FloatingLiteral:
2424
// https://angelscript.hazelight.se/scripting/format-strings/
2525
fragment Angelscriptstringprefix: 'n' | 'f';
2626

27-
StringLiteral: (Encodingprefix | Angelscriptstringprefix)? (Rawstring | '"' Schar* '"');
27+
// Angelscript Heredoc string literals
28+
// https://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes_strings.html
29+
fragment HeredocString: '"""' .*? '"""';
30+
31+
StringLiteral: (Encodingprefix | Angelscriptstringprefix)? (HeredocString | Rawstring | '"' Schar* '"');
2832

2933
BooleanLiteral: False | True;
3034

@@ -87,6 +91,12 @@ Bool: 'bool';
8791

8892
/* UnrealAngelscript */
8993

94+
NoDiscard: 'no_discard';
95+
96+
AllowDiscard: 'allow_discard';
97+
98+
AcceptTemporaryThis: 'accept_temporary_this';
99+
90100
UClass: 'UCLASS';
91101

92102
UStruct: 'USTRUCT';
@@ -109,12 +119,6 @@ Check: 'check';
109119

110120
Auto: 'auto';
111121

112-
NoDiscard: 'no_discard';
113-
114-
AllowDiscard: 'allow_discard';
115-
116-
AcceptTemporaryThis: 'accept_temporary_this';
117-
118122
Access: 'access';
119123

120124
Break: 'break';

UnrealAngelscriptParser/Grammar/UnrealAngelscriptParser.g4

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ script:
3535
declarationseq? EOF;
3636

3737
/*Angelscript */
38+
3839
annotationList:
39-
annotation (Comma annotation)*;
40+
annotation (Comma annotation)* Comma?; // trailing commas are permitted in AS
4041

4142
annotation:
4243
Identifier (Assign expression)?;
@@ -89,6 +90,7 @@ qualifiedId: nestedNameSpecifier unqualifiedId;
8990
nestedNameSpecifier:
9091
(theTypeName | namespaceName | decltypeSpecifier)? Doublecolon
9192
| nestedNameSpecifier Identifier Doublecolon;
93+
9294
lambdaExpression:
9395
lambdaIntroducer lambdaDeclarator? compoundStatement;
9496

@@ -217,6 +219,7 @@ assignmentOperator:
217219
expression: assignmentExpression (Comma assignmentExpression)*;
218220

219221
constantExpression: conditionalExpression;
222+
220223
/*Statements*/
221224

222225
statement:
@@ -394,13 +397,15 @@ namespaceName: originalNamespaceName | namespaceAlias;
394397
originalNamespaceName: Identifier;
395398

396399
namespaceDefinition:
397-
Namespace (Identifier | originalNamespaceName)? LeftBrace namespaceBody = declarationseq
398-
? RightBrace;
400+
Namespace qualifiedNamespaceName? LeftBrace namespaceBody = declarationseq? RightBrace;
399401

400402
namespaceAlias: Identifier;
401403

402404
namespaceAliasDefinition: Namespace Identifier Assign qualifiednamespacespecifier Semi;
403405

406+
qualifiedNamespaceName:
407+
Identifier (Doublecolon Identifier)*;
408+
404409
qualifiednamespacespecifier: nestedNameSpecifier? namespaceName;
405410

406411
balancedTokenSeq: balancedtoken+;
@@ -451,7 +456,7 @@ parameterDeclaration:
451456
declSpecifierSeq Identifier? (Assign initializerClause)?;
452457

453458
functionDefinition:
454-
ufunction? (accessSpecifier | accessPattern)? Mixin? declSpecifierSeq? declarator virtualSpecifierSeq? angelscriptModifierSeq? functionBody;
459+
ufunction? (accessSpecifier | accessPattern)? Mixin? declSpecifierSeq? declarator virtualSpecifierSeq? angelscriptDiscardModifier? functionBody;
455460

456461
functionBody:
457462
compoundStatement
@@ -466,10 +471,14 @@ braceOrEqualInitializer:
466471
Assign initializerClause
467472
| bracedInitList;
468473

469-
initializerClause: assignmentExpression | bracedInitList;
474+
// Angelscript supports C#-like named arguments.
475+
// https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments
476+
initializerClause:
477+
(Identifier Colon)? assignmentExpression
478+
| bracedInitList;
470479

471480
initializerList:
472-
initializerClause (Comma initializerClause)* Comma?; // I *really* don't like that trailing commas are a thing in AS...
481+
initializerClause (Comma initializerClause)* Comma?; // trailing commas are permitted in AS
473482

474483
bracedInitList: (LeftBrace|LeftBracket) (initializerList Comma?)? (RightBrace|RightBracket);
475484

@@ -514,20 +523,22 @@ memberDeclaratorList:
514523

515524
memberDeclarator:
516525
declarator (
517-
virtualSpecifierSeq? angelscriptModifierSeq?
526+
virtualSpecifierSeq? angelscriptDiscardModifier?
518527
| braceOrEqualInitializer?
519528
)
520529
| Identifier? Colon constantExpression
521530
| Identifier;
522531

523532
virtualSpecifierSeq: virtualSpecifier+;
524533

525-
virtualSpecifier: Override | Final | Property;
526-
527-
angelscriptModifier:
528-
NoDiscard | AllowDiscard | AcceptTemporaryThis;
534+
virtualSpecifier
535+
: Override
536+
| Final
537+
| Property // Angelscript
538+
;
529539

530-
angelscriptModifierSeq: angelscriptModifier+;
540+
angelscriptDiscardModifier:
541+
NoDiscard | AllowDiscard;
531542

532543
/*Derived classes*/
533544

0 commit comments

Comments
 (0)