1 2 // Copyright Tim Schendekehl 2023. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // https://www.boost.org/LICENSE_1_0.txt) 6 7 module dparsergen.generator.production; 8 public import dparsergen.core.grammarinfo; 9 import std.array; 10 11 struct TagID 12 { 13 ubyte id; 14 15 int opCmp(TagID other) const pure nothrow 16 { 17 if (id < other.id) 18 return -1; 19 if (id > other.id) 20 return 1; 21 return 0; 22 } 23 } 24 25 enum StdAnnotations = [ 26 "empty", 27 "array", 28 "backtrack", 29 "deactivated", 30 "directUnwrap", 31 "flatten", 32 "ignoreInConflict", 33 "ignoreToken", 34 "inContextOnly", 35 "lookahead", 36 "lowPrio", 37 "regArray", 38 "start", 39 "string", 40 "regexLookahead", 41 "store", 42 "compareTrue", 43 "compareFalse", 44 "eager", 45 "eagerEnd", 46 "recursiveLexer", 47 "inheritAnyTag", 48 "minimalMatch" 49 ]; 50 51 mixin(() { 52 import std.string; 53 54 string r = "enum AnnotationFlags {"; 55 r ~= "NONE = 0, "; 56 foreach (i, a; StdAnnotations) 57 r ~= format("%s = %d, ", a, 1 << i); 58 r ~= format("ALL = %d", (1 >> StdAnnotations.length) - 1); 59 r ~= "}"; 60 return r; 61 }()); 62 63 struct Annotations 64 { 65 AnnotationFlags stdAnnotations; 66 immutable(string)[] otherAnnotations; 67 this(immutable(string)[] annotations) 68 { 69 add(annotations); 70 } 71 72 void add(string annotation) 73 { 74 import std.algorithm; 75 76 mixin(() { 77 import std.string; 78 79 string r = ""; 80 foreach (i, a; StdAnnotations) 81 r ~= format("%sif(annotation == \"%s\") stdAnnotations |= AnnotationFlags.%s;", 82 (i) ? "else " : "", a, a); 83 r ~= "else if (!std.algorithm.canFind(otherAnnotations, annotation)) otherAnnotations ~= annotation;"; 84 return r; 85 }()); 86 } 87 88 void add(immutable(string)[] annotations) 89 { 90 foreach (annotation; annotations) 91 { 92 add(annotation); 93 } 94 } 95 96 void add(const Annotations annotations) 97 { 98 stdAnnotations |= annotations.stdAnnotations; 99 foreach (annotation; annotations.otherAnnotations) 100 { 101 add(annotation); 102 } 103 } 104 105 bool canFind(string annotation) const pure nothrow 106 { 107 mixin(() { 108 import std.string; 109 110 string r = ""; 111 foreach (i, a; StdAnnotations) 112 r ~= format("if (annotation == \"%s\") return (stdAnnotations & AnnotationFlags.%s) != 0;", 113 a, a); 114 return r; 115 }()); 116 import std.algorithm; 117 118 return std.algorithm.canFind(otherAnnotations, annotation); 119 } 120 121 bool contains(string annotation)() const pure nothrow 122 { 123 mixin(() { 124 import std.string; 125 126 foreach (i, a; StdAnnotations) 127 if (a == annotation) 128 return format("return (stdAnnotations & AnnotationFlags.%s) != 0;", a); 129 string r; 130 r ~= "import std.algorithm;"; 131 r ~= "return std.algorithm.canFind(otherAnnotations, annotation);"; 132 return r; 133 }()); 134 } 135 136 string toString() const 137 { 138 import std.conv; 139 import std.string; 140 141 string r = "["; 142 foreach (i, a; StdAnnotations) 143 if (stdAnnotations & (1 << i)) 144 r ~= text("\"", a, "\", "); 145 foreach (a; otherAnnotations) 146 r ~= text("\"", a, "\", "); 147 if (r.endsWith(", ")) 148 r = r[0 .. $ - 2]; 149 r ~= "]"; 150 return r; 151 } 152 153 string toStringCode(bool spaceAfter = false) const 154 { 155 Appender!string app; 156 toStringCode(app, spaceAfter); 157 return app.data; 158 } 159 160 void toStringCode(ref Appender!string app, bool spaceAfter = false) const 161 { 162 foreach (i, a; StdAnnotations) 163 if (stdAnnotations & (1 << i)) 164 { 165 if (!spaceAfter) 166 app.put(" "); 167 app.put("@"); 168 app.put(a); 169 if (spaceAfter) 170 app.put(" "); 171 } 172 foreach (a; otherAnnotations) 173 { 174 if (!spaceAfter) 175 app.put(" "); 176 app.put("@"); 177 app.put(a); 178 if (spaceAfter) 179 app.put(" "); 180 } 181 } 182 } 183 184 struct TagUsage 185 { 186 TagID tag; 187 bool inherit; 188 bool needed; 189 bool reject; 190 191 int opCmp(TagUsage other) const pure nothrow 192 { 193 if (tag.id < other.tag.id) 194 return -1; 195 if (tag.id > other.tag.id) 196 return 1; 197 return 0; 198 } 199 } 200 201 struct Token 202 { 203 string name; 204 Annotations annotations; 205 } 206 207 struct Nonterminal 208 { 209 string name; 210 NonterminalFlags flags; 211 Annotations annotations; 212 immutable(SymbolID)[] buildNonterminals; 213 immutable(TagID)[] possibleTags; 214 } 215 216 struct Tag 217 { 218 string name; 219 } 220 221 struct SymbolInstance 222 { 223 Symbol symbol; 224 alias symbol this; 225 string subToken; 226 string symbolInstanceName; 227 bool unwrapProduction; 228 bool dropNode; 229 Annotations annotations; 230 immutable(Symbol)[] negLookaheads; 231 immutable(TagUsage)[] tags; 232 } 233 234 struct Production 235 { 236 NonterminalID nonterminalID = NonterminalID(SymbolID.max); 237 immutable(SymbolInstance)[] symbols; 238 ProductionID productionID = ProductionID.max; 239 Annotations annotations; 240 Symbol[] negLookaheads; 241 bool negLookaheadsAnytoken; 242 bool isVirtual; 243 RewriteRule[] rewriteRules; 244 immutable(TagID)[] tags; 245 246 immutable(Production*) idup() const 247 { 248 immutable(RewriteRule)[] newRewriteRules; 249 foreach (rule; rewriteRules) 250 newRewriteRules ~= immutable(RewriteRule)(rule.applyProduction.idup, 251 rule.parameters.idup, rule.startOf, rule.newPos); 252 return new immutable(Production)(nonterminalID, symbols, productionID, annotations, 253 negLookaheads.idup, negLookaheadsAnytoken, isVirtual, newRewriteRules, tags); 254 } 255 256 Production* dup() const 257 { 258 RewriteRule[] newRewriteRules; 259 foreach (rule; rewriteRules) 260 newRewriteRules ~= RewriteRule(rule.applyProduction, 261 rule.parameters.dup, rule.startOf, rule.newPos); 262 return new Production(nonterminalID, symbols, productionID, annotations, 263 negLookaheads.dup, negLookaheadsAnytoken, isVirtual, newRewriteRules, tags); 264 } 265 } 266 267 struct RewriteRule 268 { 269 const Production* applyProduction; 270 size_t[] parameters; 271 size_t startOf = size_t.max; // copy start Location from here 272 size_t newPos; 273 }