OSDN Git Service

\90V\8bK\82É\8dì\90¬\82µ\82½TermLexer\82ð\97\98\97p\82µ\82Ä\93à\95\94\82ð\8fC\90³\82µ\82½\81B
[simplecms/utakata.git] / src / lexer / string_lexer.cpp
1 #include <utility>
2 #include "src/exception_macro.h"
3 #include "src/lexer/string_lexer.h"
4 #include "src/lexer/term_lexer.h"
5 #include "src/lexer/term_checker.h"
6 #include "src/lexeme.h"
7 #include "src/encoding_reader.h"
8 #include "src/unicode.h"
9
10 namespace lexer = utakata::lexer;
11 namespace term = utakata::lexer::term;
12 namespace reader = utakata::reader;
13 namespace unicode = utakata::unicode;
14
15
16 // 宣言のコメントを参照して下さい。
17 bool lexer::EscapeLexer::Lex(reader::EncodingReader* reader,
18                              unsigned int* code) {
19   unicode::UniString escape(reader->Read(kEscapeValidLength));
20   if (escape.IsEmpty() || escape.At(0).rawcode != '\\') {
21     return false;
22   }
23
24   if (escape.GetSize() < kEscapeValidLength) {
25     THROW_EXCEPTION_(lexer::LexException,
26                      unicode::Convert("invalid escape sequence"));
27   }
28
29   lexer::InlineHexEscapeLexer inline_escape;
30
31   if (inline_escape(reader, code)) {
32     return true;
33   }
34
35   reader->Read();
36   lexer::TermLexer<term::IntralineWhiteSpaceChecker> intraline;
37   lexer::TermLexer<term::LineEndingChecker> lineend;
38   if (!CheckEscapeSequence(escape.At(1)) &&
39       !intraline.CheckToken(reader) &&
40       !lineend.CheckToken(reader)) {
41     unicode::UniString encoded_string("invalid escape sequence : ");
42     encoded_string.Append(escape);
43     THROW_EXCEPTION_(lexer::LexException, encoded_string);
44   }
45
46   *code = ConvertEscapeToCode(escape, reader);
47   return true;
48 }
49
50 // \<intraline whitespace>に該当する場合、返却されるcodeは0と
51 // なります。
52 unsigned int lexer::EscapeLexer::ConvertEscapeToCode(
53     const unicode::UniString& escape, reader::EncodingReader* reader) {
54   unsigned int code = 0;
55   lexer::TermLexer<term::IntralineWhiteSpaceChecker> intraline;
56   lexer::TermLexer<term::LineEndingChecker> lineend;
57
58   if (!intraline.CheckToken(reader) && !lineend.CheckToken(reader)) {
59     lexer::EscapeConverter converter;
60     if (converter.CanConvert(escape.At(1).rawcode())) {
61       code = converter.Convert(escape.At(1).rawcode());
62     } else {
63       unicode::UniString encoded_string(
64           unicode::Convert("invalid escape sequence : "));
65       encoded_string.Append(escape);
66       THROW_EXCEPTION_(lexer::LexException, encoded_string);
67     }
68   } else {
69     // 1文字だけReadしているのは、すでに\に該当する部分がReadされており、
70     // escapeとして渡されている文字列以降をチェックするために、
71     // escape分を読捨てるためです。
72     reader->Read();
73     while (intraline.CheckToken(reader) && !reader->IsEof()) {
74       intraline.ReadToken(reader);
75     }
76
77     if (!lineend.CheckToken(reader)) {
78       unicode::UniString encoded_string;
79       THROW_EXCEPTION_(lexer::LexException,
80                        unicode::Convert("must line ending after whitespaces"));
81     }
82     lineend.ReadToken(reader);
83
84     while (intraline.CheckToken(reader) && !reader->IsEof()) {
85       intraline.ReadToken(reader);
86     }
87   }
88
89   return code;
90 }
91
92 // 宣言のコメントを参照して下さい。
93 bool lexer::EscapeConverter::CanConvert(unsigned int code) {
94   switch (code) {
95     case 'a'  :
96     case 'b'  :
97     case 't'  :
98     case 'n'  :
99     case 'v'  :
100     case 'f'  :
101     case 'r'  :
102     case '"'  :
103     case '\\' :
104       return true;
105     default:
106       return false;
107   }
108 }
109
110 // 宣言のコメントを参照してください。
111 unsigned int lexer::EscapeConverter::Convert(unsigned int code) {
112   switch (code) {
113     case 'a'  : return kAlarm;
114     case 'b'  : return kBackspace;
115     case 't'  : return kTab;
116     case 'n'  : return kLinefeed;
117     case 'v'  : return kVTab;
118     case 'f'  : return kForward;
119     case 'r'  : return kCaridgeReturn;
120     case '"'  : return kDoubleQuote;
121     case '\\' : return kBackslash;
122     default: return 0;
123   }
124 }
125
126 // 文字列の終了地点は、同一行の`"`か、\\を含む複数行後の対応する`"`となります。
127 // 対応する`"`が存在しないままreaderの末尾に到達すると、LexExceptionが
128 // 送出されます。
129 // また、\から行末まで空白文字のみが続き、次の行の最初の文字までが、改行か
130 // 空白のみである場合、その間の空白及び改行は無視され、文字列は継続している
131 // とみなされます。
132 lexer::Lexeme* lexer::StringLexer::Lex(reader::EncodingReader* reader) {
133   term::StringDelimiterChecker string_delimiter;
134   {
135     unicode::UniChar head(reader->Read());
136     if (!string_delimiter(head)) {
137       return NULL;
138     }
139   }
140
141   term::StarndardDelimiterChecker std_delimiter;
142   term::WhitespaceChecker white_delimiter;
143   term::LineEndingChecker lineending_checker;
144
145   unicode::UniString str;
146   bool syntax_ok = false;
147
148   while (!reader->IsEof() && !syntax_ok) {
149     unicode::UniChar tmp(reader->Peek());
150
151     if (string_delimiter(tmp)) {
152       reader->Read();
153       syntax_ok = true;
154       break;
155     }
156
157     if (lineending_checker(tmp)) {
158       while (!reader->IsEof() && (white_delimiter(tmp) || std_delimiter(tmp))) {
159         reader->Read();
160       }
161     } else {
162       str.Append(unicode::UniChar(reader->Read()));
163     }
164   }
165
166   if (!syntax_ok) {
167     THROW_EXCEPTION_(lexer::LexException,
168                      unicode::Convert("not found end of string."));
169   }
170
171   return new lexer::Lexeme(str, lexer::Lexeme::kString);
172 }