2 #include "Tokenizer.hpp"
3 #include "TokenStreamReader.hpp"
10 #include <glm/gtc/quaternion.hpp>
17 ostream &operator <<(ostream &out, Token::Type t) {
19 case Token::ANGLE_BRACKET_OPEN:
20 return out << "ANGLE_BRACKET_OPEN";
21 case Token::ANGLE_BRACKET_CLOSE:
22 return out << "ANGLE_BRACKET_CLOSE";
23 case Token::CHEVRON_OPEN:
24 return out << "CHEVRON_OPEN";
25 case Token::CHEVRON_CLOSE:
26 return out << "CHEVRON_CLOSE";
27 case Token::BRACKET_OPEN:
28 return out << "BRACKET_OPEN";
29 case Token::BRACKET_CLOSE:
30 return out << "BRACKET_CLOSE";
31 case Token::PARENTHESIS_OPEN:
32 return out << "PARENTHESIS_OPEN";
33 case Token::PARENTHESIS_CLOSE:
34 return out << "PARENTHESIS_CLOSE";
36 return out << "COLON";
37 case Token::SEMICOLON:
38 return out << "SEMICOLON";
40 return out << "COMMA";
42 return out << "EQUALS";
44 return out << "NUMBER";
46 return out << "STRING";
47 case Token::IDENTIFIER:
48 return out << "IDENTIFIER";
50 return out << "COMMENT";
52 return out << "UNKNOWN";
56 ostream &operator <<(ostream &out, const Token &t) {
62 case Token::IDENTIFIER:
64 return out << '(' << t.value << ')';
70 Tokenizer::Tokenizer(istream &in)
77 bool Tokenizer::HasMore() {
78 return bool(istream::sentry(in));
81 const Token &Tokenizer::Next() {
86 void Tokenizer::ReadToken() {
87 current.type = Token::UNKNOWN;
88 current.value.clear();
90 istream::sentry s(in);
92 throw runtime_error("read past the end of stream");
105 current.type = Token::Type(c);
107 case '+': case '-': case '.':
108 case '0': case '1': case '2': case '3': case '4':
109 case '5': case '6': case '7': case '8': case '9':
130 bool is_num_char(istream::char_type c) {
140 void Tokenizer::ReadNumber() {
141 current.type = Token::NUMBER;
142 istream::char_type c;
144 if (is_num_char(c)) {
153 void Tokenizer::ReadString() {
154 current.type = Token::STRING;
157 istream::char_type c;
163 current.value += '\n';
166 current.value += '\t';
169 current.value += '\t';
175 } else if (c == '"') {
177 } else if (c == '\\') {
185 void Tokenizer::ReadComment() {
186 current.type = Token::COMMENT;
187 istream::char_type c;
191 while (in.get(c) && c != '\n') {
197 // c is guaranteed to be '/' now
199 throw runtime_error("unexpected end of stream");
202 while (in.get(c) && c != '\n') {
206 } else if (c != '*') {
207 throw runtime_error("invalid character after /");
212 istream::char_type c2;
214 throw runtime_error("unexpected end of stream");
228 void Tokenizer::ReadIdentifier() {
229 current.type = Token::IDENTIFIER;
231 istream::char_type c;
233 if (isalnum(c) || c == '_' || c == '.') {
243 TokenStreamReader::TokenStreamReader(istream &in)
250 bool TokenStreamReader::HasMore() {
258 const Token &TokenStreamReader::Next() {
264 void TokenStreamReader::SkipComments() {
266 if (in.Current().type == Token::COMMENT) {
272 while (in.HasMore()) {
273 if (in.Next().type != Token::COMMENT) {
280 const Token &TokenStreamReader::Peek() {
289 void TokenStreamReader::Assert(Token::Type t) {
290 if (GetType() != t) {
292 s << "unexpected token in input stream: expected " << t << ", but got " << in.Current();
293 throw runtime_error(s.str());
297 Token::Type TokenStreamReader::GetType() const noexcept {
298 return in.Current().type;
301 const std::string &TokenStreamReader::GetValue() const noexcept {
302 return in.Current().value;
305 void TokenStreamReader::Skip(Token::Type t) {
311 void TokenStreamReader::ReadBoolean(bool &b) {
315 void TokenStreamReader::ReadIdentifier(string &out) {
317 Assert(Token::IDENTIFIER);
321 void TokenStreamReader::ReadNumber(float &n) {
325 void TokenStreamReader::ReadNumber(int &n) {
329 void TokenStreamReader::ReadNumber(unsigned long &n) {
333 void TokenStreamReader::ReadString(string &out) {
335 Assert(Token::STRING);
340 void TokenStreamReader::ReadVec(glm::vec2 &v) {
341 Skip(Token::BRACKET_OPEN);
345 Skip(Token::BRACKET_CLOSE);
348 void TokenStreamReader::ReadVec(glm::vec3 &v) {
349 Skip(Token::BRACKET_OPEN);
355 Skip(Token::BRACKET_CLOSE);
358 void TokenStreamReader::ReadVec(glm::vec4 &v) {
359 Skip(Token::BRACKET_OPEN);
367 Skip(Token::BRACKET_CLOSE);
370 void TokenStreamReader::ReadVec(glm::ivec2 &v) {
371 Skip(Token::BRACKET_OPEN);
375 Skip(Token::BRACKET_CLOSE);
378 void TokenStreamReader::ReadVec(glm::ivec3 &v) {
379 Skip(Token::BRACKET_OPEN);
385 Skip(Token::BRACKET_CLOSE);
388 void TokenStreamReader::ReadVec(glm::ivec4 &v) {
389 Skip(Token::BRACKET_OPEN);
397 Skip(Token::BRACKET_CLOSE);
400 void TokenStreamReader::ReadQuat(glm::quat &q) {
401 Skip(Token::BRACKET_OPEN);
409 Skip(Token::BRACKET_CLOSE);
413 bool TokenStreamReader::GetBool() {
417 return GetInt() != 0;
418 case Token::IDENTIFIER:
420 if (GetValue() == "true" || GetValue() == "yes" || GetValue() == "on") {
422 } else if (GetValue() == "false" || GetValue() == "no" || GetValue() == "off") {
425 throw runtime_error("unexpected value in input stream: cannot cast " + GetValue() + " to bool");
430 s << "unexpected token in input stream: cannot cast " << in.Current() << " to bool";
431 throw runtime_error(s.str());
436 float TokenStreamReader::GetFloat() {
438 Assert(Token::NUMBER);
439 return stof(GetValue());
442 int TokenStreamReader::GetInt() {
444 Assert(Token::NUMBER);
445 return stoi(GetValue());
448 unsigned long TokenStreamReader::GetULong() {
450 Assert(Token::NUMBER);
451 return stoul(GetValue());