2 #include "lib/smart_ptr.h"
3 #include "src/exception_macro.h"
4 #include "src/lexer/string_lexer.h"
5 #include "src/lexer/term_lexer.h"
6 #include "src/lexer/term_checker.h"
7 #include "src/lexer/inline_hex_escape_lexer.h"
8 #include "src/lexer/token.h"
9 #include "src/encoding_reader.h"
10 #include "src/unicode.h"
12 namespace lexer = utakata::lexer;
13 namespace term = utakata::lexer::term;
14 namespace reader = utakata::reader;
15 namespace unicode = utakata::unicode;
18 unsigned int lexer::EscapeConverter::Convert(unsigned int code) {
20 case 'a' : return kAlarm;
21 case 'b' : return kBackspace;
22 case 't' : return kTab;
23 case 'n' : return kLinefeed;
24 case 'v' : return kVTab;
25 case 'f' : return kForward;
26 case 'r' : return kCaridgeReturn;
27 case '"' : return kDoubleQuote;
28 case '\\' : return kBackslash;
34 bool lexer::EscapeLexer::Lex(reader::EncodingReader* reader,
36 unicode::UniString escape(
37 unicode::Convert(reader->Peek(kEscapeValidLength)));
38 if (escape.IsEmpty() || escape.At(0).rawcode() != '\\') {
42 if (escape.GetSize() < static_cast<unsigned int>(kEscapeValidLength)) {
43 THROW_EXCEPTION_(lexer::LexException,
44 unicode::Convert("invalid escape sequence"));
47 lexer::InlineHexEscapeLexer inline_escape;
49 if (inline_escape.Lex(reader, code)) {
56 lexer::TermLexer<term::IntralineWhitespace> intraline;
57 lexer::TermLexer<term::LineEnding> lineend;
59 if (!EscapeConverter().CanConvert(escape.At(1).rawcode()) &&
60 !intraline.CheckToken(reader) && !lineend.CheckToken(reader)) {
61 unicode::UniString encoded_string(
62 unicode::Convert("invalid escape sequence : "));
63 encoded_string.Append(escape);
64 THROW_EXCEPTION_(lexer::LexException, encoded_string);
67 *code = ConvertEscapeToCode(escape, reader);
71 // \<intraline whitespace>に該当する場合、返却されるcodeは0と
73 // Convertの直前でreader->Readとしているのは、直前で読み出されていない
74 // \<.>の<.>にあたる部分を読み飛ばすためです。
75 unsigned int lexer::EscapeLexer::ConvertEscapeToCode(
76 const unicode::UniString& escape, reader::EncodingReader* reader) {
77 unsigned int code = 0;
78 lexer::TermLexer<term::IntralineWhitespace> intraline;
79 lexer::TermLexer<term::LineEnding> lineend;
81 if (!intraline.CheckToken(reader) && !lineend.CheckToken(reader)) {
82 lexer::EscapeConverter converter;
83 if (!converter.CanConvert(escape.At(1).rawcode())) {
84 unicode::UniString encoded_string(
85 unicode::Convert("invalid escape sequence : "));
86 encoded_string.Append(escape);
87 THROW_EXCEPTION_(lexer::LexException, encoded_string);
90 code = converter.Convert(escape.At(1).rawcode());
92 ReadIntralines(reader);
98 // 処理の先頭で1文字だけReadしているのは、すでに\と次の文字が
100 void lexer::EscapeLexer::ReadIntralines(reader::EncodingReader* reader) {
101 lexer::TermLexer<term::IntralineWhitespace> intraline;
102 lexer::TermLexer<term::LineEnding> lineend;
104 while (intraline.CheckToken(reader) && !reader->IsEof()) {
105 reader->Read(intraline.previous_read_size());
108 if (!lineend.CheckToken(reader)) {
109 unicode::UniString encoded_string;
110 THROW_EXCEPTION_(lexer::LexException,
111 unicode::Convert("must line ending after whitespaces"));
113 reader->Read(lineend.previous_read_size());
115 while (intraline.CheckToken(reader) && !reader->IsEof()) {
116 reader->Read(intraline.previous_read_size());
120 // 文字列の終了地点は、同一行の`"`か、\\を含む複数行後の対応する`"`となります。
121 // 対応する`"`が存在しないままreaderの末尾に到達すると、LexExceptionが
123 // また、\から行末まで空白文字のみが続き、次の行の最初の文字までが、改行か
124 // 空白のみである場合、その間の空白及び改行は無視され、文字列は継続している
126 akebono::smart_ptr<lexer::Token> lexer::StringLexer::Lex(
127 reader::EncodingReader* reader) {
128 lexer::TermLexer<term::StringDoubleQuote> string_delimiter;
129 if (!string_delimiter.CheckToken(reader)) {
130 return akebono::smart_ptr<lexer::Token>();
132 reader->Read(string_delimiter.previous_read_size());
134 lexer::EscapeLexer escape;
135 unicode::UniString str;
136 bool syntax_ok = false;
138 while (!reader->IsEof()) {
139 if (string_delimiter.CheckToken(reader)) {
140 reader->Read(string_delimiter.previous_read_size());
145 unsigned int code = 0;
146 if (escape.Lex(reader, &code)) {
148 str.Append(unicode::UniChar(code));
151 str.Append(unicode::UniChar(reader->Read()));
156 THROW_EXCEPTION_(lexer::LexException,
157 unicode::Convert("not found end of string."));
160 return akebono::smart_ptr<lexer::Token>(
161 new lexer::Token(str, lexer::Token::kString));