1 module RuleTokenTest; 2 3 import RuleTranslatorLexer; 4 import RuleTranslatorParser: RuleTranslatorParser; 5 import RuleTranslatorBaseListener; 6 import antlr.v4.runtime.ANTLRInputStream; 7 import antlr.v4.runtime.CommonToken; 8 import antlr.v4.runtime.CommonTokenFactory; 9 import antlr.v4.runtime.TokenFactory; 10 import antlr.v4.runtime.CommonTokenStream; 11 import antlr.v4.runtime.TokenStream; 12 import antlr.v4.runtime.tree.TerminalNode; 13 import antlr.v4.runtime.CharStream; 14 import antlr.v4.runtime.LexerNoViableAltException; 15 import antlr.v4.runtime.Token; 16 import antlr.v4.runtime.TokenSource; 17 import antlr.v4.runtime.TokenStreamRewriter : TokenStreamRewriter; 18 import antlr.v4.runtime.atn.ParserATNSimulator; 19 import antlr.v4.runtime.tree.ParseTreeWalker; 20 import dshould : be, equal, not, should; 21 import dshould.thrown; 22 import std.conv : to; 23 import std.stdio : File, writefln; 24 import std.file; 25 import unit_threaded; 26 import std.typecons; 27 import std.variant; 28 29 class ResultTokenFactory : CommonTokenFactory { 30 31 this(CharStream input) { 32 } 33 34 override 35 ResultToken create(int type, Variant text) { 36 return new ResultToken(type, text); 37 } 38 39 override 40 ResultToken create(TokenFactorySourcePair source, int type, 41 Variant text, int channel, int start, int stop, 42 int line, int charPositionInLine ) { 43 auto t = new ResultToken(source, type, channel, 44 start, stop); 45 t.setLine(line); 46 t.setCharPositionInLine(charPositionInLine); 47 return t; 48 } 49 } 50 51 /** 52 * A Token source with Result as additional attribute 53 */ 54 55 alias TokenFactorySourcePair = Tuple!(TokenSource, "a", CharStream, "b"); 56 57 struct Result { ushort indent; string text;} 58 59 ushort indent; 60 61 class ResultToken : CommonToken { 62 63 public Result[] res; 64 65 this (int type, Variant text) { 66 super(type, text); 67 } 68 69 this( TokenFactorySourcePair source, int type, 70 int channel, int start, int stop) { 71 super(source, type, channel, start, stop); 72 Result r; 73 r.text = super.getText.to!string; 74 res ~= r; 75 } 76 77 override string toString() { 78 import std.format : format; 79 return format("%s", res); 80 } 81 82 override Variant getText() { 83 debug(TokenStreamRewriter) { 84 import std.stdio; 85 writefln("\ngetText: res = %s, type = %s", res, type); 86 } 87 Variant r = res; 88 return r; 89 } 90 } 91 92 public class ResultListener : RuleTranslatorBaseListener { 93 94 private TokenStreamRewriter rewriter; 95 96 private bool nextOfNewline = false; 97 98 ushort indentText = 0; 99 100 this(TokenStream tokens) 101 { 102 rewriter = new TokenStreamRewriter(tokens); 103 } 104 /** 105 * <p>The default implementation does nothing.</p> 106 */ 107 override public void enterFile_input(RuleTranslatorParser.File_inputContext ctx) { 108 } 109 110 /** 111 * {@inheritDoc} 112 * 113 * <p>The default implementation does nothing.</p> 114 */ 115 override public void exitStmt(RuleTranslatorParser.StmtContext ctx) { 116 debug(TokenStreamRewriter) { 117 import std.stdio : writefln; 118 writefln("exitStmt ctx.start = %s, ctx.stop = %s", ctx.start, ctx.stop); 119 } 120 } 121 122 /** 123 * {@inheritDoc} 124 * 125 * <p>The default implementation does nothing.</p> 126 */ 127 override public void visitTerminal(TerminalNode node) { 128 debug (TokenStreamRewriter) { 129 writefln("\nvisitTerminal -> \"%s\", node.symbol -> %s, indentText = %s", 130 node.getText, 131 node.getSymbol, 132 indentText 133 ); 134 } 135 switch (node.getSymbol.getType) { 136 137 case RuleTranslatorParser.INDENT: 138 indentText++; 139 break; 140 case RuleTranslatorParser.DEDENT: 141 indentText--; 142 break; 143 case RuleTranslatorParser.NEWLINE: 144 nextOfNewline = true; 145 import std.array : join; 146 Result r; 147 r.indent = indentText; 148 break; 149 case RuleTranslatorParser.EOF: 150 debug(TokenStreamRewriter) { 151 import std.stdio : writeln; 152 writeln("\n+++ EOF +++"); 153 } 154 break; 155 default: 156 debug(TokenStreamRewriter) 157 writefln("\ndefault: node.getText.type = %s", node.getText.type); 158 if (nextOfNewline) { 159 auto r = node.getText.get!(Result[]); 160 r[0].indent = indentText; 161 } 162 nextOfNewline = false; 163 break; 164 } 165 } 166 167 } 168 169 @Tags("CustomerToken", "tt") 170 @("using result struct") 171 unittest { 172 173 auto expected = 174 `rule Delay as DELAY de 175 base de . Phrases 176 if a : 177 "Information" "zu" 178 "Zug" ZugNr "nach" "Berlin" 179 `; 180 auto antlrInput = new ANTLRInputStream(File("unittest/complex/rule.rul", "r")); 181 auto lexer = new RuleTranslatorLexer(antlrInput); 182 auto factory = new ResultTokenFactory(antlrInput); 183 lexer.tokenFactory(factory); 184 auto ln = lexer.getGrammarFileName; 185 auto cts = new CommonTokenStream(lexer); 186 cts.fill; 187 auto parser = new RuleTranslatorParser(cts); 188 parser.tokenFactory(factory); 189 // Specify entry point 190 auto rootContext = parser.file_input; 191 parser.numberOfSyntaxErrors.should.be.equal(0); 192 auto extractor = new ResultListener(cts); 193 auto walker = new ParseTreeWalker; 194 walker.walk(extractor, rootContext); 195 auto r = extractor.rewriter.getText.get!(Result[]); 196 197 import std.array : appender; 198 auto buf = appender!(string); 199 auto nextOfNewline = false; 200 201 foreach (i, s ; r) { 202 auto t = cts.get(to!int(i)); 203 if (t.getType == RuleTranslatorParser.NEWLINE) { 204 if (i) 205 buf.put("\n"); 206 nextOfNewline = true; 207 continue; 208 } 209 else if (t.getType == RuleTranslatorParser.INDENT || 210 t.getType == RuleTranslatorParser.DEDENT) { 211 continue; 212 } 213 else { 214 if (nextOfNewline) { 215 while (s.indent--) 216 buf.put(" "); 217 buf.put(s.text); 218 } 219 else 220 buf.put(" " ~ s.text); 221 nextOfNewline = false; 222 } 223 } 224 buf.data.should.equal(expected); 225 }