1 /** 2 * Authors: 3 * Mike Bierlee, m.bierlee@lostmoment.com 4 * Copyright: 2023 Mike Bierlee 5 * License: 6 * This software is licensed under the terms of the MIT license. 7 * The full terms of the license can be found in the LICENSE.txt file. 8 */ 9 10 module preprocessor.artifacts; 11 12 import preprocessor.parsing : ParseContext, calculateLineColumn; 13 14 import std.conv : to; 15 16 alias SourceMap = string[string]; 17 alias MacroMap = string[string]; 18 19 enum FileMacro = "FILE"; 20 enum LineMacro = "LINE"; 21 enum DateMacro = "DATE"; 22 enum TimeMacro = "TIME"; 23 enum TimestampMacro = "TIMESTAMP"; 24 25 static const string[] builtInMacros = [ 26 FileMacro, LineMacro, DateMacro, TimeMacro, TimestampMacro 27 ]; 28 29 /** 30 * A context containing information regarding the build process, 31 * such a sources. 32 */ 33 struct BuildContext { 34 /// Sources to be processed. 35 SourceMap sources; 36 37 /** 38 * When specified, only these sources will be processed. 39 * Sources specified in "sources" will still be able to be included 40 * and processed, but are treated as libraries. 41 * When empty, all sources in "sources" will be processed instead. 42 */ 43 SourceMap mainSources; 44 45 /** 46 * A map of pre-defined macros. 47 * Built-in macros will override these. 48 */ 49 MacroMap macros; 50 51 /** 52 * The maximum amount of inclusions allowed. This is to prevent 53 * an endless inclusion cycle. Defaults to 4000. 54 */ 55 uint inclusionLimit = 4000; 56 57 /** 58 * Whether the parser should ignore #elif, #else and #endif 59 * directives that didn't come after a #if directive. 60 * If true they will be kept in the result. 61 */ 62 bool ignoreUnmatchedConditionalDirectives = false; 63 64 /// Wheter to enable processing of #include directives. 65 bool enableIncludeDirectives = true; 66 67 /// Wheter to enable processing of conditional directives. 68 bool enableConditionalDirectives = true; 69 70 /// Wheter to enable processing of #define directives. 71 bool enableMacroDefineDirectives = true; 72 73 /// Wheter to enable processing of #undef directives. 74 bool enableMacroUndefineDirectives = true; 75 76 /// Wheter to enable processing of #error directives. 77 bool enableErrorDirectives = true; 78 79 /// Wheter to enable processing of #pragma directives. 80 bool enablePragmaDirectives = true; 81 82 /** 83 * Disables all directives. 84 * They can then be individually enabled again. 85 */ 86 void disableAllDirectives() { 87 enableIncludeDirectives = false; 88 enableConditionalDirectives = false; 89 enableMacroDefineDirectives = false; 90 enableMacroUndefineDirectives = false; 91 enableErrorDirectives = false; 92 enablePragmaDirectives = false; 93 } 94 95 /** 96 * Enables all directives. 97 * They can then be individually disabled again. 98 */ 99 void enableAllDirectives() { 100 enableIncludeDirectives = true; 101 enableConditionalDirectives = true; 102 enableMacroDefineDirectives = true; 103 enableMacroUndefineDirectives = true; 104 enableErrorDirectives = true; 105 enablePragmaDirectives = true; 106 } 107 } 108 109 /** 110 * Result with modified source files. 111 */ 112 struct ProcessingResult { 113 /// The processed (main) sources. 114 SourceMap sources; 115 116 /** 117 * Textual date of when the processing started 118 * e.g: Feb 16 2023 119 */ 120 string date; 121 122 /** 123 * Textual time of when the processing started 124 * e.g: 22:31:01 125 */ 126 string time; 127 128 /** 129 * Textual timestamp of when the processing started 130 * e.g: Thu Feb 16 22:38:10 2023 131 */ 132 string timestamp; 133 } 134 135 /** 136 * An exception typically thrown when there are parsing errors while preprocessing. 137 */ 138 class ParseException : PreprocessException { 139 this(in ref ParseContext parseCtx, string msg, string file = __FILE__, size_t line = __LINE__) { 140 auto errorMessage = "Parse error: " ~ msg; 141 super(parseCtx, parseCtx.codePos, errorMessage, file, line); 142 } 143 } 144 145 /** 146 * An exception thrown when something fails while preprocessing. 147 * Except for parsing errors, they will be thrown as a ParseException. 148 */ 149 class PreprocessException : Exception { 150 this(in ref ParseContext parseCtx, string msg, string file = __FILE__, size_t line = __LINE__) { 151 this(parseCtx, parseCtx.codePos, msg, file, line); 152 } 153 154 this(in ref ParseContext parseCtx, ulong codePos, string msg, string file = __FILE__, size_t line = __LINE__) { 155 ulong srcLine; 156 ulong srcColumn; 157 calculateLineColumn(parseCtx, codePos, srcLine, srcColumn); 158 auto parseErrorMsg = "Error processing " ~ parseCtx.name ~ "(" ~ srcLine.to!string ~ "," ~ srcColumn 159 .to!string ~ "): " ~ msg; 160 super(parseErrorMsg, file, line); 161 } 162 }