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 }