1 /** 2 Copyright 2018 Mark Fisher 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy of 5 this software and associated documentation files (the "Software"), to deal in 6 the Software without restriction, including without limitation the rights to 7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 of the Software, and to permit persons to whom the Software is furnished to do 9 so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in all 12 copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 SOFTWARE. 21 **/ 22 module dxx.util.grammar; 23 24 public import pegged.grammar; 25 26 private import dxx.util; 27 28 template parseGrammar(string g) { 29 enum parseGrammar = grammar(g); 30 } 31 template parseGrammarFile(string fname) { 32 enum parseGrammarFile = parseGrammar!(import(fname)); 33 } 34 35 template parseData(alias Grammar,string data) { 36 enum parseData = Grammar(data); 37 } 38 template parseData(alias Grammar) { 39 auto parseData(string data) { 40 return Grammar(data); 41 } 42 } 43 //template parseData(string data,string g,alias Grammar) { 44 //auto g = parseGrammar!g; 45 // enum parseData = Grammar(data); 46 //} 47 template parseDataFile(alias Grammar,string grammarFile,string dataFile) { 48 mixin(parseGrammarFile!grammarFile); 49 enum parseDataFile = parseDataFile!(Grammar,dataFile); 50 } 51 template parseDataFile(alias Grammar,string dataFile) { 52 enum parseDataFile = Grammar(import(dataFile)); 53 } 54 template outputData(Sink,alias data) { 55 auto outputData(Sink sink) { 56 return sink ~= data; 57 } 58 } 59 60 template iterateParseTree(alias Node,alias Fnc) { 61 string iterateParseTree() { 62 appender:string s; 63 static foreach(n;Node.children) { 64 s ~= iterateParseTree!n; 65 } 66 return Fnc!(Node.name,Node,s); 67 } 68 } 69 70 string renderData(Data)() { 71 // string buffer 72 outputData!Data(sb); 73 return sb.data; 74 } 75 76 template GrammarParser(string g,string name) { 77 mixin(parseGrammar!g); 78 auto GrammarParser(string d) { 79 mixin(name)(d); 80 } 81 } 82 83 unittest { 84 85 import std.stdio; 86 import std.conv; 87 import std.array; 88 import std.algorithm; 89 90 enum g=q{ 91 MyGrammar: 92 test < "test" {myaction} test2 93 test2 < "test2" identifier 94 }; 95 enum d=`test test2 testId`; 96 97 class MyGrammar { 98 static bool _assert = false; 99 static string[] names; 100 101 mixin(parseGrammar!g); 102 103 static PT myaction(PT)(PT p) { 104 writeln(text("_action ",p)); 105 _assert = true; 106 names ~= p.name; 107 return p; 108 } 109 this() { 110 auto a = parseData!(MyGrammar)(d); 111 writeln("Grammar test " ~ a.toString); 112 assert(_assert); 113 } 114 } 115 auto a = new MyGrammar; 116 117 class MyGrammar2 { 118 enum g=q{ 119 MyGrammar2: 120 test < "test" {myaction} test2 121 test2 <- "test2" identifier 122 }; 123 enum d=`test test2 testId`; 124 mixin(parseGrammar!g); 125 126 static PT myaction(PT)(PT p) { 127 return p; 128 } 129 enum data = parseData!(MyGrammar2,d); 130 enum _dataString = dataString(data); 131 132 static string dataString(ParseTree Data) { 133 string n = ""; 134 switch(Data.name) { 135 case "MyGrammar2": 136 n = "enum __a = \""; 137 n ~= "_MY:"; 138 n ~= dataString(Data.children[0]); 139 n ~= "\";"; 140 break; 141 case "MyGrammar2.test": 142 case "MyGrammar2.test2": 143 n = nodeToString(Data); 144 n ~= Data.children.map!(dataString).join(", ").text; 145 default: 146 break; 147 } 148 return n; 149 } 150 static string nodeToString(N)(N n) { 151 return "\" ~ impl_" ~ n.name ~ "!(\""~ n.name ~ "\") ~ \""; 152 } 153 154 } 155 156 auto b = new MyGrammar2; 157 class impl_MyGrammar2 { 158 static auto test(string n)() { 159 return "TEST"; 160 } 161 static auto test2(string n)() { 162 return "TEST2"; 163 } 164 mixin(MyGrammar2._dataString); 165 } 166 writeln("Grammar2 test " ~ impl_MyGrammar2.__a); 167 168 } 169 170 unittest { 171 import std.array; 172 import std..string; 173 import std.stdio; 174 import std.algorithm; 175 import std.regex; 176 177 enum GRAMMAR = q{ 178 MYGRAMMAR(Template): 179 MyDoc <- MyLine+ :endOfInput 180 MyLine <- :LDelim ^Template :RDelim / Text 181 LDelim <- "{{" 182 RDelim <- "}}" 183 Text <- ~((!LDelim) Char )* 184 Char <- . 185 }; 186 mixin(parseGrammar!GRAMMAR); 187 188 struct range { 189 enum varOne = "varOne"; 190 static string opCall(string i)() { 191 return i; 192 } 193 } 194 195 template compile(string n) 196 { 197 enum compile = "range.opCall!(\"" ~ n ~ "\")()"; 198 } 199 200 static string dataString(alias Data)() { 201 string n = ""; 202 pragma(msg,"Data "~ Data.toString); 203 switch(Data.name) { 204 case "MYGRAMMAR": 205 case "MYGRAMMAR.MyDoc": 206 case "MYGRAMMAR.MyLine": 207 static foreach(x;Data.children) n~=dataString!x(); 208 break; 209 case "MYGRAMMAR.Text": 210 n ~= Data.matches.join(""); 211 break; 212 case "identifier": 213 n ~= compile!(Data.matches.join("")); 214 break; 215 default: 216 break; 217 } 218 return n; 219 } 220 enum d = "enum fred = {{varOne}};"; 221 enum data = parseData!(MYGRAMMAR!identifier,d); 222 pragma(msg,data); 223 enum _dataString = dataString!(data); 224 pragma(msg,_dataString); 225 writeln("Grammar Test: " ~ _dataString); 226 mixin(_dataString); 227 static assert(__traits(compiles,"writeln(fred);")); 228 writeln("" ~ fred); 229 static assert("varOne" == fred); 230 }