1 /** 2 * Stream of symbols from file 3 * 4 * Copyright: © 2017 Andrey Kabylin 5 * License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 */ 7 8 module rpdl.stream; 9 10 import std.stdio; 11 import std.file; 12 import core.stdc.stdio; 13 14 /// Represents stream of symbols - stream produces one symbol by request 15 class SymbolStream { 16 /// Get next symbol in stream 17 char read() { 18 readChar(); 19 20 if (p_lastChar == ' ' && tabSize == 0 && needCalcTabSize && needCalcIndent) 21 return calcTabSize(); 22 23 if (p_lastChar == ' ' && tabSize > 0 && needCalcIndent) 24 return calcIndent(); 25 26 if (p_lastChar == '\r' || p_lastChar == '\n') { 27 needCalcIndent = true; 28 29 p_indent = 0; 30 ++p_line; 31 32 return p_lastChar; 33 } 34 35 needCalcIndent = false; 36 return p_lastChar; 37 } 38 39 this(in string fileName) { 40 assert(fileName.isFile); 41 this.file = File(fileName); 42 } 43 44 ~this() { 45 file.close(); 46 } 47 48 /// Current line in file 49 @property int line() { return p_line; } 50 51 /// Current position in line in file 52 @property int pos() { return p_pos; } 53 54 /// Current indent - count of tabs relative to the start of the line 55 @property int indent() { return p_indent; } 56 57 /// Size of one tab - count of spaces for one indent 58 @property int tabSize() { return p_tabSize; } 59 60 /// If true then stream ended 61 @property bool eof() { return file.eof; } 62 63 /// The last given symbol 64 @property char lastChar() { return p_lastChar; } 65 66 protected: 67 this() { 68 } 69 70 /// Read one symbol from file and store it to `lastChar` 71 char readChar() { 72 char[1] buf; 73 file.rawRead!char(buf); 74 ++p_pos; 75 76 if (file.eof) p_lastChar = char.init; 77 else p_lastChar = buf[0]; 78 79 return p_lastChar; 80 } 81 82 private: 83 File file; 84 85 int p_line, p_pos; 86 char p_lastChar; 87 int p_indent = 0; 88 int p_tabSize = 0; 89 90 bool needCalcTabSize = true; 91 bool needCalcIndent = true; 92 93 /** 94 * Calculate indentation in current line - 95 * count of tabs relative to the start of the line 96 */ 97 char calcIndent() { 98 uint spaces = 0; 99 100 while (p_lastChar == ' ') { 101 ++spaces; 102 readChar(); 103 104 if (spaces == p_tabSize) { 105 ++p_indent; 106 spaces = 0; 107 } 108 } 109 110 return p_lastChar; 111 } 112 113 /// Calculate size of one tab - count of spaces for one indent 114 char calcTabSize() { 115 while (p_lastChar == ' ') { 116 ++p_tabSize; 117 readChar(); 118 } 119 120 ++p_indent; 121 needCalcTabSize = false; 122 123 return p_lastChar; 124 } 125 }