Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Content.IntegrationTests/Content.IntegrationTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<LangVersion>12</LangVersion>
<NoWarn>NU1507</NoWarn>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<RootNamespace>Content.IntegrationTests</RootNamespace>
<AssemblyName>Content.IntegrationTests</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnit" />
Expand Down
3 changes: 2 additions & 1 deletion Content.IntegrationTests/SetupCompileDM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public sealed class SetupCompileDm {

[OneTimeSetUp]
public void Compile() {
bool successfulCompile = DMCompiler.DMCompiler.Compile(new() {
DMCompiler.DMCompiler compiler = new();
bool successfulCompile = compiler.Compile(new() {
Files = new() { DmEnvironment }
});

Expand Down
2 changes: 2 additions & 0 deletions Content.Tests/Content.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<Nullable>enable</Nullable>
<NoWarn>NU1507</NoWarn>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<RootNamespace>Content.Tests</RootNamespace>
<AssemblyName>Content.Tests</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NUnit" />
Expand Down
51 changes: 26 additions & 25 deletions Content.Tests/DMTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ public enum DMTestFlags {

[OneTimeSetUp]
public void OneTimeSetup() {
var dmCompiler = new DMCompiler.DMCompiler();
IoCManager.InjectDependencies(this);
_taskManager.Initialize();
Compile(InitializeEnvironment);
Compile(dmCompiler, InitializeEnvironment);
_dreamMan.PreInitialize(Path.ChangeExtension(InitializeEnvironment, "json"));
_dreamMan.OnException += OnException;
}

private static string? Compile(string sourceFile) {
bool successfulCompile = DMCompiler.DMCompiler.Compile(new() {
private string? Compile(DMCompiler.DMCompiler compiler, string sourceFile) {
bool successfulCompile = compiler.Compile(new() {
Files = [sourceFile]
});

Expand All @@ -64,10 +65,11 @@ public void TestFiles(string sourceFile, DMTestFlags testFlags, int errorCode) {
string initialDirectory = Directory.GetCurrentDirectory();
TestContext.WriteLine($"--- TEST {sourceFile} | Flags: {testFlags}");
try {
string? compiledFile = Compile(Path.Join(initialDirectory, TestsDirectory, sourceFile));
var dmCompiler = new DMCompiler.DMCompiler();
var compiledFile = Compile(dmCompiler, Path.Join(initialDirectory, TestsDirectory, sourceFile));
if (testFlags.HasFlag(DMTestFlags.CompileError)) {
Assert.That(errorCode == -1, Is.False, "Expected an error code");
Assert.That(DMCompiler.DMCompiler.UniqueEmissions.Contains((WarningCode)errorCode), Is.True, $"Expected error code \"{errorCode}\" was not found");
Assert.That(dmCompiler.UniqueEmissions.Contains((WarningCode)errorCode), Is.True, $"Expected error code \"{errorCode}\" was not found");
Assert.That(compiledFile, Is.Null, "Expected an error during DM compilation");

Cleanup(compiledFile);
Expand Down Expand Up @@ -167,29 +169,28 @@ private static DMTestFlags GetDMTestFlags(string sourceFile, out int errorCode)
DMTestFlags testFlags = DMTestFlags.NoError;
errorCode = -1; // If it's null GetTests() fusses about a NRE

using (StreamReader reader = new StreamReader(sourceFile)) {
string? firstLine = reader.ReadLine();
if (firstLine == null)
return testFlags;
if (firstLine.Contains("IGNORE", StringComparison.InvariantCulture))
testFlags |= DMTestFlags.Ignore;
if (firstLine.Contains("COMPILE ERROR", StringComparison.InvariantCulture)) {
testFlags |= DMTestFlags.CompileError;

Match match = ErrorCodeRegex().Match(firstLine); // "OD" followed by exactly 4 numbers
if (match.Success) {
errorCode = int.Parse(match.Groups[1].Value);
}
using StreamReader reader = new StreamReader(sourceFile);
string? firstLine = reader.ReadLine();
if (firstLine == null)
return testFlags;
if (firstLine.Contains("IGNORE", StringComparison.InvariantCulture))
testFlags |= DMTestFlags.Ignore;
if (firstLine.Contains("COMPILE ERROR", StringComparison.InvariantCulture)) {
testFlags |= DMTestFlags.CompileError;

Match match = ErrorCodeRegex().Match(firstLine); // "OD" followed by exactly 4 numbers
if (match.Success) {
errorCode = int.Parse(match.Groups[1].Value);
}

if (firstLine.Contains("RUNTIME ERROR", StringComparison.InvariantCulture))
testFlags |= DMTestFlags.RuntimeError;
if (firstLine.Contains("RETURN TRUE", StringComparison.InvariantCulture))
testFlags |= DMTestFlags.ReturnTrue;
if (firstLine.Contains("NO RETURN", StringComparison.InvariantCulture))
testFlags |= DMTestFlags.NoReturn;
}

if (firstLine.Contains("RUNTIME ERROR", StringComparison.InvariantCulture))
testFlags |= DMTestFlags.RuntimeError;
if (firstLine.Contains("RETURN TRUE", StringComparison.InvariantCulture))
testFlags |= DMTestFlags.ReturnTrue;
if (firstLine.Contains("NO RETURN", StringComparison.InvariantCulture))
testFlags |= DMTestFlags.NoReturn;

return testFlags;
}

Expand Down
4 changes: 2 additions & 2 deletions DMCompiler/Compiler/DM/DMLexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace DMCompiler.Compiler.DM;

public sealed class DMLexer : TokenLexer {
internal sealed class DMLexer : TokenLexer {
public static readonly List<string> ValidEscapeSequences = [
"icon",
"Roman", "roman",
Expand Down Expand Up @@ -68,7 +68,7 @@ public sealed class DMLexer : TokenLexer {
private readonly Stack<int> _indentationStack = new(new[] { 0 });

/// <param name="source">The enumerable list of tokens output by <see cref="DMPreprocessor.DMPreprocessorLexer"/>.</param>
public DMLexer(string sourceName, IEnumerable<Token> source) : base(sourceName, source) { }
internal DMLexer(string sourceName, IEnumerable<Token> source) : base(sourceName, source) { }

protected override Token ParseNextToken() {
Token token;
Expand Down
46 changes: 23 additions & 23 deletions DMCompiler/Compiler/DM/DMParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using DMCompiler.DM;

namespace DMCompiler.Compiler.DM {
public partial class DMParser(DMLexer lexer) : Parser<Token>(lexer) {
internal partial class DMParser(DMCompiler compiler, DMLexer lexer) : Parser<Token>(compiler, lexer) {
protected Location CurrentLoc => Current().Location;
protected DreamPath CurrentPath = DreamPath.Root;

Expand Down Expand Up @@ -211,7 +211,7 @@ public DMASTFile File() {

//Proc definition
if (Check(TokenType.DM_LeftParenthesis)) {
DMCompiler.VerbosePrint($"Parsing proc {CurrentPath}()");
Compiler.VerbosePrint($"Parsing proc {CurrentPath}()");
BracketWhitespace();
var parameters = DefinitionParameters(out var wasIndeterminate);

Expand Down Expand Up @@ -249,7 +249,7 @@ public DMASTFile File() {
}

if (procBlock?.Statements.Length is 0 or null) {
DMCompiler.Emit(WarningCode.EmptyProc, loc,
Compiler.Emit(WarningCode.EmptyProc, loc,
"Empty proc detected - add an explicit \"return\" statement");
}

Expand All @@ -270,7 +270,7 @@ public DMASTFile File() {

//Object definition
if (Block() is { } block) {
DMCompiler.VerbosePrint($"Parsed object {CurrentPath}");
Compiler.VerbosePrint($"Parsed object {CurrentPath}");
return new DMASTObjectDefinition(loc, CurrentPath, block);
}

Expand Down Expand Up @@ -337,7 +337,7 @@ public DMASTFile File() {
}

//Empty object definition
DMCompiler.VerbosePrint($"Parsed object {CurrentPath}");
Compiler.VerbosePrint($"Parsed object {CurrentPath}");
return new DMASTObjectDefinition(loc, CurrentPath, null);
}

Expand Down Expand Up @@ -385,12 +385,12 @@ public DMASTFile File() {
}
} else if (Check(OperatorOverloadTypes)) {
if (operatorToken is { Type: TokenType.DM_ConstantString, Value: not "" }) {
DMCompiler.Emit(WarningCode.BadToken, operatorToken.Location,
Compiler.Emit(WarningCode.BadToken, operatorToken.Location,
"The quotes in a stringify overload must be empty");
}

if (!ImplementedOperatorOverloadTypes.Contains(operatorToken.Type)) {
DMCompiler.UnimplementedWarning(operatorToken.Location,
Compiler.UnimplementedWarning(operatorToken.Location,
$"operator{operatorToken.PrintableText} overloads are not implemented. They will be defined but never called.");
}

Expand Down Expand Up @@ -475,7 +475,7 @@ public DMASTFile File() {
do {
var identifier = Identifier();
if (identifier == null) {
DMCompiler.Emit(WarningCode.BadToken, Current().Location, "Identifier expected");
Compiler.Emit(WarningCode.BadToken, Current().Location, "Identifier expected");
return null;
}

Expand Down Expand Up @@ -1279,7 +1279,7 @@ DMASTProcBlockInner GetForBody(Location forLocation) {
} else {
statement = ProcStatement();
if (statement == null) {
DMCompiler.Emit(WarningCode.MissingBody, forLocation, "Expected body or statement");
Compiler.Emit(WarningCode.MissingBody, forLocation, "Expected body or statement");
statement = new DMASTInvalidProcStatement(loc);
}
}
Expand Down Expand Up @@ -1450,7 +1450,7 @@ private DMASTProcStatementSwitch.SwitchCase[] SwitchInner() {
DMASTExpression? expression = Expression();
if (expression == null) {
if (expressions.Count == 0)
DMCompiler.Emit(WarningCode.BadExpression, Current().Location, "Expected an expression");
Compiler.Emit(WarningCode.BadExpression, Current().Location, "Expected an expression");

break;
}
Expand All @@ -1460,7 +1460,7 @@ private DMASTProcStatementSwitch.SwitchCase[] SwitchInner() {
var loc = Current().Location;
DMASTExpression? rangeEnd = Expression();
if (rangeEnd == null) {
DMCompiler.Emit(WarningCode.BadExpression, loc, "Expected an upper limit");
Compiler.Emit(WarningCode.BadExpression, loc, "Expected an upper limit");
rangeEnd = new DMASTConstantNull(loc); // Fallback to null
}

Expand Down Expand Up @@ -1491,7 +1491,7 @@ private DMASTProcStatementSwitch.SwitchCase[] SwitchInner() {
if (Current().Type == TokenType.DM_If) {
//From now on, all if/elseif/else are actually part of this if's chain, not the switch's.
//Ambiguous, but that is parity behaviour. Ergo, the following emission.
DMCompiler.Emit(WarningCode.SuspiciousSwitchCase, loc,
Compiler.Emit(WarningCode.SuspiciousSwitchCase, loc,
"Expected \"if\" or \"else\" - \"else if\" is ambiguous as a switch case and may cause unintended flow");
}

Expand Down Expand Up @@ -1742,9 +1742,9 @@ private List<DMASTDefinitionParameter> DefinitionParameters(out bool wasIndeterm
}

var type = AsComplexTypes();
DMObjectTree.TryGetDMObject(path.Path, out var dmType);
Compiler.DMObjectTree.TryGetDMObject(path.Path, out var dmType);
if (type is { Type: not DMValueType.Anything } && (value is null or DMASTConstantNull) && (dmType?.IsSubtypeOf(DreamPath.Datum) ?? false)) {
DMCompiler.Emit(WarningCode.ImplicitNullType, loc, $"Variable \"{path.Path}\" is null but not a subtype of atom nor explicitly typed as nullable, append \"|null\" to \"as\". It will implicitly be treated as nullable.");
Compiler.Emit(WarningCode.ImplicitNullType, loc, $"Variable \"{path.Path}\" is null but not a subtype of atom nor explicitly typed as nullable, append \"|null\" to \"as\". It will implicitly be treated as nullable.");
type |= DMValueType.Null;
}

Expand Down Expand Up @@ -2220,7 +2220,7 @@ private void ExpressionTo(out DMASTExpression endRange, out DMASTExpression? ste

//TODO actual modified type support
if (Check(TokenType.DM_LeftCurlyBracket)) {
DMCompiler.UnimplementedWarning(path.Location, "Modified types are currently not supported and modified values will be ignored.");
Compiler.UnimplementedWarning(path.Location, "Modified types are currently not supported and modified values will be ignored.");

BracketWhitespace();
Check(TokenType.DM_Indent); // The body could be indented. We ignore that. TODO: Better braced block parsing
Expand Down Expand Up @@ -2376,18 +2376,18 @@ private void BracketWhitespace() {

switch (token.Type) {
case TokenType.DM_Colon:
DMCompiler.Emit(WarningCode.RuntimeSearchOperator, token.Location, "Runtime search operator ':' should be avoided; prefer typecasting and using '.' instead");
Compiler.Emit(WarningCode.RuntimeSearchOperator, token.Location, "Runtime search operator ':' should be avoided; prefer typecasting and using '.' instead");
goto case TokenType.DM_QuestionPeriod;
case TokenType.DM_QuestionColon:
DMCompiler.Emit(WarningCode.RuntimeSearchOperator, token.Location, "Runtime search operator '?:' should be avoided; prefer typecasting and using '?.' instead");
Compiler.Emit(WarningCode.RuntimeSearchOperator, token.Location, "Runtime search operator '?:' should be avoided; prefer typecasting and using '?.' instead");
goto case TokenType.DM_QuestionPeriod;
case TokenType.DM_Period:
case TokenType.DM_QuestionPeriod:
{
var identifier = Identifier();

if (identifier == null) {
DMCompiler.Emit(WarningCode.BadToken, token.Location, "Identifier expected");
Compiler.Emit(WarningCode.BadToken, token.Location, "Identifier expected");
return new DMASTConstantNull(token.Location);
}

Expand Down Expand Up @@ -2419,7 +2419,7 @@ private void BracketWhitespace() {
ConsumeRightBracket();

if (index == null) {
DMCompiler.Emit(WarningCode.BadToken, token.Location, "Expression expected");
Compiler.Emit(WarningCode.BadToken, token.Location, "Expression expected");
return new DMASTConstantNull(token.Location);
}

Expand Down Expand Up @@ -2456,7 +2456,7 @@ private void BracketWhitespace() {
break;

case DMASTDereference.IndexOperation:
DMCompiler.Emit(WarningCode.BadToken, token.Location, "Attempt to call an invalid l-value");
Compiler.Emit(WarningCode.BadToken, token.Location, "Attempt to call an invalid l-value");
return new DMASTConstantNull(token.Location);

default:
Expand Down Expand Up @@ -2740,7 +2740,7 @@ private void BracketWhitespace() {
if (path == null)
path = pathType;
else
DMCompiler.Emit(WarningCode.BadToken, CurrentLoc,
Compiler.Emit(WarningCode.BadToken, CurrentLoc,
$"Only one type path can be used, ignoring {pathType}");
}

Expand Down Expand Up @@ -2772,13 +2772,13 @@ private DMValueType SingleAsType(out DreamPath? path, bool allowPath = false) {
path = Path()?.Path;
if (allowPath) {
if (path is null) {
DMCompiler.Emit(WarningCode.BadToken, typeToken.Location, "Expected value type or path");
Compiler.Emit(WarningCode.BadToken, typeToken.Location, "Expected value type or path");
}

return DMValueType.Path;
}

DMCompiler.Emit(WarningCode.BadToken, typeToken.Location, "Expected value type");
Compiler.Emit(WarningCode.BadToken, typeToken.Location, "Expected value type");
return 0;
}

Expand Down
Loading