From 487a30cc3a59c832f04f7354f2412d3f736da032 Mon Sep 17 00:00:00 2001 From: wixoa Date: Fri, 17 Jan 2025 19:57:48 -0500 Subject: [PATCH] Fix var blocks creating an empty type named `var` (#2173) --- .../Compiler/DM/AST/DMAST.ObjectStatements.cs | 6 +++ DMCompiler/Compiler/DM/DMParser.cs | 41 ++++++++++++++----- DMCompiler/DM/Builders/DMCodeTreeBuilder.cs | 2 + 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/DMCompiler/Compiler/DM/AST/DMAST.ObjectStatements.cs b/DMCompiler/Compiler/DM/AST/DMAST.ObjectStatements.cs index a0f4f9dd81..ff3d8319ec 100644 --- a/DMCompiler/Compiler/DM/AST/DMAST.ObjectStatements.cs +++ b/DMCompiler/Compiler/DM/AST/DMAST.ObjectStatements.cs @@ -7,6 +7,12 @@ namespace DMCompiler.Compiler.DM.AST; /// public abstract class DMASTStatement(Location location) : DMASTNode(location); +/// +/// Used when there was an error parsing a statement +/// +/// Emit an error code before creating! +public sealed class DMASTInvalidStatement(Location location) : DMASTStatement(location); + public sealed class DMASTObjectDefinition(Location location, DreamPath path, DMASTBlockInner? innerBlock) : DMASTStatement(location) { /// Unlike other Path variables stored by AST nodes, this path is guaranteed to be the real, absolute path of this object definition block.
diff --git a/DMCompiler/Compiler/DM/DMParser.cs b/DMCompiler/Compiler/DM/DMParser.cs index c66199337f..2949029862 100644 --- a/DMCompiler/Compiler/DM/DMParser.cs +++ b/DMCompiler/Compiler/DM/DMParser.cs @@ -268,17 +268,28 @@ public DMASTFile File() { return new DMASTProcDefinition(loc, CurrentPath, parameters.ToArray(), procBlock, types); } - //Object definition - if (Block() is { } block) { - Compiler.VerbosePrint($"Parsed object {CurrentPath}"); - return new DMASTObjectDefinition(loc, CurrentPath, block); - } - //Var definition(s) if (CurrentPath.FindElement("var") != -1) { + bool isIndented = false; DreamPath varPath = CurrentPath; List varDefinitions = new(); + var possibleNewline = Current(); + if (Newline()) { + if (Check(TokenType.DM_Indent)) { + isIndented = true; + DMASTPath? newVarPath = Path(); + if (newVarPath == null) { + Emit(WarningCode.InvalidVarDefinition, "Expected a var definition"); + return new DMASTInvalidStatement(CurrentLoc); + } + + varPath = CurrentPath.AddToPath(newVarPath.Path.PathString); + } else { + ReuseToken(possibleNewline); + } + } + while (true) { Whitespace(); @@ -304,24 +315,26 @@ public DMASTFile File() { var varDef = new DMASTObjectVarDefinition(loc, varPath, value, valType); varDefinitions.Add(varDef); - if (Check(TokenType.DM_Comma)) { + if (Check(TokenType.DM_Comma) || (isIndented && Newline())) { Whitespace(); DMASTPath? newVarPath = Path(); if (newVarPath == null) { Emit(WarningCode.InvalidVarDefinition, "Expected a var definition"); break; - } else if (newVarPath.Path.Elements.Length > 1) { // TODO: This is valid DM - Emit(WarningCode.BadToken, newVarPath.Location, "Invalid var name"); - break; } - varPath = CurrentPath.AddToPath("../" + newVarPath.Path.PathString); + varPath = CurrentPath.AddToPath( + isIndented ? newVarPath.Path.PathString + : "../" + newVarPath.Path.PathString); } else { break; } } + if (isIndented) + Consume(TokenType.DM_Dedent, "Expected end of var block"); + return (varDefinitions.Count == 1) ? varDefinitions[0] : new DMASTMultipleObjectVarDefinitions(loc, varDefinitions.ToArray()); @@ -336,6 +349,12 @@ public DMASTFile File() { return new DMASTObjectVarOverride(loc, CurrentPath, value); } + //Object definition + if (Block() is { } block) { + Compiler.VerbosePrint($"Parsed object {CurrentPath}"); + return new DMASTObjectDefinition(loc, CurrentPath, block); + } + //Empty object definition Compiler.VerbosePrint($"Parsed object {CurrentPath} - empty"); return new DMASTObjectDefinition(loc, CurrentPath, null); diff --git a/DMCompiler/DM/Builders/DMCodeTreeBuilder.cs b/DMCompiler/DM/Builders/DMCodeTreeBuilder.cs index c4b558c95d..612576368e 100644 --- a/DMCompiler/DM/Builders/DMCodeTreeBuilder.cs +++ b/DMCompiler/DM/Builders/DMCodeTreeBuilder.cs @@ -40,6 +40,8 @@ private void ProcessStatement(DMASTStatement statement, DreamPath currentType) { } switch (statement) { + case DMASTInvalidStatement: + break; // An error should have been emitted by whatever made this case DMASTObjectDefinition objectDefinition: CodeTree.AddType(objectDefinition.Path); if (objectDefinition.InnerBlock != null)