1 module tcenal.parser_combinator.report_parsing; 2 3 import compile_time_unittest : enableCompileTimeUnittest; 4 import tcenal.parser_combinator.memo : Memo, MemoEntry; 5 6 import std.stdio : writeln; 7 import std.algorithm : sort, splitter, until; 8 import std.typecons : Tuple; 9 import std.range : repeat, retro; 10 import std.conv : to; 11 import std.array : array; 12 13 mixin enableCompileTimeUnittest; 14 15 16 void reportParsing(string input, Memo memo) 17 { 18 size_t[] positions = memo.keys; 19 positions.sort(); 20 21 foreach (position; positions) 22 { 23 with (calcLineLineNumColumnNum(input, position)) 24 { 25 writeln('='.repeat(32)); 26 writeln(lineNum, ": ", line); 27 writeln(' '.repeat(lineNum.to!string().length + 2 + columnNum), "^"); 28 } 29 30 string[] ruleNames = memo[position].keys; 31 ruleNames.sort(); 32 33 foreach (ruleName; ruleNames) 34 { 35 MemoEntry memoEntry = memo[position][ruleName]; 36 37 if (memoEntry.parsingResult.success) 38 { 39 writeln(memoEntry.parsingResult.node.toAsciiTree()); 40 } 41 else 42 { 43 writeln("+-", ruleName.retro().until('.').array().retro(), ": fail"); 44 } 45 } 46 } 47 } 48 49 50 Tuple!(string, "line", size_t, "lineNum", size_t, "columnNum") calcLineLineNumColumnNum(string input, size_t position) 51 in 52 { 53 assert (position <= input.length); 54 } 55 body 56 { 57 size_t lineNum = 1; 58 size_t totalLength; 59 60 foreach (line; input.splitter('\n')) 61 { 62 if (position < totalLength + line.length + 1) 63 { 64 return typeof(return)(line, lineNum, position - totalLength); 65 } 66 67 totalLength += line.length + 1; 68 ++lineNum; 69 } 70 71 return typeof(return)(); 72 } 73 unittest 74 { 75 with (calcLineLineNumColumnNum("foo\nbar\nfoobar", 1)) 76 { 77 assert (line == "foo"); 78 assert (lineNum == 1); 79 assert (columnNum == 1); 80 } 81 82 with (calcLineLineNumColumnNum("foo\nbar\nfoobar", 3)) 83 { 84 assert (line == "foo"); 85 assert (lineNum == 1); 86 assert (columnNum == 3); 87 } 88 89 with (calcLineLineNumColumnNum("foo\nbar\nfoobar", 5)) 90 { 91 assert (line == "bar"); 92 assert (lineNum == 2); 93 assert (columnNum == 1); 94 } 95 }