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 /// Wheter to enable macro expansion. 83 bool enableMacroExpansion = true; 84 85 /** 86 * Disables all directives. 87 * They can then be individually enabled again. 88 */ 89 void disableAllDirectives() { 90 enableIncludeDirectives = false; 91 enableConditionalDirectives = false; 92 enableMacroDefineDirectives = false; 93 enableMacroUndefineDirectives = false; 94 enableErrorDirectives = false; 95 enablePragmaDirectives = false; 96 } 97 98 /** 99 * Enables all directives. 100 * They can then be individually disabled again. 101 */ 102 void enableAllDirectives() { 103 enableIncludeDirectives = true; 104 enableConditionalDirectives = true; 105 enableMacroDefineDirectives = true; 106 enableMacroUndefineDirectives = true; 107 enableErrorDirectives = true; 108 enablePragmaDirectives = true; 109 } 110 } 111 112 /** 113 * Result with modified source files. 114 */ 115 struct ProcessingResult { 116 /// The processed (main) sources. 117 SourceMap sources; 118 119 /** 120 * Textual date of when the processing started 121 * e.g: Feb 16 2023 122 */ 123 string date; 124 125 /** 126 * Textual time of when the processing started 127 * e.g: 22:31:01 128 */ 129 string time; 130 131 /** 132 * Textual timestamp of when the processing started 133 * e.g: Thu Feb 16 22:38:10 2023 134 */ 135 string timestamp; 136 } 137 138 /** 139 * An exception typically thrown when there are parsing errors while preprocessing. 140 */ 141 class ParseException : PreprocessException { 142 this(in ref ParseContext parseCtx, string msg, string file = __FILE__, size_t line = __LINE__) { 143 auto errorMessage = "Parse error: " ~ msg; 144 super(parseCtx, parseCtx.codePos, errorMessage, file, line); 145 } 146 } 147 148 /** 149 * An exception thrown when something fails while preprocessing. 150 * Except for parsing errors, they will be thrown as a ParseException. 151 */ 152 class PreprocessException : Exception { 153 this(in ref ParseContext parseCtx, string msg, string file = __FILE__, size_t line = __LINE__) { 154 this(parseCtx, parseCtx.codePos, msg, file, line); 155 } 156 157 this(in ref ParseContext parseCtx, ulong codePos, string msg, string file = __FILE__, size_t line = __LINE__) { 158 ulong srcLine; 159 ulong srcColumn; 160 calculateLineColumn(parseCtx, codePos, srcLine, srcColumn); 161 auto parseErrorMsg = "Error processing " ~ parseCtx.name ~ "(" ~ srcLine.to!string ~ "," ~ srcColumn 162 .to!string ~ "): " ~ msg; 163 super(parseErrorMsg, file, line); 164 } 165 }