--- /dev/null
+#include <algorithm>
+
+#include "src/exception_macro.h"
+#include "src/lexer/inner_hex_lexer.h"
+#include "src/lexer/lexer_interface.h"
+#include "src/lexer/term_lexer.h"
+#include "src/lexer/term_checker.h"
+#include "src/lexer/inline_hex_escape_lexer.h"
+#include "src/unicode.h"
+#include "src/encoding_reader.h"
+#include "lib/range.h"
+
+namespace lexer = utakata::lexer;
+namespace term = utakata::lexer::term;
+namespace unicode = utakata::unicode;
+
+// 宣言のコメントを参照してください。
+bool lexer::InlineHexEscapeLexer::Lex(reader::EncodingReader* reader,
+ unsigned int* result) {
+ unicode::UniString prefix(reader->Peek(2));
+
+ if (prefix != unicode::Convert("\\x")) {
+ return false;
+ }
+
+ unicode::UniString hex_value;
+ lexer::TermLexer<term::HexValue> hex_checker;
+
+ while (hex_checker.CheckToken(reader) && reader->IsEof()) {
+ hex_value.Append(unicode::UniChar(reader->Read()));
+ }
+
+ if (hex_value.IsEmpty() ) {
+ unicode::UniString encoded_string("invalid escape sequence : ");
+ THROW_EXCEPTION_(lexer::LexException, encoded_string);
+ } else if (reader->Peek() != ';') {
+ THROW_EXCEPTION_(lexer::LexException, unicode::Convert(
+ "inline hex escape is end of ';'"));
+ }
+
+ reader->Read();
+ lexer::InnerHexValueLexer inner_hex;
+
+ inner_hex.Lex(hex_checker, result);
+
+ return true;
+}
--- /dev/null
+// <inline hex escape>に該当する字句を読み出す機能を提供します。
+// ここで提供されるデータは、次のデータを有効
+//
+#ifndef _UTAKATA_SRC_LEXER_INLINE_HEX_ESCAPE_LEXER_H_
+#define _UTAKATA_SRC_LEXER_INLINE_HEX_ESCAPE_LEXER_H_
+
+namespace utakata {
+namespace reader {
+class EncodingReader;
+}
+
+namespace lexer {
+
+// \x<hex scalar value>;に一致するエスケープを、scalar valueに一致する
+// 文字列を、一致するunicode表現とします。
+class InlineHexEscapeLexer {
+ public:
+
+ // readerの先頭が\xでは無い場合、falseを返却します。その場合、result
+ // は更新されません。
+ // 構文に一致しない場合、LexException例外が送出されます。
+ virtual bool Lex(reader::EncodingReader* reader, unsigned int* result);
+};
+}
+}
+
+#endif /* _UTAKATA_SRC_LEXER_INLINE_HEX_ESCAPE_LEXER_H_ */
#include "lib/range.h"
namespace lexer = utakata::lexer;
-namespace term = utakata::lexer::term;
namespace unicode = utakata::unicode;
// 宣言のコメントを参照してください。
end = string.End();
if (akebono::range::find_if_not(
- string, term::HexValueChecker()) != end) {
+ string, HexValueChecker()) != end) {
return false;
}
#include "src/lexer/string_lexer.h"
#include "src/lexer/term_lexer.h"
#include "src/lexer/term_checker.h"
+#include "src/lexer/inline_hex_escape_lexer.h"
#include "src/lexeme.h"
#include "src/encoding_reader.h"
#include "src/unicode.h"
namespace reader = utakata::reader;
namespace unicode = utakata::unicode;
+// 宣言のコメントを参照してください。
+unsigned int lexer::EscapeConverter::Convert(unsigned int code) {
+ switch (code) {
+ case 'a' : return kAlarm;
+ case 'b' : return kBackspace;
+ case 't' : return kTab;
+ case 'n' : return kLinefeed;
+ case 'v' : return kVTab;
+ case 'f' : return kForward;
+ case 'r' : return kCaridgeReturn;
+ case '"' : return kDoubleQuote;
+ case '\\' : return kBackslash;
+ default: return 0;
+ }
+}
// 宣言のコメントを参照して下さい。
bool lexer::EscapeLexer::Lex(reader::EncodingReader* reader,
lexer::InlineHexEscapeLexer inline_escape;
- if (inline_escape(reader, code)) {
+ if (inline_escape(reader, &code)) {
return true;
}
reader->Read();
lexer::TermLexer<term::IntralineWhiteSpaceChecker> intraline;
lexer::TermLexer<term::LineEndingChecker> lineend;
- if (!CheckEscapeSequence(escape.At(1)) &&
- !intraline.CheckToken(reader) &&
- !lineend.CheckToken(reader)) {
+
+ if (!EscapeConverter.CanConvert(escape.At(1).rawcode()) &&
+ !intraline.CheckToken(reader) && !lineend.CheckToken(reader)) {
unicode::UniString encoded_string("invalid escape sequence : ");
encoded_string.Append(escape);
THROW_EXCEPTION_(lexer::LexException, encoded_string);
THROW_EXCEPTION_(lexer::LexException, encoded_string);
}
} else {
- // 1文字だけReadしているのは、すでに\に該当する部分がReadされており、
- // escapeとして渡されている文字列以降をチェックするために、
- // escape分を読捨てるためです。
- reader->Read();
- while (intraline.CheckToken(reader) && !reader->IsEof()) {
- intraline.ReadToken(reader);
- }
-
- if (!lineend.CheckToken(reader)) {
- unicode::UniString encoded_string;
- THROW_EXCEPTION_(lexer::LexException,
- unicode::Convert("must line ending after whitespaces"));
- }
- lineend.ReadToken(reader);
-
- while (intraline.CheckToken(reader) && !reader->IsEof()) {
- intraline.ReadToken(reader);
- }
+ ReadIntralines(reader);
}
return code;
}
-// 宣言のコメントを参照して下さい。
-bool lexer::EscapeConverter::CanConvert(unsigned int code) {
- switch (code) {
- case 'a' :
- case 'b' :
- case 't' :
- case 'n' :
- case 'v' :
- case 'f' :
- case 'r' :
- case '"' :
- case '\\' :
- return true;
- default:
- return false;
+// 処理の先頭で1文字だけReadしているのは、すでに\と次の文字が
+// 読出されているためです。
+void lexer::EscapeLexer::ReadIntralines(reader::EncodingReader* reader) {
+ lexer::TermLexer<term::IntralineWhiteSpaceChecker> intraline;
+ lexer::TermLexer<term::LineEndingChecker> lineend;
+
+ reader->Read();
+ while (intraline.CheckToken(reader) && !reader->IsEof()) {
+ intraline.ReadToken(reader);
}
-}
-// 宣言のコメントを参照してください。
-unsigned int lexer::EscapeConverter::Convert(unsigned int code) {
- switch (code) {
- case 'a' : return kAlarm;
- case 'b' : return kBackspace;
- case 't' : return kTab;
- case 'n' : return kLinefeed;
- case 'v' : return kVTab;
- case 'f' : return kForward;
- case 'r' : return kCaridgeReturn;
- case '"' : return kDoubleQuote;
- case '\\' : return kBackslash;
- default: return 0;
+ if (!lineend.CheckToken(reader)) {
+ unicode::UniString encoded_string;
+ THROW_EXCEPTION_(lexer::LexException,
+ unicode::Convert("must line ending after whitespaces"));
+ }
+ lineend.ReadToken(reader);
+
+ while (intraline.CheckToken(reader) && !reader->IsEof()) {
+ intraline.ReadToken(reader);
}
}
public:
// エスケープシーケンスの文字コードである場合、trueを返します。
- bool CanConvert(unsigned int code);
+ bool CanConvert(unsigned int code) {
+ return Convert(code) == 0;
+ }
// エスケープシーケンスの文字コードから、各エスケープシーケンスに
// 該当する値を返却します。
private:
- // 渡された文字が、エスケープシーケンスとして認識される文字
- // である場合、trueを返します。
- bool CheckEscapeSeacense(const unicode::UniChar& escape);
-
// 渡されたエスケープシーケンスから、該当する文字コードを取得します。
// 内部では、\<intraline whitespace>...のチェックも行います。
// エスケープシーケンスとして認識されない文字列が渡された場合、
// LexExceptionを送出します。
unsigned int ConvertEscapeToCode(const unicode::UniString& escape,
reader::EncodingReader* reader);
+
+ // readerから、Intraline whiltespace及び改行を読み捨てます。
+ // <intraline whitespace>*<line ending><intraline whitespace>*に
+ // 一致しない場合、lexer::LexExceptionが送出されます。
+ void ReadIntralines(reader::EncodingReader* reader);
};
class StringLexer : public IPartOfLexer {
}
// 宣言のコメントを参照してください。
+bool term::HexValueChecker::operator()(const unicode::UniChar& ch) {
+ return (('a' <= ch.rawcode() && ch.rawcode() <= 'f') ||
+ ('A' <= ch.rawcode() && ch.rawcode() <= 'F') ||
+ ('0' <= ch.rawcode() && ch.rawcode() <= '9'));
+}
+
+// 宣言のコメントを参照してください。
bool term::StringDoubleQuote::operator()(reader::EncodingReader* reader,
unsigned int* size) {
unicode::UniChar ch(reader->Peek());
// 渡されたreaderの読み出し位置は更新されません。
bool operator()(reader::EncodingReader* reader, unsigned int* size);
};
-}
+
+class HexValueChecker {
+ public:
+ // 渡された文字が、HexValueの領域内であるかどうかを返します。
+ bool operator()(const unicode::UniChar& ch);
+};
+
}
}
--- /dev/null
+#include <iostream>
+
+#include <test/gtest/gtest.h>
+#include "lib/textarrayformat.h"
+#include "src/lexer/lexer_interface.h"
+#include "src/lexer/inline_hex_escape_lexer.h"
+#include "src/unicode.h"
+#include "lib/scoped_ptr.h"
+#include "src/encoding_reader.h"
+#include "src/string_reader.h"
+#include "src/utf8_transcoder.h"
+
+namespace textarrayformat = utility::textarrayformat;
+namespace lexer = utakata::lexer;
+namespace unicode = utakata::unicode;
+
+class InlineHexEscapeLexerTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ gen.reset(new textarrayformat::TextArrayGenerator("========="));
+ gen->Punctuate("\\x000F; \\x1aF;");
+ gen->Punctuate("\\9dG; \\x;");
+ gen->Punctuate("\\x; \\x1 ");
+ }
+
+ akebono::scoped_ptr<textarrayformat::TextArrayGenerator> gen;
+};
+
+TEST_F(InlineHexEscapeLexerTest, SuccessPattern) {
+ textarrayformat::TextArrayReader textarray(*gen);
+ reader::StringReader sr(textarray.GetBlockAt(0));
+ reader::EncodingReader reader(&sr, new transcoder::UTF8Transcoder);
+
+ lexer::InlineHexEscapeLexer l;
+
+ unsigned int ret = 0;
+ EXPECT_TRUE(l.Lex(&reader, &ret));
+ EXPECT_EQ(ret, static_cast<unsigned int>(0xF));
+
+ reader.Read();
+ EXPECT_TRUE(l.Lex(&reader, &ret));
+ EXPECT_EQ(ret, static_cast<unsigned int>(0x1aF));
+}
+
+TEST_F(InlineHexEscapeLexerTest, FailurePattern) {
+ textarrayformat::TextArrayReader textarray(*gen);
+ reader::StringReader sr(textarray.GetBlockAt(1));
+ reader::EncodingReader reader(&sr, new transcoder::UTF8Transcoder);
+
+ lexer::InlineHexEscapeLexer l;
+
+ unsigned int ret = 0;
+ EXPECT_THROW(l.Lex(&reader, &ret), lexer::LexException);
+
+ reader.Read(4);
+ EXPECT_THROW(l.Lex(&reader, &ret), lexer::LexException);
+}
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}