Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for #define FILE_DIR #1474

Merged
merged 2 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 25 additions & 3 deletions DMCompiler/Compiler/DMPreprocessor/DMPreprocessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,30 @@ private void HandleDefineDirective(Token defineToken) {
GetLineOfTokens(); // consume what's on this line and leave
return;
}
if(defineIdentifier.Text == "defined") {

// #define FILE_DIR is a little special
// Every define will add to a list of directories to check for resource files
if (defineIdentifier.Text == "FILE_DIR") {
Token dirToken = GetNextToken(true);
string? dirTokenValue = dirToken.Type switch {
TokenType.DM_Preproc_ConstantString => (string?)dirToken.Value,
TokenType.DM_Preproc_Punctuator_Period => ".",
_ => null
};

if (dirTokenValue is null) {
DMCompiler.Emit(WarningCode.BadDirective, dirToken.Location, $"\"{dirToken.Text}\" is not a valid directory");
return;
}

DMPreprocessorLexer currentLexer = _lexerStack.Peek();
string dir = Path.Combine(currentLexer.IncludeDirectory, dirTokenValue);
DMCompiler.AddResourceDirectory(dir);

// In BYOND it goes on to set the FILE_DIR macro's value to the added directory
// I don't see any reason to do that
return;
} else if (defineIdentifier.Text == "defined") {
DMCompiler.Emit(WarningCode.SoftReservedKeyword, defineIdentifier.Location, "Reserved keyword 'defined' cannot be used as macro name");
}

Expand All @@ -310,11 +333,10 @@ private void HandleDefineDirective(Token defineToken) {
if (macroToken.Type == TokenType.DM_Preproc_Punctuator_LeftParenthesis) { // We're a macro function!
parameters = new List<string>(1);
//Read in the parameters
Token parameterToken;
bool canConsumeComma = false;
bool foundVariadic = false;
while(true) {
parameterToken = GetNextToken(true);
var parameterToken = GetNextToken(true);
switch(parameterToken.Type) {
case TokenType.DM_Preproc_Identifier:
canConsumeComma = true;
Expand Down
26 changes: 17 additions & 9 deletions DMCompiler/DM/Expressions/Constant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,24 +364,32 @@ public Resource(Location location, string filePath) : base(location) {
// Treat backslashes as forward slashes on Linux
filePath = filePath.Replace('\\', '/');

string? finalFilePath = null;

var outputDir = System.IO.Path.GetDirectoryName(DMCompiler.Settings.Files[0]) ?? "/";
var outputDir = System.IO.Path.GetDirectoryName(DMCompiler.Settings.Files?[0]) ?? "/";
if (string.IsNullOrEmpty(outputDir))
outputDir = "./";

string? finalFilePath = null;

var fileName = System.IO.Path.GetFileName(filePath);
var fileDir = System.IO.Path.GetDirectoryName(filePath) ?? string.Empty;
var directory = FindDirectory(outputDir, fileDir);
if (directory != null) {
// Perform a case-insensitive search for the file
finalFilePath = FindFile(directory, fileName);

// Search every defined FILE_DIR
foreach (string resourceDir in DMCompiler.ResourceDirectories) {
var directory = FindDirectory(resourceDir, fileDir);

if (directory != null) {
// Perform a case-insensitive search for the file
finalFilePath = FindFile(directory, fileName);

if (finalFilePath != null)
break;
}
}

// Search relative to the source file if it wasn't in the project's directory
// Search relative to the source file if it wasn't in one of the FILE_DIRs
if (finalFilePath == null) {
var sourceDir = System.IO.Path.Combine(outputDir, System.IO.Path.GetDirectoryName(Location.SourceFile) ?? string.Empty);
directory = FindDirectory(sourceDir, fileDir);
var directory = FindDirectory(sourceDir, fileDir);

if (directory != null)
finalFilePath = FindFile(directory, fileName);
Expand Down
75 changes: 37 additions & 38 deletions DMCompiler/DMCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,22 @@
namespace DMCompiler {
//TODO: Make this not a static class
public static class DMCompiler {
public static int ErrorCount = 0;
public static int WarningCount = 0;
public static int ErrorCount;
public static int WarningCount;
public static DMCompilerSettings Settings;
public static IReadOnlyList<string> ResourceDirectories => _resourceDirectories;

private static DMCompilerConfiguration Config;
private static readonly DMCompilerConfiguration Config = new();
private static readonly List<string> _resourceDirectories = new();
private static DateTime _compileStartTime;

public static bool Compile(DMCompilerSettings settings) {
ErrorCount = 0;
WarningCount = 0;
Settings = settings;
if (Settings.Files == null) return false;
Config = new();
Config.Reset();
_resourceDirectories.Clear();

//TODO: Only use InvariantCulture where necessary instead of it being the default
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
Expand All @@ -50,25 +53,18 @@ public static bool Compile(DMCompilerSettings settings) {
DMPreprocessor preprocessor = Preprocess(settings.Files, settings.MacroDefines);
bool successfulCompile = preprocessor is not null && Compile(preprocessor);

if (successfulCompile)
{
if (successfulCompile) {
//Output file is the first file with the extension changed to .json
string outputFile = Path.ChangeExtension(settings.Files[0], "json");
List<DreamMapJson> maps = ConvertMaps(preprocessor.IncludedMaps);

if (ErrorCount > 0)
{
if (ErrorCount > 0) {
successfulCompile = false;
}
else
{
} else {
var output = SaveJson(maps, preprocessor.IncludedInterface, outputFile);
if (ErrorCount > 0)
{
if (ErrorCount > 0) {
successfulCompile = false;
}
else
{
} else {
Console.WriteLine($"Compilation succeeded with {WarningCount} warnings");
Console.WriteLine(output);
}
Expand All @@ -80,13 +76,19 @@ public static bool Compile(DMCompilerSettings settings) {
}

TimeSpan duration = DateTime.Now - _compileStartTime;
Console.WriteLine($"Total time: {duration.ToString(@"mm\:ss")}");
Console.WriteLine($"Total time: {duration:mm\\:ss}");

return successfulCompile;
}

private static DMPreprocessor? Preprocess(List<string> files, Dictionary<string, string> macroDefines) {
DMPreprocessor? build() {
public static void AddResourceDirectory(string dir) {
dir = dir.Replace('\\', Path.DirectorySeparatorChar);

_resourceDirectories.Add(dir);
}

private static DMPreprocessor? Preprocess(List<string> files, Dictionary<string, string>? macroDefines) {
DMPreprocessor? Build() {
DMPreprocessor preproc = new DMPreprocessor(true);
if (macroDefines != null) {
foreach (var (key, value) in macroDefines) {
Expand Down Expand Up @@ -130,7 +132,7 @@ public static bool Compile(DMCompilerSettings settings) {
if (Settings.DumpPreprocessor) {
//Preprocessing is done twice because the output is used up when dumping it
StringBuilder result = new();
foreach (Token t in build()) {
foreach (Token t in Build()) {
result.Append(t.Text);
}

Expand All @@ -140,7 +142,8 @@ public static bool Compile(DMCompilerSettings settings) {
File.WriteAllText(outputPath, result.ToString());
Console.WriteLine($"Preprocessor output dumped to {outputPath}");
}
return build();

return Build();
}

private static bool Compile(IEnumerable<Token> preprocessedTokens) {
Expand All @@ -154,11 +157,6 @@ private static bool Compile(IEnumerable<Token> preprocessedTokens) {
Emit(warning);
}

if (astFile is null) {
VerbosePrint("Parsing failed, exiting compilation");
return false;
}

DMASTSimplifier astSimplifier = new DMASTSimplifier();
VerbosePrint("Constant folding");
astSimplifier.SimplifyAST(astFile);
Expand Down Expand Up @@ -190,7 +188,7 @@ public static void Emit(CompilerEmission emission) {
/// <summary> Emits the given warning, according to its ErrorLevel as set in our config. </summary>
/// <returns> True if the warning was an error, false if not.</returns>
public static bool Emit(WarningCode code, Location loc, string message) {
ErrorLevel level = Config.errorConfig[code];
ErrorLevel level = Config.ErrorConfig[code];
Emit(new CompilerEmission(level, code, loc, message));
return level == ErrorLevel.Error;
}
Expand Down Expand Up @@ -328,7 +326,7 @@ private static string SaveJson(List<DreamMapJson> maps, string interfaceFile, st
public static void DefineFatalErrors() {
foreach (WarningCode code in Enum.GetValues<WarningCode>()) {
if((int)code < 1_000) {
Config.errorConfig[code] = ErrorLevel.Error;
Config.ErrorConfig[code] = ErrorLevel.Error;
}
}
}
Expand All @@ -338,32 +336,32 @@ public static void DefineFatalErrors() {
/// </summary>
public static void CheckAllPragmasWereSet() {
foreach(WarningCode code in Enum.GetValues<WarningCode>()) {
if (!Config.errorConfig.ContainsKey(code)) {
if (!Config.ErrorConfig.ContainsKey(code)) {
ForcedWarning($"Warning #{(int)code:d4} '{code.ToString()}' was never declared as error, warning, notice, or disabled.");
Config.errorConfig.Add(code, ErrorLevel.Disabled);
Config.ErrorConfig.Add(code, ErrorLevel.Disabled);
}
}
}

public static void SetPragma(WarningCode code, ErrorLevel level) {
Config.errorConfig[code] = level;
Config.ErrorConfig[code] = level;
}

public static ErrorLevel CodeToLevel(WarningCode code) {
bool didFind = Config.errorConfig.TryGetValue(code, out var ret);
bool didFind = Config.ErrorConfig.TryGetValue(code, out var ret);
DebugTools.Assert(didFind);
return ret;
}
}

public struct DMCompilerSettings {
public List<string> Files = null;
public List<string>? Files = null;
public bool SuppressUnimplementedWarnings = false;
public bool NoticesEnabled = false;
public bool DumpPreprocessor = false;
public bool NoStandard = false;
public bool Verbose = false;
public Dictionary<string, string> MacroDefines = null;
public Dictionary<string, string>? MacroDefines = null;
/// <summary> A user-provided pragma config file, if one was provided. </summary>
public string? PragmaFileOverride = null;

Expand All @@ -375,10 +373,11 @@ public DMCompilerSettings() {
}
}

class DMCompilerConfiguration {
public Dictionary<WarningCode, ErrorLevel> errorConfig;
public DMCompilerConfiguration() {
errorConfig = new(Enum.GetValues<WarningCode>().Length);
internal class DMCompilerConfiguration {
public readonly Dictionary<WarningCode, ErrorLevel> ErrorConfig = new(Enum.GetValues<WarningCode>().Length);

public void Reset() {
ErrorConfig.Clear();
}
}
}
Loading