OSDN Git Service

delimiter.h/cppを、term_lexer、term_checkerとしてテンプレートを利用するように分離した。
[simplecms/utakata.git] / src / lexer / string_lexer.cpp
1 #include "src/exception_macro.h"
2 #include "src/lexer/string_lexer.h"
3 #include "src/lexer/term_lexer.h"
4 #include "src/lexer/term_checker.h"
5 #include "src/lexeme.h"
6 #include "src/encoding_reader.h"
7 #include "src/unicode.h"
8
9 namespace lexer = utakata::lexer;
10 namespace term = utakata::lexer::term;
11 namespace reader = utakata::reader;
12 namespace unicode = utakata::unicode;
13
14 // 宣言のコメントを参照して下さい。
15 bool lexer::EscapeLexer::Lex(reader::EncodingReader* reader,
16                              unsigned int* code) {
17   unicode::UniString escape(reader->Read(kEscapeValidLength));
18   if (escape.IsEmpty() || escape.At(0).rawcode != '\\') {
19     return false;
20   }
21
22   if (escape.GetSize() < kEscapeValidLength) {
23     THROW_EXCEPTION_(lexer::LexException,
24                      unicode::Convert("invalid escape seacense"));
25   }
26
27   term::IntralineWhiteSpaceChecker intraline;
28   term::LineEndingChecker lineend;
29   if (!CheckEscapeSeacense(escape.At(1)) && !intraline(escape.At(1)) &&
30       !lineend(escape.At(1))) {
31     unicode::UniString encoded_string("invalid escape seacense : ");
32     encoded_string.Append(escape);
33     THROW_EXCEPTION_(lexer::LexException, encoded_string);
34   }
35
36   if (!intraline(escape.At(1)) && !lineend(escape.At(1))) {
37     *code = ConvertEscapeToCode(escape);
38   } else {
39     reader->Read(kEscapeValidLength);
40     unicode::UniChar checker(escape.At(1));
41     while (intraline(checker) && !reader->IsEof()) {
42       checker = unicode::UniChar(reader->Read());
43     }
44
45     if (!lineend(checker)) {
46       unicode::UniString encoded_string;
47       THROW_EXCEPTION_(lexer::LexException,
48                        unicode::Convert("must line ending after whitespaces"));
49     }
50
51     while (intraline(checker) && !reader->IsEof()) {
52       reader->Read();
53       checker = unicode::UniChar(reader->Peek());
54     }
55     *code = 0;
56   }
57
58   return true;
59 }
60
61 // 文字列の終了地点は、同一行の`"`か、\\を含む複数行後の対応する`"`となります。
62 // 対応する`"`が存在しないままreaderの末尾に到達すると、LexExceptionが
63 // 送出されます。
64 // また、\から行末まで空白文字のみが続き、次の行の最初の文字までが、改行か
65 // 空白のみである場合、その間の空白及び改行は無視され、文字列は継続している
66 // とみなされます。
67 lexer::Lexeme* lexer::StringLexer::Lex(reader::EncodingReader* reader) {
68   term::StringDelimiterChecker string_delimiter;
69   {
70     unicode::UniChar head(reader->Read());
71     if (!string_delimiter(head)) {
72       return NULL;
73     }
74   }
75
76   term::StarndardDelimiterChecker std_delimiter;
77   term::WhitespaceChecker white_delimiter;
78   term::LineEndingChecker lineending_checker;
79
80   unicode::UniString str;
81   bool syntax_ok = false;
82
83   while (!reader->IsEof() && !syntax_ok) {
84     unicode::UniChar tmp(reader->Peek());
85
86     if (string_delimiter(tmp)) {
87       reader->Read();
88       syntax_ok = true;
89       break;
90     }
91
92     if (lineending_checker(tmp)) {
93       while (!reader->IsEof() && (white_delimiter(tmp) || std_delimiter(tmp))) {
94         reader->Read();
95       }
96     } else {
97       str.Append(unicode::UniChar(reader->Read()));
98     }
99   }
100
101   if (!syntax_ok) {
102     THROW_EXCEPTION_(lexer::LexException,
103                      unicode::Convert("not found end of string."));
104   }
105
106   return new lexer::Lexeme(str, lexer::Lexeme::kString);
107 }