Line | Branch | Exec | Source |
---|---|---|---|
1 | #pragma once | ||
2 | |||
3 | #include <string> | ||
4 | |||
5 | #include "dependencies/coz_wrap.h" | ||
6 | #include "dependencies/fmt.h" | ||
7 | |||
8 | #include "dtypes.h" | ||
9 | #include "logging/exceptions.h" | ||
10 | |||
11 | /* | ||
12 | * Buffers are special reader that keep track of current line/col and indent level | ||
13 | * they only need getc() to be defined to work properly | ||
14 | * | ||
15 | * StringBuffer is made to make debugging easy (might be useful for | ||
16 | * the eval option and macro gen) | ||
17 | * | ||
18 | * FileBuffer is the usual reader | ||
19 | */ | ||
20 | namespace lython { | ||
21 | class AbstractBuffer { | ||
22 | public: | ||
23 | virtual char getc() = 0; | ||
24 | virtual const String& file_name() = 0; | ||
25 | |||
26 | AbstractBuffer() {} | ||
27 | |||
28 | virtual ~AbstractBuffer(); | ||
29 | |||
30 | void init() { _next_char = getc(); } | ||
31 | |||
32 | // TODO: add a hash digest compute | ||
33 | // so we can hash files with little overhead | ||
34 | void consume() { | ||
35 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27352 times.
|
27352 | if (_next_char == EOF) |
36 | ✗ | return; | |
37 | |||
38 | 27352 | _col += 1; | |
39 | |||
40 |
2/2✓ Branch 0 taken 1218 times.
✓ Branch 1 taken 26134 times.
|
27352 | if (_next_char == '\n') { |
41 | 1218 | _line += 1; | |
42 | 1218 | _col = 0; | |
43 | |||
44 | 1218 | _indent = 0; | |
45 | 1218 | _empty_line = true; | |
46 | 1218 | _next_char = getc(); | |
47 | 1218 | return; | |
48 | } | ||
49 | |||
50 |
2/2✓ Branch 0 taken 7634 times.
✓ Branch 1 taken 18500 times.
|
26134 | if (_next_char == ' ') { |
51 |
2/2✓ Branch 0 taken 2966 times.
✓ Branch 1 taken 4668 times.
|
7634 | if (_empty_line) |
52 | 2966 | _indent += 1; | |
53 | 7634 | _next_char = getc(); | |
54 | 7634 | return; | |
55 | } | ||
56 | |||
57 | 18500 | _empty_line = false; | |
58 | 18500 | _next_char = getc(); | |
59 | } | ||
60 | |||
61 | // Used to fetch a given line for error reporting | ||
62 | virtual String getline(int start_line, int end_line = -1) { return ""; } | ||
63 | |||
64 | char peek() { return _next_char; } | ||
65 | int32 line() { return _line; } | ||
66 | int32 col() { return _col; } | ||
67 | int32 indent() { return _indent; } | ||
68 | bool empty_line() { return _empty_line; } | ||
69 | |||
70 | virtual void reset() { | ||
71 | ✗ | _next_char = ' '; | |
72 | ✗ | _line = 1; | |
73 | ✗ | _col = 0; | |
74 | ✗ | _indent = 0; | |
75 | ✗ | _empty_line = true; | |
76 | ✗ | init(); | |
77 | ✗ | } | |
78 | |||
79 | private: | ||
80 | char _next_char{' '}; | ||
81 | int32 _line = 1; | ||
82 | int32 _col = 0; | ||
83 | int32 _indent{0}; | ||
84 | bool _empty_line{true}; | ||
85 | }; | ||
86 | |||
87 | class FileError: public Exception { | ||
88 | public: | ||
89 | template <typename... Args> | ||
90 | FileError(FmtStr fmt, const Args&... args): Exception(fmt, "FileError", args...) {} | ||
91 | }; | ||
92 | |||
93 | String read_file(String const& name); | ||
94 | |||
95 | class FileBuffer: public AbstractBuffer { | ||
96 | public: | ||
97 | FileBuffer(String const& name); | ||
98 | |||
99 | ~FileBuffer() override; | ||
100 | |||
101 | char getc() override { | ||
102 | COZ_BEGIN("T::FileBuffer::getc"); | ||
103 | |||
104 | 515 | char c = char(::getc(_file)); | |
105 | |||
106 | COZ_PROGRESS_NAMED("FileBuffer::getc"); | ||
107 | COZ_END("T::FileBuffer::getc"); | ||
108 | 515 | return c; | |
109 | } | ||
110 | |||
111 | const String& file_name() override { return _file_name; } | ||
112 | |||
113 | void reset() override; | ||
114 | |||
115 | String getline(int start_line, int end_line = -1) override; | ||
116 | |||
117 | private: | ||
118 | String _file_name; | ||
119 | FILE* _file{nullptr}; | ||
120 | }; | ||
121 | |||
122 | class StringBuffer: public AbstractBuffer { | ||
123 | public: | ||
124 | StringBuffer(String code, String const& file = "c++ string"): | ||
125 | _code(std::move(code)), _file_name(file) { | ||
126 | init(); | ||
127 | } | ||
128 | |||
129 | char getc() override { | ||
130 |
2/2✓ Branch 1 taken 858 times.
✓ Branch 2 taken 26843 times.
|
27701 | if (_pos >= _code.size()) |
131 | 858 | return EOF; | |
132 | |||
133 | 26843 | _pos += 1; | |
134 | 26843 | return _code[_pos - 1]; | |
135 | } | ||
136 | |||
137 | ~StringBuffer() override; | ||
138 | |||
139 | const String& file_name() override { return _file_name; } | ||
140 | |||
141 | private: | ||
142 | uint32 _pos{0}; | ||
143 | String _code; | ||
144 | const String _file_name; | ||
145 | |||
146 | public: | ||
147 | void reset() override { | ||
148 | ✗ | _pos = 0; | |
149 | ✗ | AbstractBuffer::reset(); | |
150 | ✗ | } | |
151 | |||
152 | String getline(int start_line, int end_line = -1) override { | ||
153 | ✗ | uint32 old_pos = _pos; | |
154 | //-- | ||
155 | |||
156 | ✗ | String result; | |
157 | ✗ | result.reserve(128); | |
158 | ✗ | _pos = start_line; | |
159 | |||
160 | ✗ | char c = getc(); | |
161 | |||
162 | ✗ | while (c != '\n') { | |
163 | ✗ | result.push_back(c); | |
164 | ✗ | c = getc(); | |
165 | } | ||
166 | |||
167 | // -- | ||
168 | ✗ | _pos = old_pos; | |
169 | ✗ | return result; | |
170 | ✗ | } | |
171 | |||
172 | // helper for testing | ||
173 | void read_all() { | ||
174 | char c; | ||
175 | do { | ||
176 | c = peek(); | ||
177 | consume(); | ||
178 | } while (c); | ||
179 | } | ||
180 | |||
181 | void load_code(const std::string& code) { | ||
182 | _code = code; | ||
183 | _pos = 0; | ||
184 | } | ||
185 | }; | ||
186 | |||
187 | // Quick solution but not satisfactory | ||
188 | class ConsoleBuffer: public AbstractBuffer { | ||
189 | public: | ||
190 | ConsoleBuffer(): _file_name("console") { init(); } | ||
191 | |||
192 | char getc() override { return char(std::getchar()); } | ||
193 | |||
194 | const String& file_name() override { return _file_name; } | ||
195 | |||
196 | ~ConsoleBuffer() override; | ||
197 | |||
198 | private: | ||
199 | const String _file_name; | ||
200 | }; | ||
201 | |||
202 | } // namespace lython | ||
203 |