-
Notifications
You must be signed in to change notification settings - Fork 0
/
code_feed.hpp
177 lines (130 loc) · 3.4 KB
/
code_feed.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include <utility>
#ifndef YS2_CODE_FEED_HPP
#define YS2_CODE_FEED_HPP
#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
// basically a string wrappper
class CodeFeed {
public:
static bool enable_token_trace;
std::string body;
// which char are we on
unsigned long long int offset : 63;
// if we need more lines can we read from stdin?
bool isStdin : 1;
//std::string file_name;
CodeFeed(bool fromStdin=false):
offset(0), isStdin(fromStdin) { }
CodeFeed(const std::string& b):
offset(0), isStdin(false), body(std::move(b)) { }
/// add a new line to the string
bool getLine(const char* prompt = ". ") {
if (!isStdin)
return false;
std::string line;
std::cout <<prompt;
if (!std::getline(std::cin, line)) // ^D
return false;
//std::cout <<"ADDED: \'" <<line <<"'\n";
body += '\n';
body += line;
//std::cout <<"BODY: \'" <<body <<"'\n";
return true;
}
void reset() {
body = "";
offset = 0;
tok = "";
}
void loadFile(const char* fname) {
std::ifstream t(fname);
std::stringstream buffer;
buffer <<" " <<t.rdbuf() <<"\n";
body = buffer.str();
}
size_t lineNumber(size_t c){
size_t line = 0;
for (size_t i = 0; i < c; i++)
if (body.at(i) == '\n')
line++;
return line;
}
size_t lineNumber(){
return lineNumber(offset);
}
std::string findLine(const size_t lineNum) {
int line = 0;
size_t start = 0;
for (; start + 1 < body.length() && line < lineNum; start++)
if (body.at(start) == '\n')
line++;
// invalid line number
if (line != lineNum)
return "";
size_t end = start;
while (end + 1< body.length()) {
end++;
if (body.at(end) == '\n')
break;
}
//std::cout <<"start: " <<start <<" end: " <<end <<std::endl;
return body.substr(start, 1 + end - start);
}
std::string tok;
std::string fromOffset() {
return body.substr(offset, body.length());
}
// sets this->tok = next token
// ie - `1 2 +` --> "1" "2" "+"
// ie - `stack:size` --> "stack" ":size"
bool setTok() {
//std::cout <<"stok::body[offset]: \'" <<fromOffset() <<"\'\n";
// skip preceding space
while (offset + 1 <= body.length() && isspace(body.at(offset)))
offset++;
//std::cout <<"stok::body[offset]: \'" <<fromOffset() <<"\'\n";
if (offset >= body.length())
return false;
size_t i = offset;
char c;
do {
c = body.at(i);
//std::cout <<i - offset << "-" << c <<"\n";
i++;
} while (i < body.length() && !isspace(c));
//
if (i > body.length())
return false;
// trim end
if (isspace(body[i - 1]))
i--;
tok = _fix_accessors(body.substr(offset, i - offset));
if (enable_token_trace)
std::cout <<"parseing token: `" <<tok <<"`\n";
return true;
}
// some people are lazy and like to say $a.b.c or $c:b:a instead of $a .b .c
inline static std::string _fix_accessors(std::string&& s) {
const size_t len = s.length();
// empty string oof
if (len <= 1)
return s;
// dont split numbers (`.123` would get treated correctly tho)
if (s[0] == '-' || isdigit(s[0]))
return s;
// chained requests $x `:a:b:c`
size_t i = (s.at(0) == ':') || (s.at(0) == '.') ? 1 : 0;
// find start of next req `:a`
while (i + 1 < len && s.at(i) != ':' && s.at(i) != '.')
i++;
// if str is different then we return new substr
if (i < len && (s.at(i) == ':' || s.at(i) == '.'))
return s.substr(0, i);
else
return s;
}
};
#endif //YS2_CODE_FEED_HPP