/*********************************************************************** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY DEVELOPER: Zihan Chen(vczh) ***********************************************************************/ #include "Vlpp.h" /*********************************************************************** .\BASIC.CPP ***********************************************************************/ #include #if defined VCZH_MSVC #include #elif defined VCZH_GCC #include #endif namespace vl { /*********************************************************************** NotCopyable ***********************************************************************/ NotCopyable::NotCopyable() { } NotCopyable::NotCopyable(const NotCopyable&) { } NotCopyable& NotCopyable::operator=(const NotCopyable&) { return *this; } /*********************************************************************** Error ***********************************************************************/ Error::Error(const wchar_t* _description) { description=_description; } const wchar_t* Error::Description()const { return description; } /*********************************************************************** Object ***********************************************************************/ Object::~Object() { } /*********************************************************************** DateTime ***********************************************************************/ #if defined VCZH_MSVC DateTime SystemTimeToDateTime(const SYSTEMTIME& systemTime) { DateTime dateTime; dateTime.year=systemTime.wYear; dateTime.month=systemTime.wMonth; dateTime.dayOfWeek=systemTime.wDayOfWeek; dateTime.day=systemTime.wDay; dateTime.hour=systemTime.wHour; dateTime.minute=systemTime.wMinute; dateTime.second=systemTime.wSecond; dateTime.milliseconds=systemTime.wMilliseconds; FILETIME fileTime; SystemTimeToFileTime(&systemTime, &fileTime); ULARGE_INTEGER largeInteger; largeInteger.HighPart=fileTime.dwHighDateTime; largeInteger.LowPart=fileTime.dwLowDateTime; dateTime.filetime=largeInteger.QuadPart; dateTime.totalMilliseconds=dateTime.filetime/10000; return dateTime; } SYSTEMTIME DateTimeToSystemTime(const DateTime& dateTime) { ULARGE_INTEGER largeInteger; largeInteger.QuadPart=dateTime.filetime; FILETIME fileTime; fileTime.dwHighDateTime=largeInteger.HighPart; fileTime.dwLowDateTime=largeInteger.LowPart; SYSTEMTIME systemTime; FileTimeToSystemTime(&fileTime, &systemTime); return systemTime; } #elif defined VCZH_GCC DateTime ConvertTMToDateTime(tm* timeinfo, vint milliseconds) { time_t timer = mktime(timeinfo); DateTime dt; dt.year = timeinfo->tm_year+1900; dt.month = timeinfo->tm_mon+1; dt.day = timeinfo->tm_mday; dt.dayOfWeek = timeinfo->tm_wday; dt.hour = timeinfo->tm_hour; dt.minute = timeinfo->tm_min; dt.second = timeinfo->tm_sec; dt.milliseconds = milliseconds; dt.filetime = (vuint64_t)timer * 1000 + milliseconds; dt.totalMilliseconds = (vuint64_t)timer * 1000 + milliseconds; return dt; } vint GetCurrentMilliseconds() { struct timeval tv; gettimeofday(&tv, nullptr); return tv.tv_usec / 1000; } #endif DateTime DateTime::LocalTime() { #if defined VCZH_MSVC SYSTEMTIME systemTime; GetLocalTime(&systemTime); return SystemTimeToDateTime(systemTime); #elif defined VCZH_GCC time_t timer = time(nullptr); tm* timeinfo = localtime(&timer); return ConvertTMToDateTime(timeinfo, GetCurrentMilliseconds()); #endif } DateTime DateTime::UtcTime() { #if defined VCZH_MSVC SYSTEMTIME utcTime; GetSystemTime(&utcTime); return SystemTimeToDateTime(utcTime); #elif defined VCZH_GCC time_t timer = time(nullptr); tm* timeinfo = gmtime(&timer); return ConvertTMToDateTime(timeinfo, GetCurrentMilliseconds()); #endif } DateTime DateTime::FromDateTime(vint _year, vint _month, vint _day, vint _hour, vint _minute, vint _second, vint _milliseconds) { #if defined VCZH_MSVC SYSTEMTIME systemTime; memset(&systemTime, 0, sizeof(systemTime)); systemTime.wYear=(WORD)_year; systemTime.wMonth=(WORD)_month; systemTime.wDay=(WORD)_day; systemTime.wHour=(WORD)_hour; systemTime.wMinute=(WORD)_minute; systemTime.wSecond=(WORD)_second; systemTime.wMilliseconds=(WORD)_milliseconds; FILETIME fileTime; SystemTimeToFileTime(&systemTime, &fileTime); FileTimeToSystemTime(&fileTime, &systemTime); return SystemTimeToDateTime(systemTime); #elif defined VCZH_GCC tm timeinfo; memset(&timeinfo, 0, sizeof(timeinfo)); timeinfo.tm_year = _year-1900; timeinfo.tm_mon = _month-1; timeinfo.tm_mday = _day; timeinfo.tm_hour = _hour; timeinfo.tm_min = _minute; timeinfo.tm_sec = _second; timeinfo.tm_isdst = -1; return ConvertTMToDateTime(&timeinfo, _milliseconds); #endif } DateTime DateTime::FromFileTime(vuint64_t filetime) { #if defined VCZH_MSVC ULARGE_INTEGER largeInteger; largeInteger.QuadPart=filetime; FILETIME fileTime; fileTime.dwHighDateTime=largeInteger.HighPart; fileTime.dwLowDateTime=largeInteger.LowPart; SYSTEMTIME systemTime; FileTimeToSystemTime(&fileTime, &systemTime); return SystemTimeToDateTime(systemTime); #elif defined VCZH_GCC time_t timer = (time_t)(filetime / 1000); tm* timeinfo = localtime(&timer); return ConvertTMToDateTime(timeinfo, filetime % 1000); #endif } DateTime::DateTime() :year(0) ,month(0) ,day(0) ,hour(0) ,minute(0) ,second(0) ,milliseconds(0) ,filetime(0) { } DateTime DateTime::ToLocalTime() { #if defined VCZH_MSVC SYSTEMTIME utcTime=DateTimeToSystemTime(*this); SYSTEMTIME localTime; SystemTimeToTzSpecificLocalTime(NULL, &utcTime, &localTime); return SystemTimeToDateTime(localTime); #elif defined VCZH_GCC time_t localTimer = time(nullptr); time_t utcTimer = mktime(gmtime(&localTimer)); time_t timer = (time_t)(filetime / 1000) + localTimer - utcTimer; tm* timeinfo = localtime(&timer); return ConvertTMToDateTime(timeinfo, milliseconds); #endif } DateTime DateTime::ToUtcTime() { #if defined VCZH_MSVC SYSTEMTIME localTime=DateTimeToSystemTime(*this); SYSTEMTIME utcTime; TzSpecificLocalTimeToSystemTime(NULL, &localTime, &utcTime); return SystemTimeToDateTime(utcTime); #elif defined VCZH_GCC time_t timer = (time_t)(filetime / 1000); tm* timeinfo = gmtime(&timer); return ConvertTMToDateTime(timeinfo, milliseconds); #endif } DateTime DateTime::Forward(vuint64_t milliseconds) { #if defined VCZH_MSVC return FromFileTime(filetime+milliseconds*10000); #elif defined VCZH_GCC return FromFileTime(filetime+milliseconds); #endif } DateTime DateTime::Backward(vuint64_t milliseconds) { #if defined VCZH_MSVC return FromFileTime(filetime-milliseconds*10000); #elif defined VCZH_GCC return FromFileTime(filetime-milliseconds); #endif } /*********************************************************************** Interface ***********************************************************************/ Interface::~Interface() { } } /*********************************************************************** .\CONSOLE.CPP ***********************************************************************/ #if defined VCZH_MSVC #elif defined VCZH_GCC #include #include using namespace std; #endif namespace vl { namespace console { /*********************************************************************** Console ***********************************************************************/ void Console::Write(const wchar_t* string, vint length) { #if defined VCZH_MSVC HANDLE outHandle=GetStdHandle(STD_OUTPUT_HANDLE); DWORD fileMode=0; DWORD written=0; if((GetFileType(outHandle) & FILE_TYPE_CHAR) && GetConsoleMode(outHandle, &fileMode)) { WriteConsole(outHandle, string, (int)length, &written,0); } else { int codePage = GetConsoleOutputCP(); int charCount = WideCharToMultiByte(codePage, 0, string, -1, 0, 0, 0, 0); char* codePageBuffer = new char[charCount]; WideCharToMultiByte(codePage, 0, string, -1, codePageBuffer, charCount, 0, 0); WriteFile(outHandle, codePageBuffer, charCount-1, &written, 0); delete[] codePageBuffer; } #elif defined VCZH_GCC wstring s(string, string+length); wcout< #pragma comment(lib, "Shlwapi.lib") #elif defined VCZH_GCC #include #include #include #endif namespace vl { namespace filesystem { using namespace collections; using namespace stream; // ReadDirectoryChangesW /*********************************************************************** FilePath ***********************************************************************/ #if defined VCZH_GCC const wchar_t FilePath::Delimiter; #endif void FilePath::Initialize() { { Array buffer(fullPath.Length() + 1); #if defined VCZH_MSVC wcscpy_s(&buffer[0], fullPath.Length() + 1, fullPath.Buffer()); #elif defined VCZH_GCC wcscpy(&buffer[0], fullPath.Buffer()); #endif for (vint i = 0; i < buffer.Count(); i++) { if (buffer[i] == L'\\' || buffer[i] == L'/') { buffer[i] = Delimiter; } } fullPath = &buffer[0]; } #if defined VCZH_MSVC if (fullPath != L"") { if (fullPath.Length() < 2 || fullPath[1] != L':') { wchar_t buffer[MAX_PATH + 1] = { 0 }; auto result = GetCurrentDirectory(sizeof(buffer) / sizeof(*buffer), buffer); if (result > MAX_PATH + 1 || result == 0) { throw ArgumentException(L"Failed to call GetCurrentDirectory.", L"vl::filesystem::FilePath::Initialize", L""); } fullPath = WString(buffer) + L"\\" + fullPath; } { wchar_t buffer[MAX_PATH + 1] = { 0 }; if (fullPath.Length() == 2 && fullPath[1] == L':') { fullPath += L"\\"; } auto result = GetFullPathName(fullPath.Buffer(), sizeof(buffer) / sizeof(*buffer), buffer, NULL); if (result > MAX_PATH + 1 || result == 0) { throw ArgumentException(L"The path is illegal.", L"vl::filesystem::FilePath::FilePath", L"_filePath"); } fullPath = buffer; } } #elif defined VCZH_GCC if (fullPath.Length() == 0) fullPath = L"/"; if (fullPath[0] != Delimiter) { char buffer[PATH_MAX] = { 0 }; getcwd(buffer, PATH_MAX); fullPath = atow(AString(buffer)) + Delimiter + fullPath; } { collections::List components; GetPathComponents(fullPath, components); for(int i = 0; i < components.Count(); i++) { if(components[i] == L".") { components.RemoveAt(i); i--; } else if(components[i] == L"..") { if(i > 0) { components.RemoveAt(i); components.RemoveAt(i - 1); i -= 2; } else { throw ArgumentException(L"Illegal path."); } } } fullPath = ComponentsToPath(components); } #endif if (fullPath != L"/" && fullPath.Length() > 0 && fullPath[fullPath.Length() - 1] == Delimiter) { fullPath = fullPath.Left(fullPath.Length() - 1); } } FilePath::FilePath() { } FilePath::FilePath(const WString& _filePath) :fullPath(_filePath) { Initialize(); } FilePath::FilePath(const wchar_t* _filePath) :fullPath(_filePath) { Initialize(); } FilePath::FilePath(const FilePath& _filePath) :fullPath(_filePath.fullPath) { Initialize(); } FilePath::~FilePath() { } vint FilePath::Compare(const FilePath& a, const FilePath& b) { return WString::Compare(a.fullPath, b.fullPath); } FilePath FilePath::operator/(const WString& relativePath)const { if (IsRoot()) { return relativePath; } else { return fullPath + L"/" + relativePath; } } bool FilePath::IsFile()const { #if defined VCZH_MSVC WIN32_FILE_ATTRIBUTE_DATA info; BOOL result = GetFileAttributesEx(fullPath.Buffer(), GetFileExInfoStandard, &info); if (!result) return false; return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0; #elif defined VCZH_GCC struct stat info; AString path = wtoa(fullPath); int result = stat(path.Buffer(), &info); if(result != 0) return false; else return S_ISREG(info.st_mode); #endif } bool FilePath::IsFolder()const { #if defined VCZH_MSVC WIN32_FILE_ATTRIBUTE_DATA info; BOOL result = GetFileAttributesEx(fullPath.Buffer(), GetFileExInfoStandard, &info); if (!result) return false; return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; #elif defined VCZH_GCC struct stat info; AString path = wtoa(fullPath); int result = stat(path.Buffer(), &info); if(result != 0) return false; else return S_ISDIR(info.st_mode); #endif } bool FilePath::IsRoot()const { #if defined VCZH_MSVC return fullPath == L""; #elif defined VCZH_GCC return fullPath == L"/"; #endif } WString FilePath::GetName()const { WString delimiter = Delimiter; auto index = INVLOC.FindLast(fullPath, delimiter, Locale::None); if (index.key == -1) return fullPath; return fullPath.Right(fullPath.Length() - index.key - 1); } FilePath FilePath::GetFolder()const { WString delimiter = Delimiter; auto index = INVLOC.FindLast(fullPath, delimiter, Locale::None); if (index.key == -1) return FilePath(); return fullPath.Left(index.key); } WString FilePath::GetFullPath()const { return fullPath; } WString FilePath::GetRelativePathFor(const FilePath& _filePath) { if (fullPath.Length()==0 || _filePath.fullPath.Length()==0 || fullPath[0] != _filePath.fullPath[0]) { return _filePath.fullPath; } #if defined VCZH_MSVC wchar_t buffer[MAX_PATH + 1] = { 0 }; PathRelativePathTo( buffer, fullPath.Buffer(), (IsFolder() ? FILE_ATTRIBUTE_DIRECTORY : 0), _filePath.fullPath.Buffer(), (_filePath.IsFolder() ? FILE_ATTRIBUTE_DIRECTORY : 0) ); return buffer; #elif defined VCZH_GCC collections::List srcComponents, tgtComponents, resultComponents; GetPathComponents(IsFolder() ? fullPath : GetFolder().GetFullPath(), srcComponents); GetPathComponents(_filePath.fullPath, tgtComponents); int minLength = srcComponents.Count() <= tgtComponents.Count() ? srcComponents.Count() : tgtComponents.Count(); int lastCommonComponent = 0; for(int i = 0; i < minLength; i++) { if(srcComponents[i] == tgtComponents[i]) { lastCommonComponent = i; } else break; } for(int i = lastCommonComponent + 1; i < srcComponents.Count(); i++) { resultComponents.Add(L".."); } for(int i = lastCommonComponent + 1; i < tgtComponents.Count(); i++) { resultComponents.Add(tgtComponents[i]); } return ComponentsToPath(resultComponents); #endif } void FilePath::GetPathComponents(WString path, collections::List& components) { WString pathRemaining = path; WString delimiter = Delimiter; components.Clear(); while(true) { auto index = INVLOC.FindFirst(pathRemaining, delimiter, Locale::None); if (index.key == -1) break; if(index.key != 0) components.Add(pathRemaining.Left(index.key)); else { #if defined VCZH_GCC // Unix absolute path starting with "/" // components[0] will be L"/" components.Add(delimiter); #elif defined VCZH_MSVC if(pathRemaining.Length() >= 2 && pathRemaining[1] == Delimiter) { // Windows UNC Path starting with "\\" // components[0] will be L"\\" components.Add(L"\\"); index.value++; } #endif } pathRemaining = pathRemaining.Right(pathRemaining.Length() - (index.key + index.value)); } if(pathRemaining.Length() != 0) { components.Add(pathRemaining); } } WString FilePath::ComponentsToPath(const collections::List& components) { WString result; WString delimiter = Delimiter; int i = 0; #if defined VCZH_GCC // For Unix-like OSes, if first component is "/" then take it as absolute path if(components.Count() > 0 && components[0] == delimiter) { result += delimiter; i++; } #elif defined VCZH_MSVC // For Windows, if first component is "\\" then it is an UNC path if(components.Count() > 0 && components[0] == L"\\") { result += delimiter; i++; } #endif for(; i < components.Count(); i++) { result += components[i]; if(i + 1 < components.Count()) result += delimiter; } return result; } /*********************************************************************** File ***********************************************************************/ File::File() { } File::File(const FilePath& _filePath) :filePath(_filePath) { } File::~File() { } const FilePath& File::GetFilePath()const { return filePath; } bool File::ReadAllTextWithEncodingTesting(WString& text, stream::BomEncoder::Encoding& encoding, bool& containsBom) { Array buffer; { FileStream fileStream(filePath.GetFullPath(), FileStream::ReadOnly); if (!fileStream.IsAvailable()) return false; if (fileStream.Size() == 0) { text = L""; encoding = BomEncoder::Mbcs; containsBom = false; return true; } buffer.Resize((vint)fileStream.Size()); vint count = fileStream.Read(&buffer[0], buffer.Count()); CHECK_ERROR(count == buffer.Count(), L"vl::filesystem::File::ReadAllTextWithEncodingTesting(WString&, BomEncoder::Encoding&, bool&)#Failed to read the whole file."); } TestEncoding(&buffer[0], buffer.Count(), encoding, containsBom); MemoryWrapperStream memoryStream(&buffer[0], buffer.Count()); if (containsBom) { BomDecoder decoder; DecoderStream decoderStream(memoryStream, decoder); StreamReader reader(decoderStream); text = reader.ReadToEnd(); } else { switch (encoding) { case BomEncoder::Utf8: { Utf8Decoder decoder; DecoderStream decoderStream(memoryStream, decoder); StreamReader reader(decoderStream); text = reader.ReadToEnd(); } break; case BomEncoder::Utf16: { Utf16Decoder decoder; DecoderStream decoderStream(memoryStream, decoder); StreamReader reader(decoderStream); text = reader.ReadToEnd(); } break; case BomEncoder::Utf16BE: { Utf16BEDecoder decoder; DecoderStream decoderStream(memoryStream, decoder); StreamReader reader(decoderStream); text = reader.ReadToEnd(); } break; default: { MbcsDecoder decoder; DecoderStream decoderStream(memoryStream, decoder); StreamReader reader(decoderStream); text = reader.ReadToEnd(); } } } return true; } WString File::ReadAllTextByBom()const { WString text; ReadAllTextByBom(text); return text; } bool File::ReadAllTextByBom(WString& text)const { FileStream fileStream(filePath.GetFullPath(), FileStream::ReadOnly); if (!fileStream.IsAvailable()) return false; BomDecoder decoder; DecoderStream decoderStream(fileStream, decoder); StreamReader reader(decoderStream); text = reader.ReadToEnd(); return true; } bool File::ReadAllLinesByBom(collections::List& lines)const { FileStream fileStream(filePath.GetFullPath(), FileStream::ReadOnly); if (!fileStream.IsAvailable()) return false; BomDecoder decoder; DecoderStream decoderStream(fileStream, decoder); StreamReader reader(decoderStream); while (!reader.IsEnd()) { lines.Add(reader.ReadLine()); } return true; } bool File::WriteAllText(const WString& text, bool bom, stream::BomEncoder::Encoding encoding) { FileStream fileStream(filePath.GetFullPath(), FileStream::WriteOnly); if (!fileStream.IsAvailable()) return false; IEncoder* encoder = nullptr; if (bom) { encoder = new BomEncoder(encoding); } else switch (encoding) { case BomEncoder::Utf8: encoder = new Utf8Encoder; break; case BomEncoder::Utf16: encoder = new Utf16Encoder; break; case BomEncoder::Utf16BE: encoder = new Utf16BEEncoder; break; default: encoder = new MbcsEncoder; break; } { EncoderStream encoderStream(fileStream, *encoder); StreamWriter writer(encoderStream); writer.WriteString(text); } delete encoder; return true; } bool File::WriteAllLines(collections::List& lines, bool bom, stream::BomEncoder::Encoding encoding) { FileStream fileStream(filePath.GetFullPath(), FileStream::WriteOnly); if (!fileStream.IsAvailable()) return false; IEncoder* encoder = nullptr; if (bom) { encoder = new BomEncoder(encoding); } else switch (encoding) { case BomEncoder::Utf8: encoder = new Utf8Encoder; break; case BomEncoder::Utf16: encoder = new Utf16Encoder; break; case BomEncoder::Utf16BE: encoder = new Utf16BEEncoder; break; default: encoder = new MbcsEncoder; break; } { EncoderStream encoderStream(fileStream, *encoder); StreamWriter writer(encoderStream); FOREACH(WString, line, lines) { writer.WriteLine(line); } } delete encoder; return true; } bool File::Exists()const { return filePath.IsFile(); } bool File::Delete()const { #if defined VCZH_MSVC return DeleteFile(filePath.GetFullPath().Buffer()) != 0; #elif defined VCZH_GCC AString path = wtoa(filePath.GetFullPath()); return unlink(path.Buffer()) == 0; #endif } bool File::Rename(const WString& newName)const { #if defined VCZH_MSVC WString oldFileName = filePath.GetFullPath(); WString newFileName = (filePath.GetFolder() / newName).GetFullPath(); return MoveFile(oldFileName.Buffer(), newFileName.Buffer()) != 0; #elif defined VCZH_GCC AString oldFileName = wtoa(filePath.GetFullPath()); AString newFileName = wtoa((filePath.GetFolder() / newName).GetFullPath()); return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0; #endif } /*********************************************************************** Folder ***********************************************************************/ Folder::Folder() { } Folder::Folder(const FilePath& _filePath) :filePath(_filePath) { } Folder::~Folder() { } const FilePath& Folder::GetFilePath()const { return filePath; } bool Folder::GetFolders(collections::List& folders)const { #if defined VCZH_MSVC if (filePath.IsRoot()) { auto bufferSize = GetLogicalDriveStrings(0, nullptr); if (bufferSize > 0) { Array buffer(bufferSize); if (GetLogicalDriveStrings((DWORD)buffer.Count(), &buffer[0]) > 0) { auto begin = &buffer[0]; auto end = begin + buffer.Count(); while (begin < end && *begin) { WString driveString = begin; begin += driveString.Length() + 1; folders.Add(Folder(FilePath(driveString))); } return true; } } return false; } else { if (!Exists()) return false; WIN32_FIND_DATA findData; HANDLE findHandle = INVALID_HANDLE_VALUE; while (true) { if (findHandle == INVALID_HANDLE_VALUE) { WString searchPath = (filePath / L"*").GetFullPath(); findHandle = FindFirstFile(searchPath.Buffer(), &findData); if (findHandle == INVALID_HANDLE_VALUE) { break; } } else { BOOL result = FindNextFile(findHandle, &findData); if (result == 0) { FindClose(findHandle); break; } } if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (wcscmp(findData.cFileName, L".") != 0 && wcscmp(findData.cFileName, L"..") != 0) { folders.Add(Folder(filePath / findData.cFileName)); } } } return true; } #elif defined VCZH_GCC if (!Exists()) return false; DIR *dir; AString searchPath = wtoa(filePath.GetFullPath()); if ((dir = opendir(searchPath.Buffer())) == NULL) { return false; } struct dirent* entry; while ((entry = readdir(dir)) != NULL) { WString childName = atow(AString(entry->d_name)); FilePath childFullPath = filePath / childName; if (childName != L"." && childName != L".." && childFullPath.IsFolder()) { folders.Add(Folder(childFullPath)); } } if (closedir(dir) != 0) { return false; } return true; #endif } bool Folder::GetFiles(collections::List& files)const { #if defined VCZH_MSVC if (filePath.IsRoot()) { return true; } if (!Exists()) return false; WIN32_FIND_DATA findData; HANDLE findHandle = INVALID_HANDLE_VALUE; while (true) { if (findHandle == INVALID_HANDLE_VALUE) { WString searchPath = (filePath / L"*").GetFullPath(); findHandle = FindFirstFile(searchPath.Buffer(), &findData); if (findHandle == INVALID_HANDLE_VALUE) { break; } } else { BOOL result = FindNextFile(findHandle, &findData); if (result == 0) { FindClose(findHandle); break; } } if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { files.Add(File(filePath / findData.cFileName)); } } return true; #elif defined VCZH_GCC if (!Exists()) return false; DIR *dir; AString searchPath = wtoa(filePath.GetFullPath()); if ((dir = opendir(searchPath.Buffer())) == NULL) { return false; } struct dirent* entry; while ((entry = readdir(dir)) != NULL) { FilePath childFullPath = filePath / (atow(AString(entry->d_name))); if (childFullPath.IsFile()) { files.Add(File(childFullPath)); } } if (closedir(dir) != 0) { return false; } return true; #endif } bool Folder::Exists()const { return filePath.IsFolder(); } bool Folder::Create(bool recursively)const { if (recursively) { auto folder = filePath.GetFolder(); if (folder.IsFile()) return false; if (folder.IsFolder()) return Create(false); return Folder(folder).Create(true) && Create(false); } else { #if defined VCZH_MSVC return CreateDirectory(filePath.GetFullPath().Buffer(), NULL) != 0; #elif defined VCZH_GCC AString path = wtoa(filePath.GetFullPath()); return mkdir(path.Buffer(), 0777) == 0; #endif } } bool Folder::Delete(bool recursively)const { if (!Exists()) return false; if (recursively) { List folders; GetFolders(folders); FOREACH(Folder, folder, folders) { if (!folder.Delete(true)) return false; } List files; GetFiles(files); FOREACH(File, file, files) { if (!file.Delete()) return false; } return Delete(false); } #if defined VCZH_MSVC return RemoveDirectory(filePath.GetFullPath().Buffer()) != 0; #elif defined VCZH_GCC AString path = wtoa(filePath.GetFullPath()); return rmdir(path.Buffer()) == 0; #endif } bool Folder::Rename(const WString& newName)const { #if defined VCZH_MSVC WString oldFileName = filePath.GetFullPath(); WString newFileName = (filePath.GetFolder() / newName).GetFullPath(); return MoveFile(oldFileName.Buffer(), newFileName.Buffer()) != 0; #elif defined VCZH_GCC AString oldFileName = wtoa(filePath.GetFullPath()); AString newFileName = wtoa((filePath.GetFolder() / newName).GetFullPath()); return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0; #endif } } } /*********************************************************************** .\GLOBALSTORAGE.CPP ***********************************************************************/ namespace vl { using namespace collections; class GlobalStorageManager { public: Ptr> storages; GlobalStorageManager() { } }; GlobalStorageManager& GetGlobalStorageManager() { static GlobalStorageManager globalStorageManager; return globalStorageManager; } /*********************************************************************** GlobalStorage ***********************************************************************/ GlobalStorage::GlobalStorage(const wchar_t* key) :cleared(false) { InitializeGlobalStorage(); GetGlobalStorageManager().storages->Add(key, this); } GlobalStorage::~GlobalStorage() { } bool GlobalStorage::Cleared() { return cleared; } /*********************************************************************** Helper Functions ***********************************************************************/ GlobalStorage* GetGlobalStorage(const wchar_t* key) { return GetGlobalStorage(WString(key, false)); } GlobalStorage* GetGlobalStorage(const WString& key) { return GetGlobalStorageManager().storages->Get(key); } void InitializeGlobalStorage() { if(!GetGlobalStorageManager().storages) { GetGlobalStorageManager().storages=new Dictionary; } } void FinalizeGlobalStorage() { if(GetGlobalStorageManager().storages) { for(vint i=0;iCount();i++) { GetGlobalStorageManager().storages->Values().Get(i)->ClearResource(); } GetGlobalStorageManager().storages=0; } } } /*********************************************************************** .\HTTPUTILITY.CPP ***********************************************************************/ #ifdef VCZH_MSVC #include #pragma comment(lib, "WinHttp.lib") namespace vl { using namespace collections; /*********************************************************************** HttpRequest ***********************************************************************/ HttpRequest::HttpRequest() :port(0) ,secure(false) { } bool HttpRequest::SetHost(const WString& inputQuery) { server=L""; query=L""; port=0; secure=false; { if(server==L"") { if(inputQuery.Length()>7) { WString protocol=inputQuery.Sub(0, 8); if(_wcsicmp(protocol.Buffer(), L"https://")==0) { const wchar_t* reading=inputQuery.Buffer()+8; const wchar_t* index1=wcschr(reading, L':'); const wchar_t* index2=wcschr(reading, L'/'); if(index2) { query=index2; server=WString(reading, (index1?index1:index2)-reading); port=INTERNET_DEFAULT_HTTPS_PORT; secure=true; if(index1) { WString portString(index1+1, index2-index1-1); port=_wtoi(portString.Buffer()); } return true; } } } } if(server==L"") { if(inputQuery.Length()>6) { WString protocol=inputQuery.Sub(0, 7); if(_wcsicmp(protocol.Buffer(), L"http://")==0) { const wchar_t* reading=inputQuery.Buffer()+7; const wchar_t* index1=wcschr(reading, L':'); const wchar_t* index2=wcschr(reading, L'/'); if(index2) { query=index2; server=WString(reading, (index1?index1:index2)-reading); port=INTERNET_DEFAULT_HTTP_PORT; if(index1) { WString portString(index1+1, index2-index1-1); port=_wtoi(portString.Buffer()); } return true; } } } } } return false; } void HttpRequest::SetBodyUtf8(const WString& bodyString) { vint utf8Size=WideCharToMultiByte(CP_UTF8, 0, bodyString.Buffer(), (int)bodyString.Length(), NULL, 0, NULL, NULL); char* utf8=new char[utf8Size+1]; ZeroMemory(utf8, utf8Size+1); WideCharToMultiByte(CP_UTF8, 0, bodyString.Buffer(), (int)bodyString.Length(), utf8, (int)utf8Size, NULL, NULL); body.Resize(utf8Size); memcpy(&body[0], utf8, utf8Size); delete[] utf8; } /*********************************************************************** HttpResponse ***********************************************************************/ HttpResponse::HttpResponse() :statusCode(0) { } WString HttpResponse::GetBodyUtf8() { WString response; char* utf8=&body[0]; vint totalSize=body.Count(); vint utf16Size=MultiByteToWideChar(CP_UTF8, 0, utf8, (int)totalSize, NULL, 0); wchar_t* utf16=new wchar_t[utf16Size+1]; ZeroMemory(utf16, (utf16Size+1)*sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, utf8, (int)totalSize, utf16, (int)utf16Size); response=utf16; delete[] utf16; return response; } /*********************************************************************** Utilities ***********************************************************************/ struct BufferPair { char* buffer; vint length; BufferPair() :buffer(0) ,length(0) { } BufferPair(char* _buffer, vint _length) :buffer(_buffer) ,length(_length) { } bool operator==(const BufferPair& pair){return false;} bool operator!=(const BufferPair& pair){return true;} }; bool HttpQuery(const HttpRequest& request, HttpResponse& response) { // initialize response.statusCode=-1; HINTERNET internet=NULL; HINTERNET connectedInternet=NULL; HINTERNET requestInternet=NULL; BOOL httpResult=FALSE; DWORD error=0; List acceptTypes; List availableBuffers; // access http internet=WinHttpOpen(L"vczh", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); error=GetLastError(); if(!internet) goto CLEANUP; // connect connectedInternet=WinHttpConnect(internet, request.server.Buffer(), (int)request.port, 0); error=GetLastError(); if(!connectedInternet) goto CLEANUP; // open request for(vint i=0;i0) { httpResult=WinHttpSendRequest(requestInternet, WINHTTP_NO_ADDITIONAL_HEADERS, 0, (LPVOID)&request.body.Get(0), (int)request.body.Count(), (int)request.body.Count(), NULL); } else { httpResult=WinHttpSendRequest(requestInternet, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL); } error=GetLastError(); if(httpResult==FALSE) goto CLEANUP; // receive response httpResult=WinHttpReceiveResponse(requestInternet, NULL); error=GetLastError(); if(httpResult!=TRUE) goto CLEANUP; // read response status code { DWORD headerLength=sizeof(DWORD); DWORD statusCode=0; httpResult=WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &headerLength, WINHTTP_NO_HEADER_INDEX); error=GetLastError(); if(httpResult==FALSE) goto CLEANUP; response.statusCode=statusCode; } // read respons cookie { DWORD headerLength=sizeof(DWORD); httpResult=WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &headerLength, WINHTTP_NO_HEADER_INDEX); error=GetLastError(); if(error==ERROR_INSUFFICIENT_BUFFER) { wchar_t* rawHeader=new wchar_t[headerLength/sizeof(wchar_t)]; ZeroMemory(rawHeader, headerLength); httpResult=WinHttpQueryHeaders(requestInternet, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, rawHeader, &headerLength, WINHTTP_NO_HEADER_INDEX); const wchar_t* cookieStart=wcsstr(rawHeader, L"Cookie:"); if(cookieStart) { const wchar_t* cookieEnd=wcsstr(cookieStart, L";"); if(cookieEnd) { response.cookie=WString(cookieStart+7, cookieEnd-cookieStart-7); } } delete[] rawHeader; } } // read response body while(true) { DWORD bytesAvailable=0; BOOL queryDataAvailableResult=WinHttpQueryDataAvailable(requestInternet, &bytesAvailable); error=GetLastError(); if(queryDataAvailableResult==TRUE && bytesAvailable!=0) { char* utf8=new char[bytesAvailable]; DWORD bytesRead=0; BOOL readDataResult=WinHttpReadData(requestInternet, utf8, bytesAvailable, &bytesRead); error=GetLastError(); if(readDataResult==TRUE) { availableBuffers.Add(BufferPair(utf8, bytesRead)); } else { delete[] utf8; } } else { break; } } { // concatincate response body vint totalSize = 0; FOREACH(BufferPair, p, availableBuffers) { totalSize += p.length; } response.body.Resize(totalSize); if (totalSize > 0) { char* utf8 = new char[totalSize]; { char* temp = utf8; FOREACH(BufferPair, p, availableBuffers) { memcpy(temp, p.buffer, p.length); temp += p.length; } } memcpy(&response.body[0], utf8, totalSize); delete[] utf8; } FOREACH(BufferPair, p, availableBuffers) { delete[] p.buffer; } } CLEANUP: if(requestInternet) WinHttpCloseHandle(requestInternet); if(connectedInternet) WinHttpCloseHandle(connectedInternet); if(internet) WinHttpCloseHandle(internet); return response.statusCode!=-1; } WString UrlEncodeQuery(const WString& query) { vint utf8Size=WideCharToMultiByte(CP_UTF8, 0, query.Buffer(),(int) query.Length(), NULL, 0, NULL, NULL); char* utf8=new char[utf8Size+1]; ZeroMemory(utf8, utf8Size+1); WideCharToMultiByte(CP_UTF8, 0, query.Buffer(), (int)query.Length(), utf8, (int)utf8Size, NULL, NULL); wchar_t* encoded=new wchar_t[utf8Size*3+1]; ZeroMemory(encoded, (utf8Size*3+1)*sizeof(wchar_t)); wchar_t* writing=encoded; for(vint i=0;i #include #endif namespace vl { using namespace collections; #if defined VCZH_MSVC extern SYSTEMTIME DateTimeToSystemTime(const DateTime& dateTime); BOOL CALLBACK Locale_EnumLocalesProcEx( _In_ LPWSTR lpLocaleString, _In_ DWORD dwFlags, _In_ LPARAM lParam ) { ((List*)lParam)->Add(Locale(lpLocaleString)); return TRUE; } BOOL CALLBACK Locale_EnumDateFormatsProcExEx( _In_ LPWSTR lpDateFormatString, _In_ CALID CalendarID, _In_ LPARAM lParam ) { ((List*)lParam)->Add(lpDateFormatString); return TRUE; } BOOL CALLBACK EnumTimeFormatsProcEx( _In_ LPWSTR lpTimeFormatString, _In_ LPARAM lParam ) { ((List*)lParam)->Add(lpTimeFormatString); return TRUE; } WString Transform(const WString& localeName, const WString& input, DWORD flag) { int length=LCMapStringEx(localeName.Buffer(), flag, input.Buffer(), (int)input.Length()+1, NULL, 0, NULL, NULL, NULL); Array buffer(length); LCMapStringEx(localeName.Buffer(), flag, input.Buffer(), (int)input.Length()+1, &buffer[0], (int)buffer.Count(), NULL, NULL, NULL); return &buffer[0]; } DWORD TranslateNormalization(Locale::Normalization normalization) { DWORD result=0; if(normalization&Locale::IgnoreCase) result|=NORM_IGNORECASE; if(normalization&Locale::IgnoreCaseLinguistic) result|=NORM_IGNORECASE | NORM_LINGUISTIC_CASING; if(normalization&Locale::IgnoreKanaType) result|=NORM_IGNOREKANATYPE; if(normalization&Locale::IgnoreNonSpace) result|=NORM_IGNORENONSPACE; if(normalization&Locale::IgnoreSymbol) result|=NORM_IGNORESYMBOLS; if(normalization&Locale::IgnoreWidth) result|=NORM_IGNOREWIDTH; if(normalization&Locale::DigitsAsNumbers) result|=SORT_DIGITSASNUMBERS; if(normalization&Locale::StringSoft) result|=SORT_STRINGSORT; return result; } #endif /*********************************************************************** Locale ***********************************************************************/ Locale::Locale(const WString& _localeName) :localeName(_localeName) { } Locale::~Locale() { } Locale Locale::Invariant() { #if defined VCZH_MSVC return Locale(LOCALE_NAME_INVARIANT); #elif defined VCZH_GCC return Locale(L""); #endif } Locale Locale::SystemDefault() { #if defined VCZH_MSVC wchar_t buffer[LOCALE_NAME_MAX_LENGTH+1]={0}; GetSystemDefaultLocaleName(buffer, LOCALE_NAME_MAX_LENGTH); return Locale(buffer); #elif defined VCZH_GCC return Locale(L"en-US"); #endif } Locale Locale::UserDefault() { #if defined VCZH_MSVC wchar_t buffer[LOCALE_NAME_MAX_LENGTH+1]={0}; GetUserDefaultLocaleName(buffer, LOCALE_NAME_MAX_LENGTH); return Locale(buffer); #elif defined VCZH_GCC return Locale(L"en-US"); #endif } void Locale::Enumerate(collections::List& locales) { #if defined VCZH_MSVC EnumSystemLocalesEx(&Locale_EnumLocalesProcEx, LOCALE_ALL, (LPARAM)&locales, NULL); #elif defined VCZH_GCC locales.Add(Locale(L"en-US")); #endif } const WString& Locale::GetName()const { return localeName; } void Locale::GetShortDateFormats(collections::List& formats)const { #if defined VCZH_MSVC EnumDateFormatsExEx(&Locale_EnumDateFormatsProcExEx, localeName.Buffer(), DATE_SHORTDATE, (LPARAM)&formats); #elif defined VCZH_GCC formats.Add(L"MM/dd/yyyy"); formats.Add(L"yyyy-MM-dd"); #endif } void Locale::GetLongDateFormats(collections::List& formats)const { #if defined VCZH_MSVC EnumDateFormatsExEx(&Locale_EnumDateFormatsProcExEx, localeName.Buffer(), DATE_LONGDATE, (LPARAM)&formats); #elif defined VCZH_GCC formats.Add(L"dddd, dd MMMM yyyy"); #endif } void Locale::GetYearMonthDateFormats(collections::List& formats)const { #if defined VCZH_MSVC EnumDateFormatsExEx(&Locale_EnumDateFormatsProcExEx, localeName.Buffer(), DATE_YEARMONTH, (LPARAM)&formats); #elif defined VCZH_GCC formats.Add(L"yyyy MMMM"); #endif } void Locale::GetLongTimeFormats(collections::List& formats)const { #if defined VCZH_MSVC EnumTimeFormatsEx(&EnumTimeFormatsProcEx, localeName.Buffer(), 0, (LPARAM)&formats); #elif defined VCZH_GCC formats.Add(L"HH:mm:ss"); #endif } void Locale::GetShortTimeFormats(collections::List& formats)const { #if defined VCZH_MSVC EnumTimeFormatsEx(&EnumTimeFormatsProcEx, localeName.Buffer(), TIME_NOSECONDS, (LPARAM)&formats); #elif defined VCZH_GCC formats.Add(L"HH:mm"); formats.Add(L"hh:mm tt"); #endif } WString Locale::FormatDate(const WString& format, DateTime date)const { #if defined VCZH_MSVC SYSTEMTIME st=DateTimeToSystemTime(date); int length=GetDateFormatEx(localeName.Buffer(), 0, &st, format.Buffer(), NULL, 0, NULL); if(length==0) return L""; Array buffer(length); GetDateFormatEx(localeName.Buffer(), 0, &st, format.Buffer(), &buffer[0], (int)buffer.Count(), NULL); return &buffer[0]; #elif defined VCZH_GCC /* auto df = L"yyyy,MM,MMM,MMMM,dd,ddd,dddd"; auto ds = L"2000,01,Jan,January,02,Sun,Sunday"; auto tf = L"hh,HH,mm,ss,tt"; auto ts = L"01,13,02,03,PM"; */ WString result; const wchar_t* reading = format.Buffer(); while (*reading) { if (wcsncmp(reading, L"yyyy", 4) == 0) { WString fragment = itow(date.year); while (fragment.Length() < 4) fragment = L"0" + fragment; result += fragment; reading += 4; } else if (wcsncmp(reading, L"MMMM", 4) == 0) { result += GetLongMonthName(date.month); reading += 4; } else if (wcsncmp(reading, L"MMM", 3) == 0) { result += GetShortMonthName(date.month); reading += 3; } else if (wcsncmp(reading, L"MM", 2) == 0) { WString fragment = itow(date.month); while (fragment.Length() < 2) fragment = L"0" + fragment; result += fragment; reading += 2; } else if (wcsncmp(reading, L"dddd", 4) == 0) { result += GetLongDayOfWeekName(date.dayOfWeek); reading += 4; } else if (wcsncmp(reading, L"ddd", 3) == 0) { result += GetShortDayOfWeekName(date.dayOfWeek); reading += 3; } else if (wcsncmp(reading, L"dd", 2) == 0) { WString fragment = itow(date.day); while (fragment.Length() < 2) fragment = L"0" + fragment; result += fragment; reading += 2; } else if (wcsncmp(reading, L"hh", 2) == 0) { WString fragment = itow(date.hour > 12 ? date.hour - 12 : date.hour); while (fragment.Length() < 2) fragment = L"0" + fragment; result += fragment; reading += 2; } else if (wcsncmp(reading, L"HH", 2) == 0) { WString fragment = itow(date.hour); while (fragment.Length() < 2) fragment = L"0" + fragment; result += fragment; reading += 2; } else if (wcsncmp(reading, L"mm", 2) == 0) { WString fragment = itow(date.minute); while (fragment.Length() < 2) fragment = L"0" + fragment; result += fragment; reading += 2; } else if (wcsncmp(reading, L"ss", 2) == 0) { WString fragment = itow(date.second); while (fragment.Length() < 2) fragment = L"0" + fragment; result += fragment; reading += 2; } else if (wcsncmp(reading, L"tt", 2) == 0) { result += date.hour > 12 ? L"PM" : L"AM"; reading += 2; } else { result += *reading; reading++; } } return result; #endif } WString Locale::FormatTime(const WString& format, DateTime time)const { #if defined VCZH_MSVC SYSTEMTIME st=DateTimeToSystemTime(time); int length=GetTimeFormatEx(localeName.Buffer(), 0, &st, format.Buffer(), NULL, 0); if(length==0) return L""; Array buffer(length); GetTimeFormatEx(localeName.Buffer(), 0, &st, format.Buffer(),&buffer[0], (int)buffer.Count()); return &buffer[0]; #elif defined VCZH_GCC return FormatDate(format, time); #endif } WString Locale::FormatNumber(const WString& number)const { #ifdef VCZH_MSVC int length=GetNumberFormatEx(localeName.Buffer(), 0, number.Buffer(), NULL, NULL, 0); if(length==0) return L""; Array buffer(length); GetNumberFormatEx(localeName.Buffer(), 0, number.Buffer(), NULL, &buffer[0], (int)buffer.Count()); return &buffer[0]; #elif defined VCZH_GCC return number; #endif } WString Locale::FormatCurrency(const WString& currency)const { #ifdef VCZH_MSVC int length=GetCurrencyFormatEx(localeName.Buffer(), 0, currency.Buffer(), NULL, NULL, 0); if(length==0) return L""; Array buffer(length); GetCurrencyFormatEx(localeName.Buffer(), 0, currency.Buffer(), NULL, &buffer[0], (int)buffer.Count()); return &buffer[0]; #elif defined VCZH_GCC return currency; #endif } WString Locale::GetShortDayOfWeekName(vint dayOfWeek)const { #if defined VCZH_MSVC return FormatDate(L"ddd", DateTime::FromDateTime(2000, 1, 2+dayOfWeek)); #elif defined VCZH_GCC switch(dayOfWeek) { case 0: return L"Sun"; case 1: return L"Mon"; case 2: return L"Tue"; case 3: return L"Wed"; case 4: return L"Thu"; case 5: return L"Fri"; case 6: return L"Sat"; } return L""; #endif } WString Locale::GetLongDayOfWeekName(vint dayOfWeek)const { #if defined VCZH_MSVC return FormatDate(L"dddd", DateTime::FromDateTime(2000, 1, 2+dayOfWeek)); #elif defined VCZH_GCC switch(dayOfWeek) { case 0: return L"Sunday"; case 1: return L"Monday"; case 2: return L"Tuesday"; case 3: return L"Wednesday"; case 4: return L"Thursday"; case 5: return L"Friday"; case 6: return L"Saturday"; } return L""; #endif } WString Locale::GetShortMonthName(vint month)const { #if defined VCZH_MSVC return FormatDate(L"MMM", DateTime::FromDateTime(2000, month, 1)); #elif defined VCZH_GCC switch(month) { case 1: return L"Jan"; case 2: return L"Feb"; case 3: return L"Mar"; case 4: return L"Apr"; case 5: return L"May"; case 6: return L"Jun"; case 7: return L"Jul"; case 8: return L"Aug"; case 9: return L"Sep"; case 10: return L"Oct"; case 11: return L"Nov"; case 12: return L"Dec"; } return L""; #endif } WString Locale::GetLongMonthName(vint month)const { #if defined VCZH_MSVC return FormatDate(L"MMMM", DateTime::FromDateTime(2000, month, 1)); #elif defined VCZH_GCC switch(month) { case 1: return L"January"; case 2: return L"February"; case 3: return L"March"; case 4: return L"April"; case 5: return L"May"; case 6: return L"June"; case 7: return L"July"; case 8: return L"August"; case 9: return L"September"; case 10: return L"October"; case 11: return L"November"; case 12: return L"December"; } return L""; #endif } #ifdef VCZH_MSVC WString Locale::ToFullWidth(const WString& str)const { return Transform(localeName, str, LCMAP_FULLWIDTH); } WString Locale::ToHalfWidth(const WString& str)const { return Transform(localeName, str, LCMAP_HALFWIDTH); } WString Locale::ToHiragana(const WString& str)const { return Transform(localeName, str, LCMAP_HIRAGANA); } WString Locale::ToKatagana(const WString& str)const { return Transform(localeName, str, LCMAP_KATAKANA); } #endif WString Locale::ToLower(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_LOWERCASE); #elif defined VCZH_GCC return wlower(str); #endif } WString Locale::ToUpper(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_UPPERCASE); #elif defined VCZH_GCC return wupper(str); #endif } WString Locale::ToLinguisticLower(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING); #elif defined VCZH_GCC return wlower(str); #endif } WString Locale::ToLinguisticUpper(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING); #elif defined VCZH_GCC return wupper(str); #endif } #ifdef VCZH_MSVC WString Locale::ToSimplifiedChinese(const WString& str)const { return Transform(localeName, str, LCMAP_SIMPLIFIED_CHINESE); } WString Locale::ToTraditionalChinese(const WString& str)const { return Transform(localeName, str, LCMAP_TRADITIONAL_CHINESE); } WString Locale::ToTileCase(const WString& str)const { return Transform(localeName, str, LCMAP_TITLECASE); } #endif vint Locale::Compare(const WString& s1, const WString& s2, Normalization normalization)const { #if defined VCZH_MSVC switch(CompareStringEx(localeName.Buffer(), TranslateNormalization(normalization), s1.Buffer(), (int)s1.Length(), s2.Buffer(), (int)s2.Length(), NULL, NULL, NULL)) { case CSTR_LESS_THAN: return -1; case CSTR_GREATER_THAN: return 1; default: return 0; } #elif defined VCZH_GCC switch(normalization) { case Normalization::None: return wcscmp(s1.Buffer(), s2.Buffer()); case Normalization::IgnoreCase: return wcscasecmp(s1.Buffer(), s2.Buffer()); } #endif } vint Locale::CompareOrdinal(const WString& s1, const WString& s2)const { #if defined VCZH_MSVC switch(CompareStringOrdinal(s1.Buffer(), (int)s1.Length(), s2.Buffer(), (int)s2.Length(), FALSE)) { case CSTR_LESS_THAN: return -1; case CSTR_GREATER_THAN: return 1; default: return 0; } #elif defined VCZH_GCC return wcscmp(s1.Buffer(), s2.Buffer()); #endif } vint Locale::CompareOrdinalIgnoreCase(const WString& s1, const WString& s2)const { #if defined VCZH_MSVC switch(CompareStringOrdinal(s1.Buffer(), (int)s1.Length(), s2.Buffer(), (int)s2.Length(), TRUE)) { case CSTR_LESS_THAN: return -1; case CSTR_GREATER_THAN: return 1; default: return 0; } #elif defined VCZH_GCC return wcscasecmp(s1.Buffer(), s2.Buffer()); #endif } collections::Pair Locale::FindFirst(const WString& text, const WString& find, Normalization normalization)const { #if defined VCZH_MSVC int length=0; int result=FindNLSStringEx(localeName.Buffer(), FIND_FROMSTART | TranslateNormalization(normalization), text.Buffer(), (int)text.Length(), find.Buffer(), (int)find.Length(), &length, NULL, NULL, NULL); return result==-1?Pair(-1, 0):Pair(result, length); #elif defined VCZH_GCC if(text.Length() < find.Length() || find.Length() == 0) { return Pair(-1, 0); } const wchar_t* result = 0; switch(normalization) { case Normalization::None: { const wchar_t* reading = text.Buffer(); while(*reading) { if (wcsncmp(reading, find.Buffer(), find.Length())==0) { result = reading; break; } reading++; } } break; case Normalization::IgnoreCase: { const wchar_t* reading = text.Buffer(); while(*reading) { if (wcsncasecmp(reading, find.Buffer(), find.Length())==0) { result = reading; break; } reading++; } } break; } return result == nullptr ? Pair(-1, 0) : Pair(result - text.Buffer(), find.Length()); #endif } collections::Pair Locale::FindLast(const WString& text, const WString& find, Normalization normalization)const { #if defined VCZH_MSVC int length=0; int result=FindNLSStringEx(localeName.Buffer(), FIND_FROMEND | TranslateNormalization(normalization), text.Buffer(), (int)text.Length(), find.Buffer(), (int)find.Length(), &length, NULL, NULL, NULL); return result==-1?Pair(-1, 0):Pair(result, length); #elif defined VCZH_GCC if(text.Length() < find.Length() || find.Length() == 0) { return Pair(-1, 0); } const wchar_t* result = 0; switch(normalization) { case Normalization::None: { const wchar_t* reading = text.Buffer(); while(*reading) { if (wcsncmp(reading, find.Buffer(), find.Length())==0) { result = reading; } reading++; } } break; case Normalization::IgnoreCase: { const wchar_t* reading = text.Buffer(); while(*reading) { if (wcsncasecmp(reading, find.Buffer(), find.Length())==0) { result = reading; } reading++; } } break; } return result == nullptr ? Pair(-1, 0) : Pair(result - text.Buffer(), find.Length()); #endif } bool Locale::StartsWith(const WString& text, const WString& find, Normalization normalization)const { #if defined VCZH_MSVC int result=FindNLSStringEx(localeName.Buffer(), FIND_STARTSWITH | TranslateNormalization(normalization), text.Buffer(), (int)text.Length(), find.Buffer(), (int)find.Length(), NULL, NULL, NULL, NULL); return result!=-1; #elif defined VCZH_GCC if(text.Length() < find.Length() || find.Length() == 0) { return false; } switch(normalization) { case Normalization::None: return wcsncmp(text.Buffer(), find.Buffer(), find.Length()) == 0; case Normalization::IgnoreCase: return wcsncasecmp(text.Buffer(), find.Buffer(), find.Length()) == 0; } #endif } bool Locale::EndsWith(const WString& text, const WString& find, Normalization normalization)const { #if defined VCZH_MSVC int result=FindNLSStringEx(localeName.Buffer(), FIND_ENDSWITH | TranslateNormalization(normalization), text.Buffer(), (int)text.Length(), find.Buffer(), (int)find.Length(), NULL, NULL, NULL, NULL); return result!=-1; #elif defined VCZH_GCC if(text.Length() < find.Length() || find.Length() == 0) { return false; } switch(normalization) { case Normalization::None: return wcsncmp(text.Buffer() + text.Length() - find.Length(), find.Buffer(), find.Length()) == 0; case Normalization::IgnoreCase: return wcsncasecmp(text.Buffer() + text.Length() - find.Length(), find.Buffer(), find.Length()) == 0; } #endif } } /*********************************************************************** .\STRING.CPP ***********************************************************************/ #if defined VCZH_MSVC #elif defined VCZH_GCC #define _strtoi64 strtoll #define _strtoui64 strtoull #define _wcstoi64 wcstoll #define _wcstoui64 wcstoull #endif namespace vl { #if defined VCZH_GCC void _itoa_s(vint32_t value, char* buffer, size_t size, vint radix) { sprintf(buffer, "%d", value); } void _itow_s(vint32_t value, wchar_t* buffer, size_t size, vint radix) { swprintf(buffer, size - 1, L"%d", value); } void _i64toa_s(vint64_t value, char* buffer, size_t size, vint radix) { sprintf(buffer, "%ld", value); } void _i64tow_s(vint64_t value, wchar_t* buffer, size_t size, vint radix) { swprintf(buffer, size - 1, L"%ld", value); } void _uitoa_s(vuint32_t value, char* buffer, size_t size, vint radix) { sprintf(buffer, "%u", value); } void _uitow_s(vuint32_t value, wchar_t* buffer, size_t size, vint radix) { swprintf(buffer, size - 1, L"%u", value); } void _ui64toa_s(vuint64_t value, char* buffer, size_t size, vint radix) { sprintf(buffer, "%lu", value); } void _ui64tow_s(vuint64_t value, wchar_t* buffer, size_t size, vint radix) { swprintf(buffer, size - 1, L"%lu", value); } void _gcvt_s(char* buffer, size_t size, double value, vint numberOfDigits) { sprintf(buffer, "%f", value); char* point = strchr(buffer, '.'); if(!point) return; char* zero = buffer + strlen(buffer); while(zero[-1] == '0') { *--zero = '\0'; } if(zero[-1] == '.') *--zero = '\0'; } void _strlwr_s(char* buffer, size_t size) { while(*buffer) { *buffer=(char)tolower(*buffer); buffer++; } } void _strupr_s(char* buffer, size_t size) { while(*buffer) { *buffer=(char)toupper(*buffer); buffer++; } } void _wcslwr_s(wchar_t* buffer, size_t size) { while(*buffer) { *buffer=(char)towlower(*buffer); buffer++; } } void _wcsupr_s(wchar_t* buffer, size_t size) { while(*buffer) { *buffer=(char)towupper(*buffer); buffer++; } } void wcscpy_s(wchar_t* buffer, size_t size, const wchar_t* text) { wcscpy(buffer, text); } #endif vint atoi_test(const AString& string, bool& success) { char* endptr = 0; vint result = strtol(string.Buffer(), &endptr, 10); success = endptr == string.Buffer() + string.Length() && itoa(result) == string; return result; } vint wtoi_test(const WString& string, bool& success) { wchar_t* endptr = 0; vint result = wcstol(string.Buffer(), &endptr, 10); success = endptr == string.Buffer() + string.Length() && itow(result) == string; return result; } vint64_t atoi64_test(const AString& string, bool& success) { char* endptr = 0; vint64_t result = _strtoi64(string.Buffer(), &endptr, 10); success = endptr == string.Buffer() + string.Length() && i64toa(result) == string; return result; } vint64_t wtoi64_test(const WString& string, bool& success) { wchar_t* endptr = 0; vint64_t result = _wcstoi64(string.Buffer(), &endptr, 10); success = endptr == string.Buffer() + string.Length() && i64tow(result) == string; return result; } vuint atou_test(const AString& string, bool& success) { char* endptr = 0; vuint result = strtoul(string.Buffer(), &endptr, 10); success = endptr == string.Buffer() + string.Length() && utoa(result) == string; return result; } vuint wtou_test(const WString& string, bool& success) { wchar_t* endptr = 0; vuint result = wcstoul(string.Buffer(), &endptr, 10); success = endptr == string.Buffer() + string.Length() && utow(result) == string; return result; } vuint64_t atou64_test(const AString& string, bool& success) { char* endptr = 0; vuint64_t result = _strtoui64(string.Buffer(), &endptr, 10); success = endptr == string.Buffer() + string.Length() && u64toa(result) == string; return result; } vuint64_t wtou64_test(const WString& string, bool& success) { wchar_t* endptr = 0; vuint64_t result = _wcstoui64(string.Buffer(), &endptr, 10); success = endptr == string.Buffer() + string.Length() && u64tow(result) == string; return result; } double atof_test(const AString& string, bool& success) { char* endptr = 0; double result = strtod(string.Buffer(), &endptr); success = endptr == string.Buffer() + string.Length(); return result; } double wtof_test(const WString& string, bool& success) { wchar_t* endptr = 0; double result = wcstod(string.Buffer(), &endptr); success = endptr == string.Buffer() + string.Length(); return result; } vint atoi(const AString& string) { bool success = false; return atoi_test(string, success); } vint wtoi(const WString& string) { bool success = false; return wtoi_test(string, success); } vint64_t atoi64(const AString& string) { bool success = false; return atoi64_test(string, success); } vint64_t wtoi64(const WString& string) { bool success = false; return wtoi64_test(string, success); } vuint atou(const AString& string) { bool success = false; return atou_test(string, success); } vuint wtou(const WString& string) { bool success = false; return wtou_test(string, success); } vuint64_t atou64(const AString& string) { bool success = false; return atou64_test(string, success); } vuint64_t wtou64(const WString& string) { bool success = false; return wtou64_test(string, success); } double atof(const AString& string) { bool success = false; return atof_test(string, success); } double wtof(const WString& string) { bool success = false; return wtof_test(string, success); } AString itoa(vint number) { char buffer[100]; ITOA_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10); return buffer; } WString itow(vint number) { wchar_t buffer[100]; ITOW_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10); return buffer; } AString i64toa(vint64_t number) { char buffer[100]; I64TOA_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10); return buffer; } WString i64tow(vint64_t number) { wchar_t buffer[100]; I64TOW_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10); return buffer; } AString utoa(vuint number) { char buffer[100]; UITOA_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10); return buffer; } WString utow(vuint number) { wchar_t buffer[100]; UITOW_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10); return buffer; } AString u64toa(vuint64_t number) { char buffer[100]; UI64TOA_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10); return buffer; } WString u64tow(vuint64_t number) { wchar_t buffer[100]; UI64TOW_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10); return buffer; } AString ftoa(double number) { char buffer[320]; _gcvt_s(buffer, 320, number, 30); vint len = (vint)strlen(buffer); if (buffer[len - 1] == '.') { buffer[len - 1] = '\0'; } return buffer; } WString ftow(double number) { return atow(ftoa(number)); } vint _wtoa(const wchar_t* w, char* a, vint chars) { #if defined VCZH_MSVC return WideCharToMultiByte(CP_THREAD_ACP, 0, w, -1, a, (int)(a ? chars : 0), 0, 0); #elif defined VCZH_GCC return wcstombs(a, w, chars-1)+1; #endif } AString wtoa(const WString& string) { vint len = _wtoa(string.Buffer(), 0, 0); char* buffer = new char[len]; memset(buffer, 0, len*sizeof(*buffer)); _wtoa(string.Buffer(), buffer, (int)len); AString s = buffer; delete[] buffer; return s; } vint _atow(const char* a, wchar_t* w, vint chars) { #if defined VCZH_MSVC return MultiByteToWideChar(CP_THREAD_ACP, 0, a, -1, w, (int)(w ? chars : 0)); #elif defined VCZH_GCC return mbstowcs(w, a, chars-1)+1; #endif } WString atow(const AString& string) { vint len = _atow(string.Buffer(), 0, 0); wchar_t* buffer = new wchar_t[len]; memset(buffer, 0, len*sizeof(*buffer)); _atow(string.Buffer(), buffer, (int)len); WString s = buffer; delete[] buffer; return s; } AString alower(const AString& string) { AString result = string.Buffer(); _strlwr_s((char*)result.Buffer(), result.Length() + 1); return result; } WString wlower(const WString& string) { WString result = string.Buffer(); _wcslwr_s((wchar_t*)result.Buffer(), result.Length() + 1); return result; } AString aupper(const AString& string) { AString result = string.Buffer(); _strupr_s((char*)result.Buffer(), result.Length() + 1); return result; } WString wupper(const WString& string) { WString result = string.Buffer(); _wcsupr_s((wchar_t*)result.Buffer(), result.Length() + 1); return result; } WString LoremIpsum(vint bestLength, LoremIpsumCasing casing) { static const wchar_t* words[] = { L"lorem", L"ipsum", L"dolor", L"sit", L"amet", L"consectetur", L"adipiscing", L"elit", L"integer", L"nec", L"odio", L"praesent", L"libero", L"sed", L"cursus", L"ante", L"dapibus", L"diam", L"sed", L"nisi", L"nulla", L"quis", L"sem", L"at", L"nibh", L"elementum", L"imperdiet", L"duis", L"sagittis", L"ipsum", L"praesent", L"mauris", L"fusce", L"nec", L"tellus", L"sed", L"augue", L"semper", L"porta", L"mauris", L"massa", L"vestibulum", L"lacinia", L"arcu", L"eget", L"nulla", L"class", L"aptent", L"taciti", L"sociosqu", L"ad", L"litora", L"torquent", L"per", L"conubia", L"nostra", L"per", L"inceptos", L"himenaeos", L"curabitur", L"sodales", L"ligula", L"in", L"libero", L"sed", L"dignissim", L"lacinia", L"nunc", L"curabitur", L"tortor", L"pellentesque", L"nibh", L"aenean", L"quam", L"in", L"scelerisque", L"sem", L"at", L"dolor", L"maecenas", L"mattis", L"sed", L"convallis", L"tristique", L"sem", L"proin", L"ut", L"ligula", L"vel", L"nunc", L"egestas", L"porttitor", L"morbi", L"lectus", L"risus", L"iaculis", L"vel", L"suscipit", L"quis", L"luctus", L"non", L"massa", L"fusce", L"ac", L"turpis", L"quis", L"ligula", L"lacinia", L"aliquet", L"mauris", L"ipsum", L"nulla", L"metus", L"metus", L"ullamcorper", L"vel", L"tincidunt", L"sed", L"euismod", L"in", L"nibh", L"quisque", L"volutpat", L"condimentum", L"velit", L"class", L"aptent", L"taciti", L"sociosqu", L"ad", L"litora", L"torquent", L"per", L"conubia", L"nostra", L"per", L"inceptos", L"himenaeos", L"nam", L"nec", L"ante", L"sed", L"lacinia", L"urna", L"non", L"tincidunt", L"mattis", L"tortor", L"neque", L"adipiscing", L"diam", L"a", L"cursus", L"ipsum", L"ante", L"quis", L"turpis", L"nulla", L"facilisi", L"ut", L"fringilla", L"suspendisse", L"potenti", L"nunc", L"feugiat", L"mi", L"a", L"tellus", L"consequat", L"imperdiet", L"vestibulum", L"sapien", L"proin", L"quam", L"etiam", L"ultrices", L"suspendisse", L"in", L"justo", L"eu", L"magna", L"luctus", L"suscipit", L"sed", L"lectus", L"integer", L"euismod", L"lacus", L"luctus", L"magna", L"quisque", L"cursus", L"metus", L"vitae", L"pharetra", L"auctor", L"sem", L"massa", L"mattis", L"sem", L"at", L"interdum", L"magna", L"augue", L"eget", L"diam", L"vestibulum", L"ante", L"ipsum", L"primis", L"in", L"faucibus", L"orci", L"luctus", L"et", L"ultrices", L"posuere", L"cubilia", L"curae;", L"morbi", L"lacinia", L"molestie", L"dui", L"praesent", L"blandit", L"dolor", L"sed", L"non", L"quam", L"in", L"vel", L"mi", L"sit", L"amet", L"augue", L"congue", L"elementum", L"morbi", L"in", L"ipsum", L"sit", L"amet", L"pede", L"facilisis", L"laoreet", L"donec", L"lacus", L"nunc", L"viverra", L"nec", L"blandit", L"vel", L"egestas", L"et", L"augue", L"vestibulum", L"tincidunt", L"malesuada", L"tellus", L"ut", L"ultrices", L"ultrices", L"enim", L"curabitur", L"sit", L"amet", L"mauris", L"morbi", L"in", L"dui", L"quis", L"est", L"pulvinar", L"ullamcorper", L"nulla", L"facilisi", L"integer", L"lacinia", L"sollicitudin", L"massa", L"cras", L"metus", L"sed", L"aliquet", L"risus", L"a", L"tortor", L"integer", L"id", L"quam", L"morbi", L"mi", L"quisque", L"nisl", L"felis", L"venenatis", L"tristique", L"dignissim", L"in", L"ultrices", L"sit", L"amet", L"augue", L"proin", L"sodales", L"libero", L"eget", L"ante", L"nulla", L"quam", L"aenean", L"laoreet", L"vestibulum", L"nisi", L"lectus", L"commodo", L"ac", L"facilisis", L"ac", L"ultricies", L"eu", L"pede", L"ut", L"orci", L"risus", L"accumsan", L"porttitor", L"cursus", L"quis", L"aliquet", L"eget", L"justo", L"sed", L"pretium", L"blandit", L"orci", L"ut", L"eu", L"diam", L"at", L"pede", L"suscipit", L"sodales", L"aenean", L"lectus", L"elit", L"fermentum", L"non", L"convallis", L"id", L"sagittis", L"at", L"neque", L"nullam", L"mauris", L"orci", L"aliquet", L"et", L"iaculis", L"et", L"viverra", L"vitae", L"ligula", L"nulla", L"ut", L"felis", L"in", L"purus", L"aliquam", L"imperdiet", L"maecenas", L"aliquet", L"mollis", L"lectus", L"vivamus", L"consectetuer", L"risus", L"et", L"tortor" }; static vint index = 0; const vint WordCount = sizeof(words) / sizeof(*words); if (bestLength < 0) bestLength = 0; vint bufferLength = bestLength + 20; wchar_t* buffer = new wchar_t[bufferLength + 1]; buffer[0] = 0; vint used = 0; wchar_t* writing = buffer; while (used < bestLength) { if (used != 0) { *writing++ = L' '; used++; } vint wordSize = (vint)wcslen(words[index]); wcscpy_s(writing, bufferLength - used, words[index]); if (casing == LoremIpsumCasing::AllWordsUpperCase || (casing == LoremIpsumCasing::FirstWordUpperCase && used == 0)) { *writing -= L'a' - L'A'; } if (used != 0 && used + wordSize > bestLength) { vint deltaShort = bestLength - used + 1; vint deltaLong = used + wordSize - bestLength; if (deltaShort < deltaLong) { *--writing = 0; used--; break; } } writing += wordSize; used += wordSize; index = (index + 1) % WordCount; } WString result = buffer; delete[] buffer; return result; } WString LoremIpsumTitle(vint bestLength) { return LoremIpsum(bestLength, LoremIpsumCasing::AllWordsUpperCase); } WString LoremIpsumSentence(vint bestLength) { return LoremIpsum(bestLength, LoremIpsumCasing::FirstWordUpperCase) + L"."; } WString LoremIpsumParagraph(vint bestLength) { srand((unsigned)time(0)); auto casing = LoremIpsumCasing::FirstWordUpperCase; vint comma = 0; WString result; while (result.Length() < bestLength) { vint offset = bestLength - result.Length(); if (comma == 0) { comma = rand() % 4 + 1; } vint length = rand() % 45 + 15; if (offset < 20) { comma = 0; length = offset - 1; } else if (length > offset) { comma = 0; length = offset + rand() % 11 - 5; } result += LoremIpsum(length, casing); if (comma == 0) { result += L"."; break; } else if (comma == 1) { result += L". "; casing = LoremIpsumCasing::FirstWordUpperCase; } else { result += L", "; casing = LoremIpsumCasing::AllWordsLowerCase; } comma--; } return result; } } /*********************************************************************** .\THREADING.CPP ***********************************************************************/ #ifdef VCZH_MSVC namespace vl { using namespace threading_internal; using namespace collections; /*********************************************************************** WaitableObject ***********************************************************************/ namespace threading_internal { struct WaitableData { HANDLE handle; WaitableData(HANDLE _handle) :handle(_handle) { } }; } WaitableObject::WaitableObject() :waitableData(0) { } void WaitableObject::SetData(threading_internal::WaitableData* data) { waitableData=data; } bool WaitableObject::IsCreated() { return waitableData!=0; } bool WaitableObject::Wait() { return WaitForTime(INFINITE); } bool WaitableObject::WaitForTime(vint ms) { if(IsCreated()) { if(WaitForSingleObject(waitableData->handle, (DWORD)ms)==WAIT_OBJECT_0) { return true; } } return false; } bool WaitableObject::WaitAll(WaitableObject** objects, vint count) { Array handles(count); for(vint i=0;iwaitableData->handle; } DWORD result=WaitForMultipleObjects((DWORD)count, &handles[0], TRUE, INFINITE); return result==WAIT_OBJECT_0 || result==WAIT_ABANDONED_0; } bool WaitableObject::WaitAllForTime(WaitableObject** objects, vint count, vint ms) { Array handles(count); for(vint i=0;iwaitableData->handle; } DWORD result=WaitForMultipleObjects((DWORD)count, &handles[0], TRUE, (DWORD)ms); return result==WAIT_OBJECT_0 || result==WAIT_ABANDONED_0; } vint WaitableObject::WaitAny(WaitableObject** objects, vint count, bool* abandoned) { Array handles(count); for(vint i=0;iwaitableData->handle; } DWORD result=WaitForMultipleObjects((DWORD)count, &handles[0], FALSE, INFINITE); if(WAIT_OBJECT_0 <= result && result handles(count); for(vint i=0;iwaitableData->handle; } DWORD result=WaitForMultipleObjects((DWORD)count, &handles[0], FALSE, (DWORD)ms); if(WAIT_OBJECT_0 <= result && resultdeleteAfterStopped; ThreadLocalStorage::FixStorages(); try { procedure(this, argument); threadState=Thread::Stopped; ThreadLocalStorage::ClearStorages(); } catch (...) { ThreadLocalStorage::ClearStorages(); throw; } if(deleteAfterStopped) { delete this; } } public: ProceduredThread(Thread::ThreadProcedure _procedure, void* _argument, bool _deleteAfterStopped) :procedure(_procedure) ,argument(_argument) ,deleteAfterStopped(_deleteAfterStopped) { } }; class LambdaThread : public Thread { private: Func procedure; bool deleteAfterStopped; protected: void Run() { bool deleteAfterStopped = this->deleteAfterStopped; ThreadLocalStorage::FixStorages(); try { procedure(); threadState=Thread::Stopped; ThreadLocalStorage::ClearStorages(); } catch (...) { ThreadLocalStorage::ClearStorages(); throw; } if(deleteAfterStopped) { delete this; } } public: LambdaThread(const Func& _procedure, bool _deleteAfterStopped) :procedure(_procedure) ,deleteAfterStopped(_deleteAfterStopped) { } }; } void InternalThreadProc(Thread* thread) { thread->Run(); } DWORD WINAPI InternalThreadProcWrapper(LPVOID lpParameter) { InternalThreadProc((Thread*)lpParameter); return 0; } Thread::Thread() { internalData=new ThreadData; internalData->handle=CreateThread(NULL, 0, InternalThreadProcWrapper, this, CREATE_SUSPENDED, &internalData->id); threadState=Thread::NotStarted; SetData(internalData); } Thread::~Thread() { if (internalData) { Stop(); CloseHandle(internalData->handle); delete internalData; } } Thread* Thread::CreateAndStart(ThreadProcedure procedure, void* argument, bool deleteAfterStopped) { if(procedure) { Thread* thread=new ProceduredThread(procedure, argument, deleteAfterStopped); if(thread->Start()) { return thread; } else { delete thread; } } return 0; } Thread* Thread::CreateAndStart(const Func& procedure, bool deleteAfterStopped) { Thread* thread=new LambdaThread(procedure, deleteAfterStopped); if(thread->Start()) { return thread; } else { delete thread; } return 0; } void Thread::Sleep(vint ms) { ::Sleep((DWORD)ms); } vint Thread::GetCPUCount() { SYSTEM_INFO info; GetSystemInfo(&info); return info.dwNumberOfProcessors; } vint Thread::GetCurrentThreadId() { return (vint)::GetCurrentThreadId(); } bool Thread::Start() { if(threadState==Thread::NotStarted && internalData->handle!=NULL) { if(ResumeThread(internalData->handle)!=-1) { threadState=Thread::Running; return true; } } return false; } bool Thread::Stop() { if(internalData->handle!=NULL) { if (SuspendThread(internalData->handle) != -1) { threadState=Thread::Stopped; return true; } } return false; } Thread::ThreadState Thread::GetState() { return threadState; } void Thread::SetCPU(vint index) { SetThreadAffinityMask(internalData->handle, ((vint)1 << index)); } /*********************************************************************** Mutex ***********************************************************************/ namespace threading_internal { struct MutexData : public WaitableData { MutexData(HANDLE _handle) :WaitableData(_handle) { } }; } Mutex::Mutex() :internalData(0) { } Mutex::~Mutex() { if(internalData) { CloseHandle(internalData->handle); delete internalData; } } bool Mutex::Create(bool owned, const WString& name) { if(IsCreated())return false; BOOL aOwned=owned?TRUE:FALSE; LPCTSTR aName=name==L""?NULL:name.Buffer(); HANDLE handle=CreateMutex(NULL, aOwned, aName); if(handle) { internalData=new MutexData(handle); SetData(internalData); } return IsCreated(); } bool Mutex::Open(bool inheritable, const WString& name) { if(IsCreated())return false; BOOL aInteritable=inheritable?TRUE:FALSE; HANDLE handle=OpenMutex(SYNCHRONIZE, aInteritable, name.Buffer()); if(handle) { internalData=new MutexData(handle); SetData(internalData); } return IsCreated(); } bool Mutex::Release() { if(IsCreated()) { return ReleaseMutex(internalData->handle)!=0; } return false; } /*********************************************************************** Semaphore ***********************************************************************/ namespace threading_internal { struct SemaphoreData : public WaitableData { SemaphoreData(HANDLE _handle) :WaitableData(_handle) { } }; } Semaphore::Semaphore() :internalData(0) { } Semaphore::~Semaphore() { if(internalData) { CloseHandle(internalData->handle); delete internalData; } } bool Semaphore::Create(vint initialCount, vint maxCount, const WString& name) { if(IsCreated())return false; LONG aInitial=(LONG)initialCount; LONG aMax=(LONG)maxCount; LPCTSTR aName=name==L""?NULL:name.Buffer(); HANDLE handle=CreateSemaphore(NULL, aInitial, aMax, aName); if(handle) { internalData=new SemaphoreData(handle); SetData(internalData); } return IsCreated(); } bool Semaphore::Open(bool inheritable, const WString& name) { if(IsCreated())return false; BOOL aInteritable=inheritable?TRUE:FALSE; HANDLE handle=OpenSemaphore(SYNCHRONIZE, aInteritable, name.Buffer()); if(handle) { internalData=new SemaphoreData(handle); SetData(internalData); } return IsCreated(); } bool Semaphore::Release() { if(IsCreated()) { return Release(1)!=-1; } return false; } vint Semaphore::Release(vint count) { if(IsCreated()) { LONG previous=-1; if(ReleaseSemaphore(internalData->handle, (LONG)count, &previous)!=0) { return (vint)previous; } } return -1; } /*********************************************************************** EventObject ***********************************************************************/ namespace threading_internal { struct EventData : public WaitableData { EventData(HANDLE _handle) :WaitableData(_handle) { } }; } EventObject::EventObject() :internalData(0) { } EventObject::~EventObject() { if(internalData) { CloseHandle(internalData->handle); delete internalData; } } bool EventObject::CreateAutoUnsignal(bool signaled, const WString& name) { if(IsCreated())return false; BOOL aSignaled=signaled?TRUE:FALSE; LPCTSTR aName=name==L""?NULL:name.Buffer(); HANDLE handle=CreateEvent(NULL, FALSE, aSignaled, aName); if(handle) { internalData=new EventData(handle); SetData(internalData); } return IsCreated(); } bool EventObject::CreateManualUnsignal(bool signaled, const WString& name) { if(IsCreated())return false; BOOL aSignaled=signaled?TRUE:FALSE; LPCTSTR aName=name==L""?NULL:name.Buffer(); HANDLE handle=CreateEvent(NULL, TRUE, aSignaled, aName); if(handle) { internalData=new EventData(handle); SetData(internalData); } return IsCreated(); } bool EventObject::Open(bool inheritable, const WString& name) { if(IsCreated())return false; BOOL aInteritable=inheritable?TRUE:FALSE; HANDLE handle=OpenEvent(SYNCHRONIZE, aInteritable, name.Buffer()); if(handle) { internalData=new EventData(handle); SetData(internalData); } return IsCreated(); } bool EventObject::Signal() { if(IsCreated()) { return SetEvent(internalData->handle)!=0; } return false; } bool EventObject::Unsignal() { if(IsCreated()) { return ResetEvent(internalData->handle)!=0; } return false; } /*********************************************************************** ThreadPoolLite ***********************************************************************/ struct ThreadPoolQueueProcArgument { void(*proc)(void*); void* argument; }; DWORD WINAPI ThreadPoolQueueProc(void* argument) { Ptr proc=(ThreadPoolQueueProcArgument*)argument; ThreadLocalStorage::FixStorages(); try { proc->proc(proc->argument); ThreadLocalStorage::ClearStorages(); } catch (...) { ThreadLocalStorage::ClearStorages(); } return 0; } DWORD WINAPI ThreadPoolQueueFunc(void* argument) { Ptr> proc=(Func*)argument; ThreadLocalStorage::FixStorages(); try { (*proc.Obj())(); ThreadLocalStorage::ClearStorages(); } catch (...) { ThreadLocalStorage::ClearStorages(); } return 0; } ThreadPoolLite::ThreadPoolLite() { } ThreadPoolLite::~ThreadPoolLite() { } bool ThreadPoolLite::Queue(void(*proc)(void*), void* argument) { ThreadPoolQueueProcArgument* p=new ThreadPoolQueueProcArgument; p->proc=proc; p->argument=argument; if(QueueUserWorkItem(&ThreadPoolQueueProc, p, WT_EXECUTEDEFAULT)) { return true; } else { delete p; return false; } } bool ThreadPoolLite::Queue(const Func& proc) { Func* p=new Func(proc); if(QueueUserWorkItem(&ThreadPoolQueueFunc, p, WT_EXECUTEDEFAULT)) { return true; } else { delete p; return false; } } /*********************************************************************** CriticalSection ***********************************************************************/ namespace threading_internal { struct CriticalSectionData { CRITICAL_SECTION criticalSection; }; } CriticalSection::Scope::Scope(CriticalSection& _criticalSection) :criticalSection(&_criticalSection) { criticalSection->Enter(); } CriticalSection::Scope::~Scope() { criticalSection->Leave(); } CriticalSection::CriticalSection() { internalData=new CriticalSectionData; InitializeCriticalSection(&internalData->criticalSection); } CriticalSection::~CriticalSection() { DeleteCriticalSection(&internalData->criticalSection); delete internalData; } bool CriticalSection::TryEnter() { return TryEnterCriticalSection(&internalData->criticalSection)!=0; } void CriticalSection::Enter() { EnterCriticalSection(&internalData->criticalSection); } void CriticalSection::Leave() { LeaveCriticalSection(&internalData->criticalSection); } /*********************************************************************** ReaderWriterLock ***********************************************************************/ namespace threading_internal { struct ReaderWriterLockData { SRWLOCK lock; }; } ReaderWriterLock::ReaderScope::ReaderScope(ReaderWriterLock& _lock) :lock(&_lock) { lock->EnterReader(); } ReaderWriterLock::ReaderScope::~ReaderScope() { lock->LeaveReader(); } ReaderWriterLock::WriterScope::WriterScope(ReaderWriterLock& _lock) :lock(&_lock) { lock->EnterWriter(); } ReaderWriterLock::WriterScope::~WriterScope() { lock->LeaveWriter(); } ReaderWriterLock::ReaderWriterLock() :internalData(new threading_internal::ReaderWriterLockData) { InitializeSRWLock(&internalData->lock); } ReaderWriterLock::~ReaderWriterLock() { delete internalData; } bool ReaderWriterLock::TryEnterReader() { return TryAcquireSRWLockShared(&internalData->lock)!=0; } void ReaderWriterLock::EnterReader() { AcquireSRWLockShared(&internalData->lock); } void ReaderWriterLock::LeaveReader() { ReleaseSRWLockShared(&internalData->lock); } bool ReaderWriterLock::TryEnterWriter() { return TryAcquireSRWLockExclusive(&internalData->lock)!=0; } void ReaderWriterLock::EnterWriter() { AcquireSRWLockExclusive(&internalData->lock); } void ReaderWriterLock::LeaveWriter() { ReleaseSRWLockExclusive(&internalData->lock); } /*********************************************************************** ConditionVariable ***********************************************************************/ namespace threading_internal { struct ConditionVariableData { CONDITION_VARIABLE variable; }; } ConditionVariable::ConditionVariable() :internalData(new threading_internal::ConditionVariableData) { InitializeConditionVariable(&internalData->variable); } ConditionVariable::~ConditionVariable() { delete internalData; } bool ConditionVariable::SleepWith(CriticalSection& cs) { return SleepConditionVariableCS(&internalData->variable, &cs.internalData->criticalSection, INFINITE)!=0; } bool ConditionVariable::SleepWithForTime(CriticalSection& cs, vint ms) { return SleepConditionVariableCS(&internalData->variable, &cs.internalData->criticalSection, (DWORD)ms)!=0; } bool ConditionVariable::SleepWithReader(ReaderWriterLock& lock) { return SleepConditionVariableSRW(&internalData->variable, &lock.internalData->lock, INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED)!=0; } bool ConditionVariable::SleepWithReaderForTime(ReaderWriterLock& lock, vint ms) { return SleepConditionVariableSRW(&internalData->variable, &lock.internalData->lock, (DWORD)ms, CONDITION_VARIABLE_LOCKMODE_SHARED)!=0; } bool ConditionVariable::SleepWithWriter(ReaderWriterLock& lock) { return SleepConditionVariableSRW(&internalData->variable, &lock.internalData->lock, INFINITE, 0)!=0; } bool ConditionVariable::SleepWithWriterForTime(ReaderWriterLock& lock, vint ms) { return SleepConditionVariableSRW(&internalData->variable, &lock.internalData->lock, (DWORD)ms, 0)!=0; } void ConditionVariable::WakeOnePending() { WakeConditionVariable(&internalData->variable); } void ConditionVariable::WakeAllPendings() { WakeAllConditionVariable(&internalData->variable); } /*********************************************************************** SpinLock ***********************************************************************/ SpinLock::Scope::Scope(SpinLock& _spinLock) :spinLock(&_spinLock) { spinLock->Enter(); } SpinLock::Scope::~Scope() { spinLock->Leave(); } SpinLock::SpinLock() :token(0) { } SpinLock::~SpinLock() { } bool SpinLock::TryEnter() { return _InterlockedExchange(&token, 1)==0; } void SpinLock::Enter() { while(_InterlockedCompareExchange(&token, 1, 0)!=0) { while(token!=0) _mm_pause(); } } void SpinLock::Leave() { _InterlockedExchange(&token, 0); } /*********************************************************************** ThreadLocalStorage ***********************************************************************/ #define KEY ((DWORD&)key) ThreadLocalStorage::ThreadLocalStorage(Destructor _destructor) :destructor(_destructor) { static_assert(sizeof(key) >= sizeof(DWORD), "ThreadLocalStorage's key storage is not large enouth."); PushStorage(this); KEY = TlsAlloc(); CHECK_ERROR(KEY != TLS_OUT_OF_INDEXES, L"vl::ThreadLocalStorage::ThreadLocalStorage()#Failed to alloc new thread local storage index."); } ThreadLocalStorage::~ThreadLocalStorage() { TlsFree(KEY); } void* ThreadLocalStorage::Get() { CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Get()#Cannot access a disposed ThreadLocalStorage."); return TlsGetValue(KEY); } void ThreadLocalStorage::Set(void* data) { CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Set()#Cannot access a disposed ThreadLocalStorage."); TlsSetValue(KEY, data); } #undef KEY } #endif /*********************************************************************** ThreadLocalStorage Common Implementations ***********************************************************************/ namespace vl { void ThreadLocalStorage::Clear() { CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Clear()#Cannot access a disposed ThreadLocalStorage."); if(destructor) { if (auto data = Get()) { destructor(data); } } Set(nullptr); } void ThreadLocalStorage::Dispose() { CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Dispose()#Cannot access a disposed ThreadLocalStorage."); Clear(); disposed = true; } struct TlsStorageLink { ThreadLocalStorage* storage = nullptr; TlsStorageLink* next = nullptr; }; volatile bool tlsFixed = false; TlsStorageLink* tlsHead = nullptr; TlsStorageLink** tlsTail = &tlsHead; void ThreadLocalStorage::PushStorage(ThreadLocalStorage* storage) { CHECK_ERROR(!tlsFixed, L"vl::ThreadLocalStorage::PushStorage(ThreadLocalStorage*)#Cannot create new ThreadLocalStorage instance after calling ThreadLocalStorage::FixStorages()."); auto link = new TlsStorageLink; link->storage = storage; *tlsTail = link; tlsTail = &link->next; } void ThreadLocalStorage::FixStorages() { tlsFixed = true; } void ThreadLocalStorage::ClearStorages() { FixStorages(); auto current = tlsHead; while (current) { current->storage->Clear(); current = current->next; } } void ThreadLocalStorage::DisposeStorages() { FixStorages(); auto current = tlsHead; tlsHead = nullptr; tlsTail = nullptr; while (current) { current->storage->Dispose(); auto temp = current; current = current->next; delete temp; } } } /*********************************************************************** .\THREADINGLINUX.CPP ***********************************************************************/ #ifdef VCZH_GCC #include #include #include #include #if defined(__APPLE__) || defined(__APPLE_CC__) #include #endif namespace vl { using namespace threading_internal; using namespace collections; /*********************************************************************** Thread ***********************************************************************/ namespace threading_internal { struct ThreadData { pthread_t id; EventObject ev; }; class ProceduredThread : public Thread { private: Thread::ThreadProcedure procedure; void* argument; bool deleteAfterStopped; protected: void Run() { bool deleteAfterStopped = this->deleteAfterStopped; ThreadLocalStorage::FixStorages(); try { procedure(this, argument); threadState=Thread::Stopped; internalData->ev.Signal(); ThreadLocalStorage::ClearStorages(); } catch (...) { ThreadLocalStorage::ClearStorages(); throw; } if(deleteAfterStopped) { delete this; } } public: ProceduredThread(Thread::ThreadProcedure _procedure, void* _argument, bool _deleteAfterStopped) :procedure(_procedure) ,argument(_argument) ,deleteAfterStopped(_deleteAfterStopped) { } }; class LambdaThread : public Thread { private: Func procedure; bool deleteAfterStopped; protected: void Run() { bool deleteAfterStopped = this->deleteAfterStopped; ThreadLocalStorage::FixStorages(); try { procedure(); threadState=Thread::Stopped; internalData->ev.Signal(); ThreadLocalStorage::ClearStorages(); } catch (...) { ThreadLocalStorage::ClearStorages(); throw; } if(deleteAfterStopped) { delete this; } } public: LambdaThread(const Func& _procedure, bool _deleteAfterStopped) :procedure(_procedure) ,deleteAfterStopped(_deleteAfterStopped) { } }; } void InternalThreadProc(Thread* thread) { thread->Run(); } void* InternalThreadProcWrapper(void* lpParameter) { InternalThreadProc((Thread*)lpParameter); return 0; } Thread::Thread() { internalData=new ThreadData; internalData->ev.CreateManualUnsignal(false); threadState=Thread::NotStarted; } Thread::~Thread() { if (internalData) { Stop(); if (threadState!=Thread::NotStarted) { pthread_detach(internalData->id); } delete internalData; } } Thread* Thread::CreateAndStart(ThreadProcedure procedure, void* argument, bool deleteAfterStopped) { if(procedure) { Thread* thread=new ProceduredThread(procedure, argument, deleteAfterStopped); if(thread->Start()) { return thread; } else { delete thread; } } return 0; } Thread* Thread::CreateAndStart(const Func& procedure, bool deleteAfterStopped) { Thread* thread=new LambdaThread(procedure, deleteAfterStopped); if(thread->Start()) { return thread; } else { delete thread; } return 0; } void Thread::Sleep(vint ms) { if (ms >= 1000) { sleep(ms / 1000); } if (ms % 1000) { usleep((ms % 1000) * 1000); } } vint Thread::GetCPUCount() { return (vint)sysconf(_SC_NPROCESSORS_ONLN); } vint Thread::GetCurrentThreadId() { return (vint)::pthread_self(); } bool Thread::Start() { if(threadState==Thread::NotStarted) { if(pthread_create(&internalData->id, nullptr, &InternalThreadProcWrapper, this)==0) { threadState=Thread::Running; return true; } } return false; } bool Thread::Wait() { return internalData->ev.Wait(); } bool Thread::Stop() { if (threadState==Thread::Running) { if(pthread_cancel(internalData->id)==0) { threadState=Thread::Stopped; internalData->ev.Signal(); return true; } } return false; } Thread::ThreadState Thread::GetState() { return threadState; } /*********************************************************************** Mutex ***********************************************************************/ namespace threading_internal { struct MutexData { Semaphore sem; }; }; Mutex::Mutex() { internalData = new MutexData; } Mutex::~Mutex() { delete internalData; } bool Mutex::Create(bool owned, const WString& name) { return internalData->sem.Create(owned ? 0 : 1, 1, name); } bool Mutex::Open(bool inheritable, const WString& name) { return internalData->sem.Open(inheritable, name); } bool Mutex::Release() { return internalData->sem.Release(); } bool Mutex::Wait() { return internalData->sem.Wait(); } /*********************************************************************** Semaphore ***********************************************************************/ namespace threading_internal { struct SemaphoreData { sem_t semUnnamed; sem_t* semNamed = nullptr; }; } Semaphore::Semaphore() :internalData(0) { } Semaphore::~Semaphore() { if (internalData) { if (internalData->semNamed) { sem_close(internalData->semNamed); } else { sem_destroy(&internalData->semUnnamed); } delete internalData; } } bool Semaphore::Create(vint initialCount, vint maxCount, const WString& name) { if (internalData) return false; if (initialCount > maxCount) return false; internalData = new SemaphoreData; #if defined(__APPLE__) AString auuid; if(name.Length() == 0) { CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault); CFStringRef cfstr = CFUUIDCreateString(kCFAllocatorDefault, cfuuid); auuid = CFStringGetCStringPtr(cfstr, kCFStringEncodingASCII); CFRelease(cfstr); CFRelease(cfuuid); } auuid = auuid.Insert(0, "/"); // OSX SEM_NAME_LENGTH = 31 if(auuid.Length() >= 30) auuid = auuid.Sub(0, 30); if ((internalData->semNamed = sem_open(auuid.Buffer(), O_CREAT, O_RDWR, initialCount)) == SEM_FAILED) { delete internalData; internalData = 0; return false; } #else if (name == L"") { if(sem_init(&internalData->semUnnamed, 0, (int)initialCount) == -1) { delete internalData; internalData = 0; return false; } } else { AString astr = wtoa(name); if ((internalData->semNamed = sem_open(astr.Buffer(), O_CREAT, 0777, initialCount)) == SEM_FAILED) { delete internalData; internalData = 0; return false; } } #endif Release(initialCount); return true; } bool Semaphore::Open(bool inheritable, const WString& name) { if (internalData) return false; if (inheritable) return false; internalData = new SemaphoreData; if (!(internalData->semNamed = sem_open(wtoa(name).Buffer(), 0))) { delete internalData; internalData = 0; return false; } return true; } bool Semaphore::Release() { return Release(1); } vint Semaphore::Release(vint count) { for (vint i = 0; i < count; i++) { if (internalData->semNamed) { sem_post(internalData->semNamed); } else { sem_post(&internalData->semUnnamed); } } return true; } bool Semaphore::Wait() { if (internalData->semNamed) { return sem_wait(internalData->semNamed) == 0; } else { return sem_wait(&internalData->semUnnamed) == 0; } } /*********************************************************************** EventObject ***********************************************************************/ namespace threading_internal { struct EventData { bool autoReset; volatile bool signaled; CriticalSection mutex; ConditionVariable cond; volatile vint counter = 0; }; } EventObject::EventObject() { internalData = nullptr; } EventObject::~EventObject() { if (internalData) { delete internalData; } } bool EventObject::CreateAutoUnsignal(bool signaled, const WString& name) { if (name!=L"") return false; if (internalData) return false; internalData = new EventData; internalData->autoReset = true; internalData->signaled = signaled; return true; } bool EventObject::CreateManualUnsignal(bool signaled, const WString& name) { if (name!=L"") return false; if (internalData) return false; internalData = new EventData; internalData->autoReset = false; internalData->signaled = signaled; return true; } bool EventObject::Signal() { if (!internalData) return false; internalData->mutex.Enter(); internalData->signaled = true; if (internalData->counter) { if (internalData->autoReset) { internalData->cond.WakeOnePending(); internalData->signaled = false; } else { internalData->cond.WakeAllPendings(); } } internalData->mutex.Leave(); return true; } bool EventObject::Unsignal() { if (!internalData) return false; internalData->mutex.Enter(); internalData->signaled = false; internalData->mutex.Leave(); return true; } bool EventObject::Wait() { if (!internalData) return false; internalData->mutex.Enter(); if (internalData->signaled) { if (internalData->autoReset) { internalData->signaled = false; } } else { internalData->counter++; internalData->cond.SleepWith(internalData->mutex); internalData->counter--; } internalData->mutex.Leave(); return true; } /*********************************************************************** ThreadPoolLite ***********************************************************************/ namespace threading_internal { struct ThreadPoolTask { Func task; Ptr next; }; struct ThreadPoolData { Semaphore semaphore; EventObject taskFinishEvent; Ptr taskBegin; Ptr* taskEnd = nullptr; volatile bool stopping = false; List taskThreads; }; SpinLock threadPoolLock; ThreadPoolData* threadPoolData = nullptr; void ThreadPoolProc(Thread* thread, void* argument) { while (true) { Ptr task; threadPoolData->semaphore.Wait(); SPIN_LOCK(threadPoolLock) { if (threadPoolData->taskBegin) { task = threadPoolData->taskBegin; threadPoolData->taskBegin = task->next; } if (!threadPoolData->taskBegin) { threadPoolData->taskEnd = &threadPoolData->taskBegin; threadPoolData->taskFinishEvent.Signal(); } } if (task) { ThreadLocalStorage::FixStorages(); try { task->task(); ThreadLocalStorage::ClearStorages(); } catch (...) { ThreadLocalStorage::ClearStorages(); } } else if (threadPoolData->stopping) { return; } } } bool ThreadPoolQueue(const Func& proc) { SPIN_LOCK(threadPoolLock) { if (!threadPoolData) { threadPoolData = new ThreadPoolData; threadPoolData->semaphore.Create(0, 65536); threadPoolData->taskFinishEvent.CreateManualUnsignal(false); threadPoolData->taskEnd = &threadPoolData->taskBegin; for (vint i = 0; i < Thread::GetCPUCount() * 4; i++) { threadPoolData->taskThreads.Add(Thread::CreateAndStart(&ThreadPoolProc, nullptr, false)); } } if (threadPoolData) { if (threadPoolData->stopping) { return false; } auto task = MakePtr(); task->task = proc; *threadPoolData->taskEnd = task; threadPoolData->taskEnd = &task->next; threadPoolData->semaphore.Release(); threadPoolData->taskFinishEvent.Unsignal(); } } return true; } bool ThreadPoolStop(bool discardPendingTasks) { SPIN_LOCK(threadPoolLock) { if (!threadPoolData) return false; if (threadPoolData->stopping) return false; threadPoolData->stopping = true; if (discardPendingTasks) { threadPoolData->taskEnd = &threadPoolData->taskBegin; threadPoolData->taskBegin = nullptr; } threadPoolData->semaphore.Release(threadPoolData->taskThreads.Count()); } threadPoolData->taskFinishEvent.Wait(); for (vint i = 0; i < threadPoolData->taskThreads.Count(); i++) { auto thread = threadPoolData->taskThreads[i]; thread->Wait(); delete thread; } threadPoolData->taskThreads.Clear(); SPIN_LOCK(threadPoolLock) { delete threadPoolData; threadPoolData = nullptr; } return true; } } ThreadPoolLite::ThreadPoolLite() { } ThreadPoolLite::~ThreadPoolLite() { } bool ThreadPoolLite::Queue(void(*proc)(void*), void* argument) { return ThreadPoolQueue([proc, argument](){proc(argument);}); } bool ThreadPoolLite::Queue(const Func& proc) { return ThreadPoolQueue(proc); } bool ThreadPoolLite::Stop(bool discardPendingTasks) { return ThreadPoolStop(discardPendingTasks); } /*********************************************************************** CriticalSection ***********************************************************************/ namespace threading_internal { struct CriticalSectionData { pthread_mutex_t mutex; }; } CriticalSection::CriticalSection() { internalData = new CriticalSectionData; pthread_mutex_init(&internalData->mutex, nullptr); } CriticalSection::~CriticalSection() { pthread_mutex_destroy(&internalData->mutex); delete internalData; } bool CriticalSection::TryEnter() { return pthread_mutex_trylock(&internalData->mutex) == 0; } void CriticalSection::Enter() { pthread_mutex_lock(&internalData->mutex); } void CriticalSection::Leave() { pthread_mutex_unlock(&internalData->mutex); } CriticalSection::Scope::Scope(CriticalSection& _criticalSection) :criticalSection(&_criticalSection) { criticalSection->Enter(); } CriticalSection::Scope::~Scope() { criticalSection->Leave(); } /*********************************************************************** ReaderWriterLock ***********************************************************************/ namespace threading_internal { struct ReaderWriterLockData { pthread_rwlock_t rwlock; }; } ReaderWriterLock::ReaderWriterLock() { internalData = new ReaderWriterLockData; pthread_rwlock_init(&internalData->rwlock, nullptr); } ReaderWriterLock::~ReaderWriterLock() { pthread_rwlock_destroy(&internalData->rwlock); delete internalData; } bool ReaderWriterLock::TryEnterReader() { return pthread_rwlock_tryrdlock(&internalData->rwlock) == 0; } void ReaderWriterLock::EnterReader() { pthread_rwlock_rdlock(&internalData->rwlock); } void ReaderWriterLock::LeaveReader() { pthread_rwlock_unlock(&internalData->rwlock); } bool ReaderWriterLock::TryEnterWriter() { return pthread_rwlock_trywrlock(&internalData->rwlock) == 0; } void ReaderWriterLock::EnterWriter() { pthread_rwlock_wrlock(&internalData->rwlock); } void ReaderWriterLock::LeaveWriter() { pthread_rwlock_unlock(&internalData->rwlock); } ReaderWriterLock::ReaderScope::ReaderScope(ReaderWriterLock& _lock) :lock(&_lock) { lock->EnterReader(); } ReaderWriterLock::ReaderScope::~ReaderScope() { lock->LeaveReader(); } ReaderWriterLock::WriterScope::WriterScope(ReaderWriterLock& _lock) :lock(&_lock) { lock->EnterWriter(); } ReaderWriterLock::WriterScope::~WriterScope() { lock->LeaveReader(); } /*********************************************************************** ConditionVariable ***********************************************************************/ namespace threading_internal { struct ConditionVariableData { pthread_cond_t cond; }; } ConditionVariable::ConditionVariable() { internalData = new ConditionVariableData; pthread_cond_init(&internalData->cond, nullptr); } ConditionVariable::~ConditionVariable() { pthread_cond_destroy(&internalData->cond); delete internalData; } bool ConditionVariable::SleepWith(CriticalSection& cs) { return pthread_cond_wait(&internalData->cond, &cs.internalData->mutex) == 0; } void ConditionVariable::WakeOnePending() { pthread_cond_signal(&internalData->cond); } void ConditionVariable::WakeAllPendings() { pthread_cond_broadcast(&internalData->cond); } /*********************************************************************** SpinLock ***********************************************************************/ SpinLock::Scope::Scope(SpinLock& _spinLock) :spinLock(&_spinLock) { spinLock->Enter(); } SpinLock::Scope::~Scope() { spinLock->Leave(); } SpinLock::SpinLock() :token(0) { } SpinLock::~SpinLock() { } bool SpinLock::TryEnter() { return __sync_lock_test_and_set(&token, 1)==0; } void SpinLock::Enter() { while(__sync_val_compare_and_swap(&token, 0, 1)!=0) { while(token!=0) _mm_pause(); } } void SpinLock::Leave() { __sync_lock_test_and_set(&token, 0); } /*********************************************************************** ThreadLocalStorage ***********************************************************************/ #define KEY ((pthread_key_t&)key) ThreadLocalStorage::ThreadLocalStorage(Destructor _destructor) :destructor(_destructor) { static_assert(sizeof(key) >= sizeof(pthread_key_t), "ThreadLocalStorage's key storage is not large enouth."); PushStorage(this); auto error = pthread_key_create(&KEY, destructor); CHECK_ERROR(error != EAGAIN && error != ENOMEM, L"vl::ThreadLocalStorage::ThreadLocalStorage()#Failed to create a thread local storage index."); } ThreadLocalStorage::~ThreadLocalStorage() { pthread_key_delete(KEY); } void* ThreadLocalStorage::Get() { CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Get()#Cannot access a disposed ThreadLocalStorage."); return pthread_getspecific(KEY); } void ThreadLocalStorage::Set(void* data) { CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Set()#Cannot access a disposed ThreadLocalStorage."); pthread_setspecific(KEY, data); } #undef KEY } #endif /*********************************************************************** .\COLLECTIONS\PARTIALORDERING.CPP ***********************************************************************/ namespace vl { namespace collections { using namespace po; /*********************************************************************** PartialOrderingProcessor ***********************************************************************/ void PartialOrderingProcessor::InitNodes(vint itemCount) { nodes.Resize(itemCount); for (vint i = 0; i < itemCount; i++) { auto& node = nodes[i]; node.ins = &emptyList; node.outs = &emptyList; vint inIndex = ins.Keys().IndexOf(i); vint outIndex = outs.Keys().IndexOf(i); if (inIndex != -1) { node.ins = &ins.GetByIndex(inIndex); } if (outIndex != -1) { node.outs = &outs.GetByIndex(outIndex); } } } void PartialOrderingProcessor::VisitUnvisitedNode(po::Node& node, Array& reversedOrder, vint& used) { node.visited = true; for (vint i = node.outs->Count() - 1; i >= 0; i--) { auto& outNode = nodes[node.outs->Get(i)]; if (!outNode.visited) { VisitUnvisitedNode(outNode, reversedOrder, used); } } reversedOrder[used++] = (vint)(&node - &nodes[0]); } void PartialOrderingProcessor::AssignUnassignedNode(po::Node& node, vint componentIndex, vint& used) { node.component = componentIndex; firstNodesBuffer[used++] = (vint)(&node - &nodes[0]); for (vint i = 0; i < node.ins->Count(); i++) { auto& inNode = nodes[node.ins->Get(i)]; if (inNode.component == -1) { AssignUnassignedNode(inNode, componentIndex, used); } } } void PartialOrderingProcessor::Sort() { // Kosaraju's Algorithm CHECK_ERROR(components.Count() == 0, L"PartialOrdering::Sort()#Sorting twice is not allowed."); Array reversedOrder(nodes.Count()); { vint used = 0; for (vint i = nodes.Count() - 1; i >= 0; i--) { auto& node = nodes[i]; if (!node.visited) { VisitUnvisitedNode(node, reversedOrder, used); } } } firstNodesBuffer.Resize(nodes.Count()); { vint lastUsed = 0; vint used = 0; for (vint i = reversedOrder.Count() - 1; i >= 0; i--) { auto& node = nodes[reversedOrder[i]]; if (node.component == -1) { AssignUnassignedNode(node, components.Count(), used); Component component; component.firstNode = &firstNodesBuffer[lastUsed]; component.nodeCount = used - lastUsed; lastUsed = used; components.Add(component); } } } } } } /*********************************************************************** .\PARSING\PARSING.CPP ***********************************************************************/ namespace vl { namespace parsing { namespace tabling { using namespace definitions; using namespace analyzing; using namespace collections; using namespace regex; /*********************************************************************** ParsingGeneralParser ***********************************************************************/ ParsingGeneralParser::ParsingGeneralParser(Ptr _table) :table(_table) { } ParsingGeneralParser::~ParsingGeneralParser() { } Ptr ParsingGeneralParser::GetTable() { return table; } void ParsingGeneralParser::BeginParse() { } bool ParsingGeneralParser::Parse(ParsingState& state, ParsingTransitionProcessor& processor, collections::List>& errors) { BeginParse(); processor.Reset(); for(vint i=0;itoken==-1 || !token->completeToken) { errors.Add(new ParsingError(token, L"Unrecognizable token: \""+WString(token->reading, token->length)+L"\".")); } } while(true) { ParsingState::TransitionResult result=ParseStep(state, errors); if(!result) { const RegexToken* token=state.GetToken(state.GetCurrentToken()); errors.Add(new ParsingError(token, L"Internal error when parsing.")); return false; } else if(result.transitionType==ParsingState::TransitionResult::SkipToken) { if(state.GetCurrentTableTokenIndex()==ParsingTable::TokenFinish) { const RegexToken* token=state.GetToken(state.GetCurrentToken()); errors.Add(new ParsingError(token, L"Failed to recover error when reaching the end of the input.")); return false; } else { state.SkipCurrentToken(); continue; } } else if(!processor.Run(result)) { const RegexToken* token=state.GetToken(state.GetCurrentToken()); errors.Add(new ParsingError(token, L"Internal error when building the parsing tree.")); return false; } if(result.tableTokenIndex==ParsingTable::TokenFinish && !processor.GetProcessingAmbiguityBranch()) { break; } } return true; } Ptr ParsingGeneralParser::Parse(ParsingState& state, collections::List>& errors) { ParsingTreeBuilder builder; Parse(state, builder, errors); Ptr node=builder.GetNode(); if(!node) { errors.Add(new ParsingError(L"Internal error when building the parsing tree after a succeeded parsing process.")); return 0; } return node; } Ptr ParsingGeneralParser::Parse(const WString& input, const WString& rule, collections::List>& errors, vint codeIndex) { ParsingState state(input, table, codeIndex); if(state.Reset(rule)==-1) { errors.Add(new ParsingError(L"Rule \""+rule+L"\" does not exist.")); return 0; } return Parse(state, errors); } /*********************************************************************** ParsingStrictParser ***********************************************************************/ bool ParsingStrictParser::OnTestErrorRecoverExists() { return false; } void ParsingStrictParser::OnClearErrorRecover() { } ParsingState::TransitionResult ParsingStrictParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List>& errors) { const RegexToken* token=state.GetToken(state.GetCurrentToken()); errors.Add(new ParsingError(token, (token==0?L"Error happened during parsing when reaching the end of the input.":L"Error happened during parsing."))); return ParsingState::TransitionResult(); } ParsingStrictParser::ParsingStrictParser(Ptr _table) :ParsingGeneralParser(_table) { } ParsingStrictParser::~ParsingStrictParser() { } ParsingState::TransitionResult ParsingStrictParser::ParseStep(ParsingState& state, collections::List>& errors) { ParsingState::TransitionResult result; if (OnTestErrorRecoverExists()) { result = OnErrorRecover(state, -1, errors); } else { result = state.ReadToken(); if (result) { OnClearErrorRecover(); } else { vint currentTokenIndex = state.GetCurrentTableTokenIndex(); if (currentTokenIndex != -1) { result = OnErrorRecover(state, currentTokenIndex, errors); } } } return result; } /*********************************************************************** ParsingAutoRecoverParser ***********************************************************************/ ParsingAutoRecoverParser::RecoverFuture& ParsingAutoRecoverParser::GetRecoverFuture(vint index) { return recoverFutures[index]; } ParsingAutoRecoverParser::RecoverFuture& ParsingAutoRecoverParser::CreateRecoverFuture(vint index, vint previousIndex) { RecoverFuture* rf = 0; if (index >= recoverFutures.Count()) { CHECK_ERROR(index == recoverFutures.Count(), L"ParsingAutoRecoverParser::CreateRecoverFuture(vint, vint)#Wrong argument: index."); RecoverFuture recoverFuture; recoverFuture.future = new ParsingState::Future; index = recoverFutures.Add(recoverFuture); } rf = &GetRecoverFuture(index); rf->index = index; rf->previousIndex = previousIndex; return *rf; } bool ParsingAutoRecoverParser::OnTestErrorRecoverExists() { return recoveringFutureIndex != -1; } void ParsingAutoRecoverParser::OnClearErrorRecover() { recoveringFutureIndex = -1; } ParsingState::TransitionResult ParsingAutoRecoverParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List>& errors) { if(recoveringFutureIndex==-1) { List prioritizedTokens; prioritizedTokens.Add(ParsingTable::TokenFinish); CopyFrom( prioritizedTokens, Range(ParsingTable::UserTokenStart, table->GetTokenCount() - ParsingTable::UserTokenStart) ); prioritizedTokens.Add(ParsingTable::LeftRecursiveReduce); prioritizedTokens.Add(ParsingTable::NormalReduce); prioritizedTokens.Remove(currentTokenIndex); prioritizedTokens.Insert(0, currentTokenIndex); vint processingFutureIndex=-1; vint usedFutureCount=0; while(processingFutureIndexcurrentState==-1) continue; FOREACH(vint, currentTableTokenIndex, prioritizedTokens) { vint newInsertedTokenCount = previous.insertedTokenCount; if (currentTableTokenIndex != ParsingTable::NormalReduce && currentTableTokenIndex != ParsingTable::LeftRecursiveReduce) { newInsertedTokenCount++; } if (currentTableTokenIndex != currentTokenIndex && newInsertedTokenCount > maxInsertedTokenCount) { continue; } RecoverFuture& now = CreateRecoverFuture(usedFutureCount, previous.index); now.insertedTokenCount = newInsertedTokenCount; if(state.ReadTokenInFuture(currentTableTokenIndex, previous.future, now.future, 0)) { if(currentTableTokenIndex==currentTokenIndex) { if(previous.future) { recoveringFutureIndex = previous.index; RecoverFuture* rf = &GetRecoverFuture(previous.index); while(rf->future->previous) { RecoverFuture* prf = &GetRecoverFuture(rf->previousIndex); prf->nextIndex = rf->index; prf->future->next = rf->future; rf = prf; } recoveringFutureIndex = rf->index; } else { recoveringFutureIndex = 0; } goto FOUND_ERROR_RECOVER_SOLUTION; } else { usedFutureCount++; } } } } } FOUND_ERROR_RECOVER_SOLUTION: RecoverFuture* rf = 0; if (recoveringFutureIndex != -1) { rf = &GetRecoverFuture(recoveringFutureIndex); if(rf->future->next) { recoveringFutureIndex = rf->nextIndex; } else { recoveringFutureIndex = -1; } } if(rf) { return state.RunTransition(rf->future->selectedItem, 0); } else { return ParsingState::TransitionResult(ParsingState::TransitionResult::SkipToken); } } ParsingAutoRecoverParser::ParsingAutoRecoverParser(Ptr _table, vint _maxInsertedTokenCount) :ParsingStrictParser(_table) , recoveringFutureIndex(-1) , maxInsertedTokenCount(_maxInsertedTokenCount == -1 ? 4 : _maxInsertedTokenCount) { } ParsingAutoRecoverParser::~ParsingAutoRecoverParser() { FOREACH(RecoverFuture, future, recoverFutures) { delete future.future; } } void ParsingAutoRecoverParser::BeginParse() { recoveringFutureIndex = -1; ParsingStrictParser::BeginParse(); } /*********************************************************************** ParsingAmbiguousParser ***********************************************************************/ ParsingAmbiguousParser::ParsingAmbiguousParser(Ptr _table) :ParsingGeneralParser(_table) ,consumedDecisionCount(0) { } ParsingAmbiguousParser::~ParsingAmbiguousParser() { } void ParsingAmbiguousParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List& futures, vint& begin, vint& end, collections::List>& errors) { begin=end; } vint ParsingAmbiguousParser::GetResolvableFutureLevels(collections::List& futures, vint begin, vint end) { if(end-begin<2) { return 1; } List resolvingFutures; for(vint i=begin;icurrentState!=second->currentState || first->reduceStateCount!=second->reduceStateCount || first->shiftStates.Count()!=second->shiftStates.Count() ) { return level; } else { for(vint j=0;jshiftStates.Count();j++) { if(first->shiftStates[j]!=second->shiftStates[j]) { return level; } } } } level++; for(vint i=0;iprevious)) { return level; } } } } vint ParsingAmbiguousParser::SearchPathForOneStep(ParsingState& state, collections::List& futures, vint& begin, vint& end, collections::List>& errors) { futures.Add(state.ExploreCreateRootFuture()); vint previousBegin = 0; vint previousEnd = 1; vint resolvableFutureLevels = 0; bool errorRecovered = false; while(true) { // keep all futures that consumed a token in a list List consumedTokenFutures; vint processBegin = previousBegin; vint processEnd = previousEnd; while (processEnd > processBegin) { // explore the current token if (state.ExploreStep(futures, processBegin, processEnd - processBegin, futures)) { CopyFrom( consumedTokenFutures, From(futures) .Skip(processEnd) .Take(futures.Count() - processEnd), true ); futures.RemoveRange(processEnd, futures.Count() - processEnd); } // explore left recursive reduce and normal reduce state.ExploreLeftRecursiveReduce(futures, processBegin, processEnd - processBegin, futures); state.ExploreNormalReduce(futures, processBegin, processEnd - processBegin, futures); // if a token is consumed, then for those reduce futures, explore them until a token is consumed, and discard all failed futures processBegin = processEnd; processEnd = futures.Count(); } if (consumedTokenFutures.Count() == 0) { // failed to get any future that consumed a token, do error recovering vint tokenIndex = state.GetCurrentTableTokenIndex(); OnErrorRecover(state, tokenIndex, futures, previousBegin, previousEnd, errors); if (previousBegin == previousEnd) { break; } } else { state.SkipCurrentToken(); // put all futures that consumed a token from consumedTokenFutures back to future list previousBegin = futures.Count(); CopyFrom(futures, consumedTokenFutures, true); previousEnd = futures.Count(); // resolve all futures and see if all futures collapsed into a equivalent single future resolvableFutureLevels = GetResolvableFutureLevels(futures, previousBegin, previousEnd); if (resolvableFutureLevels != 0) { break; } } } begin = previousBegin; end = previousEnd; return resolvableFutureLevels; } vint ParsingAmbiguousParser::GetConflictReduceCount(collections::List& futures) { vint conflictReduceCount=-1; for(vint i=0;iselectedItem->instructions.Count(); vint secondIndex=second->selectedItem->instructions.Count(); while(--firstIndex>=0 && --secondIndex>=0) { ParsingTable::Instruction* firstIns=&first->selectedItem->instructions[firstIndex]; ParsingTable::Instruction* secondIns=&second->selectedItem->instructions[secondIndex]; if(firstIns && secondIns) { if(firstIns->instructionType==secondIns->instructionType && firstIns->nameParameter==secondIns->nameParameter && firstIns->stateParameter==secondIns->stateParameter && firstIns->value==secondIns->value ) { if(firstIns->instructionType==ParsingTable::Instruction::Reduce || firstIns->instructionType==ParsingTable::Instruction::LeftRecursiveReduce) { count++; } continue; } } break; } if(conflictReduceCount==-1 || conflictReduceCount>count) { conflictReduceCount=count; } } if(conflictReduceCount==-1) { conflictReduceCount=0; } return conflictReduceCount; } void ParsingAmbiguousParser::GetConflictReduceIndices(collections::List& futures, vint conflictReduceCount, collections::Array& conflictReduceIndices) { conflictReduceIndices.Resize(futures.Count()); for(vint i=0;iselectedItem->instructions.Count(); vint count=0; while(count0) { switch(future->selectedItem->instructions[--index].instructionType) { case ParsingTable::Instruction::Reduce: case ParsingTable::Instruction::LeftRecursiveReduce: count++; break; default:; } } conflictReduceIndices[i]=index; } } vint ParsingAmbiguousParser::GetAffectedStackNodeCount(collections::List& futures, collections::Array& conflictReduceIndices) { vint affectedStackNodeCount=-1; for(vint i=0;iselectedItem) { vint start=(future==futures[i]?conflictReduceIndices[i]:future->selectedItem->instructions.Count())-1; for(vint j=start;j>=0;j--) { switch(future->selectedItem->instructions[j].instructionType) { case ParsingTable::Instruction::Reduce: count++; break; case ParsingTable::Instruction::Shift: count--; break; default:; } } future=future->previous; } if(affectedStackNodeCount==-1) { affectedStackNodeCount=count; } else if(affectedStackNodeCount!=count) { return -1; } } return affectedStackNodeCount; } void ParsingAmbiguousParser::BuildSingleDecisionPath(ParsingState& state, ParsingState::Future* future, vint lastAvailableInstructionCount) { List> path; while(future && future->selectedToken!=-1) { path.Add(Pair(future->selectedItem, future->selectedRegexToken)); future = future->previous; } for (vint j = path.Count() - 1; j >= 0; j--) { if(j==0 && lastAvailableInstructionCount!=-1) { decisions.Add(state.RunTransition(path[j].key, path[j].value, 0, lastAvailableInstructionCount, false)); } else { decisions.Add(state.RunTransition(path[j].key, path[j].value)); } } } void ParsingAmbiguousParser::BuildAmbiguousDecisions(ParsingState& state, collections::List& futures, vint begin, vint end, vint resolvableFutureLevels, collections::List>& errors) { List resolvingFutures; CopyFrom( resolvingFutures, From(futures) .Skip(begin) .Take(end - begin) ); for (vint i = 1; i < resolvableFutureLevels; i++) { for(vint j=0;jprevious; } } Array conflictReduceIndices; vint conflictReduceCount=GetConflictReduceCount(resolvingFutures); GetConflictReduceIndices(resolvingFutures, conflictReduceCount, conflictReduceIndices); WString ambiguityNodeType, ambiguityRuleName; if(resolvingFutures[0]->selectedItem->instructions.Count()==conflictReduceIndices[0]) { vint rootStartState=state.GetParsingRuleStartState(); ambiguityNodeType=state.GetTable()->GetStateInfo(rootStartState).ruleAmbiguousType; ambiguityRuleName=state.GetParsingRule(); } else { ParsingTable::Instruction& ins=resolvingFutures[0]->selectedItem->instructions[conflictReduceIndices[0]]; ambiguityNodeType=state.GetTable()->GetStateInfo(ins.stateParameter).ruleAmbiguousType; ambiguityRuleName=state.GetTable()->GetStateInfo(ins.stateParameter).ruleName; } if(ambiguityNodeType==L"") { const RegexToken* token=state.GetToken(state.GetCurrentToken()); errors.Add(new ParsingError(token, L"Ambiguity happens when reducing rule \""+ambiguityRuleName+L"\" but this rule does not have an associated ambiguous node type.")); return; } vint affectedStackNodeCount=GetAffectedStackNodeCount(resolvingFutures, conflictReduceIndices); if(affectedStackNodeCount==-1) { const RegexToken* token=state.GetToken(state.GetCurrentToken()); errors.Add(new ParsingError(token, (token==0?L"Failed to pass ambiguity checking during parsing when reaching to the end of the input.":L"Failed to pass ambiguity checking during parsing."))); return; } Ptr stateGroup; for(vint i=0;iinstructions.Count()-start, true)); } } } ParsingState::Future* lastFuture=futures[end-1]; ParsingState::Future** futureCleaner=&lastFuture; for(int i=1;iprevious; } *futureCleaner=0; if(lastFuture) { BuildSingleDecisionPath(state, lastFuture, -1); } } void ParsingAmbiguousParser::BuildDecisions(ParsingState& state, collections::List& futures, vint begin, vint end, vint resolvableFutureLevels, collections::List>& errors) { if(end-begin==0) { const RegexToken* token=state.GetToken(state.GetCurrentToken()); errors.Add(new ParsingError(token, (token==0?L"Error happened during parsing when reaching to the end of the input.":L"Error happened during parsing."))); } else if(end-begin==1) { BuildSingleDecisionPath(state, futures[begin], -1); } else { BuildAmbiguousDecisions(state, futures, begin, end, resolvableFutureLevels, errors); } } ParsingState::TransitionResult ParsingAmbiguousParser::ParseStep(ParsingState& state, collections::List>& errors) { if(decisions.Count()==consumedDecisionCount) { List futures; vint resultBegin=0; vint resultEnd=0; vint resolvableFutureLevels=SearchPathForOneStep(state, futures, resultBegin, resultEnd, errors); BuildDecisions(state, futures, resultBegin, resultEnd, resolvableFutureLevels, errors); FOREACH(ParsingState::Future*, future, futures) { delete future; } } if(decisions.Count()>consumedDecisionCount) { ParsingState::TransitionResult result=decisions[consumedDecisionCount++]; if(consumedDecisionCount==decisions.Count()) { decisions.Clear(); consumedDecisionCount=0; } return result; } else { return ParsingState::TransitionResult(); } } void ParsingAmbiguousParser::BeginParse() { decisions.Clear(); consumedDecisionCount=0; ParsingGeneralParser::BeginParse(); } /*********************************************************************** ParsingAutoRecoverAmbiguousParser ***********************************************************************/ void ParsingAutoRecoverAmbiguousParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List& futures, vint& begin, vint& end, collections::List>& errors) { vint insertedTokenCount = 0; while (insertedTokenCount++ < maxInsertedTokenCount) { // keep all futures that consumed a token in a list List consumedTokenFutures; vint processBegin = begin; vint processEnd = end; while (processEnd > processBegin) { // explore all tokens for (vint i = processBegin; i < processEnd; i++) { state.Explore(ParsingTable::TokenFinish, futures[i], futures); for (vint token = ParsingTable::UserTokenStart; token < state.GetTable()->GetTokenCount(); token++) { state.Explore(token, futures[i], futures); } } // copy all futures that consumed a token to consumedTokenFutures if (futures.Count() > processEnd) { CopyFrom( consumedTokenFutures, From(futures) .Skip(processEnd) .Take(futures.Count() - processEnd), true ); futures.RemoveRange(processEnd, futures.Count() - processEnd); } // explore left recursive reduce and normal reduce state.ExploreLeftRecursiveReduce(futures, processBegin, processEnd - processBegin, futures); state.ExploreNormalReduce(futures, processBegin, processEnd - processBegin, futures); // if a token is consumed, then for those reduce futures, explore them until a token is consumed, and discard all failed futures processBegin = processEnd; processEnd = futures.Count(); } if (consumedTokenFutures.Count() == 0) { // failed to get any future that consumed a token goto ERROR_RECOVERY_FAILED; } else { // try to see if the target token is reached List recoveryFutures; FOREACH(ParsingState::Future*, future, consumedTokenFutures) { if (future->selectedToken == currentTokenIndex) { // because this is reached by error recoverying, so all futures in availableFutures should have previous futures recoveryFutures.Add(future->previous); } } if (recoveryFutures.Count()>0) { // finally reached the expected currentTokenIndex // move these previous futures to the end // then the original parser algorith, will use these previous futures to reach the currentTokenIndex in the next step FOREACH(ParsingState::Future*, future, recoveryFutures) { futures.Remove(future); futures.Add(future); } begin = futures.Count() - recoveryFutures.Count(); end = futures.Count(); // delete all futures in consumedTokenFutures FOREACH(ParsingState::Future*, future, consumedTokenFutures) { delete future; } goto ERROR_RECOVERY_SUCCEEDED; } else { // put all futures that consumed a token from consumedTokenFutures back to future list begin = futures.Count(); CopyFrom(futures, consumedTokenFutures, true); end = futures.Count(); } } } // if the maxInsertedTokenCount is exceeded, then we get here ERROR_RECOVERY_FAILED: begin = end = futures.Count(); return; ERROR_RECOVERY_SUCCEEDED: return; } ParsingAutoRecoverAmbiguousParser::ParsingAutoRecoverAmbiguousParser(Ptr _table, vint _maxInsertedTokenCount) :ParsingAmbiguousParser(_table) , maxInsertedTokenCount(_maxInsertedTokenCount == -1 ? 4 : _maxInsertedTokenCount) { } ParsingAutoRecoverAmbiguousParser::~ParsingAutoRecoverAmbiguousParser() { } /*********************************************************************** Helper Functions ***********************************************************************/ Ptr CreateStrictParser(Ptr table) { if(table) { if(table->GetAmbiguity()) { return new ParsingAmbiguousParser(table); } else { return new ParsingStrictParser(table); } } else { return 0; } } Ptr CreateAutoRecoverParser(Ptr table) { if(table) { if(table->GetAmbiguity()) { return new ParsingAutoRecoverAmbiguousParser(table); } else { return new ParsingAutoRecoverParser(table); } } else { return 0; } } Ptr CreateBootstrapStrictParser() { List> errors; Ptr definition=CreateParserDefinition(); Ptr table=GenerateTable(definition, false, errors); return CreateStrictParser(table); } Ptr CreateBootstrapAutoRecoverParser() { List> errors; Ptr definition=CreateParserDefinition(); Ptr table=GenerateTable(definition, false, errors); return CreateAutoRecoverParser(table); } } } } /*********************************************************************** Reflection ***********************************************************************/ #ifndef VCZH_DEBUG_NO_REFLECTION namespace vl { namespace reflection { namespace description { using namespace parsing; PARSINGREFLECTION_TYPELIST(IMPL_VL_TYPE_INFO) /*********************************************************************** Type Declaration ***********************************************************************/ #define _ , BEGIN_STRUCT_MEMBER(ParsingTextPos) STRUCT_MEMBER(index) STRUCT_MEMBER(row) STRUCT_MEMBER(column) END_STRUCT_MEMBER(ParsingTextPos) BEGIN_STRUCT_MEMBER(ParsingTextRange) STRUCT_MEMBER(start) STRUCT_MEMBER(end) END_STRUCT_MEMBER(ParsingTextRange) BEGIN_CLASS_MEMBER(ParsingTreeNode) CLASS_MEMBER_PROPERTY_FAST(CodeRange) CLASS_MEMBER_PROPERTY_READONLY_FAST(Parent) CLASS_MEMBER_PROPERTY_READONLY_FAST(SubNodes) CLASS_MEMBER_METHOD(Clone, NO_PARAMETER) CLASS_MEMBER_METHOD(InitializeQueryCache, NO_PARAMETER) CLASS_MEMBER_METHOD(ClearQueryCache, NO_PARAMETER) CLASS_MEMBER_METHOD_OVERLOAD(FindSubNode, {L"position"}, ParsingTreeNode*(ParsingTreeNode::*)(const ParsingTextPos&)) CLASS_MEMBER_METHOD_OVERLOAD(FindSubNode, {L"range"}, ParsingTreeNode*(ParsingTreeNode::*)(const ParsingTextRange&)) CLASS_MEMBER_METHOD_OVERLOAD(FindDeepestNode, {L"position"}, ParsingTreeNode*(ParsingTreeNode::*)(const ParsingTextPos&)) CLASS_MEMBER_METHOD_OVERLOAD(FindDeepestNode, {L"range"}, ParsingTreeNode*(ParsingTreeNode::*)(const ParsingTextRange&)) END_CLASS_MEMBER(ParsingTreeNode) BEGIN_CLASS_MEMBER(ParsingTreeToken) CLASS_MEMBER_CONSTRUCTOR(Ptr(const WString&, vint), {L"value" _ L"tokenIndex"}) CLASS_MEMBER_PROPERTY_FAST(TokenIndex) CLASS_MEMBER_PROPERTY_FAST(Value) END_CLASS_MEMBER(ParsingTreeToken) BEGIN_CLASS_MEMBER(ParsingTreeObject) CLASS_MEMBER_CONSTRUCTOR(Ptr(const WString&), {L"type"}) CLASS_MEMBER_PROPERTY_FAST(Type) CLASS_MEMBER_PROPERTY_READONLY_FAST(Members) CLASS_MEMBER_PROPERTY_READONLY_FAST(MemberNames) CLASS_MEMBER_PROPERTY_READONLY_FAST(CreatorRules) CLASS_MEMBER_METHOD(GetMember, {L"name"}) CLASS_MEMBER_METHOD(SetMember, {L"name" _ L"node"}) END_CLASS_MEMBER(ParsingTreeObject) BEGIN_CLASS_MEMBER(ParsingTreeArray) CLASS_MEMBER_CONSTRUCTOR(Ptr(const WString&), {L"elementType"}) CLASS_MEMBER_PROPERTY_FAST(ElementType) CLASS_MEMBER_PROPERTY_READONLY_FAST(Items) CLASS_MEMBER_METHOD(GetItem, {L"index"}) CLASS_MEMBER_METHOD(SetItem, {L"index" _ L"node"}) CLASS_MEMBER_METHOD(AddItem, {L"node"}) CLASS_MEMBER_METHOD(InsertItem, {L"index" _ L"node"}) CLASS_MEMBER_METHOD_OVERLOAD(RemoveItem, {L"index"}, bool(ParsingTreeArray::*)(vint)) CLASS_MEMBER_METHOD_OVERLOAD(RemoveItem, {L"node"}, bool(ParsingTreeArray::*)(ParsingTreeNode*)) CLASS_MEMBER_METHOD(IndexOfItem, {L"node"}) CLASS_MEMBER_METHOD(ContainsItem, {L"node"}) CLASS_MEMBER_METHOD(Clone, NO_PARAMETER) CLASS_MEMBER_METHOD_RENAME(GetCount, Count, NO_PARAMETER) CLASS_MEMBER_PROPERTY_READONLY(Count, GetCount) END_CLASS_MEMBER(ParsingTreeArray) BEGIN_CLASS_MEMBER(ParsingTreeCustomBase) CLASS_MEMBER_FIELD(codeRange) CLASS_MEMBER_FIELD(creatorRules) END_CLASS_MEMBER(ParsingTreeCustomBase) BEGIN_CLASS_MEMBER(ParsingToken) CLASS_MEMBER_BASE(ParsingTreeCustomBase) CLASS_MEMBER_FIELD(tokenIndex) CLASS_MEMBER_FIELD(value) END_CLASS_MEMBER(ParsingToken) BEGIN_CLASS_MEMBER(ParsingError) CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER) CLASS_MEMBER_CONSTRUCTOR(Ptr(const WString&), {L"errorMessage"}) CLASS_MEMBER_CONSTRUCTOR(Ptr(ParsingTreeCustomBase*, const WString&), {L"parsingTree" _ L"errorMessage"}) CLASS_MEMBER_FIELD(codeRange) CLASS_MEMBER_FIELD(parsingTree) CLASS_MEMBER_FIELD(errorMessage) END_CLASS_MEMBER(ParsingError) #undef _ } } } #endif namespace vl { namespace reflection { namespace description { /*********************************************************************** Type Loader ***********************************************************************/ #ifndef VCZH_DEBUG_NO_REFLECTION class ParsingTypeLoader : public Object, public ITypeLoader { public: void Load(ITypeManager* manager) { PARSINGREFLECTION_TYPELIST(ADD_TYPE_INFO) } void Unload(ITypeManager* manager) { } }; #endif bool LoadParsingTypes() { #ifndef VCZH_DEBUG_NO_REFLECTION ITypeManager* manager=GetGlobalTypeManager(); if(manager) { Ptr loader=new ParsingTypeLoader; return manager->AddTypeLoader(loader); } #endif return false; } } } } /*********************************************************************** .\PARSING\PARSINGANALYZER.CPP ***********************************************************************/ namespace vl { namespace parsing { using namespace collections; using namespace definitions; namespace analyzing { /*********************************************************************** ParsingSymbol ***********************************************************************/ bool ParsingSymbol::AddSubSymbol(ParsingSymbol* subSymbol) { if(subSymbol->GetParentSymbol()) return false; if(subSymbolMap.Keys().IndexOf(subSymbol->GetName())!=-1) return false; switch(type) { case Global: switch(subSymbol->GetType()) { case EnumType: break; case ClassType: break; case TokenDef: break; case RuleDef: break; default: return false; } break; case EnumType: switch(subSymbol->GetType()) { case EnumItem: break; default: return false; } break; case ClassType: switch(subSymbol->GetType()) { case EnumType: case ClassType: case ClassField: break; default: return false; } break; default: return false; } subSymbol->parentSymbol=this; subSymbolList.Add(subSymbol); subSymbolMap.Add(subSymbol->GetName(), subSymbol); return true; } ParsingSymbol::ParsingSymbol(ParsingSymbolManager* _manager, SymbolType _type, const WString& _name, ParsingSymbol* _descriptorSymbol, const WString& _descriptorString) :manager(_manager) ,type(_type) ,name(_name) ,descriptorSymbol(_descriptorSymbol) ,descriptorString(_descriptorString) ,parentSymbol(0) ,arrayTypeSymbol(0) { } ParsingSymbol::~ParsingSymbol() { } ParsingSymbolManager* ParsingSymbol::GetManager() { return manager; } ParsingSymbol::SymbolType ParsingSymbol::GetType() { return type; } const WString& ParsingSymbol::GetName() { return name; } vint ParsingSymbol::GetSubSymbolCount() { return subSymbolList.Count(); } ParsingSymbol* ParsingSymbol::GetSubSymbol(vint index) { if(0<=index && indexGetSubSymbolByName(name); if(subSymbol) { return subSymbol; } else { scope=scope->GetDescriptorSymbol(); } } } return 0; } ParsingSymbol* ParsingSymbol::SearchCommonBaseClass(ParsingSymbol* classType) { if(type==ParsingSymbol::ClassType && classType->GetType()==ParsingSymbol::ClassType) { vint aCount=0; vint bCount=0; ParsingSymbol* a=this; ParsingSymbol* b=classType; while(a || b) { if(a) { aCount++; a=a->GetDescriptorSymbol(); } if(b) { bCount++; b=b->GetDescriptorSymbol(); } } a=this; b=classType; vint min=aCountmin;i--) { a=a->GetDescriptorSymbol(); } for(vint i=bCount;i>min;i--) { b=b->GetDescriptorSymbol(); } while(a!=b) { a=a->GetDescriptorSymbol(); b=b->GetDescriptorSymbol(); } return a; } return 0; } /*********************************************************************** ParsingSymbolManager ***********************************************************************/ bool ParsingSymbolManager::TryAddSubSymbol(Ptr subSymbol, ParsingSymbol* parentSymbol) { if(parentSymbol->AddSubSymbol(subSymbol.Obj())) { createdSymbols.Add(subSymbol); return true; } return false; } ParsingSymbolManager::ParsingSymbolManager() { globalSymbol=new ParsingSymbol(this, ParsingSymbol::Global, L"", 0, L""); tokenTypeSymbol=new ParsingSymbol(this, ParsingSymbol::TokenType, L"token", 0, L""); createdSymbols.Add(globalSymbol); createdSymbols.Add(tokenTypeSymbol); } ParsingSymbolManager::~ParsingSymbolManager() { } ParsingSymbol* ParsingSymbolManager::GetGlobal() { return globalSymbol; } ParsingSymbol* ParsingSymbolManager::GetTokenType() { return tokenTypeSymbol; } ParsingSymbol* ParsingSymbolManager::GetArrayType(ParsingSymbol* elementType) { if(elementType->IsType()) { if(!elementType->arrayTypeSymbol) { elementType->arrayTypeSymbol=new ParsingSymbol(this, ParsingSymbol::ArrayType, L"", elementType, L""); createdSymbols.Add(elementType->arrayTypeSymbol); } return elementType->arrayTypeSymbol; } else { return 0; } } ParsingSymbol* ParsingSymbolManager::AddClass(definitions::ParsingDefinitionClassDefinition* classDef, ParsingSymbol* baseType, ParsingSymbol* parentType) { if((!baseType || baseType->GetType()==ParsingSymbol::ClassType) && (!parentType || parentType->IsType())) { ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::ClassType, classDef->name, baseType, L""); if(TryAddSubSymbol(symbol, parentType?parentType:globalSymbol)) { symbolClassDefinitionCache.Add(symbol, classDef); classDefinitionSymbolCache.Add(classDef, symbol); return symbol; } } return 0; } ParsingSymbol* ParsingSymbolManager::AddField(const WString& name, ParsingSymbol* classType, ParsingSymbol* fieldType) { if(classType && classType->GetType()==ParsingSymbol::ClassType && fieldType && fieldType->IsType()) { ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::ClassField, name, fieldType, L""); if(TryAddSubSymbol(symbol, classType)) { return symbol; } } return 0; } ParsingSymbol* ParsingSymbolManager::AddEnum(const WString& name, ParsingSymbol* parentType) { if(!parentType || parentType->GetType()==ParsingSymbol::ClassType) { ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::EnumType, name, 0, L""); if(TryAddSubSymbol(symbol, parentType?parentType:globalSymbol)) { return symbol; } } return 0; } ParsingSymbol* ParsingSymbolManager::AddEnumItem(const WString& name, ParsingSymbol* enumType) { if(enumType && enumType->GetType()==ParsingSymbol::EnumType) { ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::EnumItem, name, enumType, L""); if(TryAddSubSymbol(symbol, enumType)) { return symbol; } } return 0; } ParsingSymbol* ParsingSymbolManager::AddTokenDefinition(const WString& name, const WString& regex) { ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::TokenDef, name, tokenTypeSymbol, regex); if(TryAddSubSymbol(symbol, globalSymbol)) { return symbol; } return 0; } ParsingSymbol* ParsingSymbolManager::AddRuleDefinition(const WString& name, ParsingSymbol* ruleType) { if(ruleType && ruleType->IsType()) { ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::RuleDef, name, ruleType, L""); if(TryAddSubSymbol(symbol, globalSymbol)) { return symbol; } } return 0; } ParsingSymbolManager::ClassDefinition* ParsingSymbolManager::CacheGetClassDefinition(ParsingSymbol* type) { vint index=symbolClassDefinitionCache.Keys().IndexOf(type); return index==-1?0:symbolClassDefinitionCache.Values().Get(index); } ParsingSymbol* ParsingSymbolManager::CacheGetClassType(ClassDefinition* type) { vint index=classDefinitionSymbolCache.Keys().IndexOf(type); return index==-1?0:classDefinitionSymbolCache.Values().Get(index); } ParsingSymbol* ParsingSymbolManager::CacheGetType(definitions::ParsingDefinitionType* type, ParsingSymbol* scope) { DefinitionTypeScopePair key(type, scope); vint index=definitionTypeSymbolCache.Keys().IndexOf(key); return index==-1?0:definitionTypeSymbolCache.Values().Get(index); } bool ParsingSymbolManager::CacheSetType(definitions::ParsingDefinitionType* type, ParsingSymbol* scope, ParsingSymbol* symbol) { DefinitionTypeScopePair key(type, scope); vint index=definitionTypeSymbolCache.Keys().IndexOf(key); if(index==-1) { definitionTypeSymbolCache.Add(key, symbol); return true; } else { return false; } } ParsingSymbol* ParsingSymbolManager::CacheGetSymbol(definitions::ParsingDefinitionGrammar* grammar) { vint index=definitionGrammarSymbolCache.Keys().IndexOf(grammar); return index==-1?0:definitionGrammarSymbolCache.Values().Get(index); } bool ParsingSymbolManager::CacheSetSymbol(definitions::ParsingDefinitionGrammar* grammar, ParsingSymbol* symbol) { vint index=definitionGrammarSymbolCache.Keys().IndexOf(grammar); if(index==-1) { definitionGrammarSymbolCache.Add(grammar, symbol); return true; } else { return false; } } ParsingSymbol* ParsingSymbolManager::CacheGetType(definitions::ParsingDefinitionGrammar* grammar) { vint index=definitionGrammarTypeCache.Keys().IndexOf(grammar); return index==-1?0:definitionGrammarTypeCache.Values().Get(index); } bool ParsingSymbolManager::CacheSetType(definitions::ParsingDefinitionGrammar* grammar, ParsingSymbol* type) { vint index=definitionGrammarTypeCache.Keys().IndexOf(grammar); if(index==-1) { definitionGrammarTypeCache.Add(grammar, type); return true; } else { return false; } } /*********************************************************************** FindType ***********************************************************************/ WString GetTypeFullName(ParsingSymbol* type) { if(type->GetType()==ParsingSymbol::ArrayType) { return GetTypeFullName(type->GetDescriptorSymbol())+L"[]"; } else { WString name=type->GetName(); type=type->GetParentSymbol(); while(type && type!=type->GetManager()->GetGlobal()) { name=type->GetName()+L"."+name; type=type->GetParentSymbol(); } return name; } } /*********************************************************************** FindType ***********************************************************************/ class FindTypeVisitor : public Object, public ParsingDefinitionType::IVisitor { public: ParsingSymbolManager* manager; ParsingSymbol* scope; List>& errors; ParsingSymbol* result; FindTypeVisitor(ParsingSymbolManager* _manager, ParsingSymbol* _scope, List>& _errors) :manager(_manager) ,scope(_scope) ,errors(_errors) ,result(0) { } void Visit(ParsingDefinitionPrimitiveType* node)override { ParsingSymbol* currentScope=scope; while(currentScope) { ParsingSymbol* type=currentScope->GetSubSymbolByName(node->name); if(type) { if(type->IsType()) { result=type; } else { errors.Add(new ParsingError(node, L"\""+node->name+L"\" in current scope is not a type.")); } return; } currentScope=currentScope->GetParentSymbol(); } errors.Add(new ParsingError(node, L"Cannot not find \""+node->name+L"\" in current scope.")); } void Visit(ParsingDefinitionTokenType* node)override { result=manager->GetTokenType(); } void Visit(ParsingDefinitionSubType* node)override { ParsingSymbol* type=FindType(node->parentType.Obj(), manager, scope, errors); if(type) { ParsingSymbol* subType=type->SearchClassSubSymbol(node->subTypeName); if(!subType) { errors.Add(new ParsingError(node, L"\""+GetTypeFullName(type)+L"\" does not has a sub type called \""+node->subTypeName+L"\".")); } else if(subType->IsType()) { result=subType; } else { errors.Add(new ParsingError(node, L"\""+GetTypeFullName(type)+L"\" contains a sub definition called \""+node->subTypeName+L"\" but this is not a type.")); } } } void Visit(ParsingDefinitionArrayType* node)override { ParsingSymbol* type=FindType(node->elementType.Obj(), manager, scope, errors); if(type) { result=manager->GetArrayType(type); } } }; ParsingSymbol* FindType(definitions::ParsingDefinitionType* type, ParsingSymbolManager* manager, ParsingSymbol* scope, collections::List>& errors) { ParsingSymbol* result=manager->CacheGetType(type, scope); if(!result) { FindTypeVisitor visitor(manager, (scope?scope:manager->GetGlobal()), errors); type->Accept(&visitor); result=visitor.result; manager->CacheSetType(type, scope, result); } return result; } /*********************************************************************** PrepareSymbols ***********************************************************************/ class PrepareSymbolsTypeDefinitionVisitor : public Object, public ParsingDefinitionTypeDefinition::IVisitor { public: ParsingSymbolManager* manager; ParsingSymbol* scope; List>& errors; PrepareSymbolsTypeDefinitionVisitor(ParsingSymbolManager* _manager, ParsingSymbol* _scope, List>& _errors) :manager(_manager) ,scope(_scope) ,errors(_errors) { } bool EnsureNameNotExists(ParsingDefinitionTypeDefinition* node, const WString& subjectName) { if(scope->SearchClassSubSymbol(node->name)) { errors.Add(new ParsingError(node, L"Cannot redefine \""+node->name+L"\" to be "+subjectName+L".")); return false; } else { return true; } } void Visit(ParsingDefinitionClassMemberDefinition* node)override { if(EnsureNameNotExists(node, L"a class field")) { ParsingSymbol* fieldType=FindType(node->type.Obj(), manager, scope, errors); if(fieldType) { ParsingSymbol* field=manager->AddField(node->name, scope, fieldType); if(!field) { errors.Add(new ParsingError(node, L"A class field cannot be defined here.")); } } } } void Visit(ParsingDefinitionClassDefinition* node)override { if(EnsureNameNotExists(node, L"a class type")) { ParsingSymbol* baseType=0; if(node->parentType) { baseType=FindType(node->parentType.Obj(), manager, scope, errors); } ParsingSymbol* classType=manager->AddClass(node, baseType, (scope->GetType()==ParsingSymbol::Global?0:scope)); if(classType) { PrepareSymbolsTypeDefinitionVisitor visitor(manager, classType, errors); FOREACH(Ptr, subType, node->subTypes) { subType->Accept(&visitor); } FOREACH(Ptr, member, node->members) { member->Accept(&visitor); } } else { errors.Add(new ParsingError(node, L"A class type cannot be defined here.")); } } } void Visit(ParsingDefinitionEnumMemberDefinition* node)override { if(EnsureNameNotExists(node, L"an enum item")) { ParsingSymbol* enumItem=manager->AddEnumItem(node->name, scope); if(!enumItem) { errors.Add(new ParsingError(node, L"An enum item cannot be defined here.")); } } } void Visit(ParsingDefinitionEnumDefinition* node)override { if(EnsureNameNotExists(node, L"an enum type")) { ParsingSymbol* enumType=manager->AddEnum(node->name, (scope->GetType()==ParsingSymbol::Global?0:scope)); if(enumType) { PrepareSymbolsTypeDefinitionVisitor visitor(manager, enumType, errors); FOREACH(Ptr, member, node->members) { member->Accept(&visitor); } } else { errors.Add(new ParsingError(node, L"An enum type cannot be defined here.")); } } } }; void PrepareSymbols(Ptr definition, ParsingSymbolManager* manager, collections::List>& errors) { { PrepareSymbolsTypeDefinitionVisitor visitor(manager, manager->GetGlobal(), errors); FOREACH(Ptr, typeDefinition, definition->types) { typeDefinition->Accept(&visitor); } } FOREACH(Ptr, token, definition->tokens) { if(manager->GetGlobal()->GetSubSymbolByName(token->name)) { errors.Add(new ParsingError(token.Obj(), L"Cannot redefine \""+token->name+L"\" to be a token definition.")); } else { manager->AddTokenDefinition(token->name, token->regex); try { regex_internal::ParseRegexExpression(token->regex); } catch(const ParsingException& ex) { errors.Add(new ParsingError(token.Obj(), L"Wrong token definition for \""+token->name+L"\": "+ex.Message())); } } } FOREACH(Ptr, rule, definition->rules) { if(manager->GetGlobal()->GetSubSymbolByName(rule->name)) { errors.Add(new ParsingError(rule.Obj(), L"Cannot redefine \""+rule->name+L"\" to be a rule definition.")); } else { ParsingSymbol* type=FindType(rule->type.Obj(), manager, 0, errors); if(type) { if(type->GetType()!=ParsingSymbol::ClassType) { errors.Add(new ParsingError(rule.Obj(), L"\""+GetTypeFullName(type)+L"\" cannot be a type of a rule because this is not a class type.")); } manager->AddRuleDefinition(rule->name, type); } } } } /*********************************************************************** ValidateRuleStructure ***********************************************************************/ class ValidateRuleStructureVisitor : public Object, public ParsingDefinitionGrammar::IVisitor { public: Ptr definition; ParsingSymbolManager* manager; ParsingDefinitionRuleDefinition* rule; List>& errors; vint loopCount; ValidateRuleStructureVisitor(Ptr _definition, ParsingSymbolManager* _manager, ParsingDefinitionRuleDefinition* _rule, List>& _errors) :definition(_definition) ,manager(_manager) ,errors(_errors) ,rule(_rule) ,loopCount(0) { } void CheckCreationType(ParsingDefinitionGrammar* node, ParsingSymbol* nodeType) { if(nodeType->GetType()==ParsingSymbol::ClassType) { ParsingSymbol* ruleType=manager->GetGlobal()->GetSubSymbolByName(rule->name)->GetDescriptorSymbol(); ParsingSymbol* currentType=nodeType; while(currentType && currentType!=ruleType) { currentType=currentType->GetDescriptorSymbol(); } if(!currentType) { errors.Add(new ParsingError(node, L"Cannot create type \""+GetTypeFullName(nodeType)+L"\" in a rule of type \""+GetTypeFullName(ruleType)+L"\" because there are no implicit conversions from the created type to the rule type.")); } } else { errors.Add(new ParsingError(node, L"\""+GetTypeFullName(nodeType)+L"\" cannot be created because this is not a class type.")); } } void Visit(ParsingDefinitionPrimitiveGrammar* node)override { ParsingSymbol* symbol=manager->GetGlobal()->GetSubSymbolByName(node->name); if(!symbol) { errors.Add(new ParsingError(node, L"Cannot find a token or a rule with name \""+node->name+L"\".")); } else switch(symbol->GetType()) { case ParsingSymbol::TokenDef: { bool discard=false; FOREACH(Ptr, token, definition->tokens) { if(token->name==symbol->GetName()) { discard=token->discard; break; } } if(discard) { errors.Add(new ParsingError(node, L"Cannot use discard token \""+node->name+L"\" as input.")); break; } } case ParsingSymbol::RuleDef: { ParsingSymbol* symbolType=symbol->GetDescriptorSymbol(); manager->CacheSetSymbol(node, symbol); manager->CacheSetType(node, symbolType); } break; default: errors.Add(new ParsingError(node, L"\""+node->name+L"\" is not a token definition or rule definition.")); } } void Visit(ParsingDefinitionTextGrammar* node)override { WString regex=regex_internal::EscapeTextForRegex(node->text); for(vint i=0;iGetGlobal()->GetSubSymbolCount();i++) { ParsingSymbol* symbol=manager->GetGlobal()->GetSubSymbol(i); if(symbol->GetType()==ParsingSymbol::TokenDef) { WString normalizedRegex=regex_internal::NormalizeEscapedTextForRegex(symbol->GetDescriptorString()); if(normalizedRegex==regex) { manager->CacheSetSymbol(node, symbol); manager->CacheSetType(node, manager->GetTokenType()); return; } } } errors.Add(new ParsingError(node, L"Cannot find a token whose definition is exactly \""+regex+L"\".")); } void Visit(ParsingDefinitionSequenceGrammar* node)override { node->first->Accept(this); node->second->Accept(this); } void Visit(ParsingDefinitionAlternativeGrammar* node)override { node->first->Accept(this); node->second->Accept(this); } void Visit(ParsingDefinitionLoopGrammar* node)override { loopCount++; node->grammar->Accept(this); loopCount--; } void Visit(ParsingDefinitionOptionalGrammar* node)override { node->grammar->Accept(this); } void Visit(ParsingDefinitionCreateGrammar* node)override { if(loopCount>0) { errors.Add(new ParsingError(node, L"Parsing tree node creation (the \"as\" operator) is not allowed inside loops.")); } if(ParsingSymbol* nodeType=FindType(node->type.Obj(), manager, 0, errors)) { CheckCreationType(node, nodeType); } node->grammar->Accept(this); } void Visit(ParsingDefinitionAssignGrammar* node)override { if(!node->grammar.Cast() && !node->grammar.Cast()) { errors.Add(new ParsingError(node, L"Only parsing tree node returned from a rule or a token can be assigned to a class field.")); } node->grammar->Accept(this); } void Visit(ParsingDefinitionUseGrammar* node)override { if(loopCount>0) { errors.Add(new ParsingError(node, L"Parsing tree node reusing (the \"!\" operator) is not allowed inside loops.")); } if(!node->grammar.Cast()) { errors.Add(new ParsingError(node, L"Only parsing tree node returned from a rule can be reused.")); } else if(ParsingSymbol* symbol=manager->CacheGetSymbol(node->grammar.Obj())) { if(symbol->GetType()!=ParsingSymbol::RuleDef) { errors.Add(new ParsingError(node, L"Only parsing tree node returned from a rule can be reused.")); } } if(ParsingSymbol* nodeType=manager->CacheGetType(node->grammar.Obj())) { CheckCreationType(node, nodeType); } node->grammar->Accept(this); } void Visit(ParsingDefinitionSetterGrammar* node)override { node->grammar->Accept(this); } }; void ValidateRuleStructure(Ptr definition, Ptr rule, ParsingSymbolManager* manager, collections::List>& errors) { FOREACH(Ptr, grammar, rule->grammars) { ValidateRuleStructureVisitor visitor(definition, manager, rule.Obj(), errors); grammar->Accept(&visitor); } } /*********************************************************************** ResolveRuleSymbols ***********************************************************************/ struct GrammarPathFragment { // primitive, text -> transition // loop, optional, create, use assign, setter -> epsilon GrammarPathFragment* previousFragment; ParsingDefinitionGrammar* grammar; bool epsilon; ParsingSymbol* createdType; GrammarPathFragment() :previousFragment(0) ,grammar(0) ,epsilon(false) ,createdType(0) { } }; struct GrammarPath { List> fragments; ParsingSymbol* pathType; GrammarPath() :pathType(0) { } WString ToString() { WString result; FOREACH(Ptr, fragment, fragments) { if(!fragment->epsilon) { if(result!=L"") result+=L" "; result+=GrammarToString(fragment->grammar); } } return result; } }; struct GrammarPathContainer { List> paths; }; class EnumerateGrammarPathVisitor : public Object, public ParsingDefinitionGrammar::IVisitor { public: ParsingSymbolManager* manager; ParsingDefinitionRuleDefinition* rule; List> createdFragments; List currentFragmentEnds; EnumerateGrammarPathVisitor(ParsingSymbolManager* _manager, ParsingDefinitionRuleDefinition* _rule) :manager(_manager) ,rule(_rule) { } EnumerateGrammarPathVisitor(const EnumerateGrammarPathVisitor& visitor) :manager(visitor.manager) ,rule(visitor.rule) { CopyFrom(currentFragmentEnds, visitor.currentFragmentEnds); } void Join(const EnumerateGrammarPathVisitor& visitor) { CopyFrom(createdFragments, visitor.createdFragments, true); CopyFrom(currentFragmentEnds, visitor.currentFragmentEnds, true); } void AddFragment(ParsingDefinitionGrammar* node, bool epsilon, ParsingSymbol* createdType) { if(currentFragmentEnds.Count()==0) { GrammarPathFragment* fragment=new GrammarPathFragment; fragment->grammar=node; fragment->epsilon=epsilon; fragment->createdType=createdType; createdFragments.Add(fragment); currentFragmentEnds.Add(fragment); } else for(vint i=0;igrammar=node; fragment->epsilon=epsilon; fragment->createdType=createdType; createdFragments.Add(fragment); fragment->previousFragment=currentFragmentEnds[i]; currentFragmentEnds[i]=fragment; } } void BuildPath(List>& paths) { FOREACH(GrammarPathFragment*, fragment, currentFragmentEnds) { Ptr path=new GrammarPath; paths.Add(path); GrammarPathFragment* current=fragment; while(current) { path->fragments.Insert(0, createdFragments[createdFragments.IndexOf(current)]); current=current->previousFragment; } } } void Visit(ParsingDefinitionPrimitiveGrammar* node)override { AddFragment(node, false, 0); } void Visit(ParsingDefinitionTextGrammar* node)override { AddFragment(node, false, 0); } void Visit(ParsingDefinitionSequenceGrammar* node)override { node->first->Accept(this); node->second->Accept(this); } void Visit(ParsingDefinitionAlternativeGrammar* node)override { EnumerateGrammarPathVisitor visitor(*this); node->second->Accept(&visitor); node->first->Accept(this); Join(visitor); } void Visit(ParsingDefinitionLoopGrammar* node)override { EnumerateGrammarPathVisitor visitor(*this); node->grammar->Accept(&visitor); AddFragment(node, true, 0); Join(visitor); } void Visit(ParsingDefinitionOptionalGrammar* node)override { EnumerateGrammarPathVisitor visitor(*this); node->grammar->Accept(&visitor); AddFragment(node, true, 0); Join(visitor); } void Visit(ParsingDefinitionCreateGrammar* node)override { node->grammar->Accept(this); AddFragment(node, true, manager->CacheGetType(node->type.Obj(), 0)); } void Visit(ParsingDefinitionAssignGrammar* node)override { node->grammar->Accept(this); AddFragment(node, true, 0); } void Visit(ParsingDefinitionUseGrammar* node)override { node->grammar->Accept(this); AddFragment(node, true, manager->CacheGetSymbol(node->grammar.Obj())->GetDescriptorSymbol()); } void Visit(ParsingDefinitionSetterGrammar* node)override { node->grammar->Accept(this); AddFragment(node, true, 0); } }; class ResolveAssignerGrammarVisitor : public Object, public ParsingDefinitionGrammar::IVisitor { public: typedef Dictionary> GrammarPathMap; ParsingSymbolManager* manager; List>& errors; GrammarPathMap& grammarPaths; ResolveAssignerGrammarVisitor(ParsingSymbolManager* _manager, List>& _errors, GrammarPathMap& _grammarPaths) :manager(_manager) ,errors(_errors) ,grammarPaths(_grammarPaths) { } ParsingSymbol* GetFieldFromCombined(ParsingDefinitionGrammar* node, const WString& fieldName) { Ptr paths=grammarPaths[node]; ParsingSymbol* pathType=paths->paths[0]->pathType; for(vint i=1;ipaths.Count();i++) { pathType=pathType->SearchCommonBaseClass(paths->paths[i]->pathType); if(!pathType) break; } WString pathNames; WString typeNames; for(int i=0;ipaths.Count();i++) { if(i>0) { pathNames+=L", "; typeNames+=L", "; } pathNames+=L"{"+paths->paths[i]->ToString()+L"}"; typeNames+=L"\""+GetTypeFullName(paths->paths[i]->pathType)+L"\""; } if(pathType) { ParsingSymbol* field=pathType->SearchClassSubSymbol(fieldName); if(!field) { errors.Add(new ParsingError(node, L"There are multiple grammar paths with different created types get through this operation for class field \""+fieldName+L"\", but the common base type \""+GetTypeFullName(pathType)+L"\" of these types doesn't contains the required class field. Types: "+typeNames+L"; Paths: "+pathNames+L".")); } else if(field->GetType()!=ParsingSymbol::ClassField) { errors.Add(new ParsingError(node, L"There are multiple grammar paths with different created types get through this operation for class field \""+fieldName+L"\", and the common base type \""+GetTypeFullName(pathType)+L"\" of these types contains a symbol called \""+fieldName+L"\", but this is not a class field. Types: "+typeNames+L"; Paths: "+pathNames+L".")); } else { return field; } } else { errors.Add(new ParsingError(node, L"There are multiple grammar paths with different created types get through this operation for class field \""+fieldName+L"\", but these types don't have a common base type. Types: "+typeNames+L"; Paths: "+pathNames+L".")); } return 0; } void Visit(ParsingDefinitionPrimitiveGrammar* node)override { } void Visit(ParsingDefinitionTextGrammar* node)override { } void Visit(ParsingDefinitionSequenceGrammar* node)override { } void Visit(ParsingDefinitionAlternativeGrammar* node)override { } void Visit(ParsingDefinitionLoopGrammar* node)override { } void Visit(ParsingDefinitionOptionalGrammar* node)override { } void Visit(ParsingDefinitionCreateGrammar* node)override { } void Visit(ParsingDefinitionAssignGrammar* node)override { if(ParsingSymbol* field=GetFieldFromCombined(node, node->memberName)) { manager->CacheSetSymbol(node, field); manager->CacheSetType(node, field->GetDescriptorSymbol()); ParsingSymbol* fieldType=field->GetDescriptorSymbol(); ParsingSymbol* valueType=manager->CacheGetType(node->grammar.Obj()); ParsingSymbol* targetFieldType=fieldType; if(targetFieldType->GetType()==ParsingSymbol::ArrayType) { targetFieldType=targetFieldType->GetDescriptorSymbol(); } if(targetFieldType!=valueType && valueType->SearchCommonBaseClass(targetFieldType)!=targetFieldType) { errors.Add(new ParsingError(node, L"Cannot assign value from grammar {"+GrammarToString(node->grammar.Obj())+L"} of type \""+GetTypeFullName(valueType)+L"\" to the field \""+node->memberName+L"\" of type \""+GetTypeFullName(fieldType)+L"\".")); } } } void Visit(ParsingDefinitionUseGrammar* node)override { } void Visit(ParsingDefinitionSetterGrammar* node)override { if(ParsingSymbol* field=GetFieldFromCombined(node, node->memberName)) { manager->CacheSetSymbol(node, field); manager->CacheSetType(node, field->GetDescriptorSymbol()); if(field->GetDescriptorSymbol()->GetType()!=ParsingSymbol::EnumType) { errors.Add(new ParsingError(node, L"Setter operation (the \"with\" operator) can only specify the value of a class field of an enum type. But \""+GetTypeFullName(field->GetDescriptorSymbol())+L"\" is not a enum type.")); } else { ParsingSymbol* enumType=field->GetDescriptorSymbol(); ParsingSymbol* enumItem=enumType->GetSubSymbolByName(node->value); if(!enumItem) { errors.Add(new ParsingError(node, L"Type \""+GetTypeFullName(enumType)+L"\" from field \""+node->memberName+L"\" does not have an enum item called \""+node->value+L"\".")); } else if(enumItem->GetType()!=ParsingSymbol::EnumItem) { errors.Add(new ParsingError(node, L"Type \""+GetTypeFullName(enumType)+L"\" from field \""+node->memberName+L"\" has a symbol called \""+node->value+L"\", but this is not an enum item.")); } } } } }; void ResolveRuleSymbols(Ptr rule, ParsingSymbolManager* manager, collections::List>& errors) { ParsingSymbol* ruleType=manager->GetGlobal()->GetSubSymbolByName(rule->name)->GetDescriptorSymbol(); FOREACH(Ptr, grammar, rule->grammars) { List> paths; { EnumerateGrammarPathVisitor visitor(manager, rule.Obj()); grammar->Accept(&visitor); visitor.BuildPath(paths); } FOREACH(Ptr, path, paths) { path->pathType=ruleType; vint createdTypeCount=0; vint transitionCount=0; FOREACH(Ptr, fragment, path->fragments) { if(fragment->createdType) { createdTypeCount++; path->pathType=fragment->createdType; } if(!fragment->epsilon) { transitionCount++; } } if(createdTypeCount==0) { errors.Add(new ParsingError(grammar.Obj(), L"No parsing tree node is created if the following path is chosen: \""+path->ToString()+L"\" in rule \""+rule->name+L"\".")); } else if(createdTypeCount>1) { errors.Add(new ParsingError(grammar.Obj(), L"Multiple parsing tree nodes are created if the following path is chosen: \""+path->ToString()+L"\" in rule \""+rule->name+L"\".")); } if(transitionCount==0) { errors.Add(new ParsingError(grammar.Obj(), L"Rule \""+rule->name+L"\" is not allowed to infer to an empty token sequence.")); } } ResolveAssignerGrammarVisitor::GrammarPathMap grammarPathMap; FOREACH(Ptr, path, paths) { FOREACH(Ptr, fragment, path->fragments) { ParsingDefinitionGrammar* grammar=fragment->grammar; Ptr container; vint index=grammarPathMap.Keys().IndexOf(grammar); if(index==-1) { container=new GrammarPathContainer; grammarPathMap.Add(grammar, container); } else { container=grammarPathMap.Values().Get(index); } container->paths.Add(path); } } ResolveAssignerGrammarVisitor visitor(manager, errors, grammarPathMap); FOREACH(ParsingDefinitionGrammar*, grammar, grammarPathMap.Keys()) { grammar->Accept(&visitor); } } } /*********************************************************************** ResolveSymbols ***********************************************************************/ void ResolveTypeSymbols(Ptr type, ParsingSymbolManager* manager, ParsingSymbol* scope, collections::List>& errors) { if(Ptr node=type.Cast()) { if(node->ambiguousType) { ParsingSymbol* ambigiousType=FindType(node->ambiguousType.Obj(), manager, scope, errors); WString ambiguousTypeText=TypeToString(node->ambiguousType.Obj()); if(!ambigiousType) { errors.Add(new ParsingError(node.Obj(), L"Ambiguous type \""+ambiguousTypeText+L"\" for type \""+node->name+L"\" does not exist.")); } else if(ambigiousType->GetType()!=ParsingSymbol::ClassType) { errors.Add(new ParsingError(node.Obj(), L"Ambiguous type \""+ambiguousTypeText+L"\" for type \""+node->name+L"\" is not a type.")); } else if(ambigiousType->GetDescriptorSymbol()!=manager->GetGlobal()->GetSubSymbolByName(node->name)) { errors.Add(new ParsingError(node.Obj(), L"Ambiguous type \""+ambiguousTypeText+L"\" for type \""+node->name+L"\" does not inherit from \""+node->name+L"\".")); } else { bool correct=false; if(ambigiousType->GetSubSymbolCount()==1) { ParsingSymbol* field=ambigiousType->GetSubSymbol(0); if(field->GetName()==L"items" && field->GetType()==ParsingSymbol::ClassField) { ParsingSymbol* fieldType=field->GetDescriptorSymbol(); if(fieldType->GetType()==ParsingSymbol::ArrayType && fieldType->GetDescriptorSymbol()==ambigiousType->GetDescriptorSymbol()) { correct=true; } } } if(!correct) { errors.Add(new ParsingError(node.Obj(), L"Ambiguous type \""+ambiguousTypeText+L"\" for type \""+node->name+L"\" can only contains one field called \"item\" which should be an array of \""+node->name+L"\".")); } } } ParsingSymbol* classType=manager->CacheGetClassType(node.Obj()); if(classType) { FOREACH(Ptr, subType, node->subTypes) { ResolveTypeSymbols(subType, manager, classType, errors); } } } } void ResolveSymbols(Ptr definition, ParsingSymbolManager* manager, collections::List>& errors) { FOREACH(Ptr, type, definition->types) { ResolveTypeSymbols(type, manager, manager->GetGlobal(), errors); } FOREACH(Ptr, rule, definition->rules) { vint errorCount=errors.Count(); ValidateRuleStructure(definition, rule, manager, errors); if(errors.Count()==errorCount) { ResolveRuleSymbols(rule, manager, errors); } } } /*********************************************************************** ValidateDefinition ***********************************************************************/ void ValidateDefinition(Ptr definition, ParsingSymbolManager* manager, collections::List>& errors) { PrepareSymbols(definition, manager, errors); if(errors.Count()>0) return; ResolveSymbols(definition, manager, errors); } } } } /*********************************************************************** .\PARSING\PARSINGAUTOMATON.CPP ***********************************************************************/ namespace vl { namespace parsing { using namespace collections; using namespace definitions; namespace analyzing { /*********************************************************************** Action ***********************************************************************/ Action::Action() :actionType(Create) ,actionSource(0) ,actionTarget(0) ,creatorRule(0) ,shiftReduceSource(0) ,shiftReduceTarget(0) { } Action::~Action() { } /*********************************************************************** Transition ***********************************************************************/ Transition::Transition() :source(0) ,target(0) ,transitionType(Epsilon) ,stackOperationType(None) ,transitionSymbol(0) { } Transition::~Transition() { } bool Transition::IsEquivalent(Transition* t1, Transition* t2, bool careSourceAndTarget) { if(careSourceAndTarget) { if(t1->source!=t2->source || t1->target!=t2->target) { return false; } } if( t1->actions.Count()!=t2->actions.Count() || t1->transitionType!=t2->transitionType || t1->transitionSymbol!=t2->transitionSymbol) { return false; } for(vint j=0;jactions.Count();j++) { Ptr a1=t1->actions[j]; Ptr a2=t2->actions[j]; if( a1->actionType!=a2->actionType || a1->actionSource!=a2->actionSource || a1->actionTarget!=a2->actionTarget || a1->shiftReduceSource!=a2->shiftReduceSource ) { return false; } } return true; } /*********************************************************************** State ***********************************************************************/ State::State() :ownerRule(0) ,ownerRuleSymbol(0) ,grammarNode(0) ,stateNode(0) ,statePosition(BeforeNode) ,endState(false) { } State::~State() { } /*********************************************************************** RuleInfo ***********************************************************************/ RuleInfo::RuleInfo() :rootRuleStartState(0) ,rootRuleEndState(0) ,startState(0) ,stateNameCount(0) { } RuleInfo::~RuleInfo() { } /*********************************************************************** Automaton ***********************************************************************/ Automaton::Automaton(ParsingSymbolManager* _symbolManager) :symbolManager(_symbolManager) { } Automaton::~Automaton() { } void Automaton::AddRuleInfo(definitions::ParsingDefinitionRuleDefinition* rule, Ptr ruleInfo) { orderedRulesDefs.Add(rule); ruleInfos.Add(ruleInfo); ruleDefToInfoMap.Add(rule, ruleInfo); } State* Automaton::RuleStartState(definitions::ParsingDefinitionRuleDefinition* ownerRule) { State* state=new State; states.Add(state); state->ownerRule=ownerRule; state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name); state->stateName=ownerRule->name+L".Start"; state->stateExpression=L"@ <"+ownerRule->name+L">"; return state; } State* Automaton::RootRuleStartState(definitions::ParsingDefinitionRuleDefinition* ownerRule) { State* state=new State; states.Add(state); state->ownerRule=ownerRule; state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name); state->stateName=ownerRule->name+L".RootStart"; state->stateExpression=L"@ $<"+ownerRule->name+L">"; return state; } State* Automaton::RootRuleEndState(definitions::ParsingDefinitionRuleDefinition* ownerRule) { State* state=new State; states.Add(state); state->ownerRule=ownerRule; state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name); state->stateName=ownerRule->name+L".RootEnd"; state->stateExpression=L"$<"+ownerRule->name+L"> @"; return state; } State* Automaton::StartState(definitions::ParsingDefinitionRuleDefinition* ownerRule, definitions::ParsingDefinitionGrammar* grammarNode, definitions::ParsingDefinitionGrammar* stateNode) { State* state=new State; states.Add(state); state->ownerRule=ownerRule; state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name); state->grammarNode=grammarNode; state->stateNode=stateNode; state->statePosition=State::BeforeNode; state->stateName=ownerRule->name+L"."+itow(++ruleDefToInfoMap[ownerRule]->stateNameCount); stateNode=FindAppropriateGrammarState(grammarNode, stateNode, true); state->stateExpression=L"<"+ownerRule->name+L">: "+GrammarStateToString(grammarNode, stateNode, true); return state; } State* Automaton::EndState(definitions::ParsingDefinitionRuleDefinition* ownerRule, definitions::ParsingDefinitionGrammar* grammarNode, definitions::ParsingDefinitionGrammar* stateNode) { State* state=new State; states.Add(state); state->ownerRule=ownerRule; state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name); state->grammarNode=grammarNode; state->stateNode=stateNode; state->statePosition=State::AfterNode; state->stateName=ownerRule->name+L"."+itow(++ruleDefToInfoMap[ownerRule]->stateNameCount); stateNode=FindAppropriateGrammarState(grammarNode, stateNode, false); state->stateExpression=L"<"+ownerRule->name+L">: "+GrammarStateToString(grammarNode, stateNode, false); return state; } State* Automaton::CopyState(State* oldState) { State* resultState=0; if(oldState->statePosition==State::BeforeNode) { resultState=StartState(oldState->ownerRule, oldState->grammarNode, oldState->stateNode); } else { resultState=EndState(oldState->ownerRule, oldState->grammarNode, oldState->stateNode); } resultState->endState=oldState->endState; return resultState; } Transition* Automaton::CreateTransition(State* start, State* end) { Transition* transition=new Transition; transitions.Add(transition); start->transitions.Add(transition); end->inputs.Add(transition); transition->source=start; transition->target=end; return transition; } Transition* Automaton::TokenBegin(State* start, State* end) { Transition* transition=CreateTransition(start, end); transition->transitionType=Transition::TokenBegin; return transition; } Transition* Automaton::TokenFinish(State* start, State* end) { Transition* transition=CreateTransition(start, end); transition->transitionType=Transition::TokenFinish; return transition; } Transition* Automaton::NormalReduce(State* start, State* end) { Transition* transition=CreateTransition(start, end); transition->transitionType=Transition::NormalReduce; return transition; } Transition* Automaton::LeftRecursiveReduce(State* start, State* end) { Transition* transition=CreateTransition(start, end); transition->transitionType=Transition::LeftRecursiveReduce; return transition; } Transition* Automaton::Epsilon(State* start, State* end) { Transition* transition=CreateTransition(start, end); transition->transitionType=Transition::Epsilon; return transition; } Transition* Automaton::Symbol(State* start, State* end, ParsingSymbol* transitionSymbol) { Transition* transition=CreateTransition(start, end); transition->transitionType=Transition::Symbol; transition->transitionSymbol=transitionSymbol; return transition; } Transition* Automaton::CopyTransition(State* start, State* end, Transition* oldTransition) { Transition* transition=CreateTransition(start, end); transition->transitionType=oldTransition->transitionType; transition->stackOperationType=oldTransition->stackOperationType; transition->transitionSymbol=oldTransition->transitionSymbol; return transition; } void Automaton::DeleteTransition(Transition* transition) { transition->source->transitions.Remove(transition); transition->target->inputs.Remove(transition); transitions.Remove(transition); } void Automaton::DeleteState(State* state) { while(state->inputs.Count()) { DeleteTransition(state->inputs[0]); } while(state->transitions.Count()) { DeleteTransition(state->transitions[0]); } states.Remove(state); } } } } /*********************************************************************** .\PARSING\PARSINGAUTOMATON_CLOSURE.CPP ***********************************************************************/ namespace vl { namespace parsing { using namespace collections; using namespace definitions; namespace analyzing { /*********************************************************************** CreateNondeterministicPDAFromEpsilonPDA::closure_searching ***********************************************************************/ // closure function for searching reachable states ClosureItem::SearchResult EpsilonClosure(Transition* transition) { return transition->transitionType!=Transition::Epsilon?ClosureItem::Hit: //transition->target->endState?ClosureItem::Blocked: ClosureItem::Continue; } // closure searching function void SearchClosureInternal(ClosureItem::SearchResult(*closurePredicate)(Transition*), List& transitionPath, Transition* transition, State* state, List& closure) { FOREACH(Transition*, singleTransitionPath, transitionPath) { if(singleTransitionPath->source==state && closurePredicate(singleTransitionPath)!=ClosureItem::Blocked) { Ptr> path=new List; CopyFrom(*path.Obj(), transitionPath); closure.Add(ClosureItem(state, path, true)); return; } } ClosureItem::SearchResult result=transition?closurePredicate(transition):ClosureItem::Continue; switch(result) { case ClosureItem::Continue: { FOREACH(Transition*, newTransition, state->transitions) { if(!transitionPath.Contains(newTransition)) { transitionPath.Add(newTransition); SearchClosureInternal(closurePredicate, transitionPath, newTransition, newTransition->target, closure); transitionPath.RemoveAt(transitionPath.Count()-1); } } } break; case ClosureItem::Hit: { Ptr> path=new List; CopyFrom(*path.Obj(), transitionPath); closure.Add(ClosureItem(state, path, false)); } break; default:; } } void SearchClosure(ClosureItem::SearchResult(*closurePredicate)(Transition*), State* startState, List& closure) { List transitionPath; SearchClosureInternal(closurePredicate, transitionPath, 0, startState, closure); } // map old state to new state and track all states that are not visited yet State* GetMappedState(Ptr newAutomaton, State* oldState, List& scanningStates, Dictionary& oldNewStateMap) { State* newState=0; vint mapIndex=oldNewStateMap.Keys().IndexOf(oldState); if(mapIndex==-1) { newState=newAutomaton->CopyState(oldState); oldNewStateMap.Add(oldState, newState); } else { newState=oldNewStateMap.Values().Get(mapIndex); } if(!scanningStates.Contains(oldState)) { scanningStates.Add(oldState); } return newState; } /*********************************************************************** RemoveEpsilonTransitions ***********************************************************************/ void RemoveEpsilonTransitions(collections::Dictionary& oldNewStateMap, collections::List& scanningStates, Ptr automaton) { vint currentStateIndex=0; while(currentStateIndex closure; SearchClosure(&EpsilonClosure, currentOldState, closure); FOREACH(ClosureItem, closureItem, closure) { Transition* oldTransition=closureItem.transitions->Get(closureItem.transitions->Count()-1); if(!closureItem.cycle || oldTransition->transitionType!=Transition::Epsilon) { // if the oldTransition begins from an end state if(oldTransition->source->endState && closureItem.transitions->Count()>1) { // keep a epsilon transition that without the last "TokenFinish" State* newEndState=GetMappedState(automaton, oldTransition->source, scanningStates, oldNewStateMap); Transition* transition=automaton->Epsilon(currentNewState, newEndState); FOREACH(Transition*, pathTransition, *closureItem.transitions.Obj()) { if(pathTransition==oldTransition) break; CopyFrom(transition->actions, pathTransition->actions, true); } } else { // build compacted non-epsilon transition to the target state of the path State* newEndState=GetMappedState(automaton, oldTransition->target, scanningStates, oldNewStateMap); Transition* transition=automaton->CopyTransition(currentNewState, newEndState, oldTransition); FOREACH(Transition*, pathTransition, *closureItem.transitions.Obj()) { CopyFrom(transition->actions, pathTransition->actions, true); } } } } } } } } } /*********************************************************************** .\PARSING\PARSINGAUTOMATON_EPDA.CPP ***********************************************************************/ namespace vl { namespace parsing { using namespace collections; using namespace definitions; namespace analyzing { /*********************************************************************** CreateEpsilonPDAVisitor ***********************************************************************/ class CreateEpsilonPDAVisitor : public Object, public ParsingDefinitionGrammar::IVisitor { public: Ptr automaton; ParsingDefinitionRuleDefinition* rule; ParsingDefinitionGrammar* ruleGrammar; State* startState; State* endState; Transition* result; CreateEpsilonPDAVisitor(Ptr _automaton, ParsingDefinitionRuleDefinition* _rule, ParsingDefinitionGrammar* _ruleGrammar, State* _startState, State* _endState) :automaton(_automaton) ,rule(_rule) ,ruleGrammar(_ruleGrammar) ,startState(_startState) ,endState(_endState) ,result(0) { } static Transition* Create(ParsingDefinitionGrammar* grammar, Ptr automaton, ParsingDefinitionRuleDefinition* rule, ParsingDefinitionGrammar* ruleGrammar, State* startState, State* endState) { CreateEpsilonPDAVisitor visitor(automaton, rule, ruleGrammar, startState, endState); grammar->Accept(&visitor); return visitor.result; } Transition* Create(ParsingDefinitionGrammar* grammar, State* startState, State* endState) { return Create(grammar, automaton, rule, ruleGrammar, startState, endState); } void Visit(ParsingDefinitionPrimitiveGrammar* node)override { result=automaton->Symbol(startState, endState, automaton->symbolManager->CacheGetSymbol(node)); } void Visit(ParsingDefinitionTextGrammar* node)override { result=automaton->Symbol(startState, endState, automaton->symbolManager->CacheGetSymbol(node)); } void Visit(ParsingDefinitionSequenceGrammar* node)override { State* middleState=automaton->EndState(startState->ownerRule, ruleGrammar, node->first.Obj()); Create(node->first.Obj(), startState, middleState); Create(node->second.Obj(), middleState, endState); } void Visit(ParsingDefinitionAlternativeGrammar* node)override { Create(node->first.Obj(), startState, endState); Create(node->second.Obj(), startState, endState); } void Visit(ParsingDefinitionLoopGrammar* node)override { State* loopStart=automaton->StartState(startState->ownerRule, ruleGrammar, node->grammar.Obj()); automaton->Epsilon(startState, loopStart); automaton->Epsilon(loopStart, endState); Create(node->grammar.Obj(), loopStart, loopStart); } void Visit(ParsingDefinitionOptionalGrammar* node)override { Create(node->grammar.Obj(), startState, endState); automaton->Epsilon(startState, endState); } void Visit(ParsingDefinitionCreateGrammar* node)override { State* middleState=automaton->EndState(startState->ownerRule, ruleGrammar, node->grammar.Obj()); Create(node->grammar.Obj(), startState, middleState); Transition* transition=automaton->Epsilon(middleState, endState); Ptr action=new Action; action->actionType=Action::Create; action->actionSource=automaton->symbolManager->CacheGetType(node->type.Obj(), 0); action->creatorRule=rule; transition->actions.Add(action); } void Visit(ParsingDefinitionAssignGrammar* node)override { Transition* transition=Create(node->grammar.Obj(), startState, endState); Ptr action=new Action; action->actionType=Action::Assign; action->actionSource=automaton->symbolManager->CacheGetSymbol(node); action->creatorRule=rule; transition->actions.Add(action); } void Visit(ParsingDefinitionUseGrammar* node)override { Transition* transition=Create(node->grammar.Obj(), startState, endState); Ptr action=new Action; action->actionType=Action::Using; action->creatorRule=rule; transition->actions.Add(action); } void Visit(ParsingDefinitionSetterGrammar* node)override { State* middleState=automaton->EndState(startState->ownerRule, ruleGrammar, node->grammar.Obj()); Create(node->grammar.Obj(), startState, middleState); Transition* transition=automaton->Epsilon(middleState, endState); Ptr action=new Action; action->actionType=Action::Setter; action->actionSource=automaton->symbolManager->CacheGetSymbol(node); action->actionTarget=action->actionSource->GetDescriptorSymbol()->GetSubSymbolByName(node->value); action->creatorRule=rule; transition->actions.Add(action); } }; /*********************************************************************** CreateRuleEpsilonPDA ***********************************************************************/ void CreateRuleEpsilonPDA(Ptr automaton, Ptr rule, ParsingSymbolManager* manager) { Ptr ruleInfo=new RuleInfo; automaton->AddRuleInfo(rule.Obj(), ruleInfo); ruleInfo->rootRuleStartState=automaton->RootRuleStartState(rule.Obj()); ruleInfo->rootRuleEndState=automaton->RootRuleEndState(rule.Obj()); ruleInfo->startState=automaton->RuleStartState(rule.Obj()); automaton->TokenBegin(ruleInfo->rootRuleStartState, ruleInfo->startState); FOREACH(Ptr, grammar, rule->grammars) { State* grammarStartState=automaton->StartState(rule.Obj(), grammar.Obj(), grammar.Obj()); State* grammarEndState=automaton->EndState(rule.Obj(), grammar.Obj(), grammar.Obj()); grammarEndState->stateName+=L".End"; grammarEndState->endState=true; automaton->Epsilon(ruleInfo->startState, grammarStartState); automaton->TokenFinish(grammarEndState, ruleInfo->rootRuleEndState); ruleInfo->endStates.Add(grammarEndState); CreateEpsilonPDAVisitor::Create(grammar.Obj(), automaton, rule.Obj(), grammar.Obj(), grammarStartState, grammarEndState); } } /*********************************************************************** CreateEpsilonPDA ***********************************************************************/ Ptr CreateEpsilonPDA(Ptr definition, ParsingSymbolManager* manager) { Ptr automaton=new Automaton(manager); FOREACH(Ptr, rule, definition->rules) { CreateRuleEpsilonPDA(automaton, rule, manager); } return automaton; } } } } /*********************************************************************** .\PARSING\PARSINGAUTOMATON_GENERATETABLE.CPP ***********************************************************************/ namespace vl { namespace parsing { using namespace collections; using namespace definitions; using namespace tabling; namespace analyzing { /*********************************************************************** GetTypeNameForCreateInstruction ***********************************************************************/ WString GetTypeNameForCreateInstruction(ParsingSymbol* type) { ParsingSymbol* parent=type->GetParentSymbol(); if(parent->GetType()==ParsingSymbol::ClassType) { return GetTypeNameForCreateInstruction(parent)+L"."+type->GetName(); } else { return type->GetName(); } } /*********************************************************************** CreateLookAhead ***********************************************************************/ void CopyStableLookAheads(List>& la, List>& sla, const List>& la2) { CopyFrom(sla, From(la) .Where([&](Ptr lai) { return From(la2).All([&](Ptr lai2) { return ParsingTable::LookAheadInfo::TestPrefix(lai, lai2)==ParsingTable::LookAheadInfo::NotPrefix; }); }), true); } void RemoveStableLookAheads(List>& la, const List>& sla) { for(vint i=la.Count()-1;i>=0;i--) { if(sla.Contains(la[i].Obj())) { la.RemoveAt(i); } } } bool WalkLookAheads(Ptr table, List>& la, vint maxTokenCount) { vint count=la.Count(); for(vint i=0;i lai=la[i]; if(lai->tokens.Count()==maxTokenCount) { return false; } ParsingTable::LookAheadInfo::Walk(table, lai, lai->state, la); } return true; } void CompactLookAheads(Ptr t, List>& sla) { CopyFrom(sla, t->lookAheads, true); CopyFrom(t->lookAheads, From(sla) .Where([&](Ptr lai) { return From(sla).All([&](Ptr lai2) { if(lai==lai2) return true; ParsingTable::LookAheadInfo::PrefixResult result=ParsingTable::LookAheadInfo::TestPrefix(lai, lai2); switch(result) { case ParsingTable::LookAheadInfo::Prefix: return false; case ParsingTable::LookAheadInfo::Equal: return sla.IndexOf(lai.Obj()) < sla.IndexOf(lai2.Obj()); default: return true; } }); })); } bool CreateLookAhead(Ptr table, Ptr t1, Ptr t2, vint maxTokenCount) { List> la1, la2, sla1, sla2; // calculate 1-token look aheads ParsingTable::LookAheadInfo::Walk(table, 0, t1->targetState, la1); ParsingTable::LookAheadInfo::Walk(table, 0, t2->targetState, la2); do { // pick up all stable look aheads and remove them from the look ahead list // stable look ahead means, when the look ahead is satisfied, then the transition is picked up with full confidence // non-stable look ahead means, when the look ahead is satisifed, it only increase confidence, needs further tokens for decision CopyStableLookAheads(la1, sla1, la2); CopyStableLookAheads(la2, sla2, la1); RemoveStableLookAheads(la1, sla1); RemoveStableLookAheads(la2, sla2); // check if there are non-stable look aheads in two transitions points to the same state // in such situation means that the two transition cannot always be determined using look aheads FOREACH(Ptr, lai1, la1) { FOREACH(Ptr, lai2, la2) { if (lai1->state == lai2->state) { if (ParsingTable::LookAheadInfo::TestPrefix(lai1, lai2) != ParsingTable::LookAheadInfo::NotPrefix) { return false; } if (ParsingTable::LookAheadInfo::TestPrefix(lai2, lai1) != ParsingTable::LookAheadInfo::NotPrefix) { return false; } } } } // use the non-stable look aheads to walk a token further if(!WalkLookAheads(table, la1, maxTokenCount) || !WalkLookAheads(table, la2, maxTokenCount)) { return false; } } while(la1.Count()>0 || la2.Count()>0); CompactLookAheads(t1, sla1); CompactLookAheads(t2, sla2); return true; } /*********************************************************************** CollectAttribute ***********************************************************************/ void CollectType(ParsingSymbol* symbol, List& types) { if(symbol->GetType()==ParsingSymbol::ClassType) { types.Add(symbol); } vint count=symbol->GetSubSymbolCount(); for(vint i=0;iGetSubSymbol(i), types); } } void CollectAttributeInfo(Ptr att, List>& atts) { FOREACH(Ptr, datt, atts) { Ptr tatt=new ParsingTable::AttributeInfo(datt->name); CopyFrom(tatt->arguments, datt->arguments); att->attributes.Add(tatt); } } Ptr CreateAttributeInfo(List>& atts) { Ptr att=new ParsingTable::AttributeInfoList; CollectAttributeInfo(att, atts); return att; } /*********************************************************************** GenerateTable ***********************************************************************/ vint LookAheadConflictPriority(vint tableTokenIndex) { switch (tableTokenIndex) { case ParsingTable::NormalReduce: return 0; case ParsingTable::LeftRecursiveReduce: return 1; default: return 2; } } void GenerateLookAhead(Ptr table, List& stateIds, vint state, vint token, Ptr t1, Ptr t2, bool enableAmbiguity, collections::List>& errors) { if(ParsingTable::TransitionItem::CheckOrder(t1, t2, ParsingTable::TransitionItem::UnknownOrder)==ParsingTable::TransitionItem::UnknownOrder) { if(enableAmbiguity || !CreateLookAhead(table, t1, t2, 16)) { if (LookAheadConflictPriority(t1->token) != LookAheadConflictPriority(t2->token)) { return; } WString stateName=itow(state)+L"["+table->GetStateInfo(state).stateName+L"]"; WString tokenName= token==ParsingTable::TokenBegin?WString(L"$TokenBegin"): token==ParsingTable::TokenFinish?WString(L"$TokenFinish"): token==ParsingTable::NormalReduce?WString(L"$NormalReduce"): token==ParsingTable::LeftRecursiveReduce?WString(L"$LeftRecursiveReduce"): table->GetTokenInfo(token).name; switch (t1->token) { case ParsingTable::NormalReduce: errors.Add(new ParsingError(stateIds[state]->ownerRule, L"Conflict happened with normal reduce in transition of \""+tokenName+L"\" of state \""+stateName+L"\".")); break; case ParsingTable::LeftRecursiveReduce: errors.Add(new ParsingError(stateIds[state]->ownerRule, L"Conflict happened with left recursive reduce in transition of \""+tokenName+L"\" of state \""+stateName+L"\".")); break; default: errors.Add(new ParsingError(stateIds[state]->ownerRule, L"Conflict happened in transition of \""+tokenName+L"\" of state \""+stateName+L"\".")); break; } } } } Ptr GenerateTableFromPDA(Ptr definition, ParsingSymbolManager* manager, Ptr jointPDA, bool enableAmbiguity, collections::List>& errors) { List> atts; /*********************************************************************** find all class types ***********************************************************************/ List types; Dictionary typeAtts; Dictionary, vint> treeFieldAtts; // stable class field order List orderedChildTypeKeys; Dictionary>> childTypeValues; // find all class types CollectType(manager->GetGlobal(), types); FOREACH(ParsingSymbol*, type, types) { Ptr typeAtt = new ParsingTable::AttributeInfoList; ParsingSymbol* parent = type; while (parent) { ParsingDefinitionClassDefinition* classDef = manager->CacheGetClassDefinition(parent); CollectAttributeInfo(typeAtt, classDef->attributes); Ptr> children; vint index = childTypeValues.Keys().IndexOf(parent); if (index == -1) { children = new List; orderedChildTypeKeys.Add(parent); childTypeValues.Add(parent, children); } else { children = childTypeValues.Values().Get(index); } children->Add(type); parent = parent->GetDescriptorSymbol(); } if (typeAtt->attributes.Count() > 0) { typeAtts.Add(GetTypeFullName(type), atts.Count()); atts.Add(typeAtt); } else { typeAtts.Add(GetTypeFullName(type), -1); } } // find all class fields FOREACH(ParsingSymbol*, type, orderedChildTypeKeys) { List& children = *childTypeValues[type].Obj(); ParsingDefinitionClassDefinition* classDef = manager->CacheGetClassDefinition(type); List fieldAtts; FOREACH_INDEXER(Ptr, field, index, classDef->members) { if (field->attributes.Count() > 0) { fieldAtts.Add(atts.Count()); atts.Add(CreateAttributeInfo(field->attributes)); } else { fieldAtts.Add(-1); } } FOREACH(ParsingSymbol*, child, children) { WString type = GetTypeFullName(child); FOREACH_INDEXER(Ptr, field, index, classDef->members) { treeFieldAtts.Add(Pair(type, field->name), fieldAtts[index]); } } } /*********************************************************************** find all tokens ***********************************************************************/ vint tokenCount = 0; vint discardTokenCount = 0; Dictionary tokenIds; List discardTokens; Dictionary tokenAtts; Dictionary ruleAtts; FOREACH(Ptr, token, definition->tokens) { if (token->attributes.Count() > 0) { tokenAtts.Add(token->name, atts.Count()); atts.Add(CreateAttributeInfo(token->attributes)); } else { tokenAtts.Add(token->name, -1); } if (token->discard) { discardTokens.Add(token->name); discardTokenCount++; } else { ParsingSymbol* tokenSymbol = jointPDA->symbolManager->GetGlobal()->GetSubSymbolByName(token->name); tokenIds.Add(tokenSymbol, tokenIds.Count() + ParsingTable::UserTokenStart); tokenCount++; } } /*********************************************************************** find all rules ***********************************************************************/ FOREACH(Ptr, rule, definition->rules) { if (rule->attributes.Count() > 0) { ruleAtts.Add(rule->name, atts.Count()); atts.Add(CreateAttributeInfo(rule->attributes)); } else { ruleAtts.Add(rule->name, -1); } } /*********************************************************************** find all available states ***********************************************************************/ List stateIds; vint availableStateCount = 0; { vint currentState = 0; List scanningStates; FOREACH(Ptr, ruleInfo, jointPDA->ruleInfos) { if (!scanningStates.Contains(ruleInfo->rootRuleStartState)) { scanningStates.Add(ruleInfo->rootRuleStartState); } while (currentState < scanningStates.Count()) { State* state = scanningStates[currentState++]; stateIds.Add(state); FOREACH(Transition*, transition, state->transitions) { if (!scanningStates.Contains(transition->target)) { scanningStates.Add(transition->target); } } } } availableStateCount = scanningStates.Count(); } // there will be some states that is used in shift and reduce but it is not a reachable state // so the state table will record all state FOREACH(Ptr, state, jointPDA->states) { if (!stateIds.Contains(state.Obj())) { stateIds.Add(state.Obj()); } } vint stateCount = stateIds.Count(); Ptr table = new ParsingTable(atts.Count(), typeAtts.Count(), treeFieldAtts.Count(), tokenCount, discardTokenCount, stateCount, definition->rules.Count()); /*********************************************************************** fill attribute infos ***********************************************************************/ FOREACH_INDEXER(Ptr, att, index, atts) { table->SetAttributeInfo(index, att); } /*********************************************************************** fill tree type infos ***********************************************************************/ typedef Pair TreeTypeAttsPair; FOREACH_INDEXER(TreeTypeAttsPair, type, index, typeAtts) { table->SetTreeTypeInfo(index, ParsingTable::TreeTypeInfo(type.key, type.value)); } /*********************************************************************** fill tree field infos ***********************************************************************/ typedef Pair, vint> TreeFieldAttsPair; FOREACH_INDEXER(TreeFieldAttsPair, field, index, treeFieldAtts) { table->SetTreeFieldInfo(index, ParsingTable::TreeFieldInfo(field.key.key, field.key.value, field.value)); } /*********************************************************************** fill token infos ***********************************************************************/ FOREACH(ParsingSymbol*, symbol, tokenIds.Keys()) { ParsingTable::TokenInfo info; info.name = symbol->GetName(); info.regex = symbol->GetDescriptorString(); info.attributeIndex = tokenAtts[info.name]; vint id = tokenIds[symbol]; table->SetTokenInfo(id, info); } FOREACH_INDEXER(WString, name, i, discardTokens) { ParsingSymbol* symbol = jointPDA->symbolManager->GetGlobal()->GetSubSymbolByName(name); ParsingTable::TokenInfo info; info.name = symbol->GetName(); info.regex = symbol->GetDescriptorString(); info.attributeIndex = tokenAtts[info.name]; table->SetDiscardTokenInfo(i, info); } /*********************************************************************** fill rule infos ***********************************************************************/ FOREACH_INDEXER(ParsingDefinitionRuleDefinition*, rule, i, jointPDA->orderedRulesDefs) { Ptr pdaRuleInfo = jointPDA->ruleDefToInfoMap[rule]; ParsingTable::RuleInfo info; info.name = rule->name; info.type = TypeToString(rule->type.Obj()); info.rootStartState = stateIds.IndexOf(pdaRuleInfo->rootRuleStartState); info.attributeIndex = ruleAtts[info.name]; if (Ptr classType = rule->type.Cast()) { ParsingSymbol* ruleSymbol = manager->GetGlobal()->GetSubSymbolByName(rule->name); ParsingSymbol* ruleType = ruleSymbol->GetDescriptorSymbol(); ParsingDefinitionClassDefinition* ruleTypeDef = manager->CacheGetClassDefinition(ruleType); if (ruleTypeDef && ruleTypeDef->ambiguousType) { ParsingSymbol* ambiguousType = manager->CacheGetType(ruleTypeDef->ambiguousType.Obj(), ruleType->GetParentSymbol()); info.ambiguousType = GetTypeFullName(ambiguousType); } } table->SetRuleInfo(i, info); } /*********************************************************************** fill state infos ***********************************************************************/ FOREACH_INDEXER(State*, state, i, stateIds) { ParsingTable::StateInfo info; info.ruleName = state->ownerRule->name; info.stateName = state->stateName; info.stateExpression = state->stateExpression; table->SetStateInfo(i, info); } /*********************************************************************** fill transition table ***********************************************************************/ FOREACH_INDEXER(State*, state, stateIndex, stateIds) { // if this state is not necessary, stop building the table if (stateIndex >= availableStateCount) break; FOREACH(Transition*, transition, state->transitions) { vint tokenIndex = -1; switch (transition->transitionType) { case Transition::TokenBegin: tokenIndex = ParsingTable::TokenBegin; break; case Transition::TokenFinish: tokenIndex = ParsingTable::TokenFinish; break; case Transition::NormalReduce: tokenIndex = ParsingTable::NormalReduce; break; case Transition::LeftRecursiveReduce: tokenIndex = ParsingTable::LeftRecursiveReduce; break; case Transition::Symbol: tokenIndex = tokenIds[transition->transitionSymbol]; break; default:; } Ptr bag = table->GetTransitionBag(stateIndex, tokenIndex); if (!bag) { bag = new ParsingTable::TransitionBag; table->SetTransitionBag(stateIndex, tokenIndex, bag); } Ptr item = new ParsingTable::TransitionItem; item->token = tokenIndex; item->targetState = stateIds.IndexOf(transition->target); bag->transitionItems.Add(item); FOREACH(Ptr, action, transition->actions) { ParsingTable::Instruction ins; switch (action->actionType) { case Action::Create: { ins.instructionType = ParsingTable::Instruction::Create; ins.nameParameter = GetTypeNameForCreateInstruction(action->actionSource); } break; case Action::Using: { ins.instructionType = ParsingTable::Instruction::Using; } break; case Action::Assign: { if (action->actionSource->GetDescriptorSymbol()->GetType() == ParsingSymbol::ArrayType) { ins.instructionType = ParsingTable::Instruction::Item; } else { ins.instructionType = ParsingTable::Instruction::Assign; } ins.nameParameter = action->actionSource->GetName(); } break; case Action::Setter: { ins.instructionType = ParsingTable::Instruction::Setter; ins.nameParameter = action->actionSource->GetName(); ins.value = action->actionTarget->GetName(); } break; case Action::Shift: { ins.instructionType = ParsingTable::Instruction::Shift; ins.stateParameter = stateIds.IndexOf(action->shiftReduceSource); } break; case Action::Reduce: { ins.instructionType = ParsingTable::Instruction::Reduce; ins.stateParameter = stateIds.IndexOf(action->shiftReduceSource); item->stackPattern.Add(ins.stateParameter); } break; case Action::LeftRecursiveReduce: { ins.instructionType = ParsingTable::Instruction::LeftRecursiveReduce; ins.stateParameter = stateIds.IndexOf(action->shiftReduceSource); } break; } ins.creatorRule = action->creatorRule->name; item->instructions.Add(ins); } } } /*********************************************************************** check conflict and build look ahead table ***********************************************************************/ for (vint i = 0; i < table->GetStateCount(); i++) { for (vint j = 0; j < table->GetTokenCount(); j++) { Ptr bag = table->GetTransitionBag(i, j); if (bag) { CopyFrom( bag->transitionItems, From(bag->transitionItems) .OrderBy([&](Ptr t1, Ptr t2) { // stable transition order vint i1 = bag->transitionItems.IndexOf(t1.Obj()); vint i2 = bag->transitionItems.IndexOf(t2.Obj()); auto defaultOrder = i1 < i2 ? ParsingTable::TransitionItem::CorrectOrder : i1 > i2 ? ParsingTable::TransitionItem::WrongOrder : ParsingTable::TransitionItem::SameOrder ; return ParsingTable::TransitionItem::Compare(t1, t2, defaultOrder); }) ); // build look ahead inside a transition for (vint k1 = 0; k1 < bag->transitionItems.Count() - 1; k1++) { for (vint k2 = k1 + 1; k2 < bag->transitionItems.Count(); k2++) { Ptr t1 = bag->transitionItems[k1]; Ptr t2 = bag->transitionItems[k2]; GenerateLookAhead(table, stateIds, i, j, t1, t2, enableAmbiguity, errors); } } // build look ahead between this transition and reduce transitions for (vint t = ParsingTable::NormalReduce; t <= ParsingTable::LeftRecursiveReduce && t < j; t++) { if (Ptr reduceBag = table->GetTransitionBag(i, t)) { for (vint k1 = 0; k1 < reduceBag->transitionItems.Count(); k1++) { for (vint k2 = 0; k2 < bag->transitionItems.Count(); k2++) { Ptr t1 = reduceBag->transitionItems[k1]; Ptr t2 = bag->transitionItems[k2]; GenerateLookAhead(table, stateIds, i, j, t1, t2, enableAmbiguity, errors); } } } } } } } /*********************************************************************** initialize table ***********************************************************************/ if (errors.Count() > 0) { table->SetAmbiguity(true); } table->Initialize(); return table; } Ptr GenerateTable(Ptr definition, bool enableAmbiguity, collections::List>& errors) { errors.Clear(); ParsingSymbolManager symbolManager; ValidateDefinition(definition, &symbolManager, errors); if(errors.Count()==0) { Ptr epsilonPDA=CreateEpsilonPDA(definition, &symbolManager); Ptr nondeterministicPDA=CreateNondeterministicPDAFromEpsilonPDA(epsilonPDA); Ptr jointPDA=CreateJointPDAFromNondeterministicPDA(nondeterministicPDA); CompactJointPDA(jointPDA); MarkLeftRecursiveInJointPDA(jointPDA, errors); if(errors.Count()==0) { Ptr table=GenerateTableFromPDA(definition, &symbolManager, jointPDA, enableAmbiguity, errors); if(enableAmbiguity || errors.Count()==0) { return table; } } } return 0; } } } } /*********************************************************************** .\PARSING\PARSINGAUTOMATON_JPDA.CPP ***********************************************************************/ namespace vl { namespace parsing { using namespace collections; using namespace definitions; namespace analyzing { /*********************************************************************** CreateJointPDAFromNondeterministicPDA ***********************************************************************/ Ptr CreateJointPDAFromNondeterministicPDA(Ptr nondeterministicPDA) { Ptr automaton=new Automaton(nondeterministicPDA->symbolManager); // build rule info data Dictionary ruleMap; Dictionary oldNewStateMap; FOREACH(ParsingDefinitionRuleDefinition*, rule, nondeterministicPDA->orderedRulesDefs) { // build new rule info Ptr ruleInfo=nondeterministicPDA->ruleDefToInfoMap[rule]; Ptr newRuleInfo=new RuleInfo; automaton->AddRuleInfo(rule, newRuleInfo); ruleMap.Add(rule->name, rule); newRuleInfo->rootRuleStartState=automaton->RootRuleStartState(rule); newRuleInfo->rootRuleEndState=automaton->RootRuleEndState(rule); newRuleInfo->startState=automaton->RuleStartState(rule); oldNewStateMap.Add(ruleInfo->rootRuleStartState, newRuleInfo->rootRuleStartState); oldNewStateMap.Add(ruleInfo->rootRuleEndState, newRuleInfo->rootRuleEndState); oldNewStateMap.Add(ruleInfo->startState, newRuleInfo->startState); newRuleInfo->rootRuleStartState->stateExpression=ruleInfo->rootRuleStartState->stateExpression; newRuleInfo->rootRuleEndState->stateExpression=ruleInfo->rootRuleEndState->stateExpression; newRuleInfo->startState->stateExpression=ruleInfo->startState->stateExpression; } FOREACH(Ptr, oldState, nondeterministicPDA->states) { if((oldState->inputs.Count()>0 || oldState->transitions.Count()>0) && !oldNewStateMap.Keys().Contains(oldState.Obj())) { State* newState=automaton->CopyState(oldState.Obj()); oldNewStateMap.Add(oldState.Obj(), newState); newState->stateExpression=oldState->stateExpression; } } // create transitions FOREACH(ParsingDefinitionRuleDefinition*, rule, nondeterministicPDA->orderedRulesDefs) { Ptr ruleInfo=nondeterministicPDA->ruleDefToInfoMap[rule]; Ptr newRuleInfo=automaton->ruleDefToInfoMap[rule]; // complete new rule info FOREACH(State*, endState, ruleInfo->endStates) { newRuleInfo->endStates.Add(oldNewStateMap[endState]); } // create joint transitions according to old automaton List scanningStates; vint currentStateIndex=0; scanningStates.Add(ruleInfo->rootRuleStartState); while(currentStateIndextransitions) { State* oldSource=oldTransition->source; State* oldTarget=oldTransition->target; State* newSource=oldNewStateMap[oldSource]; State* newTarget=oldNewStateMap[oldTarget]; if(!scanningStates.Contains(oldSource)) scanningStates.Add(oldSource); if(!scanningStates.Contains(oldTarget)) scanningStates.Add(oldTarget); if(oldTransition->transitionType==Transition::Symbol && oldTransition->transitionSymbol->GetType()==ParsingSymbol::RuleDef) { // if this is a rule transition, create // source -> ruleStart // ruleEnd[] -> target ParsingDefinitionRuleDefinition* rule=ruleMap[oldTransition->transitionSymbol->GetName()]; Ptr oldRuleInfo=nondeterministicPDA->ruleDefToInfoMap[rule]; { Transition* shiftTransition=automaton->Epsilon(newSource, oldNewStateMap[oldRuleInfo->startState]); Ptr action=new Action; action->actionType=Action::Shift; action->shiftReduceSource=newSource; action->shiftReduceTarget=newTarget; action->creatorRule=shiftTransition->source->ownerRule; shiftTransition->actions.Add(action); } FOREACH(State*, oldEndState, oldRuleInfo->endStates) { Transition* reduceTransition=automaton->NormalReduce(oldNewStateMap[oldEndState], newTarget); Ptr action=new Action; action->actionType=Action::Reduce; action->shiftReduceSource=newSource; action->shiftReduceTarget=newTarget; action->creatorRule=reduceTransition->source->ownerRule; reduceTransition->actions.Add(action); CopyFrom(reduceTransition->actions, oldTransition->actions, true); } } else { // if not, just copy Transition* newTransition=automaton->CopyTransition(newSource, newTarget, oldTransition); CopyFrom(newTransition->actions, oldTransition->actions); } } } } return automaton; } /*********************************************************************** CompactJointPDA ***********************************************************************/ // closure function for searching shift-reduce-compact transition ClosureItem::SearchResult ShiftReduceCompactClosure(Transition* transition) { return transition->stackOperationType!=Transition::None?ClosureItem::Blocked: transition->transitionType!=Transition::Epsilon?ClosureItem::Hit: ClosureItem::Continue; } void CompactJointPDA(Ptr jointPDA) { FOREACH(Ptr, state, jointPDA->states) { State* currentState=state.Obj(); // search for epsilon closure List closure; SearchClosure(&ShiftReduceCompactClosure, currentState, closure); FOREACH(ClosureItem, closureItem, closure) { Transition* lastTransition=closureItem.transitions->Get(closureItem.transitions->Count()-1); Transition::StackOperationType stackOperationType=Transition::None; Transition::TransitionType transitionType=lastTransition->transitionType; if(closureItem.cycle && lastTransition->transitionType==Transition::Epsilon) { bool containsShift=false; bool containsReduce=false; FOREACH(Transition*, pathTransition, *closureItem.transitions.Obj()) { FOREACH(Ptr, action, pathTransition->actions) { if(action->actionType==Action::Shift) containsShift=true; if(action->actionType==Action::Reduce) containsReduce=true; } } if(containsShift && !containsReduce) { // a left recursive compacted shift transition is found // if the left recursive state is not the current state // that means this transition path fall into other left recursive state // e.g. // Term = Factor | Term (here is a left recursion) * Factor // Exp = Term (this rule symbol transition will fall into Term's left recursive state) ... // if such a case happened, this transition path will be simply discarded if(closureItem.state==currentState) { stackOperationType=Transition::LeftRecursive; } } else if(!containsShift && containsReduce) { // a right recursive compacted reduce transition is found // if this state will receive $TokenFinish, then the stack pattern number can be infinite // e.g. for right recursive expression "a b c" == "(a (b c))" // when trying to do a transition by $TokenFinish // "a b" should reduce once // "a b c" should reduce twice // because that a reduce is not considered a virtual token, so this is not going to be happened } } else if(closureItem.transitions->Count()>1) { // in joint PDA, only shift and reduce transitions are epsilon transition // if there are more than one transition in a path, then there should be shift or reduce transitions in the path stackOperationType=Transition::ShiftReduceCompacted; } if(stackOperationType!=Transition::None) { // build shift-reduce-compacted transition to the target state of the path Transition* transition=jointPDA->CopyTransition(currentState, lastTransition->target, lastTransition); transition->transitionType=transitionType; transition->stackOperationType=stackOperationType; // there will be , or // but there will not be something like // so we can append stackPattern safely FOREACH(Transition*, pathTransition, *closureItem.transitions.Obj()) { CopyFrom(transition->actions, pathTransition->actions, true); } } } } // delete unnecessary transactions for(vint i=jointPDA->transitions.Count()-1;i>=0;i--) { Transition* transition=jointPDA->transitions[i].Obj(); if(transition->stackOperationType==Transition::None && transition->transitionType==Transition::Epsilon) { jointPDA->DeleteTransition(transition); } } } /*********************************************************************** MarkLeftRecursiveInJointPDA ***********************************************************************/ void MarkLeftRecursiveInJointPDA(Ptr jointPDA, collections::List>& errors) { vint errorCount=errors.Count(); // record all left recursive shifts and delete all left recursive epsilon transition SortedList> leftRecursiveShifts; FOREACH(Ptr, state, jointPDA->states) { for(vint i=state->transitions.Count()-1;i>=0;i--) { Transition* transition=state->transitions[i]; if(transition->stackOperationType==Transition::LeftRecursive) { Ptr shiftAction; FOREACH(Ptr, action, transition->actions) { if(action->actionType==Action::Shift) { if(shiftAction) { errors.Add(new ParsingError(state->ownerRule, L"Indirect left recursive transition in rule \""+state->ownerRule->name+L"\" is not allowed.")); goto FOUND_INDIRECT_LEFT_RECURSIVE_TRANSITION; } else { shiftAction=action; } } } if(shiftAction) { leftRecursiveShifts.Add(Pair(shiftAction->shiftReduceSource, shiftAction->shiftReduceTarget)); } FOUND_INDIRECT_LEFT_RECURSIVE_TRANSITION: jointPDA->DeleteTransition(transition); } } } if(errorCount!=errors.Count()) { return; } // change all reduce actions whose (shiftReduceSource, shiftReduceTarget) is recorded in leftRecursiveShifts to left-recursive-reduce // when a reduce is converted to a left-recursive-reduce, the corresponding state in stackPattern should be removed // so this will keep count(Reduce) == count(stackPattern) FOREACH(Ptr, state, jointPDA->states) { FOREACH(Transition*, transition, state->transitions) { for(vint i=transition->actions.Count()-1;i>=0;i--) { Ptr action=transition->actions[i]; if(action->actionType==Action::Reduce) { Pair shift(action->shiftReduceSource, action->shiftReduceTarget); if(leftRecursiveShifts.Contains(shift)) { // check if this is a normal reduce transition, and change it to a left recursive reduce transition. if (transition->transitionType == Transition::NormalReduce) { transition->transitionType = Transition::LeftRecursiveReduce; // need to create a new action because in the previous phrases, these action object are shared and treated as read only Ptr newAction=new Action; newAction->actionType=Action::LeftRecursiveReduce; newAction->actionSource=action->actionSource; newAction->actionTarget=action->actionTarget; newAction->creatorRule=action->creatorRule; newAction->shiftReduceSource=action->shiftReduceSource; newAction->shiftReduceTarget=action->shiftReduceTarget; newAction->creatorRule=shift.key->ownerRule; transition->actions[i]=newAction; } else { errors.Add(new ParsingError(state->ownerRule, L"Left recursive reduce action in non-normal-reduce found in rule \""+state->ownerRule->name+L"\" is not allowed.")); } } } } } } // delete complicated transitions FOREACH(Ptr, state, jointPDA->states) { while(true) { bool deleted=false; FOREACH(Transition*, t1, state->transitions) FOREACH(Transition*, t2, state->transitions) if(t1!=t2) { if(Transition::IsEquivalent(t1, t2, true)) { jointPDA->DeleteTransition(t2); deleted=true; goto TRANSITION_DELETED; } } TRANSITION_DELETED: if(!deleted) break; } } } } } } /*********************************************************************** .\PARSING\PARSINGAUTOMATON_MERGESTATES.CPP ***********************************************************************/ namespace vl { namespace parsing { using namespace collections; using namespace definitions; namespace analyzing { /*********************************************************************** DeleteUnnecessaryStates ***********************************************************************/ void DeleteUnnecessaryStates(Ptr automaton, Ptr ruleInfo, List& newStates) { // delete all states that are not reachable to the end state while(true) { // find a non-end state without out transitions vint deleteCount=0; for(vint i=newStates.Count()-1;i>=0;i--) { State* newState=newStates[i]; if(newState->transitions.Count()==0) { if(newState!=ruleInfo->rootRuleEndState && !newState->endState) { automaton->DeleteState(newState); newStates.RemoveAt(i); } } } if(deleteCount==0) { break; } } } /*********************************************************************** IsMergableCandidate ***********************************************************************/ bool IsMergableCandidate(State* state, Ptr ruleInfo) { if(state==ruleInfo->rootRuleStartState || state==ruleInfo->rootRuleEndState || state==ruleInfo->startState) { return false; } return true; } /*********************************************************************** RearrangeState ***********************************************************************/ #define COMPARE_SYMBOL(S1, S2)\ if (S1 && S2)\ {\ if (S1->GetType() < S2->GetType()) return -1;\ if (S1->GetType() > S2->GetType()) return 1;\ if (S1->GetName() < S2->GetName()) return -1;\ if (S1->GetName() > S2->GetName()) return 1;\ }\ else if (S1)\ {\ return 1;\ }\ else if (S2)\ {\ return -1;\ }\ vint CompareTransitionForRearranging(Transition* t1, Transition* t2) { if (t1->transitionType < t2->transitionType) return -1; if (t1->transitionType > t2->transitionType) return 1; COMPARE_SYMBOL(t1->transitionSymbol, t2->transitionSymbol); return 0; } vint CompareActionForRearranging(Ptr a1, Ptr a2) { if(a1->actionTypeactionType) return -1; if(a1->actionType>a2->actionType) return 1; COMPARE_SYMBOL(a1->actionSource, a2->actionSource); COMPARE_SYMBOL(a1->actionTarget, a2->actionTarget); return 0; } #undef COMPARE_SYMBOL void RearrangeState(State* state, SortedList& stateContentSorted) { if(!stateContentSorted.Contains(state)) { FOREACH(Transition*, transition, state->transitions) { CopyFrom(transition->actions, From(transition->actions).OrderBy(&CompareActionForRearranging)); } CopyFrom(state->transitions, From(state->transitions).OrderBy(&CompareTransitionForRearranging)); stateContentSorted.Add(state); } } /*********************************************************************** MoveActionsForMergingState ***********************************************************************/ void MoveActionsForMergingState(Transition* transition) { // collect all movable actions List> movableActions; for(vint i=transition->actions.Count()-1;i>=0;i--) { switch(transition->actions[i]->actionType) { // Using and Assign actions are not movable case Action::Using: case Action::Assign: break; default: movableActions.Add(transition->actions[i]); transition->actions.RemoveAt(i); } } // copy all movable actions FOREACH(Transition*, t, transition->source->inputs) { CopyFrom(t->actions, movableActions, true); } } /*********************************************************************** IsMergableBecause(Transitions|Input) ***********************************************************************/ bool IsMergableBecauseTransitions(State* state1, State* state2) { if(state1->transitions.Count()!=state2->transitions.Count()) return false; if(state1->transitions.Count()==1 && state2->transitions.Count()==1) { Transition* t1=state1->transitions[0]; Transition* t2=state2->transitions[0]; if(CompareTransitionForRearranging(t1, t2)==0 && !Transition::IsEquivalent(t1, t2, false) && t1->target==t2->target) { MoveActionsForMergingState(t1); MoveActionsForMergingState(t2); } } for(vint i=0;itransitions.Count();i++) { Transition* t1=state1->transitions[i]; Transition* t2=state2->transitions[i]; if(!Transition::IsEquivalent(t1, t2, false) || t1->target!=t2->target) { return false; } } return true; } bool IsMergableBecauseInputs(State* state1, State* state2) { if(state1->inputs.Count()!=state2->inputs.Count()) return false; for(vint i=0;iinputs.Count();i++) { Transition* t1=state1->inputs[i]; Transition* t2=state2->inputs[i]; if(!Transition::IsEquivalent(t1, t2, false) || t1->source!=t2->source) { return false; } } return true; } /*********************************************************************** MergeState2ToState1Because(Transitions|Input) ***********************************************************************/ void MergeState2ToState1BecauseTransitions(Ptr automaton, State* state1, State* state2) { // modify state1's expression state1->stateExpression+=L"\r\n"+state2->stateExpression; // retarget state2's input to state1 for(vint i=state2->inputs.Count()-1;i>=0;i--) { Transition* t2=state2->inputs[i]; bool add=true; FOREACH(Transition*, t1, state1->inputs) { if(Transition::IsEquivalent(t1, t2, false) && t1->source==t2->source) { add=false; break; } } if(add) { state1->inputs.Add(t2); t2->target=state1; state2->inputs.RemoveAt(i); } } automaton->DeleteState(state2); } void MergeState2ToState1BecauseInputs(Ptr automaton, State* state1, State* state2) { // modify state1's expression state1->stateExpression+=L"\r\n"+state2->stateExpression; // retarget state2's input to state1 for(vint i=state2->transitions.Count()-1;i>=0;i--) { Transition* t2=state2->transitions[i]; bool add=true; FOREACH(Transition*, t1, state1->transitions) { if(Transition::IsEquivalent(t1, t2, false) && t1->target==t2->target) { add=false; break; } } if(add) { state1->transitions.Add(t2); t2->source=state1; state2->transitions.RemoveAt(i); } } automaton->DeleteState(state2); } /*********************************************************************** MergeStates ***********************************************************************/ void MergeStates(Ptr automaton, Ptr ruleInfo, List& newStates) { SortedList stateContentSorted; while(true) { for(vint i=0;i CreateNondeterministicPDAFromEpsilonPDA(Ptr epsilonPDA) { Ptr automaton=new Automaton(epsilonPDA->symbolManager); FOREACH(ParsingDefinitionRuleDefinition*, rule, epsilonPDA->orderedRulesDefs) { // build new rule info Ptr ruleInfo=epsilonPDA->ruleDefToInfoMap[rule]; Ptr newRuleInfo=new RuleInfo; automaton->AddRuleInfo(rule, newRuleInfo); newRuleInfo->rootRuleStartState=automaton->RootRuleStartState(rule); newRuleInfo->rootRuleEndState=automaton->RootRuleEndState(rule); newRuleInfo->startState=automaton->RuleStartState(rule); // build state mapping and state visiting tracking Dictionary oldNewStateMap; List scanningStates; vint currentStateIndex=0; oldNewStateMap.Add(ruleInfo->rootRuleStartState, newRuleInfo->rootRuleStartState); oldNewStateMap.Add(ruleInfo->rootRuleEndState, newRuleInfo->rootRuleEndState); oldNewStateMap.Add(ruleInfo->startState, newRuleInfo->startState); // begin with a root rule state state scanningStates.Add(ruleInfo->rootRuleStartState); // remove epsilon transitions RemoveEpsilonTransitions(oldNewStateMap, scanningStates, automaton); // stable state orders List newStates; CopyFrom( newStates, From(epsilonPDA->states) .Where([&](Ptr s) {return oldNewStateMap.Keys().Contains(s.Obj()); }) .Select([&](Ptr s) { return oldNewStateMap[s.Obj()]; }) ); DeleteUnnecessaryStates(automaton, newRuleInfo, newStates); MergeStates(automaton, newRuleInfo, newStates); // there should be at east one and only one transition that is TokenBegin from rootRuleStartState // update the startState because the startState may be deleted newRuleInfo->startState=newRuleInfo->rootRuleStartState->transitions[0]->target; // record end states FOREACH(State*, state, newStates) { if(state->endState) { newRuleInfo->endStates.Add(state); } } } return automaton; } } } } /*********************************************************************** .\PARSING\PARSINGDEFINITIONS.CPP ***********************************************************************/ namespace vl { using namespace collections; namespace parsing { namespace definitions { /*********************************************************************** ParsingDefinitionType(Visitor) ***********************************************************************/ void ParsingDefinitionPrimitiveType::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionTokenType::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionSubType::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionArrayType::Accept(IVisitor* visitor) { visitor->Visit(this); } /*********************************************************************** ParsingDefinitionTypeDefinition(Visitor) ***********************************************************************/ void ParsingDefinitionClassMemberDefinition::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionClassDefinition::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionEnumMemberDefinition::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionEnumDefinition::Accept(IVisitor* visitor) { visitor->Visit(this); } /*********************************************************************** ParsingDefinitionGrammar(Visitor) ***********************************************************************/ void ParsingDefinitionPrimitiveGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionTextGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionSequenceGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionAlternativeGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionLoopGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionOptionalGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionCreateGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionAssignGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionUseGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } void ParsingDefinitionSetterGrammar::Accept(IVisitor* visitor) { visitor->Visit(this); } /*********************************************************************** ParsingDefinitionTypeWriter ***********************************************************************/ ParsingDefinitionAttributeWriter::ParsingDefinitionAttributeWriter(const WString& name) { attribute=new ParsingDefinitionAttribute; attribute->name=name; } ParsingDefinitionAttributeWriter::ParsingDefinitionAttributeWriter(const ParsingDefinitionAttributeWriter& attributeWriter) { attribute=attributeWriter.attribute; } ParsingDefinitionAttributeWriter& ParsingDefinitionAttributeWriter::Argument(const WString& argument) { attribute->arguments.Add(argument); return *this; } Ptr ParsingDefinitionAttributeWriter::Attribute()const { return attribute; } ParsingDefinitionAttributeWriter Attribute(const WString& name) { return ParsingDefinitionAttributeWriter(name); } /*********************************************************************** ParsingDefinitionTypeWriter ***********************************************************************/ ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(Ptr internalType) { type=internalType; } ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(const ParsingDefinitionTypeWriter& typeWriter) { type=typeWriter.type; } ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(const WString& name) { Ptr primitiveType=new ParsingDefinitionPrimitiveType; primitiveType->name=name; type=primitiveType; } ParsingDefinitionTypeWriter ParsingDefinitionTypeWriter::Sub(const WString& subTypeName)const { Ptr subType=new ParsingDefinitionSubType; subType->parentType=type; subType->subTypeName=subTypeName; return ParsingDefinitionTypeWriter(subType); } ParsingDefinitionTypeWriter ParsingDefinitionTypeWriter::Array()const { Ptr arrayType=new ParsingDefinitionArrayType; arrayType->elementType=type; return ParsingDefinitionTypeWriter(arrayType); } Ptr ParsingDefinitionTypeWriter::Type()const { return type; } ParsingDefinitionTypeWriter Type(const WString& name) { return ParsingDefinitionTypeWriter(name); } ParsingDefinitionTypeWriter TokenType() { Ptr type=new ParsingDefinitionTokenType; return ParsingDefinitionTypeWriter(type); } /*********************************************************************** ParsingDefinitionClassDefinitionWriter ***********************************************************************/ ParsingDefinitionClassDefinitionWriter::ParsingDefinitionClassDefinitionWriter(const WString& name) { definition=new ParsingDefinitionClassDefinition; definition->name=name; currentDefinition=definition; } ParsingDefinitionClassDefinitionWriter::ParsingDefinitionClassDefinitionWriter(const WString& name, const ParsingDefinitionTypeWriter& parentType) { definition=new ParsingDefinitionClassDefinition; definition->name=name; definition->parentType=parentType.Type(); currentDefinition=definition; } ParsingDefinitionClassDefinitionWriter& ParsingDefinitionClassDefinitionWriter::AmbiguousType(const ParsingDefinitionTypeWriter& ambiguousType) { definition->ambiguousType=ambiguousType.Type(); return *this; } ParsingDefinitionClassDefinitionWriter& ParsingDefinitionClassDefinitionWriter::Member(const WString& name, const ParsingDefinitionTypeWriter& type, const WString& unescapingFunction) { Ptr member=new ParsingDefinitionClassMemberDefinition; member->name=name; member->type=type.Type(); member->unescapingFunction=unescapingFunction; definition->members.Add(member); currentDefinition=member; return *this; } ParsingDefinitionClassDefinitionWriter& ParsingDefinitionClassDefinitionWriter::SubType(const ParsingDefinitionTypeDefinitionWriter& type) { definition->subTypes.Add(type.Definition()); return *this; } ParsingDefinitionClassDefinitionWriter& ParsingDefinitionClassDefinitionWriter::Attribute(const ParsingDefinitionAttributeWriter& attribute) { currentDefinition->attributes.Add(attribute.Attribute()); return *this; } Ptr ParsingDefinitionClassDefinitionWriter::Definition()const { return definition; } ParsingDefinitionClassDefinitionWriter Class(const WString& name) { return ParsingDefinitionClassDefinitionWriter(name); } ParsingDefinitionClassDefinitionWriter Class(const WString& name, const ParsingDefinitionTypeWriter& parentType) { return ParsingDefinitionClassDefinitionWriter(name, parentType); } /*********************************************************************** ParsingDefinitionEnumDefinitionWriter ***********************************************************************/ ParsingDefinitionEnumDefinitionWriter::ParsingDefinitionEnumDefinitionWriter(const WString& name) { definition=new ParsingDefinitionEnumDefinition; definition->name=name; currentDefinition=definition; } ParsingDefinitionEnumDefinitionWriter& ParsingDefinitionEnumDefinitionWriter::Member(const WString& name) { Ptr member=new ParsingDefinitionEnumMemberDefinition; member->name=name; definition->members.Add(member); currentDefinition=member; return *this; } ParsingDefinitionEnumDefinitionWriter& ParsingDefinitionEnumDefinitionWriter::Attribute(const ParsingDefinitionAttributeWriter& attribute) { currentDefinition->attributes.Add(attribute.Attribute()); return *this; } Ptr ParsingDefinitionEnumDefinitionWriter::Definition()const { return definition; } ParsingDefinitionEnumDefinitionWriter Enum(const WString& name) { return ParsingDefinitionEnumDefinitionWriter(name); } /*********************************************************************** ParsingDefinitionGrammarWriter ***********************************************************************/ ParsingDefinitionGrammarWriter::ParsingDefinitionGrammarWriter(Ptr internalGrammar) { grammar=internalGrammar; } ParsingDefinitionGrammarWriter::ParsingDefinitionGrammarWriter(const ParsingDefinitionGrammarWriter& grammarWriter) { grammar=grammarWriter.grammar; } ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator+(const ParsingDefinitionGrammarWriter& next)const { Ptr sequence=new ParsingDefinitionSequenceGrammar; sequence->first=grammar; sequence->second=next.Grammar(); return ParsingDefinitionGrammarWriter(sequence); } ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator|(const ParsingDefinitionGrammarWriter& next)const { Ptr alternative=new ParsingDefinitionAlternativeGrammar; alternative->first=grammar; alternative->second=next.Grammar(); return ParsingDefinitionGrammarWriter(alternative); } ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator*()const { Ptr loop=new ParsingDefinitionLoopGrammar; loop->grammar=grammar; return ParsingDefinitionGrammarWriter(loop); } ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::As(const ParsingDefinitionTypeWriter& type)const { Ptr create=new ParsingDefinitionCreateGrammar; create->grammar=grammar; create->type=type.Type(); return ParsingDefinitionGrammarWriter(create); } ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator[](const WString& memberName)const { Ptr assign=new ParsingDefinitionAssignGrammar; assign->grammar=grammar; assign->memberName=memberName; return ParsingDefinitionGrammarWriter(assign); } ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator!()const { Ptr use=new ParsingDefinitionUseGrammar; use->grammar=grammar; return ParsingDefinitionGrammarWriter(use); } ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::Set(const WString& memberName, const WString& value)const { Ptr setter=new ParsingDefinitionSetterGrammar; setter->grammar=grammar; setter->memberName=memberName; setter->value=value; return ParsingDefinitionGrammarWriter(setter); } Ptr ParsingDefinitionGrammarWriter::Grammar()const { return grammar; } ParsingDefinitionGrammarWriter Rule(const WString& name) { Ptr grammar=new ParsingDefinitionPrimitiveGrammar; grammar->name=name; return ParsingDefinitionGrammarWriter(grammar); } ParsingDefinitionGrammarWriter Text(const WString& text) { Ptr grammar=new ParsingDefinitionTextGrammar; grammar->text=text; return ParsingDefinitionGrammarWriter(grammar); } ParsingDefinitionGrammarWriter Opt(const ParsingDefinitionGrammarWriter& writer) { Ptr grammar=new ParsingDefinitionOptionalGrammar; grammar->grammar=writer.Grammar(); return ParsingDefinitionGrammarWriter(grammar); } /*********************************************************************** ParsingDefinitionTokenDefinitionWriter ***********************************************************************/ ParsingDefinitionTokenDefinitionWriter::ParsingDefinitionTokenDefinitionWriter(ParsingDefinitionWriter& _owner, Ptr _token) :owner(_owner) ,token(_token) { } ParsingDefinitionTokenDefinitionWriter& ParsingDefinitionTokenDefinitionWriter::Attribute(const ParsingDefinitionAttributeWriter& attribute) { token->attributes.Add(attribute.Attribute()); return *this; } ParsingDefinitionWriter& ParsingDefinitionTokenDefinitionWriter::EndToken() { return owner; } /*********************************************************************** ParsingDefinitionRuleDefinitionWriter ***********************************************************************/ ParsingDefinitionRuleDefinitionWriter::ParsingDefinitionRuleDefinitionWriter(ParsingDefinitionWriter& _owner, Ptr _rule) :owner(_owner) ,rule(_rule) { } ParsingDefinitionRuleDefinitionWriter& ParsingDefinitionRuleDefinitionWriter::Imply(const ParsingDefinitionGrammarWriter& grammar) { rule->grammars.Add(grammar.Grammar()); return *this; } ParsingDefinitionRuleDefinitionWriter& ParsingDefinitionRuleDefinitionWriter::Attribute(const ParsingDefinitionAttributeWriter& attribute) { rule->attributes.Add(attribute.Attribute()); return *this; } ParsingDefinitionWriter& ParsingDefinitionRuleDefinitionWriter::EndRule() { return owner; } /*********************************************************************** ParsingDefinitionWriter ***********************************************************************/ ParsingDefinitionWriter::ParsingDefinitionWriter() { definition=new ParsingDefinition; } ParsingDefinitionWriter& ParsingDefinitionWriter::Type(const ParsingDefinitionTypeDefinitionWriter& type) { definition->types.Add(type.Definition()); return *this; } ParsingDefinitionWriter& ParsingDefinitionWriter::Token(const WString& name, const WString& regex) { return TokenAtt(name, regex).EndToken(); } ParsingDefinitionTokenDefinitionWriter ParsingDefinitionWriter::TokenAtt(const WString& name, const WString& regex) { Ptr token=new ParsingDefinitionTokenDefinition; token->name=name; token->regex=regex; token->discard=false; definition->tokens.Add(token); return ParsingDefinitionTokenDefinitionWriter(*this, token); } ParsingDefinitionWriter& ParsingDefinitionWriter::Discard(const WString& name, const WString& regex) { Ptr token=new ParsingDefinitionTokenDefinition; token->name=name; token->regex=regex; token->discard=true; definition->tokens.Add(token); return *this; } ParsingDefinitionRuleDefinitionWriter ParsingDefinitionWriter::Rule(const WString& name, const ParsingDefinitionTypeWriter& type) { Ptr rule=new ParsingDefinitionRuleDefinition; rule->name=name; rule->type=type.Type(); definition->rules.Add(rule); return ParsingDefinitionRuleDefinitionWriter(*this, rule); } Ptr ParsingDefinitionWriter::Definition()const { return definition; } } } } /*********************************************************************** .\PARSING\PARSINGDEFINITIONS_CREATEPARSERDEFINITION.CPP ***********************************************************************/ namespace vl { namespace parsing { namespace definitions { using namespace collections; /*********************************************************************** Bootstrap ***********************************************************************/ Ptr CreateParserDefinition() { ParsingDefinitionWriter definitionWriter; definitionWriter .Type( Class(L"AttributeDef") .Member(L"name", TokenType()) .Attribute(Attribute(L"Semantic").Argument(L"Attribute")) .Member(L"arguments", TokenType().Array()) ) .Type( Class(L"DefBase") .Member(L"attributes", Type(L"AttributeDef").Array()) ) //------------------------------------- .Type( Class(L"TypeObj") ) .Type( Class(L"PrimitiveTypeObj", Type(L"TypeObj")) .Member(L"name", TokenType()) .Attribute(Attribute(L"Semantic").Argument(L"Type")) ) .Type( Class(L"TokenTypeObj", Type(L"TypeObj")) ) .Type( Class(L"SubTypeObj", Type(L"TypeObj")) .Member(L"parentType", Type(L"TypeObj")) .Member(L"name", TokenType()) .Attribute(Attribute(L"Semantic").Argument(L"Type")) ) .Type( Class(L"ArrayTypeObj", Type(L"TypeObj")) .Member(L"elementType", Type(L"TypeObj")) ) //------------------------------------- .Type( Class(L"TypeDef", Type(L"DefBase")) .Member(L"name", TokenType()) .Attribute(Attribute(L"Color").Argument(L"Type")) ) .Type( Class(L"ClassMemberDef", Type(L"DefBase")) .Member(L"type", Type(L"TypeObj")) .Member(L"name", TokenType()) .Member(L"unescapingFunction", TokenType()) ) .Type( Class(L"ClassTypeDef", Type(L"TypeDef")) .Member(L"ambiguousType", Type(L"TypeObj")) .Member(L"parentType", Type(L"TypeObj")) .Member(L"members", Type(L"ClassMemberDef").Array()) .Member(L"subTypes", Type(L"TypeDef").Array()) ) .Type( Class(L"EnumMemberDef", Type(L"DefBase")) .Member(L"name", TokenType()) ) .Type( Class(L"EnumTypeDef", Type(L"TypeDef")) .Member(L"members", Type(L"EnumMemberDef").Array()) ) //------------------------------------- .Type( Class(L"GrammarDef") ) .Type( Class(L"PrimitiveGrammarDef", Type(L"GrammarDef")) .Member(L"name", TokenType()) .Attribute(Attribute(L"Semantic").Argument(L"Token").Argument(L"Rule")) ) .Type( Class(L"TextGrammarDef", Type(L"GrammarDef")) .Member(L"text", TokenType()) .Attribute(Attribute(L"Semantic").Argument(L"Literal")) ) .Type( Class(L"SequenceGrammarDef", Type(L"GrammarDef")) .Member(L"first", Type(L"GrammarDef")) .Member(L"second", Type(L"GrammarDef")) ) .Type( Class(L"AlternativeGrammarDef", Type(L"GrammarDef")) .Member(L"first", Type(L"GrammarDef")) .Member(L"second", Type(L"GrammarDef")) ) .Type( Class(L"LoopGrammarDef", Type(L"GrammarDef")) .Member(L"grammar", Type(L"GrammarDef")) ) .Type( Class(L"OptionalGrammarDef", Type(L"GrammarDef")) .Member(L"grammar", Type(L"GrammarDef")) ) .Type( Class(L"CreateGrammarDef", Type(L"GrammarDef")) .Member(L"grammar", Type(L"GrammarDef")) .Member(L"type", Type(L"TypeObj")) ) .Type( Class(L"AssignGrammarDef", Type(L"GrammarDef")) .Member(L"grammar", Type(L"GrammarDef")) .Member(L"memberName", TokenType()) .Attribute(Attribute(L"Semantic").Argument(L"Field")) ) .Type( Class(L"UseGrammarDef", Type(L"GrammarDef")) .Member(L"grammar", Type(L"GrammarDef")) ) .Type( Class(L"SetterGrammarDef", Type(L"GrammarDef")) .Member(L"grammar", Type(L"GrammarDef")) .Member(L"memberName", TokenType()) .Attribute(Attribute(L"Semantic").Argument(L"Field")) .Member(L"value", TokenType()) .Attribute(Attribute(L"Semantic").Argument(L"EnumValue")) ) //------------------------------------- .Type( Class(L"TokenDef", Type(L"DefBase")) .SubType( Enum(L"DiscardOption") .Member(L"DiscardToken") .Member(L"KeepToken") ) .Member(L"name", TokenType()) .Attribute(Attribute(L"Color").Argument(L"Token")) .Member(L"regex", TokenType()) .Member(L"discard", Type(L"DiscardOption")) ) .Type( Class(L"RuleDef", Type(L"DefBase")) .Member(L"name", TokenType()) .Attribute(Attribute(L"Color").Argument(L"Rule")) .Member(L"type", Type(L"TypeObj")) .Member(L"grammars", Type(L"GrammarDef").Array()) ) .Type( Class(L"ParserDef") .Member(L"definitions", Type(L"DefBase").Array()) ) //------------------------------------- .TokenAtt(L"CLASS", L"class") .Attribute(Attribute(L"Color").Argument(L"Keyword")) .Attribute(Attribute(L"Candidate")) .EndToken() .TokenAtt(L"AMBIGUOUS", L"ambiguous") .Attribute(Attribute(L"Color").Argument(L"Keyword")) .Attribute(Attribute(L"Candidate")) .EndToken() .TokenAtt(L"ENUM", L"enum") .Attribute(Attribute(L"Color").Argument(L"Keyword")) .Attribute(Attribute(L"Candidate")) .EndToken() .TokenAtt(L"TOKEN", L"token") .Attribute(Attribute(L"Color").Argument(L"Keyword")) .Attribute(Attribute(L"Candidate")) .EndToken() .TokenAtt(L"DISCARDTOKEN", L"discardtoken") .Attribute(Attribute(L"Color").Argument(L"Keyword")) .Attribute(Attribute(L"Candidate")) .EndToken() .TokenAtt(L"RULE", L"rule") .Attribute(Attribute(L"Color").Argument(L"Keyword")) .Attribute(Attribute(L"Candidate")) .EndToken() .TokenAtt(L"AS", L"as") .Attribute(Attribute(L"Color").Argument(L"Keyword")) .Attribute(Attribute(L"Candidate")) .EndToken() .TokenAtt(L"WITH", L"with") .Attribute(Attribute(L"Color").Argument(L"Keyword")) .Attribute(Attribute(L"Candidate")) .EndToken() .Token(L"OPEN", L"/{") .Token(L"CLOSE", L"/}") .Token(L"SEMICOLON", L";") .Token(L"COLON", L":") .Token(L"COMMA", L",") .Token(L"DOT", L".") .Token(L"ASSIGN", L"/=") .Token(L"USING", L"/!") .Token(L"OR", L"/|") .Token(L"OPTOPEN", L"/[") .Token(L"OPTCLOSE", L"/]") .Token(L"PREOPEN", L"/(") .Token(L"PRECLOSE", L"/)") .TokenAtt(L"ATT", L"@") .Attribute(Attribute(L"Color").Argument(L"Attribute")) .EndToken() .TokenAtt(L"NAME", L"[a-zA-Z_]/w*") .Attribute(Attribute(L"Color").Argument(L"Default")) .Attribute(Attribute(L"ContextColor")) .Attribute(Attribute(L"AutoComplete")) .EndToken() .TokenAtt(L"STRING", L"\"([^\"]|\"\")*\"") .Attribute(Attribute(L"Color").Argument(L"String")) .Attribute(Attribute(L"AutoComplete")) .EndToken() .Discard(L"SPACE", L"/s+") .Discard(L"COMMENT", L"////[^\\r\\n]*") //------------------------------------- .Rule(L"Attribute", Type(L"AttributeDef")) .Imply( (Text(L"@") + Rule(L"NAME")[L"name"] + Text(L"(") + Opt(Rule(L"STRING")[L"arguments"] + *(Text(L",") + Rule(L"STRING")[L"arguments"])) + Text(L")")) .As(Type(L"AttributeDef")) ) .EndRule() //------------------------------------- .Rule(L"Type", Type(L"TypeObj")) .Imply( (Rule(L"NAME")[L"name"]) .As(Type(L"PrimitiveTypeObj")) ) .Imply( Text(L"token") .As(Type(L"TokenTypeObj")) ) .Imply( (Rule(L"Type")[L"parentType"] + Text(L".") + Rule(L"NAME")[L"name"]) .As(Type(L"SubTypeObj")) ) .Imply( (Rule(L"Type")[L"elementType"] + Text(L"[") + Text(L"]")) .As(Type(L"ArrayTypeObj")) ) .EndRule() //------------------------------------- .Rule(L"EnumMember", Type(L"EnumMemberDef")) .Imply( ( Rule(L"NAME")[L"name"] + Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"])) + Text(L",") ) .As(Type(L"EnumMemberDef")) ) .EndRule() .Rule(L"Enum", Type(L"EnumTypeDef")) .Imply( ( Text(L"enum") + Rule(L"NAME")[L"name"] + Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"])) + Text(L"{") + *(Rule(L"EnumMember")[L"members"]) + Text(L"}") ) .As(Type(L"EnumTypeDef")) ) .EndRule() .Rule(L"ClassMember", Type(L"ClassMemberDef")) .Imply( ( Rule(L"Type")[L"type"] + Rule(L"NAME")[L"name"] + Opt(Text(L"(") + Rule(L"NAME")[L"unescapingFunction"] + Text(L")")) + Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"])) + Text(L";") ) .As(Type(L"ClassMemberDef")) ) .EndRule() .Rule(L"Class", Type(L"ClassTypeDef")) .Imply( ( Text(L"class") + Rule(L"NAME")[L"name"] + Opt(Text(L"ambiguous") + Text(L"(") + Rule(L"Type")[L"ambiguousType"] + Text(L")")) + Opt(Text(L":") + Rule(L"Type")[L"parentType"]) + Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"])) + Text(L"{") + *(Rule(L"ClassMember")[L"members"] | Rule(L"TypeDecl")[L"subTypes"]) + Text(L"}") ) .As(Type(L"ClassTypeDef")) ) .EndRule() .Rule(L"TypeDecl", Type(L"TypeDef")) .Imply(!Rule(L"Enum") | !Rule(L"Class")) .EndRule() //------------------------------------ .Rule(L"PrimitiveGrammar", Type(L"GrammarDef")) .Imply( (Rule(L"NAME")[L"name"]) .As(Type(L"PrimitiveGrammarDef")) ) .Imply( (Rule(L"STRING")[L"text"]) .As(Type(L"TextGrammarDef")) ) .Imply( (Rule(L"PrimitiveGrammar")[L"grammar"] + Text(L":") + Rule(L"NAME")[L"memberName"]) .As(Type(L"AssignGrammarDef")) ) .Imply( (Text(L"!") + Rule(L"PrimitiveGrammar")[L"grammar"]) .As(Type(L"UseGrammarDef")) ) .Imply( (Text(L"[") + Rule(L"Grammar")[L"grammar"] + Text(L"]")) .As(Type(L"OptionalGrammarDef")) ) .Imply( (Text(L"{") + Rule(L"Grammar")[L"grammar"] + Text(L"}")) .As(Type(L"LoopGrammarDef")) ) .Imply( (Text(L"(") + !Rule(L"Grammar") + Text(L")")) ) .EndRule() .Rule(L"SequenceGrammar", Type(L"GrammarDef")) .Imply( !Rule(L"PrimitiveGrammar") ) .Imply( (Rule(L"SequenceGrammar")[L"first"] + Rule(L"PrimitiveGrammar")[L"second"]) .As(Type(L"SequenceGrammarDef")) ) .EndRule() .Rule(L"AlternativeGrammar", Type(L"GrammarDef")) .Imply( !Rule(L"SequenceGrammar") ) .Imply( (Rule(L"AlternativeGrammar")[L"first"] + Text(L"|") + Rule(L"SequenceGrammar")[L"second"]) .As(Type(L"AlternativeGrammarDef")) ) .EndRule() .Rule(L"Grammar", Type(L"GrammarDef")) .Imply( !Rule(L"AlternativeGrammar") ) .Imply( (Rule(L"Grammar")[L"grammar"] + Text(L"as") + Rule(L"Type")[L"type"]) .As(Type(L"CreateGrammarDef")) ) .Imply( (Rule(L"Grammar")[L"grammar"] + Text(L"with") + Text(L"{") + Rule(L"NAME")[L"memberName"] + Text(L"=") + Rule(L"STRING")[L"value"] + Text(L"}")) .As(Type(L"SetterGrammarDef")) ) .EndRule() //------------------------------------ .Rule(L"TokenDecl", Type(L"TokenDef")) .Imply( ( Text(L"token") + Rule(L"NAME")[L"name"] + Text(L"=") + Rule(L"STRING")[L"regex"] + Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"])) + Text(L";") ) .As(Type(L"TokenDef")) .Set(L"discard", L"KeepToken") ) .Imply( (Text(L"discardtoken") + Rule(L"NAME")[L"name"] + Text(L"=") + Rule(L"STRING")[L"regex"] + Text(L";")) .As(Type(L"TokenDef")) .Set(L"discard", L"DiscardToken") ) .EndRule() .Rule(L"RuleDecl", Type(L"RuleDef")) .Imply( ( Text(L"rule") + Rule(L"Type")[L"type"] + Rule(L"NAME")[L"name"] + Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"])) + *(Text(L"=") + Rule(L"Grammar")[L"grammars"]) + Text(L";") ) .As(Type(L"RuleDef")) ) .EndRule() //------------------------------------ .Rule(L"ParserDecl", Type(L"ParserDef")) .Imply( ( *( Rule(L"TypeDecl")[L"definitions"] | Rule(L"TokenDecl")[L"definitions"] | Rule(L"RuleDecl")[L"definitions"] ) +( Rule(L"TypeDecl")[L"definitions"] | Rule(L"TokenDecl")[L"definitions"] | Rule(L"RuleDecl")[L"definitions"] ) ) .As(Type(L"ParserDef")) ) .EndRule() ; return definitionWriter.Definition(); } WString DeserializeString(const WString& value) { if(value.Length()>=2 && value[0]==L'"' && value[value.Length()-1]==L'"') { Array chars(value.Length()); memset(&chars[0], 0, chars.Count()*sizeof(wchar_t)); const wchar_t* reading=value.Buffer()+1; wchar_t* writing=&chars[0]; while(*reading) { if(*reading!=L'"') { *writing++=*reading++; } else if(reading[1]!=L'"') { break; } else { *writing++=L'"'; reading+=2; } } return &chars[0]; } return L""; } WString DeserializeString(Ptr token) { const WString& value=token->GetValue(); return DeserializeString(value); } void SetName(WString& target, Ptr node) { Ptr token=node.Cast(); if(token) { target=token->GetValue(); } } void SetText(WString& target, Ptr node) { Ptr token=node.Cast(); if(token) { target=DeserializeString(token); } } extern Ptr Deserialize(Ptr node); template void SetArray(List>& target, Ptr node) { Ptr source=node.Cast(); if(source) { for(vint i=0;iCount();i++) { target.Add(Deserialize(source->GetItem(i).Cast()).Cast()); } } } void SetArray(List& target, Ptr node) { Ptr source=node.Cast(); if(source) { for(vint i=0;iCount();i++) { WString name; SetName(name, source->GetItem(i)); target.Add(name); } } } template void SetMember(Ptr& target, Ptr node) { Ptr source=node.Cast(); if(source) { target=Deserialize(source).Cast(); } } Ptr Deserialize(Ptr node) { if(!node) { return 0; } else if(node->GetType()==L"AttributeDef") { Ptr target=new ParsingDefinitionAttribute; SetName(target->name, node->GetMember(L"name")); SetArray(target->arguments, node->GetMember(L"arguments")); for(vint i=0;iarguments.Count();i++) { target->arguments[i]=DeserializeString(target->arguments[i]); } return target; } else if(node->GetType()==L"PrimitiveTypeObj") { Ptr target=new ParsingDefinitionPrimitiveType; SetName(target->name, node->GetMember(L"name")); return target; } else if(node->GetType()==L"TokenTypeObj") { Ptr target=new ParsingDefinitionTokenType; return target; } else if(node->GetType()==L"SubTypeObj") { Ptr target=new ParsingDefinitionSubType; SetMember(target->parentType, node->GetMember(L"parentType")); SetName(target->subTypeName, node->GetMember(L"name")); return target; } else if(node->GetType()==L"ArrayTypeObj") { Ptr target=new ParsingDefinitionArrayType; SetMember(target->elementType, node->GetMember(L"elementType")); return target; } else if(node->GetType()==L"ClassMemberDef") { Ptr target=new ParsingDefinitionClassMemberDefinition; SetArray(target->attributes, node->GetMember(L"attributes")); SetMember(target->type, node->GetMember(L"type")); SetName(target->name, node->GetMember(L"name")); SetName(target->unescapingFunction, node->GetMember(L"unescapingFunction")); return target; } else if(node->GetType()==L"ClassTypeDef") { Ptr target=new ParsingDefinitionClassDefinition; SetArray(target->attributes, node->GetMember(L"attributes")); SetMember(target->ambiguousType, node->GetMember(L"ambiguousType")); SetMember(target->parentType, node->GetMember(L"parentType")); SetName(target->name, node->GetMember(L"name")); SetArray(target->members, node->GetMember(L"members")); SetArray(target->subTypes, node->GetMember(L"subTypes")); return target; } else if(node->GetType()==L"EnumMemberDef") { Ptr target=new ParsingDefinitionEnumMemberDefinition; SetArray(target->attributes, node->GetMember(L"attributes")); SetName(target->name, node->GetMember(L"name")); return target; } else if(node->GetType()==L"EnumTypeDef") { Ptr target=new ParsingDefinitionEnumDefinition; SetArray(target->attributes, node->GetMember(L"attributes")); SetName(target->name, node->GetMember(L"name")); SetArray(target->members, node->GetMember(L"members")); return target; } else if(node->GetType()==L"PrimitiveGrammarDef") { Ptr target=new ParsingDefinitionPrimitiveGrammar; SetName(target->name, node->GetMember(L"name")); return target; } else if(node->GetType()==L"TextGrammarDef") { Ptr target=new ParsingDefinitionTextGrammar; SetText(target->text, node->GetMember(L"text")); return target; } else if(node->GetType()==L"SequenceGrammarDef") { Ptr target=new ParsingDefinitionSequenceGrammar; SetMember(target->first, node->GetMember(L"first")); SetMember(target->second, node->GetMember(L"second")); return target; } else if(node->GetType()==L"AlternativeGrammarDef") { Ptr target=new ParsingDefinitionAlternativeGrammar; SetMember(target->first, node->GetMember(L"first")); SetMember(target->second, node->GetMember(L"second")); return target; } else if(node->GetType()==L"LoopGrammarDef") { Ptr target=new ParsingDefinitionLoopGrammar; SetMember(target->grammar, node->GetMember(L"grammar")); return target; } else if(node->GetType()==L"OptionalGrammarDef") { Ptr target=new ParsingDefinitionOptionalGrammar; SetMember(target->grammar, node->GetMember(L"grammar")); return target; } else if(node->GetType()==L"CreateGrammarDef") { Ptr target=new ParsingDefinitionCreateGrammar; SetMember(target->grammar, node->GetMember(L"grammar")); SetMember(target->type, node->GetMember(L"type")); return target; } else if(node->GetType()==L"AssignGrammarDef") { Ptr target=new ParsingDefinitionAssignGrammar; SetMember(target->grammar, node->GetMember(L"grammar")); SetName(target->memberName, node->GetMember(L"memberName")); return target; } else if(node->GetType()==L"UseGrammarDef") { Ptr target=new ParsingDefinitionUseGrammar; SetMember(target->grammar, node->GetMember(L"grammar")); return target; } else if(node->GetType()==L"SetterGrammarDef") { Ptr target=new ParsingDefinitionSetterGrammar; SetMember(target->grammar, node->GetMember(L"grammar")); SetName(target->memberName, node->GetMember(L"memberName")); SetText(target->value, node->GetMember(L"value")); return target; } else if(node->GetType()==L"TokenDef") { Ptr target=new ParsingDefinitionTokenDefinition; SetArray(target->attributes, node->GetMember(L"attributes")); SetName(target->name, node->GetMember(L"name")); SetText(target->regex, node->GetMember(L"regex")); Ptr token=node->GetMember(L"discard").Cast(); target->discard=(token && token->GetValue()==L"DiscardToken"); return target; } else if(node->GetType()==L"RuleDef") { Ptr target=new ParsingDefinitionRuleDefinition; SetArray(target->attributes, node->GetMember(L"attributes")); SetName(target->name, node->GetMember(L"name")); SetMember(target->type, node->GetMember(L"type")); SetArray(target->grammars, node->GetMember(L"grammars")); return target; } else if(node->GetType()==L"ParserDef") { Ptr target=new ParsingDefinition; Ptr defs=node->GetMember(L"definitions").Cast(); if(defs) { vint count=defs->Count(); for(vint i=0;i def=defs->GetItem(i).Cast(); Ptr defObject=Deserialize(def); if(Ptr defType=defObject.Cast()) { target->types.Add(defType); } else if(Ptr defToken=defObject.Cast()) { target->tokens.Add(defToken); } else if(Ptr defRule=defObject.Cast()) { target->rules.Add(defRule); } } } return target; } else { return 0; } } Ptr DeserializeDefinition(Ptr node) { return Deserialize(node.Cast()).Cast(); } } } } /*********************************************************************** .\PARSING\PARSINGLOGGING.CPP ***********************************************************************/ namespace vl { using namespace stream; using namespace collections; namespace parsing { namespace definitions { void LogString(const WString& input, TextWriter& writer) { writer.WriteChar(L'\"'); for(int i=0;iattributes.Count();i++) { ParsingDefinitionAttribute* att=definition->attributes[i].Obj(); if(i>0) writer.WriteChar(L','); writer.WriteString(L" @"); writer.WriteString(att->name); writer.WriteChar(L'('); for(vint j=0;jarguments.Count();j++) { if(j>0) writer.WriteString(L", "); LogString(att->arguments[j], writer); } writer.WriteChar(L')'); } } /*********************************************************************** Logger (ParsingDefinitionType) ***********************************************************************/ class ParsingDefinitionTypeLogger : public Object, public ParsingDefinitionType::IVisitor { public: TextWriter& writer; ParsingDefinitionTypeLogger(TextWriter& _writer) :writer(_writer) { } static void LogInternal(ParsingDefinitionType* type, TextWriter& writer) { ParsingDefinitionTypeLogger visitor(writer); type->Accept(&visitor); } void Visit(ParsingDefinitionPrimitiveType* node)override { writer.WriteString(node->name); } void Visit(ParsingDefinitionTokenType* node)override { writer.WriteString(L"token"); } void Visit(ParsingDefinitionSubType* node)override { LogInternal(node->parentType.Obj(), writer); writer.WriteString(L"."); writer.WriteString(node->subTypeName); } void Visit(ParsingDefinitionArrayType* node)override { LogInternal(node->elementType.Obj(), writer); writer.WriteString(L"[]"); } }; void Log(ParsingDefinitionType* type, TextWriter& writer) { ParsingDefinitionTypeLogger::LogInternal(type, writer); } /*********************************************************************** Logger (ParsingDefinitionTypeDefinition) ***********************************************************************/ class ParsingDefinitionTypeDefinitionLogger : public Object, public ParsingDefinitionTypeDefinition::IVisitor { public: WString prefix; TextWriter& writer; static void LogInternal(ParsingDefinitionTypeDefinition* definition, const WString& prefix, TextWriter& writer) { ParsingDefinitionTypeDefinitionLogger visitor(prefix, writer); definition->Accept(&visitor); } ParsingDefinitionTypeDefinitionLogger(const WString& _prefix, TextWriter& _writer) :prefix(_prefix) ,writer(_writer) { } void Visit(ParsingDefinitionClassMemberDefinition* node)override { writer.WriteString(prefix); Log(node->type.Obj(), writer); writer.WriteString(L" "); writer.WriteString(node->name); if(node->unescapingFunction!=L"") { writer.WriteString(L" ("); writer.WriteString(node->unescapingFunction); writer.WriteString(L")"); } LogAttributeList(node, writer); writer.WriteLine(L";"); } void Visit(ParsingDefinitionClassDefinition* node)override { writer.WriteString(prefix); writer.WriteString(L"class "); writer.WriteString(node->name); if(node->ambiguousType) { writer.WriteString(L" ambiguous("); Log(node->ambiguousType.Obj(), writer); writer.WriteString(L")"); } if(node->parentType) { writer.WriteString(L" : "); Log(node->parentType.Obj(), writer); } LogAttributeList(node, writer); writer.WriteLine(L""); writer.WriteString(prefix); writer.WriteLine(L"{"); for(int i=0;isubTypes.Count();i++) { LogInternal(node->subTypes[i].Obj(), prefix+L" ", writer); writer.WriteLine(L""); } for(int i=0;imembers.Count();i++) { LogInternal(node->members[i].Obj(), prefix+L" ", writer); } writer.WriteString(prefix); writer.WriteLine(L"}"); } void Visit(ParsingDefinitionEnumMemberDefinition* node)override { writer.WriteString(prefix); writer.WriteString(node->name); LogAttributeList(node, writer); writer.WriteLine(L","); } void Visit(ParsingDefinitionEnumDefinition* node)override { writer.WriteString(prefix); writer.WriteString(L"enum "); writer.WriteString(node->name); LogAttributeList(node, writer); writer.WriteLine(L""); writer.WriteString(prefix); writer.WriteLine(L"{"); for(int i=0;imembers.Count();i++) { LogInternal(node->members[i].Obj(), prefix+L" ", writer); } writer.WriteString(prefix); writer.WriteLine(L"}"); } }; void Log(ParsingDefinitionTypeDefinition* definition, const WString& prefix, TextWriter& writer) { ParsingDefinitionTypeDefinitionLogger::LogInternal(definition, prefix, writer); } /*********************************************************************** Logger (ParsingDefinitionGrammar) ***********************************************************************/ #define PRIORITY_NONE 0 #define PRIORITY_CREATE 1 #define PRIORITY_SET 1 #define PRIORITY_ALTERNATIVE 2 #define PRIORITY_SEQUENCE 3 #define PRIORITY_USE 4 #define PRIORITY_ASSIGN 4 class ParsingDefinitionGrammarLogger : public Object, public ParsingDefinitionGrammar::IVisitor { public: TextWriter& writer; int parentPriority; ParsingDefinitionGrammar* stateNode; bool beforeNode; ParsingDefinitionGrammarLogger(TextWriter& _writer, int _parentPriority, ParsingDefinitionGrammar* _stateNode, bool _beforeNode) :writer(_writer) ,parentPriority(_parentPriority) ,stateNode(_stateNode) ,beforeNode(_beforeNode) { } static void LogInternal(ParsingDefinitionGrammar* grammar, int parentPriority, ParsingDefinitionGrammar* stateNode, bool beforeNode, TextWriter& writer) { if(grammar==stateNode && beforeNode) { writer.WriteString(L"@"); } ParsingDefinitionGrammarLogger visitor(writer, parentPriority, stateNode, beforeNode); grammar->Accept(&visitor); if(grammar==stateNode && !beforeNode) { writer.WriteString(L"@"); } } void LogInternal(ParsingDefinitionGrammar* grammar, int parentPriority, TextWriter& writer) { LogInternal(grammar, parentPriority, stateNode, beforeNode, writer); } void Visit(ParsingDefinitionPrimitiveGrammar* node)override { writer.WriteString(node->name); } void Visit(ParsingDefinitionTextGrammar* node)override { LogString(node->text, writer); } void Visit(ParsingDefinitionSequenceGrammar* node)override { int priority=PRIORITY_SEQUENCE; if(parentPriority>priority) { writer.WriteString(L"( "); } LogInternal(node->first.Obj(), priority, writer); writer.WriteString(L" "); LogInternal(node->second.Obj(), priority, writer); if(parentPriority>priority) { writer.WriteString(L" )"); } } void Visit(ParsingDefinitionAlternativeGrammar* node)override { int priority=PRIORITY_ALTERNATIVE; if(parentPriority>priority) { writer.WriteString(L"( "); } LogInternal(node->first.Obj(), priority, writer); writer.WriteString(L" | "); LogInternal(node->second.Obj(), priority, writer); if(parentPriority>priority) { writer.WriteString(L" )"); } } void Visit(ParsingDefinitionLoopGrammar* node)override { writer.WriteString(L"{ "); LogInternal(node->grammar.Obj(), PRIORITY_NONE, writer); writer.WriteString(L" }"); } void Visit(ParsingDefinitionOptionalGrammar* node)override { writer.WriteString(L"[ "); LogInternal(node->grammar.Obj(), PRIORITY_NONE, writer); writer.WriteString(L" ]"); } void Visit(ParsingDefinitionCreateGrammar* node)override { int priority=PRIORITY_CREATE; if(parentPriority>priority) { writer.WriteString(L"( "); } LogInternal(node->grammar.Obj(), priority, writer); writer.WriteString(L" as "); Log(node->type.Obj(), writer); if(parentPriority>priority) { writer.WriteString(L" )"); } } void Visit(ParsingDefinitionAssignGrammar* node)override { int priority=PRIORITY_ASSIGN; if(parentPriority>priority) { writer.WriteString(L"( "); } LogInternal(node->grammar.Obj(), priority, writer); writer.WriteString(L" : "); writer.WriteString(node->memberName); if(parentPriority>priority) { writer.WriteString(L" )"); } } void Visit(ParsingDefinitionUseGrammar* node)override { int priority=PRIORITY_USE; if(parentPriority>priority) { writer.WriteString(L"( "); } writer.WriteString(L"!"); LogInternal(node->grammar.Obj(), priority, writer); if(parentPriority>priority) { writer.WriteString(L" )"); } } void Visit(ParsingDefinitionSetterGrammar* node)override { int priority=PRIORITY_SET; if(parentPriority>priority) { writer.WriteString(L"( "); } LogInternal(node->grammar.Obj(), priority, writer); writer.WriteString(L" with { "); writer.WriteString(node->memberName); writer.WriteString(L" = "); LogString(node->value, writer); writer.WriteString(L" }"); if(parentPriority>priority) { writer.WriteString(L" )"); } } }; void Log(ParsingDefinitionGrammar* grammar, TextWriter& writer) { ParsingDefinitionGrammarLogger::LogInternal(grammar, PRIORITY_NONE, 0, true, writer); } void Log(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode, TextWriter& writer) { ParsingDefinitionGrammarLogger::LogInternal(grammar, PRIORITY_NONE, stateNode, beforeNode, writer); } #undef PRIORITY_NONE #undef PRIORITY_CREATE #undef PRIORITY_SET #undef PRIORITY_ALTERNATIVE #undef PRIORITY_SEQUENCE #undef PRIORITY_USE #undef PRIORITY_ASSIGN /*********************************************************************** FindAppropriateGrammarState ***********************************************************************/ class FindAppropriateGrammarStateVisitor : public Object, public ParsingDefinitionGrammar::IVisitor { public: ParsingDefinitionGrammar* stateNode; bool beforeNode; ParsingDefinitionGrammar* beforeReference; ParsingDefinitionGrammar* afterReference; ParsingDefinitionGrammar* result; FindAppropriateGrammarStateVisitor(ParsingDefinitionGrammar* _stateNode, bool _beforeNode, ParsingDefinitionGrammar* _beforeReference, ParsingDefinitionGrammar* _afterReference) :stateNode(_stateNode) ,beforeNode(_beforeNode) ,beforeReference(_beforeReference) ,afterReference(_afterReference) ,result(0) { } static ParsingDefinitionGrammar* Find(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode, ParsingDefinitionGrammar* beforeReference, ParsingDefinitionGrammar* afterReference) { if(grammar==stateNode) { return beforeNode ?(beforeReference?beforeReference:stateNode) :(afterReference?afterReference:stateNode) ; } else { FindAppropriateGrammarStateVisitor visitor(stateNode, beforeNode, beforeReference, afterReference); grammar->Accept(&visitor); return visitor.result; } } void Visit(ParsingDefinitionPrimitiveGrammar* node)override { } void Visit(ParsingDefinitionTextGrammar* node)override { } void Visit(ParsingDefinitionSequenceGrammar* node)override { result=Find(node->first.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), 0); if(!result) { result=Find(node->second.Obj(), stateNode, beforeNode, 0, (afterReference?afterReference:node)); } } void Visit(ParsingDefinitionAlternativeGrammar* node)override { result=Find(node->first.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node)); if(!result) { result=Find(node->second.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node)); } } void Visit(ParsingDefinitionLoopGrammar* node)override { result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node)); } void Visit(ParsingDefinitionOptionalGrammar* node)override { result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node)); } void Visit(ParsingDefinitionCreateGrammar* node)override { result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node)); } void Visit(ParsingDefinitionAssignGrammar* node)override { result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node)); } void Visit(ParsingDefinitionUseGrammar* node)override { result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node)); } void Visit(ParsingDefinitionSetterGrammar* node)override { result=Find(node->grammar.Obj(), stateNode, beforeNode, beforeReference, afterReference); } }; /*********************************************************************** Logger (ParsingDefinitionGrammar) ***********************************************************************/ WString TypeToString(ParsingDefinitionType* type) { return GenerateToStream([&](StreamWriter& writer) { Log(type, writer); }, 64); } WString GrammarToString(ParsingDefinitionGrammar* grammar) { return GrammarStateToString(grammar, 0, true); } WString GrammarStateToString(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode) { return GenerateToStream([&](StreamWriter& writer) { Log(grammar, stateNode, beforeNode, writer); }, 64); } ParsingDefinitionGrammar* FindAppropriateGrammarState(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode) { return FindAppropriateGrammarStateVisitor::Find(grammar, stateNode, beforeNode, 0, 0); } void Log(Ptr definition, TextWriter& writer) { FOREACH(Ptr, type, definition->types) { Log(type.Obj(), L"", writer); writer.WriteLine(L""); } FOREACH(Ptr, token, definition->tokens) { if(token->discard) { writer.WriteString(L"discardtoken "); } else { writer.WriteString(L"token "); } writer.WriteString(token->name); writer.WriteString(L" = "); LogString(token->regex, writer); LogAttributeList(token.Obj(), writer); writer.WriteLine(L";"); } writer.WriteLine(L""); FOREACH(Ptr, rule, definition->rules) { writer.WriteString(L"rule "); Log(rule->type.Obj(), writer); writer.WriteString(L" "); writer.WriteString(rule->name); LogAttributeList(rule.Obj(), writer); writer.WriteLine(L""); FOREACH(Ptr, grammar, rule->grammars) { writer.WriteString(L" = "); Log(grammar.Obj(), writer); writer.WriteLine(L""); } writer.WriteLine(L" ;"); } } } namespace analyzing { /*********************************************************************** Logger (Automaton) ***********************************************************************/ void LogTransitionSymbol(ParsingSymbol* symbol, stream::TextWriter& writer) { if(symbol->GetType()==ParsingSymbol::TokenDef) { writer.WriteString(L"["); writer.WriteString(symbol->GetName()); WString regex=symbol->GetDescriptorString(); if(regex_internal::IsRegexEscapedLiteralString(regex)) { writer.WriteString(L" "); definitions::LogString(regex_internal::UnescapeTextForRegex(regex), writer); } writer.WriteString(L"]"); } else { writer.WriteString(L"<"); writer.WriteString(symbol->GetName()); writer.WriteString(L">"); } } void Log(Ptr automaton, stream::TextWriter& writer) { FOREACH(Ptr, ruleInfo, automaton->ruleInfos) { writer.WriteString(L"Root Rule Start: "); writer.WriteLine(ruleInfo->rootRuleStartState->stateName); writer.WriteString(L"Root Rule End: "); writer.WriteLine(ruleInfo->rootRuleEndState->stateName); writer.WriteString(L"Rule Start: "); writer.WriteLine(ruleInfo->startState->stateName); FOREACH(State*, endState, ruleInfo->endStates) { writer.WriteString(L"Rule End: "); writer.WriteLine(endState->stateName); } writer.WriteLine(L""); } List states; FOREACH(Ptr, ruleInfo, automaton->ruleInfos) { vint currentState=states.Count(); states.Add(ruleInfo->rootRuleStartState); while(currentStatestateExpression); if(state->endState) { writer.WriteString(L"END STATE "); } else { writer.WriteString(L"STATE "); } writer.WriteLine(state->stateName); FOREACH(Transition*, transition, state->transitions) { if(!states.Contains(transition->target)) { states.Add(transition->target); } switch(transition->transitionType) { case Transition::Epsilon: writer.WriteString(L" EPSILON"); break; case Transition::TokenBegin: writer.WriteString(L" TOKEN-BEGIN"); break; case Transition::TokenFinish: writer.WriteString(L" TOKEN-FINISH"); break; case Transition::NormalReduce: writer.WriteString(L" NORMAL-REDUCE"); break; case Transition::LeftRecursiveReduce: writer.WriteString(L" LREC-REDUCE"); break; case Transition::Symbol: { writer.WriteString(L" "); if(transition->transitionSymbol) { LogTransitionSymbol(transition->transitionSymbol, writer); } } break; } switch(transition->stackOperationType) { case Transition::None: writer.WriteString(L" => "); break; case Transition::ShiftReduceCompacted: writer.WriteString(L" [SHIFT-REDUCE-COMPACTED] => "); break; case Transition::LeftRecursive: writer.WriteString(L" [LEFT-RECURSIVE] => "); break; } writer.WriteLine(transition->target->stateName); FOREACH(Ptr, action, transition->actions) { switch(action->actionType) { case Action::Create: writer.WriteString(L" CREATE "); break; case Action::Assign: writer.WriteString(L" ASSIGN "); break; case Action::Using: writer.WriteString(L" USING "); break; case Action::Setter: writer.WriteString(L" SET "); break; case Action::Shift: writer.WriteString(L" SHIFT "); break; case Action::Reduce: writer.WriteString(L" REDUCE "); break; case Action::LeftRecursiveReduce: writer.WriteString(L" LR-REDUCE "); break; } if(action->shiftReduceSource && action->shiftReduceTarget) { writer.WriteString(L"["); writer.WriteString(action->shiftReduceSource->stateName); writer.WriteString(L" => "); writer.WriteString(action->shiftReduceTarget->stateName); writer.WriteString(L"] "); } if(action->actionSource) { writer.WriteString(action->actionSource->GetName()); } if(action->actionTarget) { writer.WriteString(L" => "); writer.WriteString(action->actionTarget->GetName()); } writer.WriteLine(L""); } } writer.WriteLine(L""); } writer.WriteLine(L"--------------------------------"); } } } namespace tabling { /*********************************************************************** Logger (ParsingTable) ***********************************************************************/ void LogAttributeList(Ptr table, vint attributeIndex, const WString& prefix, stream::TextWriter& writer) { if(attributeIndex!=-1) { Ptr atts=table->GetAttributeInfo(attributeIndex); FOREACH(Ptr, att, atts->attributes) { writer.WriteString(prefix); writer.WriteString(L"@"); writer.WriteString(att->name); writer.WriteString(L"("); for(vint i=0;iarguments.Count();i++) { if(i>0) writer.WriteString(L", "); definitions::LogString(att->arguments[i], writer); } writer.WriteLine(L")"); } } } void Log(Ptr table, stream::TextWriter& writer) { vint rows=table->GetStateCount()+1; vint columns=table->GetTokenCount()+1; Array stringTable(rows*columns); stringTable[0]=L""; for(vint row=0; rowGetStateCount();row++) { stringTable[(row+1)*columns]=itow(row)+L": "+table->GetStateInfo(row).stateName; } for(vint column=0;columnGetTokenCount();column++) { WString content= column==ParsingTable::TokenBegin?L"0: $TokenBegin": column==ParsingTable::TokenFinish?L"1: $TokenFinish": column==ParsingTable::NormalReduce?L"2: $NormalReduce": column==ParsingTable::LeftRecursiveReduce?L"3: $LeftRecursiveReduce": itow(column)+L": "+table->GetTokenInfo(column).name+L"\r\n "+table->GetTokenInfo(column).regex; stringTable[column+1]=content; } for(vint row=0; rowGetStateCount();row++) { for(vint column=0;columnGetTokenCount();column++) { Ptr bag=table->GetTransitionBag(row, column); if(bag) { WString content; FOREACH(Ptr, item, bag->transitionItems) { if(content!=L"") content+=L"\r\n"; content+=itow(item->targetState); FOREACH_INDEXER(vint, state, index, item->stackPattern) { content+=(index==0?L" : ":L", "); content+=itow(state); } content+=L"\r\n"; FOREACH(Ptr, lookAhead, item->lookAheads) { content+=L" "; FOREACH_INDEXER(vint, token, index, lookAhead->tokens) { content+=(index==0?L"> ":L", "); content+=itow(token); } content+=L"\r\n"; } content+=L" "; FOREACH(ParsingTable::Instruction, ins, item->instructions) { switch(ins.instructionType) { case ParsingTable::Instruction::Create: content+=L"C"; break; case ParsingTable::Instruction::Using: content+=L"U"; break; case ParsingTable::Instruction::Assign: content+=L"A"; break; case ParsingTable::Instruction::Item: content+=L"I"; break; case ParsingTable::Instruction::Setter: content+=L"S"; break; case ParsingTable::Instruction::Shift: content+=L"[+"+itow(ins.stateParameter)+L"]"; break; case ParsingTable::Instruction::Reduce: content+=L"[-"+itow(ins.stateParameter)+L"]"; break; case ParsingTable::Instruction::LeftRecursiveReduce: content+=L"[!"+itow(ins.stateParameter)+L"]"; break; } } } stringTable[(row+1)*columns+(column+1)]=content; } } } writer.WriteLine(L"Target-State : Stack-Pattern ..."); writer.WriteLine(L"> Look-Ahead ..."); writer.WriteLine(L"C: Create"); writer.WriteLine(L"U: Using"); writer.WriteLine(L"A: Assign"); writer.WriteLine(L"I: Item"); writer.WriteLine(L"S: Setter"); writer.WriteLine(L"[+s]: Shift[push s]"); writer.WriteLine(L"[-s]: Reduce[pop s]"); writer.WriteLine(L"[!s]: Left-Recursive-Reduce[fake s]"); writer.WriteLine(L""); for(vint i=0;iGetRuleCount();i++) { const ParsingTable::RuleInfo& ruleInfo=table->GetRuleInfo(i); writer.WriteString(ruleInfo.name); writer.WriteChar(L'<'); writer.WriteString(ruleInfo.type); if(ruleInfo.ambiguousType!=L"") { writer.WriteString(L", "); writer.WriteString(ruleInfo.ambiguousType); } writer.WriteString(L">: "); writer.WriteString(itow(ruleInfo.rootStartState)); writer.WriteChar(L'['); writer.WriteString(table->GetStateInfo(ruleInfo.rootStartState).stateName); writer.WriteChar(L']'); writer.WriteLine(L""); } writer.WriteMonospacedEnglishTable(stringTable, rows, columns); writer.WriteLine(L""); writer.WriteLine(L"Metadata(Tokens):"); for(vint i=0;iGetTokenCount();i++) { const ParsingTable::TokenInfo& info=table->GetTokenInfo(i); writer.WriteString(L" "); writer.WriteString(info.name); writer.WriteString(L"="); writer.WriteLine(info.regex); LogAttributeList(table, info.attributeIndex, L" ", writer); } writer.WriteLine(L""); writer.WriteLine(L"Metadata(Rules):"); for(vint i=0;iGetRuleCount();i++) { const ParsingTable::RuleInfo& info=table->GetRuleInfo(i); writer.WriteString(L" "); writer.WriteLine(info.name); LogAttributeList(table, info.attributeIndex, L" ", writer); } writer.WriteLine(L""); writer.WriteLine(L"Metadata(Classes):"); for(vint i=0;iGetTreeTypeInfoCount();i++) { const ParsingTable::TreeTypeInfo& info=table->GetTreeTypeInfo(i); writer.WriteString(L" "); writer.WriteLine(info.type); LogAttributeList(table, info.attributeIndex, L" ", writer); } writer.WriteLine(L""); writer.WriteLine(L"Metadata(Class Members):"); for(vint i=0;iGetTreeFieldInfoCount();i++) { const ParsingTable::TreeFieldInfo& info=table->GetTreeFieldInfo(i); writer.WriteString(L" "); writer.WriteString(info.type); writer.WriteString(L"."); writer.WriteLine(info.field); LogAttributeList(table, info.attributeIndex, L" ", writer); } writer.WriteLine(L""); } } /*********************************************************************** Logger (ParsingTreeNode) ***********************************************************************/ class LogParsingTreeNodeVisitor : public Object, public ParsingTreeNode::IVisitor { protected: TextWriter& writer; WString prefix; WString originalInput; public: LogParsingTreeNodeVisitor(TextWriter& _writer, const WString& _originalInput, const WString& _prefix) :writer(_writer) ,prefix(_prefix) ,originalInput(_originalInput) { } void Write(ParsingTreeNode* node) { if(node) { node->Accept(this); } else { writer.WriteString(L"null"); } } void WriteInput(ParsingTreeNode* node) { if(originalInput!=L"") { ParsingTextRange range=node->GetCodeRange(); if(range.start.index!=ParsingTextPos::UnknownValue && range.end.index!=ParsingTextPos::UnknownValue) { vint start=range.start.index; vint length=range.end.index-start+1; if(length>0) { writer.WriteString(L" // ["); writer.WriteString(originalInput.Sub(start, length)); writer.WriteString(L"]"); } } } } void Visit(ParsingTreeToken* node) { writer.WriteChar(L'['); writer.WriteString(node->GetValue()); writer.WriteChar(L']'); WriteInput(node); } void Visit(ParsingTreeObject* node) { WString oldPrefix=prefix; writer.WriteString(node->GetType()); writer.WriteString(L" <"); for(vint i=0;iGetCreatorRules().Count();i++) { if(i!=0) writer.WriteString(L", "); writer.WriteString(node->GetCreatorRules()[i]); } writer.WriteString(L"> {"); WriteInput(node); writer.WriteLine(L""); prefix+=L" "; for(vint i=0;iGetMembers().Count();i++) { writer.WriteString(prefix); writer.WriteString(node->GetMembers().Keys().Get(i)); writer.WriteString(L" = "); Write(node->GetMembers().Values().Get(i).Obj()); writer.WriteLine(L""); } prefix=oldPrefix; writer.WriteString(prefix); writer.WriteString(L"}"); } void Visit(ParsingTreeArray* node) { WString oldPrefix=prefix; writer.WriteString(node->GetElementType()); writer.WriteString(L"[] {"); WriteInput(node); writer.WriteLine(L""); prefix+=L" "; for(vint i=0;iCount();i++) { writer.WriteString(prefix); Write(node->GetItem(i).Obj()); writer.WriteLine(L","); } prefix=oldPrefix; writer.WriteString(prefix); writer.WriteString(L"}"); } }; void Log(ParsingTreeNode* node, const WString& originalInput, stream::TextWriter& writer, const WString& prefix) { writer.WriteString(prefix); LogParsingTreeNodeVisitor visitor(writer, originalInput, prefix); node->Accept(&visitor); } } } /*********************************************************************** .\PARSING\PARSINGSTATE.CPP ***********************************************************************/ #if defined(VCZH_GCC) && defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnull-dereference" #endif namespace vl { namespace parsing { namespace tabling { using namespace collections; using namespace regex; /*********************************************************************** ParsingTokenWalker::LookAheadEnumerator ***********************************************************************/ ParsingTokenWalker::LookAheadEnumerator::LookAheadEnumerator(const ParsingTokenWalker* _walker, vint _currentToken) :walker(_walker) ,firstToken(_currentToken) ,currentToken(_currentToken) ,currentValue(-1) ,index(-1) { } ParsingTokenWalker::LookAheadEnumerator::LookAheadEnumerator(const LookAheadEnumerator& _enumerator) :walker(_enumerator.walker) ,firstToken(_enumerator.firstToken) ,currentToken(_enumerator.currentToken) ,currentValue(_enumerator.currentValue) ,index(_enumerator.index) { } IEnumerator* ParsingTokenWalker::LookAheadEnumerator::Clone()const { return new LookAheadEnumerator(*this); } const vint& ParsingTokenWalker::LookAheadEnumerator::Current()const { return currentValue; } vint ParsingTokenWalker::LookAheadEnumerator::Index()const { return index; } bool ParsingTokenWalker::LookAheadEnumerator::Next() { vint newToken=walker->GetNextIndex(currentToken); if(newToken==-3) return false; currentToken=newToken; index++; currentValue=walker->GetTableTokenIndex(currentToken); return true; } void ParsingTokenWalker::LookAheadEnumerator::Reset() { currentToken=firstToken; currentValue=-1; index=-1; } /*********************************************************************** ParsingTokenWalker::TokenLookAhead ***********************************************************************/ ParsingTokenWalker::TokenLookAhead::TokenLookAhead(const ParsingTokenWalker* _walker) :walker(_walker) { } collections::IEnumerator* ParsingTokenWalker::TokenLookAhead::CreateEnumerator()const { return new LookAheadEnumerator(walker, walker->currentToken); } /*********************************************************************** ParsingTokenWalker::ReduceLookAhead ***********************************************************************/ ParsingTokenWalker::ReduceLookAhead::ReduceLookAhead(const ParsingTokenWalker* _walker) :walker(_walker) { } collections::IEnumerator* ParsingTokenWalker::ReduceLookAhead::CreateEnumerator()const { return new LookAheadEnumerator(walker, walker->currentToken - 1); } /*********************************************************************** ParsingTokenWalker ***********************************************************************/ vint ParsingTokenWalker::GetNextIndex(vint index)const { if(index==-2) { return -1; } else if(-1<=index && indexIsInputToken(tokens[index].token)) { break; } else { index++; } } return index; } else { return -3; } } vint ParsingTokenWalker::GetTableTokenIndex(vint index)const { if(index==-1) { return ParsingTable::TokenBegin; } else if(index==tokens.Count()) { return ParsingTable::TokenFinish; } else if(0<=index && indexGetTableTokenIndex(tokens[index].token); } else { return -1; } } ParsingTokenWalker::ParsingTokenWalker(collections::List& _tokens, Ptr _table) :tokens(_tokens) ,table(_table) ,currentToken(-2) , tokenLookAhead(this) , reduceLookAhead(this) { } ParsingTokenWalker::~ParsingTokenWalker() { } const collections::IEnumerable& ParsingTokenWalker::GetTokenLookahead()const { return tokenLookAhead; } const collections::IEnumerable& ParsingTokenWalker::GetReduceLookahead()const { return reduceLookAhead; } void ParsingTokenWalker::Reset() { currentToken=-2; } bool ParsingTokenWalker::Move() { currentToken=GetNextIndex(currentToken); return currentToken!=-3; } vint ParsingTokenWalker::GetTableTokenIndex()const { return GetTableTokenIndex(currentToken); } regex::RegexToken* ParsingTokenWalker::GetRegexToken()const { vint index=GetTokenIndexInStream(); return index==-1?0:&tokens[index]; } vint ParsingTokenWalker::GetTokenIndexInStream()const { if(0<=currentToken && currentToken _table, vint codeIndex) :input(_input.Buffer()) ,table(_table) ,parsingRuleStartState(-1) { CopyFrom(tokens, table->GetLexer().Parse(input, codeIndex)); walker=new ParsingTokenWalker(tokens, table); } ParsingState::~ParsingState() { } const WString& ParsingState::GetInput() { return input; } Ptr ParsingState::GetTable() { return table; } const collections::List& ParsingState::GetTokens() { return tokens; } regex::RegexToken* ParsingState::GetToken(vint index) { if(index<=0) { index=0; } else if(index>tokens.Count()) { index=tokens.Count(); } return index==tokens.Count()?0:&tokens[index]; } vint ParsingState::Reset(const WString& rule) { const ParsingTable::RuleInfo& info=table->GetRuleInfo(rule); auto infoExists = &info; if(infoExists) { walker->Reset(); walker->Move(); stateGroup=new StateGroup(info); parsingRule=rule; parsingRuleStartState=info.rootStartState; return stateGroup->currentState; } return -1; } WString ParsingState::GetParsingRule() { return parsingRule; } vint ParsingState::GetParsingRuleStartState() { return parsingRuleStartState; } vint ParsingState::GetCurrentToken() { return walker->GetTableTokenIndex()==ParsingTable::TokenFinish ?tokens.Count() :walker->GetTokenIndexInStream(); } vint ParsingState::GetCurrentTableTokenIndex() { return walker->GetTableTokenIndex(); } const collections::List& ParsingState::GetStateStack() { return stateGroup->stateStack; } vint ParsingState::GetCurrentState() { return stateGroup->currentState; } void ParsingState::SkipCurrentToken() { walker->Move(); } bool ParsingState::TestTransitionItemInFuture(vint tableTokenIndex, Future* future, ParsingTable::TransitionItem* item, const collections::IEnumerable* lookAheadTokens) { bool passLookAheadTest=true; if(item->lookAheads.Count()>0 && lookAheadTokens) { passLookAheadTest=false; FOREACH(Ptr, info, item->lookAheads) { vint index=0; FOREACH(vint, token, *lookAheadTokens) { if(info->tokens[index]!=token) { break; } index++; if(index>=info->tokens.Count()) { break; } } if(index==info->tokens.Count()) { passLookAheadTest=true; break; } } } if(!passLookAheadTest) { return false; } vint availableStackDepth=stateGroup->stateStack.Count()-future->reduceStateCount; vint totalStackDepth=stateGroup->stateStack.Count()-future->reduceStateCount+future->shiftStates.Count(); if(item->stackPattern.Count()<=totalStackDepth) { if(tableTokenIndex!=ParsingTable::TokenFinish || item->stackPattern.Count()==totalStackDepth) { bool match=true; for(vint j=0;jstackPattern.Count();j++) { vint state= jshiftStates.Count() ?future->shiftStates[future->shiftStates.Count()-1-j] :stateGroup->stateStack[availableStackDepth-1-(j-future->shiftStates.Count())] ; if(item->stackPattern[j]!=state) { match=false; } } if(match) { return true; } } } return false; } ParsingTable::TransitionItem* ParsingState::MatchTokenInFuture(vint tableTokenIndex, Future* future, const collections::IEnumerable* lookAheadTokens) { ParsingTable::TransitionBag* bag=table->GetTransitionBag(future->currentState, tableTokenIndex).Obj(); if(bag) { for(vint i=0;itransitionItems.Count();i++) { ParsingTable::TransitionItem* item=bag->transitionItems[i].Obj(); if(TestTransitionItemInFuture(tableTokenIndex, future, item, lookAheadTokens)) { return item; } } } return 0; } ParsingTable::TransitionItem* ParsingState::MatchToken(vint tableTokenIndex, const collections::IEnumerable* lookAheadTokens) { Future future; future.currentState=stateGroup->currentState; return MatchTokenInFuture(tableTokenIndex, &future, lookAheadTokens); } void ParsingState::RunTransitionInFuture(ParsingTable::TransitionItem* transition, Future* previous, Future* now) { if(previous) { now->reduceStateCount=previous->reduceStateCount; CopyFrom(now->shiftStates, previous->shiftStates); } else { now->reduceStateCount=0; now->shiftStates.Clear(); } now->currentState=transition->targetState; now->selectedToken=transition->token; now->selectedItem=transition; now->previous=previous; now->next=0; for(vint j=0;jinstructions.Count();j++) { ParsingTable::Instruction& ins=transition->instructions[j]; switch(ins.instructionType) { case ParsingTable::Instruction::Shift: { now->shiftStates.Add(ins.stateParameter); } break; case ParsingTable::Instruction::Reduce: { if(now->shiftStates.Count()==0) { now->reduceStateCount++; } else { now->shiftStates.RemoveAt(now->shiftStates.Count()-1); } } break; default:; } } } ParsingState::TransitionResult ParsingState::RunTransition(ParsingTable::TransitionItem* transition, regex::RegexToken* regexToken, vint instructionBegin, vint instructionCount, bool lastPart) { if(regexToken) { if(!stateGroup->shiftToken) { stateGroup->shiftToken=regexToken; stateGroup->reduceToken=regexToken; } } if(transition->token>=ParsingTable::UserTokenStart) { if(stateGroup->tokenSequenceIndex==0) { stateGroup->shiftTokenStack.Add(stateGroup->shiftToken); } stateGroup->tokenSequenceIndex++; } TransitionResult result; result.tableTokenIndex=transition->token; result.token=regexToken; result.tokenIndexInStream=regexToken?walker->GetTokenIndexInStream():-1; result.tableStateSource=stateGroup->currentState; result.tableStateTarget=transition->targetState; result.transition=transition; result.instructionBegin=instructionBegin; result.instructionCount=instructionCount; for(vint j=instructionBegin;jinstructions[j]; switch(ins.instructionType) { case ParsingTable::Instruction::Shift: { stateGroup->stateStack.Add(ins.stateParameter); stateGroup->shiftTokenStack.Add(stateGroup->shiftToken); stateGroup->shiftToken=regexToken; stateGroup->reduceToken=regexToken; } break; case ParsingTable::Instruction::Reduce: { stateGroup->stateStack.RemoveAt(stateGroup->stateStack.Count()-1); result.AddShiftReduceRange(stateGroup->shiftToken, stateGroup->reduceToken); stateGroup->shiftToken=stateGroup->shiftTokenStack[stateGroup->shiftTokenStack.Count()-1]; stateGroup->shiftTokenStack.RemoveAt(stateGroup->shiftTokenStack.Count()-1); } break; case ParsingTable::Instruction::LeftRecursiveReduce: { result.AddShiftReduceRange(stateGroup->shiftToken, stateGroup->reduceToken); if(regexToken) { stateGroup->reduceToken=regexToken; } } break; default:; } } if(regexToken) { stateGroup->reduceToken=regexToken; } if(transition->token==ParsingTable::TokenFinish && lastPart) { stateGroup->shiftToken=stateGroup->shiftTokenStack[stateGroup->shiftTokenStack.Count()-1]; stateGroup->shiftTokenStack.RemoveAt(stateGroup->shiftTokenStack.Count()-1); result.AddShiftReduceRange(stateGroup->shiftToken, stateGroup->reduceToken); } stateGroup->currentState=transition->targetState; return result; } ParsingState::TransitionResult ParsingState::RunTransition(ParsingTable::TransitionItem* transition, regex::RegexToken* regexToken) { return RunTransition(transition, regexToken, 0, transition->instructions.Count(), true); } bool ParsingState::ReadTokenInFuture(vint tableTokenIndex, Future* previous, Future* now, const collections::IEnumerable* lookAheadTokens) { ParsingTable::TransitionItem* selectedItem=0; if(previous) { selectedItem=MatchTokenInFuture(tableTokenIndex, previous, lookAheadTokens); } else { selectedItem=MatchToken(tableTokenIndex, lookAheadTokens); } if(!selectedItem) { return false; } RunTransitionInFuture(selectedItem, previous, now); return true; } ParsingState::TransitionResult ParsingState::ReadToken(vint tableTokenIndex, regex::RegexToken* regexToken, const collections::IEnumerable* lookAheadTokens) { ParsingTable::TransitionItem* item=MatchToken(tableTokenIndex, lookAheadTokens); if(item) { return RunTransition(item, regexToken); } return TransitionResult(); } ParsingState::TransitionResult ParsingState::ReadToken() { if(walker->GetTableTokenIndex()==-1) { return TransitionResult(); } vint token=walker->GetTableTokenIndex(); RegexToken* regexToken=walker->GetRegexToken(); bool tryReduce=false; TransitionResult result=ReadToken(token, regexToken, &walker->GetTokenLookahead()); if(!result) { result=ReadToken(ParsingTable::LeftRecursiveReduce, 0, &walker->GetReduceLookahead()); tryReduce=true; } if(!result) { result=ReadToken(ParsingTable::NormalReduce, 0, &walker->GetReduceLookahead()); tryReduce=true; } if(result && !tryReduce) { walker->Move(); } return result; } bool ParsingState::TestExplore(vint tableTokenIndex, Future* previous) { Future fakePrevious; fakePrevious.currentState=stateGroup->currentState; Future* realPrevious=previous?previous:&fakePrevious; ParsingTable::TransitionBag* bag=table->GetTransitionBag(realPrevious->currentState, tableTokenIndex).Obj(); if(bag) { for(vint i=0;itransitionItems.Count();i++) { ParsingTable::TransitionItem* item=bag->transitionItems[i].Obj(); if(TestTransitionItemInFuture(tableTokenIndex, realPrevious, item, 0)) { return true; } } } return false; } bool ParsingState::Explore(vint tableTokenIndex, Future* previous, collections::List& possibilities) { Future fakePrevious; fakePrevious.currentState=stateGroup->currentState; Future* realPrevious=previous?previous:&fakePrevious; ParsingTable::TransitionBag* bag=table->GetTransitionBag(realPrevious->currentState, tableTokenIndex).Obj(); bool successful = false; if(bag) { for(vint i=0;itransitionItems.Count();i++) { ParsingTable::TransitionItem* item=bag->transitionItems[i].Obj(); if(TestTransitionItemInFuture(tableTokenIndex, realPrevious, item, 0)) { Future* now=new Future; RunTransitionInFuture(item, previous, now); possibilities.Add(now); successful = true; } } } return successful; } bool ParsingState::ExploreStep(collections::List& previousFutures, vint start, vint count, collections::List& possibilities) { if(walker->GetTableTokenIndex()==-1) { return false; } vint token = walker->GetTableTokenIndex(); RegexToken* regexToken = walker->GetRegexToken(); vint oldPossibilitiesCount = possibilities.Count(); for (vint i = 0; iselectedRegexToken = regexToken; } return true; } bool ParsingState::ExploreNormalReduce(collections::List& previousFutures, vint start, vint count, collections::List& possibilities) { if(walker->GetTableTokenIndex()==-1) { return false; } vint oldPossibilitiesCount = possibilities.Count(); for(vint i=0;i oldPossibilitiesCount; } bool ParsingState::ExploreLeftRecursiveReduce(collections::List& previousFutures, vint start, vint count, collections::List& possibilities) { if(walker->GetTableTokenIndex()==-1) { return false; } vint oldPossibilitiesCount = possibilities.Count(); for(vint i=0;i oldPossibilitiesCount; } ParsingState::Future* ParsingState::ExploreCreateRootFuture() { Future* future=new Future; future->currentState=stateGroup->currentState; return future; } Ptr ParsingState::TakeSnapshot() { return new StateGroup(*stateGroup.Obj()); } void ParsingState::RestoreSnapshot(Ptr group) { stateGroup=new StateGroup(*group.Obj()); } /*********************************************************************** ParsingTreeBuilder ***********************************************************************/ ParsingTreeBuilder::ParsingTreeBuilder() :processingAmbiguityBranch(false) ,ambiguityBranchSharedNodeCount(0) { } ParsingTreeBuilder::~ParsingTreeBuilder() { } void ParsingTreeBuilder::Reset() { createdObject=0; operationTarget=new ParsingTreeObject(); nodeStack.Clear(); processingAmbiguityBranch=false; ambiguityBranchCreatedObject=0; ambiguityBranchOperationTarget=0; ambiguityBranchSharedNodeCount=0; ambiguityBranchNodeStack.Clear(); ambiguityNodes.Clear(); } bool ParsingTreeBuilder::Run(const ParsingState::TransitionResult& result) { if(!operationTarget) { return false; } switch(result.transitionType) { case ParsingState::TransitionResult::AmbiguityBegin: { if(processingAmbiguityBranch) return false; processingAmbiguityBranch=true; if(createdObject) { ambiguityBranchCreatedObject=createdObject->Clone(); } else { ambiguityBranchCreatedObject=0; } ambiguityBranchOperationTarget=operationTarget->Clone().Cast(); ambiguityBranchNodeStack.Clear(); ambiguityBranchSharedNodeCount=nodeStack.Count()-result.ambiguityAffectedStackNodeCount+1; for(vint i=ambiguityBranchSharedNodeCount;iClone().Cast()); } ambiguityNodes.Clear(); } break; case ParsingState::TransitionResult::AmbiguityBranch: { if(!processingAmbiguityBranch) return false; if(nodeStack.Count()!=ambiguityBranchSharedNodeCount) return false; ambiguityNodes.Add(operationTarget); if(ambiguityBranchCreatedObject) { createdObject=ambiguityBranchCreatedObject->Clone(); } else { createdObject=0; } operationTarget=ambiguityBranchOperationTarget->Clone().Cast(); for(vint i=0;iClone().Cast()); } } break; case ParsingState::TransitionResult::AmbiguityEnd: { if(!processingAmbiguityBranch) return false; if(nodeStack.Count()!=ambiguityBranchSharedNodeCount) return false; ambiguityNodes.Add(operationTarget); processingAmbiguityBranch=false; createdObject=0; ambiguityBranchCreatedObject=0; ambiguityBranchOperationTarget=0; ambiguityBranchSharedNodeCount=0; ambiguityBranchNodeStack.Clear(); { Ptr ambiguousNode=new ParsingTreeObject(result.ambiguityNodeType, operationTarget->GetCodeRange()); Ptr items=new ParsingTreeArray(L"", operationTarget->GetCodeRange()); FOREACH(Ptr, node, ambiguityNodes) { items->AddItem(node); } ambiguousNode->SetMember(L"items", items); operationTarget=ambiguousNode; } ambiguityNodes.Clear(); } break; case ParsingState::TransitionResult::ExecuteInstructions: { vint shiftReduceRangeIndex=0; for(vint j=result.instructionBegin;jinstructions[j]; switch(ins.instructionType) { case ParsingTable::Instruction::Create: { if(operationTarget->GetType()!=L"") { return false; } operationTarget->SetType(ins.nameParameter); operationTarget->GetCreatorRules().Add(ins.creatorRule); } break; case ParsingTable::Instruction::Using: { if(operationTarget->GetType()!=L"" || !createdObject) { return false; } Ptr obj=createdObject.Cast(); if(!obj) { return false; } for(vint i=0;iGetMembers().Count();i++) { WString name=operationTarget->GetMembers().Keys().Get(i); Ptr value=operationTarget->GetMembers().Values().Get(i); obj->SetMember(name, value); } operationTarget=obj; operationTarget->GetCreatorRules().Add(ins.creatorRule); createdObject=0; } break; case ParsingTable::Instruction::Assign: { if(!createdObject) { Ptr value; if(result.token==0) { value=new ParsingTreeToken(L"", result.tokenIndexInStream); } else { value=new ParsingTreeToken(WString(result.token->reading, result.token->length), result.tokenIndexInStream); value->SetCodeRange(ParsingTextRange(result.token, result.token)); } operationTarget->SetMember(ins.nameParameter, value); } else { operationTarget->SetMember(ins.nameParameter, createdObject); createdObject=0; } } break; case ParsingTable::Instruction::Item: { Ptr arr=operationTarget->GetMember(ins.nameParameter).Cast();; if(!arr) { arr=new ParsingTreeArray(); operationTarget->SetMember(ins.nameParameter, arr); } ParsingTextRange arrRange=arr->GetCodeRange(); ParsingTextRange itemRange; if(!createdObject) { Ptr value; if(result.token==0) { value=new ParsingTreeToken(L"", result.tokenIndexInStream); } else { value=new ParsingTreeToken(WString(result.token->reading, result.token->length), result.tokenIndexInStream); value->SetCodeRange(ParsingTextRange(result.token, result.token)); itemRange=value->GetCodeRange(); } arr->AddItem(value); } else { arr->AddItem(createdObject); itemRange=createdObject->GetCodeRange(); createdObject=0; } if(arrRange.start.index==ParsingTextPos::UnknownValue || itemRange.startarrRange.end) { arrRange.end=itemRange.end; } arr->SetCodeRange(arrRange); } break; case ParsingTable::Instruction::Setter: { Ptr value=new ParsingTreeToken(ins.value, -1); operationTarget->SetMember(ins.nameParameter, value); } break; case ParsingTable::Instruction::Shift: { nodeStack.Add(operationTarget); operationTarget=new ParsingTreeObject(); createdObject=0; } break; case ParsingTable::Instruction::Reduce: { if(nodeStack.Count()==0) { return false; } createdObject=operationTarget; operationTarget=nodeStack[nodeStack.Count()-1]; nodeStack.RemoveAt(nodeStack.Count()-1); if(result.shiftReduceRanges) { ParsingState::ShiftReduceRange tokenRange=result.shiftReduceRanges->Get(shiftReduceRangeIndex++); if(tokenRange.shiftToken && tokenRange.reduceToken) { ParsingTextRange codeRange(tokenRange.shiftToken, tokenRange.reduceToken); createdObject->SetCodeRange(codeRange); } } } break; case ParsingTable::Instruction::LeftRecursiveReduce: { createdObject=operationTarget; operationTarget=new ParsingTreeObject(); if(result.shiftReduceRanges) { ParsingState::ShiftReduceRange tokenRange=result.shiftReduceRanges->Get(shiftReduceRangeIndex++); if(tokenRange.shiftToken && tokenRange.reduceToken) { ParsingTextRange codeRange(tokenRange.shiftToken, tokenRange.reduceToken); createdObject->SetCodeRange(codeRange); } } } break; default: return false; } } if(result.tableTokenIndex==ParsingTable::TokenFinish && !processingAmbiguityBranch) { if(result.shiftReduceRanges) { ParsingState::ShiftReduceRange tokenRange=result.shiftReduceRanges->Get(shiftReduceRangeIndex++); if(tokenRange.shiftToken && tokenRange.reduceToken) { ParsingTextRange codeRange(tokenRange.shiftToken, tokenRange.reduceToken); operationTarget->SetCodeRange(codeRange); } } } } break; default: return false; } return true; } bool ParsingTreeBuilder::GetProcessingAmbiguityBranch() { return processingAmbiguityBranch; } Ptr ParsingTreeBuilder::GetNode()const { if(nodeStack.Count()==0) { return operationTarget; } else { return 0; } } /*********************************************************************** ParsingTransitionCollector ***********************************************************************/ ParsingTransitionCollector::ParsingTransitionCollector() :ambiguityBegin(-1) { } ParsingTransitionCollector::~ParsingTransitionCollector() { } void ParsingTransitionCollector::Reset() { ambiguityBegin=-1; transitions.Clear(); ambiguityBeginToEnds.Clear(); ambiguityBeginToBranches.Clear(); ambiguityBranchToBegins.Clear(); } bool ParsingTransitionCollector::Run(const ParsingState::TransitionResult& result) { vint index=transitions.Count(); switch(result.transitionType) { case ParsingState::TransitionResult::AmbiguityBegin: if(ambiguityBegin!=-1) return false; ambiguityBegin=index; break; case ParsingState::TransitionResult::AmbiguityBranch: { if(ambiguityBegin==-1) return false; ambiguityBeginToBranches.Add(ambiguityBegin, index); ambiguityBranchToBegins.Add(index, ambiguityBegin); } break; case ParsingState::TransitionResult::AmbiguityEnd: { if(ambiguityBegin==-1) return false; ambiguityBeginToEnds.Add(ambiguityBegin, index); ambiguityBegin=-1; } break; case ParsingState::TransitionResult::ExecuteInstructions: break; default: return false; } transitions.Add(result); return true; } bool ParsingTransitionCollector::GetProcessingAmbiguityBranch() { return ambiguityBegin!=-1; } const ParsingTransitionCollector::TransitionResultList& ParsingTransitionCollector::GetTransitions()const { return transitions; } vint ParsingTransitionCollector::GetAmbiguityEndFromBegin(vint transitionIndex)const { vint index=ambiguityBeginToEnds.Keys().IndexOf(transitionIndex); return index==-1?-1:ambiguityBeginToEnds.Values()[index]; } const collections::List& ParsingTransitionCollector::GetAmbiguityBranchesFromBegin(vint transitionIndex)const { vint index=ambiguityBeginToBranches.Keys().IndexOf(transitionIndex); return index==-1?*(collections::List*)0:ambiguityBeginToBranches.GetByIndex(index); } vint ParsingTransitionCollector::GetAmbiguityBeginFromBranch(vint transitionIndex)const { vint index=ambiguityBranchToBegins.Keys().IndexOf(transitionIndex); return index==-1?-1:ambiguityBranchToBegins.Values()[index]; } } } } #if defined(VCZH_GCC) && defined(__clang__) #pragma clang diagnostic pop #endif /*********************************************************************** .\PARSING\PARSINGTABLE.CPP ***********************************************************************/ namespace vl { namespace stream { namespace internal { using namespace vl::parsing::tabling; /*********************************************************************** ParsingTable (Serialization) ***********************************************************************/ BEGIN_SERIALIZATION(ParsingTable::AttributeInfo) SERIALIZE(name) SERIALIZE(arguments) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::AttributeInfoList) SERIALIZE(attributes) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::TreeTypeInfo) SERIALIZE(type) SERIALIZE(attributeIndex) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::TreeFieldInfo) SERIALIZE(type) SERIALIZE(field) SERIALIZE(attributeIndex) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::TokenInfo) SERIALIZE(name) SERIALIZE(regex) SERIALIZE(regexTokenIndex) SERIALIZE(attributeIndex) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::StateInfo) SERIALIZE(ruleName) SERIALIZE(stateName) SERIALIZE(stateExpression) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::RuleInfo) SERIALIZE(name) SERIALIZE(type) SERIALIZE(ambiguousType) SERIALIZE(rootStartState) SERIALIZE(attributeIndex) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::Instruction) SERIALIZE(instructionType) SERIALIZE(stateParameter) SERIALIZE(nameParameter) SERIALIZE(value) SERIALIZE(creatorRule) END_SERIALIZATION SERIALIZE_ENUM(ParsingTable::Instruction::InstructionType) BEGIN_SERIALIZATION(ParsingTable::LookAheadInfo) SERIALIZE(tokens) SERIALIZE(state) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::TransitionItem) SERIALIZE(token) SERIALIZE(targetState) SERIALIZE(lookAheads) SERIALIZE(stackPattern) SERIALIZE(instructions) END_SERIALIZATION BEGIN_SERIALIZATION(ParsingTable::TransitionBag) SERIALIZE(transitionItems) END_SERIALIZATION } } namespace parsing { namespace tabling { using namespace collections; using namespace regex; #ifdef VCZH_GCC const vint ParsingTable::TokenBegin; const vint ParsingTable::TokenFinish; const vint ParsingTable::NormalReduce; const vint ParsingTable::LeftRecursiveReduce; const vint ParsingTable::UserTokenStart; #endif /*********************************************************************** ParsingTable::AttributeInfoList ***********************************************************************/ Ptr ParsingTable::AttributeInfoList::FindFirst(const WString& name) { for(vint i=0;iname==name) { return attributes[i]; } } return 0; } /*********************************************************************** ParsingTable::LookAheadInfo ***********************************************************************/ ParsingTable::LookAheadInfo::PrefixResult ParsingTable::LookAheadInfo::TestPrefix(Ptr a, Ptr b) { if(a->tokens.Count()>b->tokens.Count()) { return ParsingTable::LookAheadInfo::NotPrefix; } for(vint i=0;itokens.Count();i++) { if(a->tokens[i]!=b->tokens[i]) { return ParsingTable::LookAheadInfo::NotPrefix; } } return a->tokens.Count()tokens.Count()?ParsingTable::LookAheadInfo::Prefix:ParsingTable::LookAheadInfo::Equal; } void ParsingTable::LookAheadInfo::WalkInternal(Ptr table, Ptr previous, vint state, collections::SortedList& walkedStates, collections::List>& newInfos) { if (walkedStates.Contains(state)) return; walkedStates.Add(state); for (vint i = 0; i < table->GetTokenCount(); i++) { if(Ptr bag=table->GetTransitionBag(state, i)) { FOREACH(Ptr, item, bag->transitionItems) { if (i == ParsingTable::NormalReduce || i == ParsingTable::LeftRecursiveReduce) { WalkInternal(table, previous, item->targetState, walkedStates, newInfos); } else { Ptr info=new LookAheadInfo; info->state=item->targetState; if(previous) { CopyFrom(info->tokens, previous->tokens); } info->tokens.Add(i); newInfos.Add(info); } } } } walkedStates.Remove(state); } void ParsingTable::LookAheadInfo::Walk(Ptr table, Ptr previous, vint state, collections::List>& newInfos) { SortedList walkedStates; WalkInternal(table, previous, state, walkedStates, newInfos); } /*********************************************************************** ParsingTable::TransitionItem ***********************************************************************/ enum TransitionLevel { ReduceTransition, LeftRecursiveReduceTransition, NormalTransition, }; TransitionLevel GetTransitionLevel(Ptr t) { bool hasReduce=false; bool hasLrReduce=false; FOREACH(ParsingTable::Instruction, ins, t->instructions) { switch(ins.instructionType) { case ParsingTable::Instruction::Reduce: hasReduce=true; break; case ParsingTable::Instruction::LeftRecursiveReduce: hasLrReduce=true; break; default:; } } return hasLrReduce?LeftRecursiveReduceTransition: hasReduce?ReduceTransition: NormalTransition; } ParsingTable::TransitionItem::OrderResult ParsingTable::TransitionItem::CheckOrder(Ptr t1, Ptr t2, OrderResult defaultResult) { if(t1->token!=t2->token) return UnknownOrder; if (defaultResult != UnknownOrder) { TransitionLevel level1 = GetTransitionLevel(t1); TransitionLevel level2 = GetTransitionLevel(t2); if (level1 > level2) return CorrectOrder; if (level1 < level2) return WrongOrder; } vint ic1=t1->stackPattern.Count(); vint ic2=t2->stackPattern.Count(); vint ic=ic1stackPattern[i]; vint s2=t2->stackPattern[i]; if(s1>s2) { return CorrectOrder; } else if(s1token==TokenFinish) { if(ic1>ic2) { return CorrectOrder; } else if(ic1 t1, Ptr t2, OrderResult defaultResult) { OrderResult order=CheckOrder(t1, t2, defaultResult); switch(order) { case CorrectOrder: return -1; case WrongOrder: return 1; default: return 0; } } template void ParsingTable::IO(TIO& io) { io << ambiguity << attributeInfos << treeTypeInfos << treeFieldInfos << tokenCount << stateCount << tokenInfos << discardTokenInfos << stateInfos << ruleInfos << transitionBags ; } ParsingTable::ParsingTable(stream::IStream& input) { stream::internal::ContextFreeReader reader(input); IO(reader); } void ParsingTable::Serialize(stream::IStream& output) { stream::internal::ContextFreeWriter writer(output); IO(writer); } /*********************************************************************** ParsingTable ***********************************************************************/ #if defined(VCZH_GCC) && defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnull-dereference" #endif ParsingTable::ParsingTable(vint _attributeInfoCount, vint _treeTypeInfoCount, vint _treeFieldInfoCount, vint _tokenCount, vint discardTokenCount, vint _stateCount, vint _ruleCount) :ambiguity(false) ,tokenCount(_tokenCount+UserTokenStart) ,stateCount(_stateCount) ,attributeInfos(_attributeInfoCount) ,treeTypeInfos(_treeTypeInfoCount) ,treeFieldInfos(_treeFieldInfoCount) ,tokenInfos(_tokenCount+UserTokenStart) ,discardTokenInfos(discardTokenCount) ,stateInfos(_stateCount) ,ruleInfos(_ruleCount) ,transitionBags((_tokenCount+UserTokenStart)*_stateCount) { } ParsingTable::~ParsingTable() { } bool ParsingTable::GetAmbiguity() { return ambiguity; } void ParsingTable::SetAmbiguity(bool value) { ambiguity=value; } vint ParsingTable::GetAttributeInfoCount() { return attributeInfos.Count(); } Ptr ParsingTable::GetAttributeInfo(vint index) { return attributeInfos[index]; } void ParsingTable::SetAttributeInfo(vint index, Ptr info) { attributeInfos[index]=info; } vint ParsingTable::GetTreeTypeInfoCount() { return treeTypeInfos.Count(); } const ParsingTable::TreeTypeInfo& ParsingTable::GetTreeTypeInfo(vint index) { return treeTypeInfos[index]; } const ParsingTable::TreeTypeInfo& ParsingTable::GetTreeTypeInfo(const WString& type) { vint index=treeTypeInfoMap.Keys().IndexOf(type); if(index==-1) return *(const TreeTypeInfo*)0; return treeTypeInfos[treeTypeInfoMap.Values().Get(index)]; } void ParsingTable::SetTreeTypeInfo(vint index, const TreeTypeInfo& info) { treeTypeInfos[index]=info; } vint ParsingTable::GetTreeFieldInfoCount() { return treeFieldInfos.Count(); } const ParsingTable::TreeFieldInfo& ParsingTable::GetTreeFieldInfo(vint index) { return treeFieldInfos[index]; } const ParsingTable::TreeFieldInfo& ParsingTable::GetTreeFieldInfo(const WString& type, const WString& field) { Pair key(type, field); vint index=treeFieldInfoMap.Keys().IndexOf(key); if(index==-1) return *(const TreeFieldInfo*)0; return treeFieldInfos[treeFieldInfoMap.Values().Get(index)]; } void ParsingTable::SetTreeFieldInfo(vint index, const TreeFieldInfo& info) { treeFieldInfos[index]=info; } vint ParsingTable::GetTokenCount() { return tokenCount; } const ParsingTable::TokenInfo& ParsingTable::GetTokenInfo(vint token) { return tokenInfos[token]; } void ParsingTable::SetTokenInfo(vint token, const TokenInfo& info) { tokenInfos[token]=info; } vint ParsingTable::GetDiscardTokenCount() { return discardTokenInfos.Count(); } const ParsingTable::TokenInfo& ParsingTable::GetDiscardTokenInfo(vint token) { return discardTokenInfos[token]; } void ParsingTable::SetDiscardTokenInfo(vint token, const TokenInfo& info) { discardTokenInfos[token]=info; } vint ParsingTable::GetStateCount() { return stateCount; } const ParsingTable::StateInfo& ParsingTable::GetStateInfo(vint state) { return stateInfos[state]; } void ParsingTable::SetStateInfo(vint state, const StateInfo& info) { stateInfos[state]=info; } vint ParsingTable::GetRuleCount() { return ruleInfos.Count(); } const ParsingTable::RuleInfo& ParsingTable::GetRuleInfo(const WString& ruleName) { vint index=ruleMap.Keys().IndexOf(ruleName); if(index==-1) return *(const RuleInfo*)0; return ruleInfos[ruleMap.Values().Get(index)]; } const ParsingTable::RuleInfo& ParsingTable::GetRuleInfo(vint rule) { return ruleInfos[rule]; } void ParsingTable::SetRuleInfo(vint rule, const RuleInfo& info) { ruleInfos[rule]=info; } const regex::RegexLexer& ParsingTable::GetLexer() { return *lexer.Obj(); } Ptr ParsingTable::GetTransitionBag(vint state, vint token) { return transitionBags[state*tokenCount+token]; } void ParsingTable::SetTransitionBag(vint state, vint token, Ptr bag) { transitionBags[state*tokenCount+token]=bag; } void ParsingTable::Initialize() { List tokens; FOREACH(TokenInfo, info, From(tokenInfos).Skip(UserTokenStart)) { tokens.Add(info.regex); } FOREACH(TokenInfo, info, discardTokenInfos) { tokens.Add(info.regex); } vint regexTokenIndex=0; for(vint i=UserTokenStart;i key(info.type, info.field); treeFieldInfoMap.Add(key, index); } } bool ParsingTable::IsInputToken(vint regexTokenIndex) { return regexTokenIndex>=0 && regexTokenIndex=tokenCount-UserTokenStart?regexTokenIndex-(tokenCount-UserTokenStart):-1; } #if defined(VCZH_GCC) && defined(__clang__) #pragma clang diagnostic pop #endif } } } /*********************************************************************** .\PARSING\PARSINGTREE.CPP ***********************************************************************/ #if defined(VCZH_GCC) && defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnull-dereference" #endif namespace vl { using namespace collections; namespace parsing { vint CompareTextRange(Ptr r1, Ptr r2) { return ParsingTextPos::Compare(r1->GetCodeRange().start, r2->GetCodeRange().start); } /*********************************************************************** ParsingTreeNode::TraversalVisitor ***********************************************************************/ ParsingTreeNode::TraversalVisitor::TraversalVisitor(TraverseDirection _direction) :direction(_direction) { } void ParsingTreeNode::TraversalVisitor::BeforeVisit(ParsingTreeToken* node) { } void ParsingTreeNode::TraversalVisitor::AfterVisit(ParsingTreeToken* node) { } void ParsingTreeNode::TraversalVisitor::BeforeVisit(ParsingTreeObject* node) { } void ParsingTreeNode::TraversalVisitor::AfterVisit(ParsingTreeObject* node) { } void ParsingTreeNode::TraversalVisitor::BeforeVisit(ParsingTreeArray* node) { } void ParsingTreeNode::TraversalVisitor::AfterVisit(ParsingTreeArray* node) { } void ParsingTreeNode::TraversalVisitor::Visit(ParsingTreeToken* node) { BeforeVisit(node); AfterVisit(node); } void ParsingTreeNode::TraversalVisitor::Visit(ParsingTreeObject* node) { BeforeVisit(node); switch(direction) { case TraverseDirection::ByTextPosition: { FOREACH(Ptr, node, node->GetSubNodes()) { node->Accept(this); } } break; case TraverseDirection::ByStorePosition: { FOREACH(Ptr, node, node->GetMembers().Values()) { node->Accept(this); } } break; } AfterVisit(node); } void ParsingTreeNode::TraversalVisitor::Visit(ParsingTreeArray* node) { BeforeVisit(node); switch(direction) { case TraverseDirection::ByTextPosition: { FOREACH(Ptr, node, node->GetSubNodes()) { node->Accept(this); } } break; case TraverseDirection::ByStorePosition: { FOREACH(Ptr, node, node->GetItems()) { node->Accept(this); } } break; } AfterVisit(node); } /*********************************************************************** ParsingTreeNode ***********************************************************************/ bool ParsingTreeNode::BeforeAddChild(Ptr node) { return node->parent==0; } void ParsingTreeNode::AfterAddChild(Ptr node) { node->parent=this; ClearQueryCache(); } bool ParsingTreeNode::BeforeRemoveChild(Ptr node) { return node->parent!=0; } void ParsingTreeNode::AfterRemoveChild(Ptr node) { node->parent=0; ClearQueryCache(); } ParsingTreeNode::ParsingTreeNode(const ParsingTextRange& _codeRange) :codeRange(_codeRange) ,parent(0) { } ParsingTreeNode::~ParsingTreeNode() { } ParsingTextRange ParsingTreeNode::GetCodeRange() { return codeRange; } void ParsingTreeNode::SetCodeRange(const ParsingTextRange& range) { codeRange=range; } void ParsingTreeNode::InitializeQueryCache() { const NodeList& subNodes=GetSubNodesInternal(); ClearQueryCache(); auto subNodesExists = &subNodes; if(subNodesExists) { FOREACH(Ptr, node, subNodes) { node->InitializeQueryCache(); } //if (codeRange.start.IsInvalid() || codeRange.start.IsInvalid()) { FOREACH(Ptr, subNode, subNodes) { const auto& subRange = subNode->codeRange; const auto& min = !subRange.start.IsInvalid() ? subRange.start : subRange.end; const auto& max = !subRange.end.IsInvalid() ? subRange.end : subRange.start; if (codeRange.start.IsInvalid() || (!min.IsInvalid() && codeRange.start > min)) { codeRange.start = min; } if (codeRange.end.IsInvalid() || (!max.IsInvalid() && codeRange.end < max)) { codeRange.end = max; } } } CopyFrom( cachedOrderedSubNodes, From(subNodes) .Where([=](Ptr node) { const auto& range = node->GetCodeRange(); return !range.start.IsInvalid() && !range.end.IsInvalid(); }) .OrderBy(&CompareTextRange) ); } } void ParsingTreeNode::ClearQueryCache() { cachedOrderedSubNodes.Clear(); } ParsingTreeNode* ParsingTreeNode::GetParent() { return parent; } const ParsingTreeNode::NodeList& ParsingTreeNode::GetSubNodes() { return cachedOrderedSubNodes; } ParsingTreeNode* ParsingTreeNode::FindSubNode(const ParsingTextPos& position) { return FindSubNode(ParsingTextRange(position, position)); } ParsingTreeNode* ParsingTreeNode::FindSubNode(const ParsingTextRange& range) { if (codeRange.start <= range.start && range.end <= codeRange.end) { vint start = 0; vint end = cachedOrderedSubNodes.Count() - 1; while (start <= end) { vint selected = (start + end) / 2; ParsingTreeNode* selectedNode = cachedOrderedSubNodes[selected].Obj(); const ParsingTextRange& selectedRange = selectedNode->codeRange; if (range.endselectedRange.end) { start = selected + 1; } else if (selectedRange.start <= range.start && range.end <= selectedRange.end) { return selectedNode; } else { return this; } } } return this; } ParsingTreeNode* ParsingTreeNode::FindDeepestNode(const ParsingTextPos& position) { return FindDeepestNode(ParsingTextRange(position, position)); } ParsingTreeNode* ParsingTreeNode::FindDeepestNode(const ParsingTextRange& range) { ParsingTreeNode* result=0; ParsingTreeNode* node=this; do { result=node; node=node->FindSubNode(range); }while(result!=node); return result; } /*********************************************************************** ParsingTreeToken ***********************************************************************/ const ParsingTreeToken::NodeList& ParsingTreeToken::GetSubNodesInternal() { return *(NodeList*)0; } ParsingTreeToken::ParsingTreeToken(const WString& _value, vint _tokenIndex, const ParsingTextRange& _codeRange) :ParsingTreeNode(_codeRange) ,value(_value) ,tokenIndex(_tokenIndex) { } ParsingTreeToken::~ParsingTreeToken() { } void ParsingTreeToken::Accept(IVisitor* visitor) { visitor->Visit(this); } Ptr ParsingTreeToken::Clone() { Ptr clone=new ParsingTreeToken(value, tokenIndex, codeRange); return clone; } vint ParsingTreeToken::GetTokenIndex() { return tokenIndex; } void ParsingTreeToken::SetTokenIndex(vint _tokenIndex) { tokenIndex=_tokenIndex; } const WString& ParsingTreeToken::GetValue() { return value; } void ParsingTreeToken::SetValue(const WString& _value) { value=_value; } /*********************************************************************** ParsingTreeObject ***********************************************************************/ const ParsingTreeObject::NodeList& ParsingTreeObject::GetSubNodesInternal() { return members.Values(); } ParsingTreeObject::ParsingTreeObject(const WString& _type, const ParsingTextRange& _codeRange) :ParsingTreeNode(_codeRange) ,type(_type) { } ParsingTreeObject::~ParsingTreeObject() { } void ParsingTreeObject::Accept(IVisitor* visitor) { visitor->Visit(this); } Ptr ParsingTreeObject::Clone() { Ptr clone=new ParsingTreeObject(type, codeRange); CopyFrom(clone->rules, rules); for(vint i=0;i node=members.Values().Get(i)->Clone(); clone->SetMember(name, node); } return clone; } const WString& ParsingTreeObject::GetType() { return type; } void ParsingTreeObject::SetType(const WString& _type) { type=_type; } ParsingTreeObject::NodeMap& ParsingTreeObject::GetMembers() { return members; } Ptr ParsingTreeObject::GetMember(const WString& name) { vint index=members.Keys().IndexOf(name); if(index==-1) return 0; return members.Values().Get(index); } bool ParsingTreeObject::SetMember(const WString& name, Ptr node) { vint index=members.Keys().IndexOf(name); if(index!=-1) { Ptr previous=members.Values().Get(index); if(previous==node) return true; if(!BeforeRemoveChild(previous) || !BeforeAddChild(node)) return false; members.Remove(name); AfterRemoveChild(previous); } members.Add(name, node); AfterAddChild(node); return true; } bool ParsingTreeObject::RemoveMember(const WString& name) { vint index=members.Keys().IndexOf(name); if(index!=-1) { Ptr previous=members.Values().Get(index); if(BeforeRemoveChild(previous)) { members.Remove(name); AfterRemoveChild(previous); return true; } } return false; } const ParsingTreeObject::NameList& ParsingTreeObject::GetMemberNames() { return members.Keys(); } ParsingTreeObject::RuleList& ParsingTreeObject::GetCreatorRules() { return rules; } /*********************************************************************** ParsingTreeArray ***********************************************************************/ const ParsingTreeArray::NodeList& ParsingTreeArray::GetSubNodesInternal() { return items; } ParsingTreeArray::ParsingTreeArray(const WString& _elementType, const ParsingTextRange& _codeRange) :ParsingTreeNode(_codeRange) ,elementType(_elementType) { } ParsingTreeArray::~ParsingTreeArray() { } void ParsingTreeArray::Accept(IVisitor* visitor) { visitor->Visit(this); } Ptr ParsingTreeArray::Clone() { Ptr clone=new ParsingTreeArray(elementType, codeRange); for(vint i=0;i node=items.Get(i)->Clone(); clone->AddItem(node); } return clone; } const WString& ParsingTreeArray::GetElementType() { return elementType; } void ParsingTreeArray::SetElementType(const WString& _elementType) { elementType=_elementType; } ParsingTreeArray::NodeArray& ParsingTreeArray::GetItems() { return items; } Ptr ParsingTreeArray::GetItem(vint index) { if(0<=index && index node) { if(0<=index && index node) { return InsertItem(items.Count(), node); } bool ParsingTreeArray::InsertItem(vint index, Ptr node) { if(0<=index && index<=items.Count()) { if(BeforeAddChild(node)) { items.Insert(index, node); AfterAddChild(node); return true; } } return false; } bool ParsingTreeArray::RemoveItem(vint index) { if(0<=index && index previous=items[index]; if(BeforeRemoveChild(previous)) { items.RemoveAt(index); AfterRemoveChild(previous); return true; } } return false; } bool ParsingTreeArray::RemoveItem(ParsingTreeNode* node) { return RemoveItem(items.IndexOf(node)); } vint ParsingTreeArray::IndexOfItem(ParsingTreeNode* node) { return items.IndexOf(node); } bool ParsingTreeArray::ContainsItem(ParsingTreeNode* node) { return items.Contains(node); } vint ParsingTreeArray::Count() { return items.Count(); } bool ParsingTreeArray::Clear() { FOREACH(Ptr, node, items) { if(!BeforeRemoveChild(node)) return false; } FOREACH(Ptr, node, items) { AfterRemoveChild(node); } items.Clear(); return true; } /*********************************************************************** ParsingError ***********************************************************************/ ParsingError::ParsingError() :token(0) ,parsingTree(0) { } ParsingError::ParsingError(const WString& _errorMessage) :token(0) ,parsingTree(0) ,errorMessage(_errorMessage) { } ParsingError::ParsingError(const regex::RegexToken* _token, const WString& _errorMessage) :token(_token) ,parsingTree(0) ,errorMessage(_errorMessage) { if(token) { codeRange.start.row=_token->rowStart; codeRange.start.column=_token->columnStart; codeRange.start.index=_token->start; codeRange.end.row=_token->rowEnd; codeRange.end.column=_token->columnEnd; codeRange.end.index=_token->start+_token->length-1; codeRange.codeIndex = _token->codeIndex; } } ParsingError::ParsingError(ParsingTreeCustomBase* _parsingTree, const WString& _errorMessage) :codeRange(_parsingTree->codeRange) ,token(0) ,parsingTree(_parsingTree) ,errorMessage(_errorMessage) { } ParsingError::~ParsingError() { } /*********************************************************************** ParsingEmptyPrintNodeRecorder ***********************************************************************/ ParsingEmptyPrintNodeRecorder::ParsingEmptyPrintNodeRecorder() { } ParsingEmptyPrintNodeRecorder::~ParsingEmptyPrintNodeRecorder() { } void ParsingEmptyPrintNodeRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range) { } /*********************************************************************** ParsingMultiplePrintNodeRecorder ***********************************************************************/ ParsingMultiplePrintNodeRecorder::ParsingMultiplePrintNodeRecorder() { } ParsingMultiplePrintNodeRecorder::~ParsingMultiplePrintNodeRecorder() { } void ParsingMultiplePrintNodeRecorder::AddRecorder(Ptr recorder) { recorders.Add(recorder); } void ParsingMultiplePrintNodeRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range) { FOREACH(Ptr, recorder, recorders) { recorder->Record(node, range); } } /*********************************************************************** ParsingOriginalLocationRecorder ***********************************************************************/ ParsingOriginalLocationRecorder::ParsingOriginalLocationRecorder(Ptr _recorder) :recorder(_recorder) { } ParsingOriginalLocationRecorder::~ParsingOriginalLocationRecorder() { } void ParsingOriginalLocationRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range) { auto codeRange = node->codeRange; codeRange.codeIndex = range.codeIndex; recorder->Record(node, codeRange); } /*********************************************************************** ParsingGeneratedLocationRecorder ***********************************************************************/ ParsingGeneratedLocationRecorder::ParsingGeneratedLocationRecorder(RangeMap& _rangeMap) :rangeMap(_rangeMap) { } ParsingGeneratedLocationRecorder::~ParsingGeneratedLocationRecorder() { } void ParsingGeneratedLocationRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range) { rangeMap.Add(node, range); } /*********************************************************************** ParsingUpdateLocationRecorder ***********************************************************************/ ParsingUpdateLocationRecorder::ParsingUpdateLocationRecorder() { } ParsingUpdateLocationRecorder::~ParsingUpdateLocationRecorder() { } void ParsingUpdateLocationRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range) { node->codeRange = range; } /*********************************************************************** ParsingWriter ***********************************************************************/ void ParsingWriter::HandleChar(wchar_t c) { lastPos = currentPos; switch (c) { case L'\n': currentPos.index++; currentPos.row++; currentPos.column = 0; break; default: currentPos.index++; currentPos.column++; } } ParsingWriter::ParsingWriter(stream::TextWriter& _writer, Ptr _recorder, vint _codeIndex) :writer(_writer) , recorder(_recorder) , codeIndex(_codeIndex) , lastPos(-1, 0, -1) , currentPos(0, 0, 0) { } ParsingWriter::~ParsingWriter() { } void ParsingWriter::WriteChar(wchar_t c) { writer.WriteChar(c); if (!recorder) return; HandleChar(c); } void ParsingWriter::WriteString(const wchar_t* string, vint charCount) { writer.WriteString(string, charCount); if (!recorder) return; for (vint i = 0; i < charCount; i++) { HandleChar(string[i]); } } void ParsingWriter::BeforePrint(ParsingTreeCustomBase* node) { if (!recorder) return; nodePositions.Add(NodePosPair(node, currentPos)); } void ParsingWriter::AfterPrint(ParsingTreeCustomBase* node) { if (!recorder) return; auto pair = nodePositions[nodePositions.Count() - 1]; nodePositions.RemoveAt(nodePositions.Count() - 1); CHECK_ERROR(pair.key == node, L"vl::parsing::ParsingWriter::AfterPrint(ParsingTreeNode*)#BeforePrint and AfterPrint should be call in pairs."); ParsingTextRange range(pair.value, lastPos, codeIndex); recorder->Record(node, range); } } } #if defined(VCZH_GCC) && defined(__clang__) #pragma clang diagnostic pop #endif /*********************************************************************** .\PARSING\JSON\PARSINGJSON.CPP ***********************************************************************/ namespace vl { namespace parsing { namespace json { using namespace stream; using namespace collections; /*********************************************************************** Unescaping Function Foward Declarations ***********************************************************************/ void JsonUnescapingString(vl::parsing::ParsingToken& value, const vl::collections::List& tokens) { value.value = GenerateToStream([&](StreamWriter& writer) { JsonUnescapeString(value.value.Sub(1, value.value.Length() - 2), writer); }); } /*********************************************************************** JsonPrintVisitor ***********************************************************************/ class JsonPrintVisitor : public Object, public JsonNode::IVisitor { public: TextWriter& writer; JsonPrintVisitor(TextWriter& _writer) :writer(_writer) { } void Visit(JsonLiteral* node) { switch(node->value) { case JsonLiteral::JsonValue::True: writer.WriteString(L"true"); break; case JsonLiteral::JsonValue::False: writer.WriteString(L"false"); break; case JsonLiteral::JsonValue::Null: writer.WriteString(L"null"); break; } } void Visit(JsonString* node) { writer.WriteChar(L'\"'); JsonEscapeString(node->content.value, writer); writer.WriteChar(L'\"'); } void Visit(JsonNumber* node) { writer.WriteString(node->content.value); } void Visit(JsonArray* node) { writer.WriteChar(L'['); FOREACH_INDEXER(Ptr, item, i, node->items) { if(i>0) writer.WriteChar(L','); item->Accept(this); } writer.WriteChar(L']'); } void Visit(JsonObjectField* node) { writer.WriteChar(L'\"'); JsonEscapeString(node->name.value, writer); writer.WriteString(L"\":"); node->value->Accept(this); } void Visit(JsonObject* node) { writer.WriteChar(L'{'); FOREACH_INDEXER(Ptr, field, i, node->fields) { if(i>0) writer.WriteChar(L','); field->Accept(this); } writer.WriteChar(L'}'); } }; /*********************************************************************** API ***********************************************************************/ void JsonEscapeString(const WString& text, stream::TextWriter& writer) { const wchar_t* reading=text.Buffer(); while(wchar_t c=*reading++) { switch(c) { case L'\"': writer.WriteString(L"\\\""); break; case L'\\': writer.WriteString(L"\\\\"); break; case L'/': writer.WriteString(L"\\/"); break; case L'\b': writer.WriteString(L"\\b"); break; case L'\f': writer.WriteString(L"\\f"); break; case L'\n': writer.WriteString(L"\\n"); break; case L'\r': writer.WriteString(L"\\r"); break; case L'\t': writer.WriteString(L"\\t"); break; default: writer.WriteChar(c); } } } vuint16_t GetHex(wchar_t c) { if(L'0'<=c && c<=L'9') { return c-L'0'; } else if(L'A'<=c && c<=L'F') { return c-L'A'; } else if(L'a'<=c && c<=L'f') { return c-L'a'; } else { return 0; } } void JsonUnescapeString(const WString& text, stream::TextWriter& writer) { const wchar_t* reading=text.Buffer(); while(wchar_t c=*reading++) { if(c==L'\\' && *reading) { switch(c=*reading++) { case L'b': writer.WriteChar(L'\b'); break; case L'f': writer.WriteChar(L'\f'); break; case L'n': writer.WriteChar(L'\n'); break; case L'r': writer.WriteChar(L'\r'); break; case L't': writer.WriteChar(L'\t'); break; case L'u': { wchar_t h1, h2, h3, h4; if((h1=reading[0]) && (h2=reading[1]) && (h3=reading[2]) && (h4=reading[3])) { reading+=4; wchar_t h=(wchar_t)(vuint16_t)( (GetHex(h1)<<12) + (GetHex(h2)<<8) + (GetHex(h3)<<4) + (GetHex(h4)<<0) ); writer.WriteChar(h); } } break; default: writer.WriteChar(c); } } else { writer.WriteChar(c); } } } void JsonPrint(Ptr node, stream::TextWriter& writer) { JsonPrintVisitor visitor(writer); node->Accept(&visitor); } WString JsonToString(Ptr node) { return GenerateToStream([&](StreamWriter& writer) { JsonPrint(node, writer); }); } } } } /*********************************************************************** .\PARSING\JSON\PARSINGJSON_AST.CPP ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Parser::ParsingJson.parser.txt This file is generated by: Vczh Parser Generator ***********************************************************************/ namespace vl { namespace parsing { namespace json { /*********************************************************************** Visitor Pattern Implementation ***********************************************************************/ void JsonLiteral::Accept(JsonNode::IVisitor* visitor) { visitor->Visit(this); } void JsonString::Accept(JsonNode::IVisitor* visitor) { visitor->Visit(this); } void JsonNumber::Accept(JsonNode::IVisitor* visitor) { visitor->Visit(this); } void JsonArray::Accept(JsonNode::IVisitor* visitor) { visitor->Visit(this); } void JsonObjectField::Accept(JsonNode::IVisitor* visitor) { visitor->Visit(this); } void JsonObject::Accept(JsonNode::IVisitor* visitor) { visitor->Visit(this); } } } } namespace vl { namespace reflection { namespace description { #ifndef VCZH_DEBUG_NO_REFLECTION using namespace vl::parsing::json; #define PARSING_TOKEN_FIELD(NAME)\ CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(get_##NAME, NO_PARAMETER, vl::WString(ClassType::*)(), [](ClassType* node) { return node->NAME.value; }, L"*", L"*")\ CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(set_##NAME, { L"value" }, void(ClassType::*)(const vl::WString&), [](ClassType* node, const vl::WString& value) { node->NAME.value = value; }, L"*", L"*")\ CLASS_MEMBER_PROPERTY_REFERENCETEMPLATE(NAME, get_##NAME, set_##NAME, L"$This->$Name.value")\ IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonNode, system::JsonNode) IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonLiteral, system::JsonLiteral) IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonLiteral::JsonValue, system::JsonLiteral::JsonValue) IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonString, system::JsonString) IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonNumber, system::JsonNumber) IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonArray, system::JsonArray) IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonObjectField, system::JsonObjectField) IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonObject, system::JsonObject) IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonNode::IVisitor, system::JsonNode::IVisitor) BEGIN_CLASS_MEMBER(JsonNode) CLASS_MEMBER_METHOD_OVERLOAD(Accept, {L"visitor"}, void(JsonNode::*)(JsonNode::IVisitor* visitor)) END_CLASS_MEMBER(JsonNode) BEGIN_CLASS_MEMBER(JsonLiteral) CLASS_MEMBER_BASE(JsonNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_FIELD(value) END_CLASS_MEMBER(JsonLiteral) BEGIN_ENUM_ITEM(JsonLiteral::JsonValue) ENUM_ITEM_NAMESPACE(JsonLiteral::JsonValue) ENUM_NAMESPACE_ITEM(True) ENUM_NAMESPACE_ITEM(False) ENUM_NAMESPACE_ITEM(Null) END_ENUM_ITEM(JsonLiteral::JsonValue) BEGIN_CLASS_MEMBER(JsonString) CLASS_MEMBER_BASE(JsonNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(content) END_CLASS_MEMBER(JsonString) BEGIN_CLASS_MEMBER(JsonNumber) CLASS_MEMBER_BASE(JsonNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(content) END_CLASS_MEMBER(JsonNumber) BEGIN_CLASS_MEMBER(JsonArray) CLASS_MEMBER_BASE(JsonNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_FIELD(items) END_CLASS_MEMBER(JsonArray) BEGIN_CLASS_MEMBER(JsonObjectField) CLASS_MEMBER_BASE(JsonNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(name) CLASS_MEMBER_FIELD(value) END_CLASS_MEMBER(JsonObjectField) BEGIN_CLASS_MEMBER(JsonObject) CLASS_MEMBER_BASE(JsonNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_FIELD(fields) END_CLASS_MEMBER(JsonObject) BEGIN_INTERFACE_MEMBER(JsonNode::IVisitor) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonLiteral* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonString* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonNumber* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonArray* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonObjectField* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonObject* node)) END_INTERFACE_MEMBER(JsonNode) #undef PARSING_TOKEN_FIELD class JsonTypeLoader : public vl::Object, public ITypeLoader { public: void Load(ITypeManager* manager) { ADD_TYPE_INFO(vl::parsing::json::JsonNode) ADD_TYPE_INFO(vl::parsing::json::JsonLiteral) ADD_TYPE_INFO(vl::parsing::json::JsonLiteral::JsonValue) ADD_TYPE_INFO(vl::parsing::json::JsonString) ADD_TYPE_INFO(vl::parsing::json::JsonNumber) ADD_TYPE_INFO(vl::parsing::json::JsonArray) ADD_TYPE_INFO(vl::parsing::json::JsonObjectField) ADD_TYPE_INFO(vl::parsing::json::JsonObject) ADD_TYPE_INFO(vl::parsing::json::JsonNode::IVisitor) } void Unload(ITypeManager* manager) { } }; #endif bool JsonLoadTypes() { #ifndef VCZH_DEBUG_NO_REFLECTION ITypeManager* manager=GetGlobalTypeManager(); if(manager) { Ptr loader=new JsonTypeLoader; return manager->AddTypeLoader(loader); } #endif return false; } } } } /*********************************************************************** .\PARSING\JSON\PARSINGJSON_PARSER.CPP ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Parser::ParsingJson.parser.txt This file is generated by: Vczh Parser Generator ***********************************************************************/ namespace vl { namespace parsing { namespace json { /*********************************************************************** ParserText ***********************************************************************/ const wchar_t* const parserTextBuffer[] = { L"" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"// AST" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"" L"\r\n" , L"class Node" L"\r\n" , L"{" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Literal:Node" L"\r\n" , L"{" L"\r\n" , L"\tenum Value" L"\r\n" , L"\t{" L"\r\n" , L"\t\tTrue," L"\r\n" , L"\t\tFalse," L"\r\n" , L"\t\tNull," L"\r\n" , L"\t}" L"\r\n" , L"" L"\r\n" , L"\tValue value;" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class String:Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken content(JsonUnescapingString)\t\t\t\t@Color(\"String\");" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Number:Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken content;" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Array:Node" L"\r\n" , L"{" L"\r\n" , L"\tNode[] items;" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class ObjectField:Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken name(JsonUnescapingString)\t\t\t\t@Color(\"AttName\");" L"\r\n" , L"\tNode value;" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Object:Node" L"\r\n" , L"{" L"\r\n" , L"\tObjectField[] fields;" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"// Lexer" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"" L"\r\n" , L"token TRUEVALUE = \"true\"\t\t\t\t\t\t\t@Color(\"Keyword\");" L"\r\n" , L"token FALSEVALUE = \"false\"\t\t\t\t\t\t\t@Color(\"Keyword\");" L"\r\n" , L"token NULLVALUE = \"null\"\t\t\t\t\t\t\t@Color(\"Keyword\");" L"\r\n" , L"token OBJOPEN = \"\\{\"\t\t\t\t\t\t\t\t@Color(\"Boundary\");" L"\r\n" , L"token OBJCLOSE = \"\\}\"\t\t\t\t\t\t\t\t@Color(\"Boundary\");" L"\r\n" , L"token ARROPEN = \"\\[\"\t\t\t\t\t\t\t\t@Color(\"Boundary\");" L"\r\n" , L"token ARRCLOSE = \"\\]\"\t\t\t\t\t\t\t\t@Color(\"Boundary\");" L"\r\n" , L"token COMMA = \",\";" L"\r\n" , L"token COLON = \":\";" L"\r\n" , L"token NUMBER = \"[\\-]?\\d+(.\\d+)?([eE][+\\-]?\\d+)?\"\t@Color(\"Number\");" L"\r\n" , L"token STRING = \"\"\"([^\\\\\"\"]|\\\\[^u]|\\\\u\\d{4})*\"\"\"\t\t@ContextColor();" L"\r\n" , L"" L"\r\n" , L"discardtoken SPACE = \"\\s+\";" L"\r\n" , L"" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"// Rules" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"" L"\r\n" , L"rule Node JLiteral" L"\r\n" , L"\t= STRING:content as String" L"\r\n" , L"\t= NUMBER:content as Number" L"\r\n" , L"\t= \"true\" as Literal with {value = \"True\"}" L"\r\n" , L"\t= \"false\" as Literal with {value = \"False\"}" L"\r\n" , L"\t= \"null\" as Literal with {value = \"Null\"}" L"\r\n" , L"\t;" L"\r\n" , L"" L"\r\n" , L"rule ObjectField JField" L"\r\n" , L"\t= STRING:name \":\" JValue:value as ObjectField" L"\r\n" , L"\t;" L"\r\n" , L"" L"\r\n" , L"rule Object JObject" L"\r\n" , L"\t= \"{\" [JField:fields {\",\" JField:fields} ] \"}\" as Object" L"\r\n" , L"\t;" L"\r\n" , L"" L"\r\n" , L"rule Array JArray" L"\r\n" , L"\t= \"[\" [JValue:items {\",\" JValue:items} ] \"]\" as Array" L"\r\n" , L"\t;" L"\r\n" , L"" L"\r\n" , L"rule Node JValue" L"\r\n" , L"\t= !JLiteral" L"\r\n" , L"\t= !JObject" L"\r\n" , L"\t= !JArray" L"\r\n" , L"\t;" L"\r\n" , L"" L"\r\n" , L"rule Node JRoot" L"\r\n" , L"\t= !JObject" L"\r\n" , L"\t= !JArray" L"\r\n" , L"\t;" L"\r\n" }; const vint lengthTextBuffer[] = { 2, 68, 8, 68, 2, 12, 3, 3, 2, 20, 3, 13, 4, 9, 10, 9, 4, 2, 15, 3, 2, 19, 3, 59, 3, 2, 19, 3, 17, 3, 2, 18 , 3, 16, 3, 2, 24, 3, 57, 14, 3, 2, 19, 3, 24, 3, 2, 68, 10, 68, 2, 51, 53, 51, 49, 50, 49, 50, 20, 20, 68, 67, 2, 29 , 2, 68, 10, 68, 2, 20, 29, 29, 44, 46, 44, 4, 2, 25, 48, 4, 2, 21, 59, 4, 2, 19, 56, 4, 2, 18, 14, 13, 12, 4, 2, 17 , 13, 12, 4 }; const vint lengthTextBufferTotal = 2018; vl::WString JsonGetParserTextBuffer() { vl::collections::Array textBuffer(lengthTextBufferTotal + 1); wchar_t* reading = &textBuffer[0]; for(vint i = 0; i < sizeof(parserTextBuffer) / sizeof(*parserTextBuffer); i++) { memcpy(reading, parserTextBuffer[i], lengthTextBuffer[i] * sizeof(wchar_t)); reading += lengthTextBuffer[i]; } *reading = 0; return &textBuffer[0]; } /*********************************************************************** SerializedTable ***********************************************************************/ const vint parserBufferLength = 3809; // 17748 bytes before compressing const vint parserBufferBlock = 1024; const vint parserBufferRemain = 737; const vint parserBufferRows = 4; const char* const parserBuffer[] = { "\x00\x0B\x00\x02\x83\x80\x07\x7D\x00\x82\x03\xFF\x45\x08\x82\x83\x86\x81\x21\x6F\x6C\x2F\x32\x37\x84\x86\x02\x86\x00\x17\x82\x93\x24\x3A\x39\x34\x37\x67\x06\x98\x8A\x88\x8E\x84\x00\x88\x12\x94\x98\x87\x0B\x93\x81\x20\x3A\x74\x4E\x21\x2D\x35\x32\x90\x86\x92\x0C\xA6\xA8\x93\x85\x88\x84\x96\x86\x3F\x80\x0B\x25\x39\x3F\x3B\x88\x32\x36\x88\xB8\x88\x8A\x99\x88\x9F\x96\x40\x83\x83\xA5\xA7\xA1\xA4\x83\xA5\x04\xCD\xA9\x9D\x94\x81\xA1\xAE\xA9\x44\xC6\xB2\x28\xAC\xA9\x86\x93\xAC\x03\xBB\xAA\x8C\x88\x00\x8D\xB6\x81\x42\x6F\x35\x2E\x34\x31\x32\x39\x3C\x56\xE6\xA5\x89\xBE\xA3\xB4\x85\xB7\x7F\x83\xB1\xB3\xB5\xBF\xB9\xBC\x81\x58\x83\x9A\xAF\xAC\xB6\xB6\xC0\xB9\x74\xF6\xB8\xA5\xB8\xC7\xB2\xC4\xBE\x5B\x8E\xCD\xD0\xB0\xCD\xC3\xC9\x91\x96\x8D\x98\xCC\xC8\x82\x8D\xD3\x81\x4E\x75\x2D\x22\x35\x32\x3B\xC3\x82\x0C\x18\xB1\xCF\x8F\x36\x34\x3B\x32\x78\x74\x2A\xB8\x80\x06\xAF\xCB\x9C\x2E\xF2\x32\x21\x38\xBF\x7E\xE3\xE3\xFF\x3E\xC2\x81\xAC\x21\x37\xDB\xE1\x6C\x48\xC8\xE4\x08\x8C\xEA\x80\x27\x6F\x64\x35\x92\xE6\xE6\xD0\x82\xD3\xA9\xAB\xED\xDC\xED\xE8\x8E\xD3\x27\x62\x6A\x25\x23\x34\x3C\xF3\x7F\x80\x0C\xF0\xC0\x08\xFA\xF4\xF6\x23\x34\x65\x6C\x08\xA4\xFE\xEB\x82\xD2\x8E\x1E\x60\x4E\x7A\x72\x00\x21\x65\x81\x70\xC3\x79\x16\x82\x49\xCE\x65\x1D\x1B\x1C\x03\x90\x50\x01\x73\xCF\x61\x1C\x1B\x82\x03\x76\x16\x85\x1D\xDB\x5C\x7D\x7E\x40\xE0\x6A\x6C\x6A\x1C\x04\x81\x53\x19\x6D\xB7\x76\x6E\x7B\x87\x19\x43\x44\x7F\x7A\x74\x2C\x86\x6A\x19\xF8\x7A\x70\x84\x79\xF2\x44\x42\x7F\x8B\xF6\x75\x84\x1A\x75\x08\x40\x9E\x1B\x4C\x65\x14\x60\x40\x46\x3B\xA9\x70\x8F\x7D\xF9\x64\x18\x86\x40\x1A\xAC\x1C\x87\x8A\xE6\x43\x40\x83\x47\x67\x25\x83\x43\x89\xB6\x65\x16\x6C\x6F\x0F\x18\x44\x08\x46\x61\xBC\x66\x9A\x52\xEE\x64\x77\x9B\x4D\x69\x9C\x7B\x98\x9A\x6D\x88\x7F\x9B\x55\x71\x88\x79\x00\x46\x77\x82\x44\x16\x14\x55\x05\x16\x15\x10\x4C\x3D\x90\x90\x41\x40\x9D\x4C\x84\x6F\x02\x18\x4A\x02\xA2\x03\x46\x10\xA3\x14\x7E\x80\xAD\x9F\x93\x00\x26\x16\x87\x1C\x45\x98\x43\x00\x9E\x9C\x97\x75\x14\x13\x4C\x3F\x91\xA1\x11\x83\x83\x42\x91\x1D\x6C\x2C\x19\xA0\x43\xA5\x8B\x72\x87\x13\x42\x0A\x1F\x10\x14\x45\x0E\x1B\xA8\x42\xB7\x9C\x1B\x1F\xA6\xC0\x5B\x61\x62\x40\xB0\x8A\x13\x10\x13\x4F\x10\xA7\xAC\x41\xB9\xBD\x1D\xA9\x8B\x51\x4D\xB0\x01\x10\x52\x12\x13\xAD\xAD\xC7\x83\x49\xAF\x16\x06\x84\x80\x60\x41\x80\x50\xB2\x17\xB0\xC5\x85\x15\xB6\x40\xB9\x9D\x1C\x8B\xB6\xBF\x4C\x59\x5B\x13\x4D\x0D\x11\x12\x91\x3D\x6C\x04\x82\x7B\x94\x83\x1F\x10\xB1\x4E\x30\xB3\x42\x0E\xE8\x88\x6C\x7D\x95\x9E\x8D\x12\x11\x11\x52\x1F\x08\x46\xC1\x02\x5B\x1C\x15\x0B\x5D\x3F\x0C\x14\x19\x2B\x28\x0E\x0B\xC3\x2B\x29\x0F\x0C\x0A\x5B\x25\x15\x11\x17\x5B\x2B\x0B\xC1\xC3\x14\xD6\xC9\x9C\x42\x23\xDF\x70\xC0\x00\x53\x3B\x99\x12\x13\x47\x1B\x08\x46\xCB\x02\x62\x08\xC6\x17\x5C\x1C\x12\x09\x17\x7C\x35\xCB\x16\x17\x75\x38\xC5\xCD\x1D\x0F\xFB\x14\x0D\x1F\x29\x2A\x02\x0B\xA2\x0C\x48\xD8\x42\x91\x94\x93\x10\x15\x10\x43\x05\x1C\xAC\x42\x53\xDC\x13\x1F\x0A\x39\x89\x44\x7B\x98\xBE\x9C\xB3\x42\x12\x14\xAD\x66\x86\x04\x18\x64\xD2\x40\xD8\x0D\x90\x7E\x0A\x14\x6F\x2F\x14\x1C\x47\x76\x74\x1D\x00\x46\x73\xC2\x40\x10\x08\x24\x3C\x08\xD9\x85\x6C\x3E\x0D\xBC\x00\x80\x7B\xD2\xD8\x1B\x0E\x18\x45\xE3\xD9\x61\xEA\xD0\xDE\x1C\x74\x33\x68\x42\xE3\x77\xFA\xD9\xE2\x85\x7E\xDA\x60\x02\xE0\xD0\x4A\xD4\x42\xD2\x98\xD6\x8E\x09\x0C\xFA\x18\x41\xEA\x40\x92\xE9\xD4\xE6\x0E\x20\x29\xC2\x17\xCA\x47\x20\x08\xE8\x97\x29\xB4\x10\x09\x18\x73\x29\xED\x44\x96\x40\x0D\x0A\x01\xE9\x7C\xFE\x08\xEA\x13\x55\x02\xC4\xC2\xEB\x20\x30\xEE\x96\xEC\xB4\xE0\x01\x7B\x88\xB9\xFB\xED\xE5\xDF\xA8\xE2\x06\xA1\x19\x22\x33\xE5\xEF\xE4\x6C\x37\xD7\x1E\x73\x68\x20\x0B\x1C\x08\x51\x9C\x80\x09\x0F\x20\x22\x04\x16\x1C\x1C\x95\xFD\x1E\xEE\xBC\xC3\xEE\xED\xF9\x96\xAC\x18\xA5\xF5\xC9\xD8\xFA\xF4\xF7\xDE\xE0\xFB\x85\x19\xE3\xE5\xF6\x13\xA5\xD4\x60\x07\xFA\x4E\x78\x7B\xF7\x62\x06\x0D\xA8\x4C\x0C\xFD\x57\x76\x75\xEC\x60\x03\x7B\x74\x1D\x7B\xF7\x61\x7C\x7E\xF2\x62\x01\x35\xA9\x4A\x7F\xDF\x01\x78\x7A\x08\x18\x26\x83\x88\x6D\x83\xDA\x6D\x64\x0F\x22\x34\x2D\x6E\x08\x28\x85\xDE\x4F\x7E\x06\x10\x00\x0A\x46\x5F\x76\x0B\xFE\x1B\x81\x87\xFD\x5F\x75\x07\x18\x38\x84\xE9\x4A\x02\x86\x29\x65\x0F\x7D\x21\x0F\x79\xF3\x7A\x6D\x86", "\x0E\x40\x8A\x56\x4A\x4C\x3F\x10\xBC\x8B\x7F\x23\x81\x0A\x38\xC4\x2F\x87\xC9\x4A\x0C\x48\xFD\x34\x87\x6C\x55\x84\x0E\x0B\x33\x0A\x06\x8C\x1D\x8B\x87\x59\x8F\x7E\xEA\x2C\x74\x79\x21\x74\x25\x7C\x3A\x15\x78\x13\xBE\x84\x78\x0A\x96\x78\x04\x3C\x54\x0D\x16\xD2\x86\x23\xAF\x4F\x89\x41\x57\x97\x73\x1D\xC4\x3E\x04\x19\x0C\x10\x23\x7F\x9B\x87\x1E\xF9\x06\x81\x2D\x15\x7B\x0B\x20\x0B\x8E\xF8\x28\x7D\x41\x07\x77\x6F\x7B\x22\x0C\x06\x1A\xC5\x8C\x7E\x46\xB7\x37\x41\x02\x80\x05\x17\x65\x7D\x0B\x05\xA0\x03\x90\xEC\x6A\x0B\x20\x85\x97\x91\x44\x94\x94\x78\x8D\x95\x74\x10\x10\x92\x92\x53\xBB\x78\x95\x97\x95\x75\x1F\x1A\x9C\x92\x4F\x83\x90\x86\x67\x74\x93\xE1\x08\x2B\x96\x45\xA5\x0B\x84\x6E\x66\x84\x19\x59\x62\x20\xF9\x2B\x84\x92\x2D\x94\x8F\x69\x58\x8E\x47\x5D\x84\x25\x97\x59\x80\x99\x09\xF4\x24\x99\x23\x42\x23\x85\x61\x8E\x86\x96\x67\x61\x8F\x92\x43\x23\x64\x48\x95\x3C\x1D\x7D\x84\x12\x8C\x25\x9B\x87\x71\x86\x83\x1E\x25\x94\x8A\x1F\x44\x7C\x46\x4D\x53\x0F\x23\xE5\x7D\x95\x76\x8D\x4F\x9D\x3E\x52\x94\x2D\xA2\x0D\x0E\x4F\xB1\x89\x94\xE9\x91\x7B\x3A\xA0\x08\x90\x7B\xBA\x38\x9F\xF1\x8E\x84\x2B\xEA\x89\x8A\x84\xB6\x41\x93\x9B\x9C\x9E\x3F\xC9\x81\x47\x29\x83\x91\x8F\xA2\x90\x89\x1E\x5B\x85\x08\x8C\x1D\xA2\x90\x1A\xA4\x94\x41\xAE\x9C\x8C\x4B\x8E\x45\x76\x0B\xA4\xA7\x22\xA0\x09\x94\x88\xB5\x97\x8D\x83\x8A\x9A\xC9\x67\x67\xA2\xCB\x59\xA1\x41\x2E\x14\x07\x47\x88\x2B\xA6\xBD\x63\x91\x7A\x86\x83\xA6\x2F\xB0\x97\xA5\xFC\x51\x92\x04\x77\x63\xAA\x49\x98\x93\x97\x88\x9D\x90\xA6\x1A\xBB\x9B\xE5\x5D\x9D\x53\xA9\x94\xA1\xA7\x49\x18\x21\x56\xE8\x94\xA2\x75\xAC\x9D\xA1\xA8\x70\x9F\x43\x8B\xA9\xA8\xB0\xA0\x02\xAC\x64\x1A\x9D\x44\xFD\x9F\x8D\x38\x92\xA9\x9C\x30\x5E\x9A\x40\x60\x91\x8F\x2D\x9B\xA8\x21\x77\xBA\x6D\x40\xE5\x73\xA1\x82\xA6\xA8\xAD\x28\xB4\x9C\x43\xEE\x91\xAD\x7C\xAE\xA2\xA2\x6D\xB4\xA2\x4C\xFE\x36\x8E\x8D\x8E\x9B\x20\xBD\x83\x92\x34\xC2\x95\x9A\x63\xBE\xA1\xA4\x2E\x94\x52\x12\x6C\x6E\x6D\xB7\x9C\xB3\x9C\x31\x05\x04\x46\x22\xBB\x87\xCF\x87\x89\x8E\x4B\x86\xB4\xEA\x41\x81\xA7\xB7\x94\xAC\x21\x74\xB7\xA9\x0C\x77\xA4\x21\xBC\xB0\xAC\x3D\x5E\xB7\x6E\x5F\x84\xB7\xAC\xC3\xA9\xA6\xA0\x64\x0E\xA1\x5A\x87\xBC\xAD\xE4\x71\x88\x97\x7A\x9A\xA0\x46\x92\xB1\x07\x9D\x84\x25\xA7\x37\xA4\x38\x29\xBA\xBA\xA5\x4A\xAC\xA1\x96\x46\xB5\x9F\x29\xCB\xAA\xAD\x97\x89\x7F\x96\x53\x99\x88\x46\xD1\x91\x07\x2F\x88\x26\xBC\x7A\x61\x8C\xEA\x63\x8C\x65\x32\x84\x4F\x6E\x22\x09\x8D\x75\xED\x8F\x94\xE3\x94\xA1\x8B\xAE\xB4\xA1\x99\x08\x2B\xBF\xDB\xA3\x9F\xB3\xC2\x8E\x70\x41\x0E\x7B\x85\x74\x99\xB3\x2F\x67\x7F\xB0\x0A\x84\x28\x85\xCD\xA4\x83\xB2\x74\x3A\x73\x40\x4A\x6B\x84\xD3\xAE\x80\xB9\xC0\xA3\xBE\x8F\x7D\x86\xBC\x82\x28\xB8\xB8\x62\x8A\x65\x7B\xA8\x76\x8C\xFE\x71\xB8\xA9\xF3\xA8\x76\x1B\xF6\xB2\x9D\x2C\x98\xC1\x8B\x20\x88\x21\x8C\xC0\xB2\x9B\xC5\x74\x0D\xB2\x03\x37\x6C\x36\xBE\x4E\x07\x17\xFE\x42\xC0\x03\x2E\x70\x8D\xB6\xC2\xC2\x81\x0A\x69\x72\x20\xD9\xBE\x38\x91\x08\x22\x26\xDC\x9F\xAA\x9F\xB6\xC4\x90\x82\x20\x72\xBC\x7A\xAD\xAB\x4A\xD0\x47\x82\x83\x2D\xC1\xBA\xB6\xC0\xC7\x76\x60\x07\x95\xE2\x9D\xC6\x8B\x9A\xA1\xC6\x04\x33\xC6\x64\xD1\xC4\x0F\xB8\x60\xC8\x00\x3A\xD7\xB1\x82\x65\xC5\x8E\x9A\x9A\xA3\xCA\x00\x02\xCA\x64\xC4\xCC\x51\x30\xF2\xCA\xBA\x18\xD4\x90\x9A\x83\x23\xC6\x4A\xB5\xC5\xCD\x8C\x6F\xCD\x9C\xBE\x94\xCF\x65\x97\x74\x92\x78\xC2\xCA\xA1\xFC\xC9\x69\x1C\xE2\xCC\xD1\x9A\xBF\xB3\x7E\x84\x2D\xBF\xCF\x87\xD1\x6E\x45\xC0\x03\x91\xD6\xCE\xC0\xB7\x7E\x01\xD3\x24\x8F\xCD\xA9\xE3\x96\xC6\xB9\x80\x03\x64\x48\xC6\xB4\x46\xD8\x71\xD4\xCE\x58\x7D\x8F\xA3\x68\x21\xAE\xED\x70\x3B\x10\xEB\x73\xC4\xC5\x68\x47\xF1\x6F\x87\x4A\x90\x0B\x8D\x80\xBF\x61\x7B\xC0\x52\x04\x78\xE3\x76\x37\x8D\xCB\x6D\x37\xB1\x8D\x86\x81\xE9\x5E\x90\x7B\x0F\x98\x7F\x04\xAF\x96\x83\xF3\x69\x7A\x80\xD3\xDD\x75\xF4\x71\x73\x7F\x37\x98\xD8\x82\x12\x9A\x7C\x1B\x96\x8F\x7E\xF9\x41\x85\x0F\xE1\xCE\x7D\xF4\x08\x89\x82\x73\xCD\x81\xDB\x11\x99\x7E\x1B\x96\x88\x82\x05\xA0\xDE\xC7\x4D\x5A\xC1\x93\x39\xAD\xC3\x7D\x43\x21\xBD\x3C\xCB\xBE\x88\xAD\x74\xC4\x22\x68\x8B\x92\xAF\x8A\xC5\x7D\xB5\x71\x8F\x39\x99\xCC\x3D\xAE\xD1\xB6\x38\xAE\x05\x06\xDA\x83\x26\xB6\x7B\xA2\x05\x5F\x89\x9F\xAE\xDF\x82\xB4\xE4\xBC\xA0\xB0\x71\x93\xA2\x9D\xC5", "\xA0\x45\xB1\x78\x96\xA6\x64\xB5\x0E\xB9\x81\x10\xBF\xA7\xE5\x61\xA9\x41\xDB\xB7\xBB\xA2\xBF\xB4\xE7\x2D\xAD\xAA\x77\xB5\x71\xA7\x73\x76\xA0\x7B\xCB\x40\x48\x76\x5A\x33\x4E\xAD\x5E\x41\xBC\x3E\x4F\xCD\xC5\xBE\x4C\x36\x0B\x23\x24\x3C\x17\xF5\xA1\x9D\xF3\x34\xA2\xDE\x18\x07\xEA\x4F\xFB\xE9\x74\x8A\x48\xC1\x67\x5A\xA4\x37\x1A\x00\xEE\x74\x01\xDB\x7F\xA4\xE8\x31\x3B\x65\x1C\x34\x07\x6A\xE8\x38\x54\xEE\x6E\xED\xD7\x30\xEC\x6F\x1E\x04\xEF\xE3\x1C\x03\x5C\xAF\x3F\x1C\x6F\x46\x4D\xE9\xC2\xF3\x49\xF0\xCB\x43\x5E\xE1\x80\x0A\xF1\x65\x7C\x34\x52\x14\x98\xEC\x00\x5E\xD5\x0D\x59\xCD\x86\xF0\x52\xB8\x78\x6F\x16\xFC\x6F\xC0\xC6\x42\xF1\x86\xED\xF1\xE1\x90\xFB\x7E\x4A\x6D\xD8\x53\x9C\xE3\x70\xE6\x92\x4A\xF2\xCB\x5E\x69\x84\x9D\xE6\x4B\x3F\x2C\x40\xF5\xC2\xE2\xF5\xE9\xA4\xFE\x86\xE4\xFD\xD9\xF4\xE8\x2B\xF6\x59\xAD\xFD\x6B\x40\x1C\x87\xF2\xA5\x32\xF3\xCB\xE4\x4B\xF0\x43\x0A\xF4\xF0\x09\x5F\x2A\x20\xCE\xD4\x0F\xE6\xC7\xE5\xF9\xA6\xC8\xB9\xDA\x72\x13\xFA\xAF\x4F\x71\xF1\xC7\x89\xFA\xF9\xC8\x58\x21\xF3\xCE\x5F\xF8\x00\x11\xFA\xFB\xBF\x57\x71\xF0\xF3\x48\xB9\x62\xE7\x08\xFD\xAF\xEA\xFF\xE5\x81\xF6\x49\xA9\x60\xFE\x4C\x81\xF7\xF7\x9C\x46\x4D\x02\x8C\x0A\xF4\x45\xFD\x77\x7F\x02\x1D\x7B\x16\x26\x7F\x02\x8B\x75\x33\x5F\x68\xFB\x37\x80\x37\x12\x7B\x46\x24\x20\x0C\x85\x10\x06\x88\x18\x8A\x76\x20\x83\x78\x11\x15\x0E\x7F\x27\x34\x10\x19\x87\x80\x6C\x7E\x43\xE3\x7A\x2E\xBD\x20\x00\x14\x4C\x1B\x00\x7A\x1F\xFF\x0F\x7F\x85\x76\x24\x4E\x68\x2B\x1B\x83\x10\x2D\x87\x7F\x1F\x8C\x21\xB5\x73\x82\x68\x12\x10\xA9\x46\x82\x66\x69\x20\x29\x8F\x82\x67\x26\x24\xD5\x4A\x82\xF1\x1C\x80\x33\x85\x06\x35\x82\x82\x48\x89\x83\x3E\x8C\x2C\xC9\x59\x20\x87\x7E\x80\xAE\x70\x7E\x21\x8F\x26\x52\x77\x5F\x54\x7B\x84\xA6\x10\x5C\x3D\x87\x13\x8A\x7E\x6A\x17\x8C\x10\x83\x62\x10\x13\x8B\x78\x55\x8D\x62\x57\x88\x80\x8C\x5C\x4C\x4D\x2C\x22\x61\x8B\x78\x27\x84\x06\x47\x89\x80\x09\x80\x58\xBC\x19\x75\x5B\x84\x32\x2B\x82\x1B\x9A\x2C\x80\x65\x8B\x24\x67\x8E\x68\x09\x80\x5C\x2C\x28\x67\x86\x7F\x86\x71\x89\x86\x8E\x64\x87\xCE\x73\x10\x41\x1E\x5F\x07\x81\x78\xB5\x61\x81\x23\x12\x7B\x6F\x62\x89\x96\x8A\x7C\x81\x7F\x37\xC8\x77\x89\x81\x75\x4D\x84\x8C\x89\x50\x8C\x10\xDE\x7B\x78\x53\x8B\x26\x94\x23\x48\x3A\x82\x76\x83\x47\x87\x57\x1A\x78\x9B\x6B\x26\x46\x28\x30\x54\x3C\x80\xA7\x87\x76\x58\x80\x73\xC4\x1C\x22\xB2\x82\x83\x3B\x84\x1C\x63\x81\x81\x76\x7D\x1E\xFA\x7F\x26\xFC\x7B\x87\x07\x85\x8B\x4E\x87\x8B\x76\x69\x20\x00\x84\x84\xBD\x89\x07\xBF\x8E\x8C\x62\x74\x49\x86\x78\x78\x1A\x87\x80\xCB\x26\x20\xD5\x45\x88\xCF\x86\x20\x01\x82\x80\x45\x8E\x78\x65\x77\x83\x24\x8D\x76\xD5\x13\x10\x94\x74\x80\x6C\x0F\x7B\x3E\x13\x10\xEB\x71\x7F\xF1\x7C\x7D\xB2\x7F\x79\x0C\x89\x8D\x48\x22\x8D\x8E\x63\x76\xDE\x88\x8F\x81\x84\x49\xE2\x86\x83\xE9\x24\x41\xA6\x70\x40\xEA\x8C\x8E\xE5\x7F\x8E\xC3\x74\x7D\xB1\x73\x12\xB4\x75\x8F\xE3\x83\x10\xDB\x85\x78\x18\x63\x48\xFB\x8E\x81\x53\x4E\x8F\xA3\x75\x76\x91\x77\x8E\xD7\x19\x40\x05\x95\x78\x99\x75\x7D\xE9\x71\x8F\xD8\x31\x78\x04\x2D\x86\xA1\x7F\x90\xC5\x4C\x8F\x88\x8A\x8F\x18\x1F\x8D\xBC\x83\x8D\x0B\x81\x78\xAE\x61\x83\xE0\x75\x81\xF7\x86\x91\xAA\x8A\x51\x15\x90\x8E\x17\x9B\x80\x88\x17\x7C\xD7\x82\x80\xF6\x83\x84\x3A\x99\x8F\x14\x9F\x92\x2C\x9F\x72\xB9\x4B\x3F\xA5\x8E\x2A\xCE\x27\x7E\x51\x83\x80\x5F\x38\x90\x67\x27\x7D\x22\x2D\x1A\xF0\x79\x90\xB0\x73\x38\xDD\x73\x94\xF7\x75\x94\x08\x11\x91\xD6\x7D\x8D\x4A\x97\x94\xFD\x8E\x94\x20\x92\x21\x52\x92\x7C\x54\x9D\x95\xBE\x72\x91\x27\x3E\x7E\x5B\x9F\x96\xF2\x7C\x37\x4D\x7F\x95\x0C\x16\x36\x02\x88\x93\x0C\x1F\x89\x4D\x79\x75\x4F\x90\x00\x92\x75\x62\xA9\x89\x8F\x59\x45\x10\xA1\x88\x10\x13\x0C\x80\x83\x97\x98\x09\x81\x47\x75\x82\x21\xFE\x5C\x8A\x09\x1E\x8A\x79\x8C\x10\xBB\x83\x10\xD1\x85\x96\x5B\x72\x99\x8B\x80\x95\x56\x52\x4E\xBA\x8C\x80\x59\x7D\x99\x02\x81\x8C\x96\x92\x10\xFF\x8B\x34\x67\x93\x8B\x68\x98\x88\xA0\x94\x7E\x8C\x8F\x35\xC7\x5F\x9A\xF7\x77\x9A\x97\x82\x87\x2D\x94\x8D\xA0\x83\x89\x18\x14\x01\xBB\x91\x81\x99\x84\x37\xC3\x90\x9C\x37\x13\x8A\x7C\x97\x7F\x7E\x92\x63\xA6\x94\x99\x71\x43\x98\x85\x94\x24\x90\x9D\x92\x89\x99\x10\xB2\x79\x78\x0E\x90\x90\x02\x16\x93\xCA\x73\x91\x3C\x98\x9B\xE0\x71\x8E\x19\x93\x82\x1B\x9C\x2A\xE8\x88\x3E", "\x95\x7A\x90\xAA\x7B\x96\xC0\x72\x92\xF0\x8C\x95\x77\x9E\x95\xF3\x80\x96\xE0\x72\x96\x04\x1E\x9D\x6E\x86\x96\x0C\x10\x93\xE3\x9F\x93\xBA\x75\x9E\x48\x82\x90\x65\x77\x7A\xEB\x9B\x7D\x56\x96\x26\x21\x98\x97\x53\x90\x38\x55\x9D\x40\x81\x7D\x90\xD8\x8A\x92\x00\x0A\x9F\xDC\x8B\x93\x09\x2D\x93\x31\x99\x8F\x18\x98\x7B\x1A\x96\x8E\xE8\x9D\x91\xA9\x2F\x91\x81\x9C\x7A\xF0\x92\x9F\x24\x90\xA1\xB2\x77\x92\x0C\x8D\x9C\xF9\x9B\x94\x4C\x8E\x92\xFD\x90\xA3\x59\x84\x8D\x34\x9D\x64\x2D\xA4\xA1\x16\xA2\x97\x18\xA4\x1C\x1A\xAF\x9F\x32\x9E\x43\x90\x8D\x67\xC7\x9A\x98\x23\x1B\x89\x87\x87\x26\xF8\x90\x83\x34\xA8\x8B\x64\x73\xA3\xB1\x9C\x94\x0A\x80\x82\xEE\x9D\x8E\xD0\x72\x6C\x5F\x2D\xA0\xC4\x7C\xA0\x9E\x9E\x68\xD8\x75\x97\x0E\xA0\x97\x16\x2A\x97\x2E\x83\xA1\xDC\x95\xA1\x4D\xAB\x8C\x3E\xA2\x9E\xDF\x90\xA0\x1C\x23\x98\x52\x5D\x96\x23\x92\x9F\xCF\x37\xA1\x8E\x64\x97\x5A\xAF\xA0\x5C\xA8\x7F\xB2\x78\x67\x1D\x85\xA4\x80\xA1\x94\x23\x1A\x9D\x66\xA8\x84\x1C\x89\xA6\x97\x39\x45\x3F\xAD\xA6\x41\xAC\x21\xAD\x94\x8E\xE4\x87\x9E\x41\x29\x9E\x1C\x24\xA2\x73\x2B\xA0\xED\x9E\x96\x61\xA3\x9F\xD0\x1E\x79\xF6\x9A\x7C\x4B\xA2\x10\x7F\xAB\xA1\x81\x8A\xA8\x6C\xAB\x9F\x8D\xA5\x06\x8F\xA9\x2E\x91\xA5\x7A\x05\xA4\x90\xEC\x91\x97\x25\xAF\x9E\x7B\xA1\x9F\x76\x92\x8F\x0C\x9F\xA9\x8B\x71\xAA\x00\x03\xAA\x40\xA8\x98\x3E\x2B\xA8\xA8\xAC\xA1\x20\xA3\x27\xB9\x7E\xA8\x1C\x90\x00\xBC\x71\xAB\x16\x26\x90\xB5\x92\x10\x09\xAA\x8E\x26\x9F\x41\x39\xA7\xA6\xBE\xAC\xA8\xC0\xAD\x24\xC2\xA6\xA7\x69\x9E\x43\x46\xA7\x13\x35\x95\xAD\x86\xA3\x10\xD7\xA3\xAC\xA5\xA1\xAC\xA7\xAC\xAD\xBD\x90\x94\xDF\xAA\x14\x48\xAB\x9D\xE3\xA2\xAA\x88\xA0\x5C\xDB\xAC\xA3\xC4\xA4\xA5\xB3\xA6\xA5\xE6\x78\xA5\xD2\x79\xA7\x62\xAB\x8E\xF6\xA9\x80\x5F\xAE\xAF\x9C\xA3\xA6\xB2\x73\x8A\x49\xA6\x26\xBC\xA5\xAE\xEA\xA2\xA5\xF4\xA9\xAE\x01\xBB\xAE\xF8\xA7\xA9\x6C\x9C\xAF\x60\xAB\xA5\x99\xAC\x7E\x73\x97\x3B\x20\x17\xB1\x7A\xA4\x9F\x23\x1C\x1B\x17\x01\xA8\x96\x84\xA6\x04\x1B\x9C\x52\x82\x7E\x85\x73\x9D\x34\x15\x9D\x0E\xB9\x45\x81\x7C\x1B\x19\x04\xB2\x98\x8B\xA2\xD4\xA4\xB3\x82\xA7\x13\xBC\x10\x33\x38\xB5\x8D\xB2\x71\xAE\x34\xB1\xB3\x10\xBD\xB3\xD8\x93\xA8\xBA\xA6\x78\x63\x85\xAF\x5D\xAD\xAD\xC8\xAE\xA1\xE6\x95\xAC\x84\x24\xA9\x07\xA9\x7E\x75\xA5\xA5\x07\x97\xA2\x76\x99\xA2\x0B\x97\x13\xF4\x87\x80\x49\xB3\xB4\x1A\xB9\xAA\xAB\xA2\x1A\x4F\xBE\x43\x03\x9E\x6E\x96\xAF\x26\x98\xA2\xAB\x73\xA7\xAB\x25\x92\x7B\x12\xA2\x80\x5F\xB0\xA5\x3E\x92\xB6\x02\xAD\xAA\x01\xA1\xA2\xCA\xAE\x91\xCC\xA0\xB0\xF9\xA7\xB5\xB5\xA8\xA2\x74\xAF\xB6\x23\x1C\xA2\x07\x8C\x34\x60\xBF\x26\x45\x8D\xAE\x57\x10\xB4\x02\x88\xB8\x74\xB4\xAA\x12\xB7\x28\x39\xBE\xAE\x47\xB5\x78\x73\xB8\x10\xFE\x98\xAD\x4C\xB9\x29\x7F\xBF\xAC\xFB\xAD\x25\x59\xAA\xA9\x18\xBC\xB6\x8A\xB7\x32\x03\xB4\xBA\x1F\xBD\xA9\x07\xB7\xB9\x4D\x79\xB9\x04\x1B\xB9\xE6\xA3\xB9\x9E\xB4\xB1\x51\x96\xB1\x04\xB5\xB5\x4B\xB8\x88\x78\xAA\xBA\xFF\xA2\xB4\x9A\x94\xB4\x79\x96\xB3\x60\x8E\x98\x14\xAB\x99\xCA\x71\x8C\x8C\xB9\x10\x8E\xB7\x7F\x90\xB8\x10\xC8\xBB\x78\xCA\xB2\xBC\x92\x80", }; void JsonGetParserBuffer(vl::stream::MemoryStream& stream) { vl::stream::MemoryStream compressedStream; for (vint i = 0; i < parserBufferRows; i++) { vint size = i == parserBufferRows - 1 ? parserBufferRemain : parserBufferBlock; compressedStream.Write((void*)parserBuffer[i], size); } compressedStream.SeekFromBegin(0); vl::stream::LzwDecoder decoder; vl::stream::DecoderStream decoderStream(compressedStream, decoder); vl::collections::Array buffer(65536); while (true) { vl::vint size = decoderStream.Read(&buffer[0], 65536); if (size == 0) break; stream.Write(&buffer[0], size); } stream.SeekFromBegin(0); } /*********************************************************************** Unescaping Function Foward Declarations ***********************************************************************/ extern void JsonUnescapingString(vl::parsing::ParsingToken& value, const vl::collections::List& tokens); /*********************************************************************** Parsing Tree Conversion Driver Implementation ***********************************************************************/ class JsonTreeConverter : public vl::parsing::ParsingTreeConverter { public: using vl::parsing::ParsingTreeConverter::SetMember; bool SetMember(JsonLiteral::JsonValue& member, vl::Ptr node, const TokenList& tokens) { vl::Ptr token=node.Cast(); if(token) { if(token->GetValue()==L"True") { member=JsonLiteral::JsonValue::True; return true; } else if(token->GetValue()==L"False") { member=JsonLiteral::JsonValue::False; return true; } else if(token->GetValue()==L"Null") { member=JsonLiteral::JsonValue::Null; return true; } else { member=JsonLiteral::JsonValue::True; return false; } } member=JsonLiteral::JsonValue::True; return false; } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->value, obj->GetMember(L"value"), tokens); } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { if(SetMember(tree->content, obj->GetMember(L"content"), tokens)) { JsonUnescapingString(tree->content, tokens); } } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->content, obj->GetMember(L"content"), tokens); } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->items, obj->GetMember(L"items"), tokens); } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { if(SetMember(tree->name, obj->GetMember(L"name"), tokens)) { JsonUnescapingString(tree->name, tokens); } SetMember(tree->value, obj->GetMember(L"value"), tokens); } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->fields, obj->GetMember(L"fields"), tokens); } vl::Ptr ConvertClass(vl::Ptr obj, const TokenList& tokens)override { if(obj->GetType()==L"Literal") { vl::Ptr tree = new JsonLiteral; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"String") { vl::Ptr tree = new JsonString; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"Number") { vl::Ptr tree = new JsonNumber; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"Array") { vl::Ptr tree = new JsonArray; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"ObjectField") { vl::Ptr tree = new JsonObjectField; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"Object") { vl::Ptr tree = new JsonObject; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else return 0; } }; vl::Ptr JsonConvertParsingTreeNode(vl::Ptr node, const vl::collections::List& tokens) { JsonTreeConverter converter; vl::Ptr tree; converter.SetMember(tree, node, tokens); return tree; } /*********************************************************************** Parsing Tree Conversion Implementation ***********************************************************************/ vl::Ptr JsonLiteral::Convert(vl::Ptr node, const vl::collections::List& tokens) { return JsonConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr JsonString::Convert(vl::Ptr node, const vl::collections::List& tokens) { return JsonConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr JsonNumber::Convert(vl::Ptr node, const vl::collections::List& tokens) { return JsonConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr JsonArray::Convert(vl::Ptr node, const vl::collections::List& tokens) { return JsonConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr JsonObjectField::Convert(vl::Ptr node, const vl::collections::List& tokens) { return JsonConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr JsonObject::Convert(vl::Ptr node, const vl::collections::List& tokens) { return JsonConvertParsingTreeNode(node, tokens).Cast(); } /*********************************************************************** Parser Function ***********************************************************************/ vl::Ptr JsonParseAsParsingTreeNode(const vl::WString& input, vl::Ptr table, vl::collections::List>& errors, vl::vint codeIndex) { vl::parsing::tabling::ParsingState state(input, table, codeIndex); state.Reset(L"JRoot"); vl::Ptr parser=vl::parsing::tabling::CreateStrictParser(table); vl::Ptr node=parser->Parse(state, errors); return node; } vl::Ptr JsonParseAsParsingTreeNode(const vl::WString& input, vl::Ptr table, vl::vint codeIndex) { vl::collections::List> errors; return JsonParseAsParsingTreeNode(input, table, errors, codeIndex); } vl::Ptr JsonParse(const vl::WString& input, vl::Ptr table, vl::collections::List>& errors, vl::vint codeIndex) { vl::parsing::tabling::ParsingState state(input, table, codeIndex); state.Reset(L"JRoot"); vl::Ptr parser=vl::parsing::tabling::CreateStrictParser(table); vl::Ptr node=parser->Parse(state, errors); if(node && errors.Count()==0) { return JsonConvertParsingTreeNode(node, state.GetTokens()).Cast(); } return 0; } vl::Ptr JsonParse(const vl::WString& input, vl::Ptr table, vl::vint codeIndex) { vl::collections::List> errors; return JsonParse(input, table, errors, codeIndex); } /*********************************************************************** Table Generation ***********************************************************************/ vl::Ptr JsonLoadTable() { vl::stream::MemoryStream stream; JsonGetParserBuffer(stream); vl::Ptr table=new vl::parsing::tabling::ParsingTable(stream); table->Initialize(); return table; } } } } /*********************************************************************** .\PARSING\XML\PARSINGXML.CPP ***********************************************************************/ namespace vl { namespace parsing { namespace xml { using namespace stream; using namespace collections; using namespace regex; /*********************************************************************** Unescaping Function Foward Declarations ***********************************************************************/ void XmlMergeTextFragment(vl::collections::List>& value, const vl::collections::List& tokens) { vint begin=-1; vint end=-1; for(vint i=value.Count()-1;i>=-1;i--) { if(i==-1) { if(end!=-1) begin=0; } else if(value[i].Cast()) { if(end==-1) end=i; } else { if(end!=-1) begin=i+1; } if(begin!=-1 && end!=-1) { vint tokenBegin=value[begin].Cast()->content.tokenIndex; vint tokenEnd=value[end].Cast()->content.tokenIndex; while(tokenBegin>0) { if(tokens.Get(tokenBegin-1).token==(vint)XmlParserTokenIndex::SPACE || tokens.Get(tokenBegin-1).token==-1) { tokenBegin--; } else { break; } } while(tokenEnd xmlText=new XmlText; xmlText->codeRange=range; xmlText->content.codeRange=range; xmlText->content.value=XmlUnescapeValue(text); value.RemoveRange(begin, end-begin+1); value.Insert(begin, xmlText); begin=-1; end=-1; } } } void XmlUnescapeAttributeValue(vl::parsing::ParsingToken& value, const vl::collections::List& tokens) { value.value=XmlUnescapeValue(value.value.Sub(1, value.value.Length()-2)); } void XmlUnescapeCData(vl::parsing::ParsingToken& value, const vl::collections::List& tokens) { value.value=XmlUnescapeCData(value.value); } void XmlUnescapeComment(vl::parsing::ParsingToken& value, const vl::collections::List& tokens) { value.value=XmlUnescapeComment(value.value); } /*********************************************************************** XmlPrintVisitor ***********************************************************************/ class XmlPrintVisitor : public Object, public XmlNode::IVisitor { public: TextWriter& writer; XmlPrintVisitor(TextWriter& _writer) :writer(_writer) { } void Visit(XmlText* node) { writer.WriteString(XmlEscapeValue(node->content.value)); } void Visit(XmlCData* node) { writer.WriteString(XmlEscapeCData(node->content.value)); } void Visit(XmlAttribute* node) { writer.WriteString(node->name.value); writer.WriteString(L"=\""); writer.WriteString(XmlEscapeValue(node->value.value)); writer.WriteString(L"\""); } void Visit(XmlComment* node) { writer.WriteString(XmlEscapeComment(node->content.value)); } void Visit(XmlElement* node) { writer.WriteChar(L'<'); writer.WriteString(node->name.value); FOREACH(Ptr, att, node->attributes) { writer.WriteChar(L' '); att->Accept(this); } if(node->subNodes.Count()==0) { writer.WriteString(L"/>"); } else { writer.WriteChar(L'>'); FOREACH(Ptr, subNode, node->subNodes) { subNode->Accept(this); } writer.WriteString(L"name.value); writer.WriteChar(L'>'); } } void Visit(XmlInstruction* node) { writer.WriteString(L"name.value); FOREACH(Ptr, att, node->attributes) { writer.WriteChar(L' '); att->Accept(this); } writer.WriteString(L"?>"); } void Visit(XmlDocument* node) { FOREACH(Ptr, prolog, node->prologs) { prolog->Accept(this); } node->rootElement->Accept(this); } }; /*********************************************************************** API ***********************************************************************/ WString XmlEscapeValue(const WString& value) { WString result; const wchar_t* reading=value.Buffer(); while(wchar_t c=*reading++) { switch(c) { case L'<': result+=L"<"; break; case L'>': result+=L">"; break; case L'&': result+=L"&"; break; case L'\'': result+=L"'"; break; case L'\"': result+=L"""; break; default: result+=c; } } return result; } WString XmlUnescapeValue(const WString& value) { WString result; const wchar_t* reading=value.Buffer(); while(*reading) { if(wcsncmp(reading, L"<", 4)==0) { result+=L'<'; reading+=4; } else if(wcsncmp(reading, L">", 4)==0) { result+=L'>'; reading+=4; } else if(wcsncmp(reading, L"&", 5)==0) { result+=L'&'; reading+=5; } else if(wcsncmp(reading, L"'", 6)==0) { result+=L'\''; reading+=6; } else if(wcsncmp(reading, L""", 6)==0) { result+=L'\"'; reading+=6; } else { result+=*reading++; } } return result; } WString XmlEscapeCData(const WString& value) { return L""; } WString XmlUnescapeCData(const WString& value) { return value.Sub(9, value.Length()-12); } WString XmlEscapeComment(const WString& value) { return L""; } WString XmlUnescapeComment(const WString& value) { return value.Sub(4, value.Length()-7); } void XmlPrint(Ptr node, stream::TextWriter& writer) { XmlPrintVisitor visitor(writer); node->Accept(&visitor); } void XmlPrintContent(Ptr element, stream::TextWriter& writer) { XmlPrintVisitor visitor(writer); FOREACH(Ptr, node, element->subNodes) { node->Accept(&visitor); } } WString XmlToString(Ptr node) { return GenerateToStream([&](StreamWriter& writer) { XmlPrint(node, writer); }); } /*********************************************************************** Linq To Xml ***********************************************************************/ Ptr XmlGetAttribute(Ptr element, const WString& name) { return XmlGetAttribute(element.Obj(), name); } Ptr XmlGetElement(Ptr element, const WString& name) { return XmlGetElement(element.Obj(), name); } collections::LazyList> XmlGetElements(Ptr element) { return XmlGetElements(element.Obj()); } collections::LazyList> XmlGetElements(Ptr element, const WString& name) { return XmlGetElements(element.Obj(), name); } WString XmlGetValue(Ptr element) { return XmlGetValue(element.Obj()); } Ptr XmlGetAttribute(XmlElement* element, const WString& name) { FOREACH(Ptr, att, element->attributes) { if(att->name.value==name) { return att; } } return 0; } Ptr XmlGetElement(XmlElement* element, const WString& name) { FOREACH(Ptr, node, element->subNodes) { Ptr subElement=node.Cast(); if(subElement && subElement->name.value==name) { return subElement; } } return 0; } collections::LazyList> XmlGetElements(XmlElement* element) { return From(element->subNodes) .FindType(); } collections::LazyList> XmlGetElements(XmlElement* element, const WString& name) { return From(element->subNodes) .FindType() .Where([name](Ptr e){return e->name.value==name;}); } WString XmlGetValue(XmlElement* element) { WString result; FOREACH(Ptr, node, element->subNodes) { if(Ptr text=node.Cast()) { result+=text->content.value; } else if(Ptr text=node.Cast()) { result+=text->content.value; } } return result; } /*********************************************************************** XmlElementWriter ***********************************************************************/ XmlElementWriter::XmlElementWriter(Ptr _element, const XmlElementWriter* _previousWriter) :element(_element) ,previousWriter(_previousWriter) { } XmlElementWriter::~XmlElementWriter() { } const XmlElementWriter& XmlElementWriter::Attribute(const WString& name, const WString& value)const { Ptr node=new XmlAttribute; node->name.value=name; node->value.value=value; element->attributes.Add(node); return *this; } XmlElementWriter XmlElementWriter::Element(const WString& name)const { Ptr node=new XmlElement; node->name.value=name; element->subNodes.Add(node); return XmlElementWriter(node, this); } const XmlElementWriter& XmlElementWriter::End()const { return *previousWriter; } const XmlElementWriter& XmlElementWriter::Text(const WString& value)const { Ptr node=new XmlText; node->content.value=value; element->subNodes.Add(node); return *this; } const XmlElementWriter& XmlElementWriter::CData(const WString& value)const { Ptr node=new XmlCData; node->content.value=value; element->subNodes.Add(node); return *this; } const XmlElementWriter& XmlElementWriter::Comment(const WString& value)const { Ptr node=new XmlComment; node->content.value=value; element->subNodes.Add(node); return *this; } } } } /*********************************************************************** .\PARSING\XML\PARSINGXML_AST.CPP ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Parser::ParsingXml.parser.txt This file is generated by: Vczh Parser Generator ***********************************************************************/ namespace vl { namespace parsing { namespace xml { /*********************************************************************** Visitor Pattern Implementation ***********************************************************************/ void XmlText::Accept(XmlNode::IVisitor* visitor) { visitor->Visit(this); } void XmlCData::Accept(XmlNode::IVisitor* visitor) { visitor->Visit(this); } void XmlAttribute::Accept(XmlNode::IVisitor* visitor) { visitor->Visit(this); } void XmlComment::Accept(XmlNode::IVisitor* visitor) { visitor->Visit(this); } void XmlElement::Accept(XmlNode::IVisitor* visitor) { visitor->Visit(this); } void XmlInstruction::Accept(XmlNode::IVisitor* visitor) { visitor->Visit(this); } void XmlDocument::Accept(XmlNode::IVisitor* visitor) { visitor->Visit(this); } } } } namespace vl { namespace reflection { namespace description { #ifndef VCZH_DEBUG_NO_REFLECTION using namespace vl::parsing::xml; #define PARSING_TOKEN_FIELD(NAME)\ CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(get_##NAME, NO_PARAMETER, vl::WString(ClassType::*)(), [](ClassType* node) { return node->NAME.value; }, L"*", L"*")\ CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(set_##NAME, { L"value" }, void(ClassType::*)(const vl::WString&), [](ClassType* node, const vl::WString& value) { node->NAME.value = value; }, L"*", L"*")\ CLASS_MEMBER_PROPERTY_REFERENCETEMPLATE(NAME, get_##NAME, set_##NAME, L"$This->$Name.value")\ IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlNode, system::XmlNode) IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlText, system::XmlText) IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlCData, system::XmlCData) IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlAttribute, system::XmlAttribute) IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlComment, system::XmlComment) IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlElement, system::XmlElement) IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlInstruction, system::XmlInstruction) IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlDocument, system::XmlDocument) IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlNode::IVisitor, system::XmlNode::IVisitor) BEGIN_CLASS_MEMBER(XmlNode) CLASS_MEMBER_METHOD_OVERLOAD(Accept, {L"visitor"}, void(XmlNode::*)(XmlNode::IVisitor* visitor)) END_CLASS_MEMBER(XmlNode) BEGIN_CLASS_MEMBER(XmlText) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(content) END_CLASS_MEMBER(XmlText) BEGIN_CLASS_MEMBER(XmlCData) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(content) END_CLASS_MEMBER(XmlCData) BEGIN_CLASS_MEMBER(XmlAttribute) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(name) PARSING_TOKEN_FIELD(value) END_CLASS_MEMBER(XmlAttribute) BEGIN_CLASS_MEMBER(XmlComment) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(content) END_CLASS_MEMBER(XmlComment) BEGIN_CLASS_MEMBER(XmlElement) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(name) PARSING_TOKEN_FIELD(closingName) CLASS_MEMBER_FIELD(attributes) CLASS_MEMBER_FIELD(subNodes) END_CLASS_MEMBER(XmlElement) BEGIN_CLASS_MEMBER(XmlInstruction) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) PARSING_TOKEN_FIELD(name) CLASS_MEMBER_FIELD(attributes) END_CLASS_MEMBER(XmlInstruction) BEGIN_CLASS_MEMBER(XmlDocument) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_FIELD(prologs) CLASS_MEMBER_FIELD(rootElement) END_CLASS_MEMBER(XmlDocument) BEGIN_INTERFACE_MEMBER(XmlNode::IVisitor) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlText* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlCData* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlAttribute* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlComment* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlElement* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlInstruction* node)) CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlDocument* node)) END_INTERFACE_MEMBER(XmlNode) #undef PARSING_TOKEN_FIELD class XmlTypeLoader : public vl::Object, public ITypeLoader { public: void Load(ITypeManager* manager) { ADD_TYPE_INFO(vl::parsing::xml::XmlNode) ADD_TYPE_INFO(vl::parsing::xml::XmlText) ADD_TYPE_INFO(vl::parsing::xml::XmlCData) ADD_TYPE_INFO(vl::parsing::xml::XmlAttribute) ADD_TYPE_INFO(vl::parsing::xml::XmlComment) ADD_TYPE_INFO(vl::parsing::xml::XmlElement) ADD_TYPE_INFO(vl::parsing::xml::XmlInstruction) ADD_TYPE_INFO(vl::parsing::xml::XmlDocument) ADD_TYPE_INFO(vl::parsing::xml::XmlNode::IVisitor) } void Unload(ITypeManager* manager) { } }; #endif bool XmlLoadTypes() { #ifndef VCZH_DEBUG_NO_REFLECTION ITypeManager* manager=GetGlobalTypeManager(); if(manager) { Ptr loader=new XmlTypeLoader; return manager->AddTypeLoader(loader); } #endif return false; } } } } /*********************************************************************** .\PARSING\XML\PARSINGXML_PARSER.CPP ***********************************************************************/ /*********************************************************************** Vczh Library++ 3.0 Developer: Zihan Chen(vczh) Parser::ParsingXml.parser.txt This file is generated by: Vczh Parser Generator ***********************************************************************/ namespace vl { namespace parsing { namespace xml { /*********************************************************************** ParserText ***********************************************************************/ const wchar_t* const parserTextBuffer[] = { L"" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"// AST" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"" L"\r\n" , L"class Node" L"\r\n" , L"{" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Text : Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken content;" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class CData : Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken content (XmlUnescapeCData);" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Attribute : Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken name\t\t\t\t\t\t\t\t\t@Color(\"AttName\");" L"\r\n" , L"\ttoken value (XmlUnescapeAttributeValue)\t\t@Color(\"AttValue\");" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Comment : Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken content (XmlUnescapeComment);" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Element : Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken name\t\t\t\t\t\t\t\t\t@Color(\"TagName\");" L"\r\n" , L"\ttoken closingName\t\t\t\t\t\t\t@Color(\"TagName\");" L"\r\n" , L"\tAttribute[] attributes;" L"\r\n" , L"\tNode[] subNodes (XmlMergeTextFragment);" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Instruction : Node" L"\r\n" , L"{" L"\r\n" , L"\ttoken name\t\t\t\t\t\t\t\t\t@Color(\"TagName\");" L"\r\n" , L"\tAttribute[] attributes;" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"class Document : Node" L"\r\n" , L"{" L"\r\n" , L"\tNode[] prologs;" L"\r\n" , L"\tElement rootElement;" L"\r\n" , L"}" L"\r\n" , L"" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"// Lexer" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"" L"\r\n" , L"token INSTRUCTION_OPEN = \"/\"\t\t@Color(\"Boundary\");" L"\r\n" , L"token COMPLEX_ELEMENT_OPEN = \"/\"\t\t@Color(\"Boundary\");" L"\r\n" , L"token ELEMENT_OPEN = \"/<\"\t\t\t\t@Color(\"Boundary\");" L"\r\n" , L"token ELEMENT_CLOSE = \"/>\"\t\t\t\t@Color(\"Boundary\");" L"\r\n" , L"token EQUAL = \"/=\";" L"\r\n" , L"" L"\r\n" , L"token NAME = \"[a-zA-Z0-9:._/-]+\"\t\t\t\t\t\t\t\t@ContextColor();" L"\r\n" , L"token ATTVALUE = \"\"\"[^<>\"\"]*\"\"|\'[^<>\']*\'\"\t\t\t\t\t\t@ContextColor();" L"\r\n" , L"token COMMENT = \"/]|-[^/->]|--[^>])*--/>\"\t\t\t@Color(\"Comment\");" L"\r\n" , L"token CDATA = \"/])*/]/]/>\";" L"\r\n" , L"token TEXT = \"([^<>=\"\"\' /r/n/ta-zA-Z0-9:._/-])+|\"\"|\'\";" L"\r\n" , L"" L"\r\n" , L"discardtoken SPACE = \"/s+\";" L"\r\n" , L"" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"// Rules" L"\r\n" , L"//////////////////////////////////////////////////////////////////" L"\r\n" , L"" L"\r\n" , L"rule Attribute XAttribute = NAME:name \"=\" ATTVALUE:value as Attribute;" L"\r\n" , L"rule Text XText = (NAME:content | EQUAL:content | ATTVALUE:content | TEXT:content) as Text;" L"\r\n" , L"rule CData XCData = CDATA:content as CData;" L"\r\n" , L"rule Comment XComment = COMMENT:content as Comment;" L"\r\n" , L"rule Element XElement = \"<\" NAME:name {XAttribute:attributes} (\"/>\" | \">\" {XSubNode:subNodes} \"\") as Element;" L"\r\n" , L"rule Node XSubNode = !XText | !XCData | !XComment | !XElement;" L"\r\n" , L"rule Instruction XInstruction = \"\" as Instruction;" L"\r\n" , L"rule Document XDocument = {XInstruction:prologs | XComment:prologs} XElement:rootElement as Document;" L"\r\n" }; const vint lengthTextBuffer[] = { 2, 68, 8, 68, 2, 12, 3, 3, 2, 19, 3, 17, 3, 2, 20, 3, 36, 3, 2, 24, 3, 40, 63, 3, 2, 22, 3, 38, 3, 2, 22, 3 , 40, 45, 26, 42, 3, 2, 26, 3, 40, 26, 3, 2, 23, 3, 18, 23, 3, 2, 68, 10, 68, 2, 55, 55, 58, 58, 50, 51, 21, 2, 58, 65 , 75, 63, 56, 2, 29, 2, 68, 10, 68, 2, 72, 93, 45, 53, 134, 64, 93, 103 }; const vint lengthTextBufferTotal = 2487; vl::WString XmlGetParserTextBuffer() { vl::collections::Array textBuffer(lengthTextBufferTotal + 1); wchar_t* reading = &textBuffer[0]; for(vint i = 0; i < sizeof(parserTextBuffer) / sizeof(*parserTextBuffer); i++) { memcpy(reading, parserTextBuffer[i], lengthTextBuffer[i] * sizeof(wchar_t)); reading += lengthTextBuffer[i]; } *reading = 0; return &textBuffer[0]; } /*********************************************************************** SerializedTable ***********************************************************************/ const vint parserBufferLength = 4440; // 18926 bytes before compressing const vint parserBufferBlock = 1024; const vint parserBufferRemain = 344; const vint parserBufferRows = 5; const char* const parserBuffer[] = { "\x00\x0E\x00\x02\x83\x80\x07\x7D\x00\x82\x03\xFF\x45\x08\x82\x83\x86\x81\x21\x6F\x6C\x2F\x32\x37\x84\x87\x02\x86\x00\x17\x82\x81\x24\x3C\x3A\x27\x30\x6D\x65\x06\x98\x8A\x80\x8E\x86\x00\x10\x92\x94\x98\x88\x04\x97\x80\x8E\x74\x56\x21\x2C\x35\x3A\x91\x8A\x84\x25\x8C\xA7\x89\x93\x8F\x98\x82\x8D\x08\xC0\x94\x21\x37\x37\x8D\x91\x91\x0C\xB9\x88\x9B\x91\x8D\x9C\x8C\xA0\x3F\x83\x83\xA5\xA0\x96\x98\x93\x93\x04\xCC\xAA\x9E\x93\x80\xA9\xAE\xA9\x44\xC6\x96\xA9\xA8\xAB\x82\xAC\xA7\x0C\xAD\xA9\xA3\x82\x27\x35\x3A\x37\x64\x61\x32\x39\x38\xA0\x9D\xB3\x86\x03\xBC\xAB\x8B\xBC\xB8\x01\xB7\xB7\x71\xF3\xB5\xA4\x8A\xA1\xAD\xBD\xA6\x7B\x88\xAA\xAA\xCC\xB6\xB4\xB8\xB9\x74\xDC\x82\x85\xC6\xB7\xC3\xAC\x97\x7D\xFF\x8F\xC2\xC2\xCD\x83\xBA\x00\x67\x89\xC4\x8B\xC3\xD5\xC4\xC0\xC8\x83\x89\x9F\xC1\xDD\xCC\xD3\x81\xC5\x9A\x81\xD1\xC4\x9C\x00\x8D\xDB\x87\x6F\x6E\x34\x25\x38\x3C\x3A\xBC\x8C\x05\x9D\xFF\x77\xD8\x84\xE0\x88\xDD\xBC\xBE\xC8\xC0\xE9\xD3\xCB\xD4\xCB\x68\xC1\x8F\xA7\xCD\x31\x92\xDC\xD7\x02\x89\x18\x9A\xEB\x8D\x8E\x39\x34\x62\x75\x3B\xDF\x74\xF5\xF0\xF3\xE7\x0F\xC4\x21\x34\x31\x36\xF2\xF2\xAF\x02\xC0\x90\x95\xE5\x32\xDE\xF7\xF2\xD8\x80\x0B\xC4\x2F\x33\x31\x3A\xEB\x74\x37\x74\x78\x7C\x19\x43\x45\x10\x1B\x65\x00\x82\x83\x3F\x0B\x18\x4D\x82\x40\x49\x2E\x13\x1C\x1D\x72\x35\x13\x18\x1D\x69\x39\x6B\x80\x01\x18\x5C\x82\x42\x13\x6F\x24\x12\x4A\x80\x1E\x88\x45\x88\x15\xC9\x4B\x8D\x03\x76\x2C\x9D\x74\x84\x78\xE2\x65\x15\x88\x41\x25\xAE\x15\x54\x70\xDC\x48\x49\x8C\x4C\xDF\x61\x7B\x6C\x7A\x00\x36\x13\x4D\x4D\x9D\x40\x93\x12\x7A\xEC\x44\x80\x53\x18\xB9\x7B\x66\x7E\x80\x4A\x94\x70\x81\x94\x02\x4C\x98\x73\x93\xF7\x79\x7B\x7D\x7F\xFF\x75\x74\x1C\x95\x00\x30\x12\x1D\x53\x67\x33\x1B\x82\x96\x03\x7C\x7E\x7C\x80\x0F\x88\x4D\x9B\x98\x6F\x34\x17\x81\x82\x5E\x8B\x80\x9B\x9C\x00\x8A\x08\x46\x9E\x02\x6B\x7F\x8A\x8F\x65\x26\x90\x97\x74\x02\x78\x9E\x95\x9B\x04\x6D\x93\x1A\x44\x73\x29\x1E\x18\x55\x21\x43\x04\xA2\x74\x85\x88\x80\x83\x8C\x03\x75\x85\x56\x00\x93\x91\x55\xA4\x9D\xD7\x58\x60\x03\x1C\x75\x22\x10\x8A\x88\x82\xB7\x78\xA3\x40\x6D\x91\x83\x85\x85\x17\x99\x8E\x18\x9F\x08\x74\xAE\x9D\x8F\x31\xA9\xAE\x7B\xAA\x02\x6D\xA2\x84\x85\x16\x98\x89\x6C\xA6\x02\x5A\xA1\x48\xB1\x00\x08\xB7\x89\x72\x60\x96\x9E\x91\x80\x02\x90\x08\x45\x0C\x18\x52\xB0\x73\xB5\x38\x4B\x82\x80\xB6\x49\x5A\xB7\x7C\xB7\xD9\x9E\xB6\x78\xB8\x84\x62\xB6\x7A\xB5\x08\x68\xB9\x12\x13\x53\x14\x12\x15\x15\x43\x14\x19\x13\x13\x4E\x1F\x1F\x10\x14\x45\x0E\x1A\xB3\x40\x2F\x3C\x0F\x0B\x0F\xC0\x5F\x61\x04\x46\x03\xD0\x8C\xBA\xBB\xF0\xB2\xB4\xBF\x17\x43\x0C\x1F\x13\x14\x45\x3B\xB2\x43\xBF\x2F\x3E\x0D\x66\x01\x18\x54\x09\xC5\x5E\x4F\x0D\x10\x14\x13\x45\x18\x1F\x15\x11\x20\xCD\x19\xBC\x15\xF6\xB8\xBA\xBD\x87\xFC\xBE\xBF\x08\xA7\x16\x5B\xCC\x42\xC6\x02\x53\x1B\xBB\x11\x20\xE3\xC5\xCB\xC9\x0C\xCE\xC0\xC6\xC4\x00\x2F\x02\xD2\x0F\x92\xBD\x54\x40\x71\x47\xC6\x8B\xCE\x13\x28\xF7\xB9\xBC\xCC\x08\x50\xDD\xBC\xB2\x39\x84\x4B\x88\x43\x57\xC0\x04\xC9\x11\x26\xCC\xDD\xCF\xC3\x45\x10\xD4\x42\xD4\x3E\x1F\x64\xAE\x61\x3A\x46\x81\x15\x15\x41\x0C\x12\xDB\x40\x52\xFD\x08\xC5\xB7\xF7\x40\xDE\x11\x10\x26\xC5\xC8\x42\xDE\x5B\x21\x1D\x0A\x1E\x41\x2D\x0A\x14\x0C\x2D\x39\x0A\x0E\x0B\x5F\x2F\x0D\x09\x17\x2B\x04\x8C\xAE\x7E\xA2\x81\x14\x14\x15\x56\x2D\xD5\x15\x11\x13\x18\x49\xE6\x40\x22\x1B\x1E\x14\x0F\x3E\x22\x0D\x16\x0A\x22\x3C\x17\x0A\xE7\xA0\xE7\x03\xEB\x09\xF9\x48\xDF\x55\xCC\x0F\x5D\xCD\xD4\x15\x22\x18\x45\xEF\xC4\xFE\xA1\x0D\x09\x0B\x28\x1E\xEA\xE2\x0F\x5D\x3C\x1D\x0A\xEF\x2D\x00\xF2\xF3\xF0\x5E\x00\xF9\x0A\x0A\xBB\xD5\xC5\xD7\x40\x59\xE8\xDB\x51\x5E\x44\x12\xE1\x10\x0B\x18\x58\xF8\xEF\x0B\x21\x2F\x0B\x17\x91\xD6\xDE\xFD\xEE\x17\x2F\x1D\x11\xF1\xF9\xBE\xE6\xFC\x1D\xF9\xE8\xC9\xFD\x17\xF2\xEC\xDD\x15\xC7\xD9\x09\x64\x8C\xCA\x40\x54\x21\xC4\x14\x09\x18\x7C\xF2\x43\xF8\xA0\x7D\x06\x08\x27\x00\x05\x17\x32\x0F\x05\x6E\x0F\x04\x7B\x7F\x61\x71\xC1\x45\x77\x70\x89\x6B\x71\x0A\x2B\x0C\x0F\xD2\x67\x07\x71\x0B\x45\x4A\x49\x03\x23\x0A\x28\x01\x0B\x08\x45\x05\x68\x42\x22\x8F\x05\x39\x2B\x06\x75\x93\x22\x40\xB5\x0C\x24\x7E\x81\x34\x50\x0B\x3C\x50\x47\x6E\x34\x68\x20\x1A\xB0\x86\x3B\x32\x85\x0E\x0B\x52\x0F\x0D\x38\x53\x0C\x3D\x72\x14\x0F\x03\x18\x23\x88", "\x81\x00\x08\x04\x24\x1C\x07\x0D\xFF\x41\x46\x1F\x2D\x80\x00\x2F\x91\x84\xA0\x68\x54\x20\x74\x4B\x88\x57\xBB\x2E\x07\x0F\xF2\x24\x0F\x80\x0C\x26\x8B\x00\x07\x8A\x12\xD2\x8D\x89\x27\x91\x88\x87\x80\x48\x84\x00\x44\x37\x8B\x1C\xAE\x01\x06\x3C\x18\x21\x1C\x82\x23\x8C\x34\x8D\x8A\x07\x20\x17\x6E\xC9\x20\x08\x8E\x1B\x61\x27\x88\x22\x02\x80\x08\x12\x74\x72\xCB\x45\x0C\x8F\x20\x02\x48\x4D\x65\x00\x05\x30\x33\x0B\x90\x76\x9B\x36\x19\x83\x2D\x8D\x34\xB6\x34\x92\x64\x99\x8A\x0C\x73\x88\x20\x4E\xB5\x8C\x89\xBB\x3E\x04\x1E\xFA\x87\x91\x3E\x95\x28\x04\x81\x82\x07\x11\x84\x95\x72\x26\x17\x70\x91\x8A\x95\x25\x23\x8F\x99\x93\x32\x13\x92\x20\x95\x91\x46\x1A\xEC\x85\x96\x17\x33\x04\x93\x04\x3E\x91\x2E\xA1\x93\x94\xBC\x65\x90\x04\x7E\x8C\x91\x2A\x83\x93\x73\x56\xAF\x90\x8F\xB1\x8C\x92\x23\x90\x90\x95\x32\x00\x0F\x96\x00\x03\x99\x19\x12\x08\x22\x6E\xB8\x95\x97\x3C\x91\x4D\x11\x70\x25\x88\x84\x25\x99\x89\xDA\x9E\x04\x08\x40\x08\x4C\x5C\x86\x52\x37\xD8\x98\x0B\x3B\xF4\x0E\x04\x19\x0E\x02\x32\xF7\x94\x8E\x3C\x96\x5E\x4A\x51\xA8\x94\x07\x22\x19\x8E\x31\x88\x99\x99\x23\xBB\x08\x04\xDA\x88\x93\xAD\x39\x8F\x91\x3E\x20\x00\x05\xA8\x95\x61\x40\xFC\x08\x95\xD0\x60\x07\xA0\x58\x13\x09\xA9\x27\x5C\x90\x3C\xA4\x56\x54\x21\x41\x50\x08\x0E\xA2\x04\x7F\x41\xA4\x94\x88\x8B\x53\x1B\x0D\x5F\x50\xB1\x15\xA1\xA0\x29\x13\x94\x08\x73\x9D\x00\x05\x0A\x8B\x9E\xFE\x85\xA7\x49\x83\xA6\x95\x90\x2B\x98\xA3\xB5\x8A\xA1\x24\xA2\xAE\xA0\x88\xA2\x02\xA2\x20\x14\xA2\x08\x16\xA8\xA2\x8D\xA0\xA2\x44\x88\x9F\xA0\x47\x8D\xAF\x9F\x17\x3B\xA3\x8F\x78\x8A\xA4\x4B\x90\x5A\x98\x8B\xB1\xA3\x9A\xF3\x9B\x94\x25\xAE\x50\x59\x58\x79\x30\x8C\x04\x20\x8C\x16\x64\xA0\x56\x61\x6E\x0D\x9E\xA4\x18\x21\x5C\xFA\x9C\xAD\x60\x72\x51\xA7\x3C\x1F\x07\x55\xC7\x95\xA1\x8B\x88\xA1\xA8\x78\x8B\xA0\xA0\x54\xA2\x05\x1F\x16\xA3\x9A\x75\xA6\xAE\x1B\x35\xAA\x89\xC4\xAE\xA8\xAF\x7A\xA2\xA0\x56\xC8\x97\x94\x20\x00\xAB\xA8\x42\xB5\x98\x61\x86\xB1\xA0\xC4\xBF\x55\xAD\xB2\x4D\x9D\x36\xF3\x91\x9F\x79\xAE\x04\x06\xF9\x88\x21\x6A\xB7\xAC\x9E\xDD\x38\xAB\xAF\x04\xA7\x97\x65\xD5\x99\xB2\x2C\x84\xAF\xA1\x11\xB6\xA2\x52\xA1\x76\xA0\x84\x8E\xAC\xA3\x51\xBB\xA1\x48\x84\xB6\xA4\xC9\x87\x9A\xAB\x8E\x5C\xAB\x4B\xA0\x0F\xAB\x47\xB4\xA6\xA6\xFB\x80\x54\x1D\x2F\xB6\xB9\xD8\xBE\xA3\xB6\xB6\xB5\xB4\x43\xA3\xA8\xB7\xA3\xBA\xB3\xB9\x96\xBE\xB6\x70\xD0\xAE\xA3\xF1\xB7\xB5\xA4\x56\xB5\xB9\x56\x8C\x59\xB8\x97\x8B\xA8\xA6\x32\xB3\x9E\x68\xD1\xB9\x4F\x3D\x54\x96\xB4\x33\x06\x10\x46\x7A\xBA\x9E\x9C\xB8\x8A\xA7\xEA\xB4\xB3\x75\xFF\xA8\xB3\xC0\x83\xAC\xAA\x46\xA8\xAB\x6E\x81\xAD\xA8\xF3\x81\xBF\xA9\xE7\xA5\xB8\x4A\xEB\xBB\xA5\xF6\xA7\x97\xBD\xCC\xB1\xBD\x6B\xF4\x00\x08\xB1\xB8\x96\xB1\xB2\x48\xAF\x40\x6A\xA0\xC5\xDC\x3E\x91\x0A\x18\x28\xC4\x5D\x9F\xB6\xAF\xDC\x10\xB0\xB6\x3D\xAC\x90\x76\xB9\x8A\xBB\xC1\x9C\xBD\xB0\x87\xAF\x91\x89\xEE\x0C\x9C\x51\x74\xBE\x4B\xA5\xBB\xC2\x0B\x36\x0C\xBE\x84\x05\xCC\xB5\xD2\xB4\xBB\x84\x82\xC2\xC6\x02\xF4\xB6\xC0\x9A\xBC\xB9\x82\xDF\xB8\xC3\x06\xD0\xC7\xC1\x53\xB7\xC6\x49\xC7\x8B\xC8\xE4\xAD\xA7\xC2\x5E\xBA\xC2\x74\xC0\x48\x0A\x14\x7D\x30\x4C\x65\xC9\x3B\x1B\xD8\x08\x22\x36\xFA\x9E\xCC\xD3\xA5\x9B\x64\xCE\x5E\x4B\xA4\xB3\xA3\x6D\x6D\x69\xA5\x93\x75\xC4\xA2\x56\x86\x92\xCF\x57\x54\x0E\x9D\xF9\x75\xCC\x40\xCF\x5A\xA6\x70\xC0\x0B\xDC\x08\x2B\xD0\x2C\x07\x4B\x3D\x61\x13\xBF\xA3\xEC\x3F\x8D\x11\x18\x26\xD2\xFA\x93\xD1\x18\x7E\x90\x7C\x2A\x01\x0E\xD0\x75\xD3\x9A\xA6\xBD\xCD\x2E\x47\xEF\x0C\x3E\xF0\x96\xBC\x2E\xF3\x30\x41\x37\xA9\x00\x23\xAF\xD9\xD3\xA9\x80\x4C\xD2\xD9\x67\x60\xD4\xBA\x32\xA4\xAB\xDE\x44\xD4\xC6\x2E\x9B\xC3\x41\xD2\xBB\x1B\xC5\xC4\x21\x23\xFF\xC6\xB5\xFF\xA0\xA0\x97\xBC\xAC\xC8\xBF\x89\xA0\xCA\xB6\xA8\xC1\x6E\x93\xAB\xB8\x2B\xC0\xBD\xBC\x10\xC4\xB9\x7A\xDD\xCC\xBD\x2F\xFE\xA0\xC3\xCD\xB3\xA7\x86\xF3\xB3\x9E\x2A\x83\x26\x8A\xA6\xA1\x9E\x9C\x70\x21\x7A\xE8\x43\x20\x9D\x38\xAB\x9F\x7C\xBF\xB1\xA5\x78\xB4\xDA\x44\x6F\x95\x04\x46\x7A\xDA\x9F\x7B\xE5\x0E\x9F\x21\x09\xCD\x6F\x76\xC1\xE0\x4D\xC4\xE6\xD4\xA8\xC2\xD0\x45\x81\xE3\x9E\x20\x0F\x79\x3B\x94\x8A\x4D\x97\x3A\x3F\x71\x36\x58\x0A\xE2\xAD\xD1\x04\x18\x18\x2B\xE2\x7D\x98\xE5\x9F\x78\x98\xA3\x8E\x88\x92\x4C\x32\x4F\x94\xA2\x08\xE0\x40\xC9\xE3\x42\x23\x32", "\x5C\xBF\xD8\x82\xD8\x8C\x9C\x72\x4B\xC2\x99\x9F\xE2\x37\x1D\xD7\x93\x87\xAC\xCA\xB0\x1A\x84\x26\x86\x3B\xDB\x85\x0F\xEB\xD4\x0C\xBD\x44\x22\x6F\xE8\x9B\xC6\x3A\x8E\xED\x45\x6C\xB7\xE4\x0E\x15\xF1\xE0\x97\x2D\xD2\x07\x8E\xC8\x26\xEA\x4A\x8F\xEA\x3F\xE1\xBB\xAC\x9E\xEE\xAB\xE5\x26\xF6\xCD\xCA\xF5\xC8\x8F\x92\xED\xE4\xAA\x30\xE8\x93\xCC\xF3\x96\xE7\xA9\xDE\x4C\xDC\xC0\xCA\xD7\x68\xC2\xC7\x06\x62\xC3\x26\xD8\xFE\xBF\x9C\x8C\xCD\xD3\xC6\x40\x75\xC1\x57\x52\xD3\xDA\x9D\xD5\xC2\xBD\x2B\xD8\xD9\xCB\x24\xB2\xC0\xB3\xDE\xCC\xAA\x40\xA1\xC8\xAC\x1B\xC4\xCC\x9C\xED\xD2\x21\xAC\x42\xE4\x9E\xEA\xC3\x9C\x19\x58\x98\x9C\x38\xCB\xEB\xD1\x04\x2D\xD2\xA6\xA2\xC2\x20\xB5\x9A\xD2\xE8\xE2\x90\x2D\xD4\x82\x28\x9C\x4D\xCB\xEA\xD2\xB3\xDE\x4A\xB9\x82\x26\x8B\x5D\xFA\x30\xF5\x44\xF4\xF0\x00\x59\x6D\xF5\xD8\xEE\xB2\xDE\x3E\xDE\xDF\xEC\x80\x06\x8A\x7F\xF8\xF2\xF3\xBA\xFC\xF6\x12\xFE\xDB\xE9\x87\xC0\x01\x47\x17\xEE\xEE\x6E\x46\xE3\x20\xBD\x51\xFB\x4D\x5E\x47\xF8\x5C\x24\xF0\x21\x77\xD9\xEA\xFA\xD3\xAB\x9E\x87\xD9\x9B\xC6\xEE\xE4\xC6\xEB\xB2\x4F\x8E\x8A\x88\x2B\xFD\xC6\xA8\xFE\xC5\xC9\xDA\xAF\xB2\x93\xB9\x98\x67\xC0\xB5\x91\x07\xD7\xC4\x67\xB2\xAB\xC6\xC9\xC9\x3D\x9C\x04\x15\x4E\x97\x78\x7B\x5B\x41\x44\xD8\x47\x44\x9D\x79\x1C\x65\x3B\x41\xB8\x40\x67\xAB\x79\x4D\x70\x6A\x45\x40\x44\x07\xCE\x79\x23\x62\x47\x79\x3E\x00\x7A\x03\x12\x7A\x48\x21\x06\xC3\x75\x7B\x1D\x84\x80\x13\x8F\x80\x08\x8A\x44\xAE\x7A\x81\x02\x1C\x81\x90\x63\x7E\x8E\x61\x82\x05\x84\x07\x07\x80\x02\x26\x8D\x81\x3E\x00\x7B\x09\x7E\x4D\x08\x18\x83\x63\x77\x7B\xEA\x6F\x82\xC9\x73\x10\x25\x8B\x83\xD3\x56\x83\x00\x26\x7E\x94\x46\x7B\xF4\x4F\x82\xE3\x77\x81\x48\x85\x83\x3E\x63\x4F\x38\x84\x10\x3A\x89\x6E\x43\x7E\x83\x18\x19\x35\x41\x88\x53\x70\x72\x5D\x46\x8F\x6B\xC2\x6A\x84\x3A\x71\x46\x32\x80\x73\x4E\x85\x6A\xFE\x61\x85\x03\x1A\x83\xC6\x7D\x83\x13\x8F\x83\x46\x48\x44\xCB\x76\x5E\x65\x8E\x6B\xD9\x4E\x6F\x5D\x85\x87\xE6\x52\x81\x5C\x4B\x84\x63\x8C\x7C\x2C\x8B\x63\x16\x08\x11\x81\x8B\x73\xAF\x2D\x62\x6F\x5C\x86\x5C\x44\x7D\x02\x1A\x37\x41\x8A\x74\x7F\x8F\x7E\x6E\x08\x86\x02\x1A\x83\x41\x7F\x82\x1F\x80\x84\x63\x8A\x74\x15\x82\x75\xD8\x7A\x1B\x9B\x38\x10\x9F\x87\x7D\x13\x78\x79\x55\x83\x81\x77\x81\x84\x5A\x7B\x89\xB8\x4F\x74\x00\x83\x10\x02\x8F\x74\x7A\x81\x44\x6E\x82\x86\xDF\x7D\x89\xD3\x51\x4F\xB5\x4C\x82\xBD\x44\x03\xC0\x43\x10\xC2\x45\x4B\xFE\x4B\x64\xF5\x7B\x4C\x7E\x6E\x4A\xC7\x41\x4D\x32\x55\x4B\x40\x0E\x7F\x67\x63\x29\x03\x82\x03\x6E\x68\x10\xD1\x8A\x44\x9E\x72\x67\xC7\x5B\x67\xB9\x64\x51\x45\x08\x67\x4C\x08\x6B\x0A\x7C\x4C\x85\x46\x8C\xDE\x83\x68\xFA\x33\x8E\xD3\x49\x68\x28\x80\x00\x2A\x8C\x1E\x92\x61\x82\x32\x08\x69\x08\x10\x8F\x33\x80\x69\x9C\x65\x3D\x9E\x66\x8E\x8F\x43\x6A\x44\x80\x64\x72\x72\x84\xF5\x41\x6B\x08\x10\x90\x26\x8E\x7B\x71\x60\x02\x43\x06\x6B\x4C\x38\x8F\x06\x94\x90\xBD\x65\x1A\x5E\x85\x5F\x2C\x47\x5F\x42\x65\x03\x76\x72\x10\x78\x7B\x61\x4A\x6C\x6C\xF5\x7D\x77\x31\x2F\x77\xBB\x12\x6D\xDE\x54\x6D\x84\x79\x51\x0E\x67\x78\xC3\x5A\x65\xDB\x6B\x78\xDD\x6A\x5C\xE0\x62\x66\x00\x29\x73\x0C\x1C\x46\xE5\x78\x11\xE7\x75\x88\x8A\x57\x5A\xEB\x74\x10\xED\x7D\x75\x36\x9F\x58\xF1\x7B\x77\x1B\x9E\x64\xD9\x50\x6D\xDB\x54\x52\xFB\x7E\x59\x3D\x92\x2B\x4C\x7C\x10\xD0\x7F\x74\x0F\x82\x8A\xAD\x63\x03\x56\x74\x10\x58\x70\x95\x20\x7E\x6C\x23\x75\x76\x2C\x7F\x06\x2E\x78\x72\x48\x80\x76\x67\x7F\x72\x6C\x72\x73\x43\x7C\x76\xD3\x4F\x74\x0D\x93\x10\xB8\x83\x54\xAA\x80\x00\xB5\x44\x2E\xF5\x37\x1F\xCC\x84\x07\x40\x30\x67\xC0\x1C\x01\x24\x12\x20\xE9\x8B\x8E\x61\x06\x24\x1D\x80\x1C\x1E\x09\x97\x59\x2E\x63\x48\x80\x26\x48\x80\x1C\x20\x02\x98\xEE\x1B\x85\x53\x23\x29\xF3\x40\x1C\xB7\x31\x2E\x8B\x91\x7C\xE6\x56\x37\x21\x50\x1C\xFE\x32\x99\xE6\x1F\x88\x49\x99\x1B\x0F\x8B\x63\xC0\x16\x02\x8A\x96\x1E\x6D\x96\x95\xA1\x2D\x17\x4F\x70\x1C\x28\x03\x9A\xE5\x10\x01\x22\x49\x10\xC2\x10\x1C\x9D\x10\x97\xB4\x95\x9B\x38\x12\x1C\x8F\x3F\x36\xB6\x90\x00\x9D\x13\x9B\xF7\x36\x22\x03\x19\x4C\xC0\x1B\x96\xD5\x40\x97\xCD\x15\x10\x4F\x4F\x9A\xBB\x9B\x9C\x24\x12\x1C\x6A\x48\x2C\xB5\x9D\x9B\xB4\x90\x24\xD1\x43\x9C\xFD\x8F\x96\xB0\x9D\x9C\x0C\x8C\x9C\xBC\x9C\x9D\x10\x7C\x94\x2F\x13\x54\xD6\x91\x91\xDF\x43\x54\xFF\x0A\x9B\x05\x18\x9E", "\x04\x22\x9B\x9D\x23\x10\xCA\x9B\x9B\x6D\x98\x9D\xE4\x95\x2B\x98\x43\x54\xE9\x8B\x9E\xB4\x94\x9C\xB6\x58\x9E\xE3\x94\x9F\x7D\x27\x60\xC0\x1C\x99\x65\x5E\x56\xE7\x98\x11\xE9\x8C\x9E\x0C\x19\x8E\xEF\x96\x9B\xF1\x92\x9E\x72\x74\x10\x67\x45\x4D\x7B\x9E\x9D\x50\x47\x9D\x43\x5C\x9F\x0F\xAA\x96\x03\x12\x58\xB9\x20\x1C\x8C\x9E\x25\x14\xA4\x2E\xC7\x9F\x0F\x04\x2E\x7C\x21\xA1\x1C\x24\x1E\x7C\xF9\x17\xA2\x23\xA9\x9B\x14\xA8\x9E\x9F\x17\xA0\xB4\x9F\xA1\xBA\x1E\x9B\x0C\x10\x34\xC2\x99\xA1\x2E\x45\x9F\xC5\x9C\x1C\xC2\x16\x36\x27\xAC\x2D\x2D\xA8\x11\x18\xA0\x97\x30\xAD\x9E\xBB\x92\xA0\xA0\x59\x1B\x36\xA0\x9C\x37\xA1\x9C\x37\x2A\xA3\x15\xA5\x9E\x3D\xAE\xA3\x24\x19\x8E\x8F\x3C\xA2\xC2\x19\x1F\xAD\x8B\x9B\x47\xA6\x34\xCB\x94\xA3\x74\x0F\x19\x25\x04\xA1\xF3\x66\x5E\x28\xA9\x14\x4F\x4A\x46\xB5\x9B\xA0\x9F\x1B\xA2\x33\xAF\x84\x91\x78\x11\x65\xAE\x9D\x67\xA0\x61\x4D\xAE\x29\x94\x20\x00\x74\x6A\x1B\x01\x3B\x9D\x97\x73\xA4\x31\x94\xA1\x6E\xA2\x2A\xCC\x92\xA6\x64\xA6\xA6\x94\x98\xA7\xB4\x9D\x2C\xD8\x84\x07\x7F\xA9\x36\x0D\x89\x22\xCE\x91\x86\xCC\x95\xA8\x60\xAB\x9B\x88\xA4\xA7\x8A\xA6\x86\xE6\x59\xA7\xAF\x3B\xA7\x7D\xA0\xA9\xDB\x92\x3D\x81\xA2\x1C\xBA\x7C\x7D\x6D\xA5\xAA\xAF\x1D\xA9\x74\x80\x73\x89\xA6\xA7\x8B\xAC\x51\xA0\xA1\x1F\x93\x23\xAA\x1E\xA4\x98\x04\x93\xA2\xDC\x7A\x7B\xAB\xA2\xA9\x74\x87\xA8\x72\xA3\x66\x9C\xA2\xAB\x9E\xAC\xA8\x70\x9E\xA8\x81\x60\x1C\x13\xAB\x6A\x1D\x83\xA2\x5D\xAB\x46\x84\xAC\xAA\x02\x10\xA7\x70\x9B\xA9\x0C\x15\xA7\xDC\x97\xA7\xB4\xAD\xA8\xB7\xAF\xA8\x91\xA3\x3D\x93\xAD\x1B\x69\xA7\x9B\xD5\x24\xA1\xB5\xA7\x2D\x77\x2B\x61\xB9\xA5\x6A\xF3\x4F\x0F\x0B\xA5\xA0\x0C\x12\x89\xD7\x2D\x19\x00\x94\x10\x0B\xA5\x9B\xEB\xA2\x5D\xED\xAF\xAA\xF3\x49\x8E\xF7\xA1\xA6\xC3\xA0\x20\xE9\xAF\x80\x6B\x7C\xAE\x4D\x74\x10\x4D\x90\x7E\xF2\xAB\x37\xB4\x9D\x19\xDA\xA8\xAF\x14\xAB\xAF\x00\x2D\xAF\x0E\x93\x77\xD2\x59\x8E\x11\xB2\xB0\xEE\xAB\x61\xF9\xAE\xAA\x17\xB4\x92\x10\x6D\xB0\x52\x8F\xB0\x32\x33\x42\x13\xBE\x98\x08\xB9\xA9\x90\x3F\x90\x5E\x29\x8E\x3E\x7C\xB1\xFE\xAB\x61\x05\xBE\x20\x03\x17\xB0\xFC\xA9\xB0\x03\x1B\xB0\xB6\x86\x9C\xC2\x1D\x19\x9F\x8C\x9C\xE9\xA0\x1C\x9F\x90\x89\x01\xA1\x86\x3C\x93\xA0\xB2\x24\xB2\x09\x18\x9E\x31\xB8\x2D\xF6\xA8\x11\x1F\xB0\x97\x45\xBD\x99\x6E\x07\xB4\x83\xA4\x88\x4A\xB9\x1B\x00\xB4\xA1\x4A\xA6\x88\x45\xAB\xA7\x7A\xA6\x76\x5C\x93\x07\x38\x2D\x74\xA6\x91\x20\x4E\xB6\xB2\x33\x32\xB5\x14\xA5\xB5\x5B\xB7\xB5\x96\xA3\x10\x32\x90\x89\x30\xBE\xB5\x48\xBB\x63\x61\xBA\xA7\x63\xBB\x95\x65\x27\xB6\xE0\x9B\x8A\xE0\x71\xA2\x82\xA8\x10\x15\x08\xAE\x18\x15\xB3\x0C\x1A\x28\x2B\x92\x16\x16\xBD\xAA\x2E\xBE\xA7\x84\x1F\xB3\x82\x88\xB8\xDE\x95\x97\xC9\x11\xAE\xA6\xA0\x67\x23\xA8\x9E\x8A\x85\xAF\xC5\xA8\xB2\x97\xBF\x9B\x76\x94\xAD\xA0\x14\x49\x70\x6A\xB1\x14\xA3\x97\x53\xBB\xAD\xB3\xA7\x99\x22\xA4\xB9\x0C\x17\x01\x96\xBC\x9D\x7E\x90\x69\xCC\xA6\xA0\x47\x8F\xAC\xC2\x1E\xB9\x6C\xB8\x10\x1B\xB2\x10\xAD\xB0\x2E\xB7\xBC\x1E\xB9\xB9\xA0\xBB\xB0\x69\xAA\xBE\x9D\xCD\xA9\x4D\x9A\x63\xBC\x32\xB1\xB2\xFE\x6E\xB3\xDA\x9C\x10\x18\x05\xBB\xCC\x96\x98\x04\x9F\xB8\xD5\xA7\x84\xBB\xA1\xAF\x6B\xB0\x97\x51\xBC\x10\xD0\xB8\x2D\xDA\xB9\x70\xDC\xBD\xB2\xCE\xB4\x90\x5D\xB6\xAC\xAF\xA8\x84\x7B\xB1\xAA\x7D\xB6\x72\x80\xBA\x23\x9C\x83\x8A\x4C\xBB\x88\xBF\xB4\x10\xC1\xB0\x00\xE5\xBA\xAE\x93\x27\x98\x86\xA0\xB9\xEB\xB9\x70\xCB\xBE\xBA\xA5\x68\x84\xFF\xB5\x9B\xDC\xA1\x52\xF9\xB0\x00\x4F\xB0\xBA\x6D\xB4\xBE\x29\xB0\x3B\x28\x1B\xBD\x03\xCD\xBD\xAB\x6C\xBE\x27\xB2\xAC\x09\xC4\x90\xF1\xB6\xAB\x16\xC4\xB6\x7F\xBA\xB3\xDF\x9E\x74\x83\xB4\xA1\x85\xB1\x7A\xD8\xB3\x10\xE9\xA8\xA3\x51\xAC\xB2\x8B\x10\x73\xDC\x93\xA2\x9D\x19\x01\x41\xA6\xAE\x49\x18\x9E\xD6\xA8\x10\xAD\x14\xA4\xBA\xBC\xB2\x0C\xCF\xBA\x22\x21\xC2\xEA\xB7\xB1\x52\x53\x5C\xE9\xB3\xC3\x8F\x91\xBB\xD5\xB8\x10\x1A\x0D\xC2\x9A\xA2\x2A\xA9\x96\xC2\xCF\x77\xBF\x15\xB9\xC3\x49\x12\x1C\xC8\x2B\x01\x52\xC7\xBA\x13\xCC\x9D\xA5\x95\xC5\xE5\xA4\x18\x5C\xAF\xC5\x9F\x11\xC1\xB5\x93\xC6\x29\xC3\x19\xA8\xA4\x93\x2F\xA6\xBA\x6A\xC4\x9B\x6C\xC6\x8B\xE9\xAA\xAC\xCF\x2B\xC4\xDE\xB8\xBE\xD8\x23\xA2\x6D\x9A\xC5\x80\xC1\xC8\x82\xCF\xC4\x84\x1F\x38\xF8\x92\xBE\x89\xB4\x9B\x30\xC1\x12\x58\xB5\x1C\x63\x56\xB4\xD9\x99\x14\xC0\x1D\x01\x83", "\xC4\xB8\xC2\x1B\xA6\x5F\xC7\xC7\xDF\xAB\xAC\xA6\xB7\x12\xA7\xA4\x12\x8F\x3C\xA6\xFB\xBE\xC2\xDE\xA6\xC1\xB8\xAD\xC9\xA8\xB4\xA9\xB4\x13\xB7\xBB\x92\x9D\xC9\xAB\xC9\x79\xC8\xCA\xE3\xA4\xAA\xD0\xAC\xCA\xB6\x9E\xCA\xE4\x28\xC7\x20\xA2\xCB\x10\x8A\xCA\x92\xC8\x11\x1F\x05\xC9\x39\xCC\xAB\x57\x89\xC9\xA5\xC2\xAA\xE0\xA1\xC4\x8C\x69\xBC\xC6\xB3\xA2\xC0\x11\x02\xC2\xCA\xA5\x24\x19\xAA\xC6\xCF\xCA\xA6\xC9\xCC\x32\xCB\xC7\x59\xCE\xCC\x97\x61\xCD\xCB\x93\xA2\x67\xCE\xCD\x65\xC9\x10\xC0\x1D\xBF\xE2\xCD\xC7\x5B\xA4\x44\x68\xC1\xBA\x1E\xCF\xAA\xD3\xB3\xA2\x98\xCE\x9D\x5F\xA0\xBC\x20\xB4\xC0\x22\xBD\xAD\xD6\xC8\xCC\x9C\xC0\xAC\x9B\xBE\xCB\x38\x11\xCA\x71\xCC\xCF\x03\x16\xCE\x71\xA7\xAC\xF8\xC9\xCB\xB0\xCB\xCB\x02\xD8\x17\xB3\xC3\xA2\xE3\x7C\x9C\xF3\xCC\xBF\xF5\xCA\xC1\x78\x88\xAC\x08\xD7\xCD\xFB\xC2\xAE\x1A\xDF\xC9\x49\x14\xCD\xF2\xC6\xBA\x04\xD7\xAD\x44\xC5\x06\x9A\xC8\xD1\xB1\xC9\xCD\x1B\xC9\x70\xC4\xC8\x35\x01\xDA\xD1\x12\xDE\xBE\xD2\xBF\xA9\xC7\xCA\xA7\xA7\xC8\xBC\x36\xDE\xBC\xBC\xB4\x12\xD1\xA2\xCA\x46\xA0\xD2\x13\xDA\xBE\xF7\xC1\x52\x25\xDA\xCF\x27\xDE\xD2\x95\x1D\xD0\xB1\x98\x11\x27\x07\xCE\xE0\x23\xA2\x5D\xCC\xD4\x91\xC8\x13\xC0\x11\xB0\x50\xDA\xC3\x38\x1F\xD4\xDE\x9A\x41\x0C\x14\xD5\x0C\xA8\xB6\x64\xC0\xCE\xEA\xC9\xD5\xA6\xBC\xD5\x6B\xCE\xD5\x6D\xC3\xCE\x93\x1E\xD1\xDC\x91\xD1\x03\x14\xD6\x74\xC6\xD6\x76\xC3\xD3\xA1\xA5\xD3\xC1\xA6\xCF\x02\xC5\xD5\x78\xD0\xC8", }; void XmlGetParserBuffer(vl::stream::MemoryStream& stream) { vl::stream::MemoryStream compressedStream; for (vint i = 0; i < parserBufferRows; i++) { vint size = i == parserBufferRows - 1 ? parserBufferRemain : parserBufferBlock; compressedStream.Write((void*)parserBuffer[i], size); } compressedStream.SeekFromBegin(0); vl::stream::LzwDecoder decoder; vl::stream::DecoderStream decoderStream(compressedStream, decoder); vl::collections::Array buffer(65536); while (true) { vl::vint size = decoderStream.Read(&buffer[0], 65536); if (size == 0) break; stream.Write(&buffer[0], size); } stream.SeekFromBegin(0); } /*********************************************************************** Unescaping Function Foward Declarations ***********************************************************************/ extern void XmlMergeTextFragment(vl::collections::List>& value, const vl::collections::List& tokens); extern void XmlUnescapeAttributeValue(vl::parsing::ParsingToken& value, const vl::collections::List& tokens); extern void XmlUnescapeCData(vl::parsing::ParsingToken& value, const vl::collections::List& tokens); extern void XmlUnescapeComment(vl::parsing::ParsingToken& value, const vl::collections::List& tokens); /*********************************************************************** Parsing Tree Conversion Driver Implementation ***********************************************************************/ class XmlTreeConverter : public vl::parsing::ParsingTreeConverter { public: using vl::parsing::ParsingTreeConverter::SetMember; void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->content, obj->GetMember(L"content"), tokens); } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { if(SetMember(tree->content, obj->GetMember(L"content"), tokens)) { XmlUnescapeCData(tree->content, tokens); } } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->name, obj->GetMember(L"name"), tokens); if(SetMember(tree->value, obj->GetMember(L"value"), tokens)) { XmlUnescapeAttributeValue(tree->value, tokens); } } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { if(SetMember(tree->content, obj->GetMember(L"content"), tokens)) { XmlUnescapeComment(tree->content, tokens); } } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->name, obj->GetMember(L"name"), tokens); SetMember(tree->closingName, obj->GetMember(L"closingName"), tokens); SetMember(tree->attributes, obj->GetMember(L"attributes"), tokens); if(SetMember(tree->subNodes, obj->GetMember(L"subNodes"), tokens)) { XmlMergeTextFragment(tree->subNodes, tokens); } } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->name, obj->GetMember(L"name"), tokens); SetMember(tree->attributes, obj->GetMember(L"attributes"), tokens); } void Fill(vl::Ptr tree, vl::Ptr obj, const TokenList& tokens) { SetMember(tree->prologs, obj->GetMember(L"prologs"), tokens); SetMember(tree->rootElement, obj->GetMember(L"rootElement"), tokens); } vl::Ptr ConvertClass(vl::Ptr obj, const TokenList& tokens)override { if(obj->GetType()==L"Text") { vl::Ptr tree = new XmlText; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"CData") { vl::Ptr tree = new XmlCData; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"Attribute") { vl::Ptr tree = new XmlAttribute; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"Comment") { vl::Ptr tree = new XmlComment; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"Element") { vl::Ptr tree = new XmlElement; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"Instruction") { vl::Ptr tree = new XmlInstruction; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else if(obj->GetType()==L"Document") { vl::Ptr tree = new XmlDocument; vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules()); Fill(tree, obj, tokens); Fill(tree.Cast(), obj, tokens); return tree; } else return 0; } }; vl::Ptr XmlConvertParsingTreeNode(vl::Ptr node, const vl::collections::List& tokens) { XmlTreeConverter converter; vl::Ptr tree; converter.SetMember(tree, node, tokens); return tree; } /*********************************************************************** Parsing Tree Conversion Implementation ***********************************************************************/ vl::Ptr XmlText::Convert(vl::Ptr node, const vl::collections::List& tokens) { return XmlConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr XmlCData::Convert(vl::Ptr node, const vl::collections::List& tokens) { return XmlConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr XmlAttribute::Convert(vl::Ptr node, const vl::collections::List& tokens) { return XmlConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr XmlComment::Convert(vl::Ptr node, const vl::collections::List& tokens) { return XmlConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr XmlElement::Convert(vl::Ptr node, const vl::collections::List& tokens) { return XmlConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr XmlInstruction::Convert(vl::Ptr node, const vl::collections::List& tokens) { return XmlConvertParsingTreeNode(node, tokens).Cast(); } vl::Ptr XmlDocument::Convert(vl::Ptr node, const vl::collections::List& tokens) { return XmlConvertParsingTreeNode(node, tokens).Cast(); } /*********************************************************************** Parser Function ***********************************************************************/ vl::Ptr XmlParseDocumentAsParsingTreeNode(const vl::WString& input, vl::Ptr table, vl::collections::List>& errors, vl::vint codeIndex) { vl::parsing::tabling::ParsingState state(input, table, codeIndex); state.Reset(L"XDocument"); vl::Ptr parser=vl::parsing::tabling::CreateStrictParser(table); vl::Ptr node=parser->Parse(state, errors); return node; } vl::Ptr XmlParseDocumentAsParsingTreeNode(const vl::WString& input, vl::Ptr table, vl::vint codeIndex) { vl::collections::List> errors; return XmlParseDocumentAsParsingTreeNode(input, table, errors, codeIndex); } vl::Ptr XmlParseDocument(const vl::WString& input, vl::Ptr table, vl::collections::List>& errors, vl::vint codeIndex) { vl::parsing::tabling::ParsingState state(input, table, codeIndex); state.Reset(L"XDocument"); vl::Ptr parser=vl::parsing::tabling::CreateStrictParser(table); vl::Ptr node=parser->Parse(state, errors); if(node && errors.Count()==0) { return XmlConvertParsingTreeNode(node, state.GetTokens()).Cast(); } return 0; } vl::Ptr XmlParseDocument(const vl::WString& input, vl::Ptr table, vl::vint codeIndex) { vl::collections::List> errors; return XmlParseDocument(input, table, errors, codeIndex); } vl::Ptr XmlParseElementAsParsingTreeNode(const vl::WString& input, vl::Ptr table, vl::collections::List>& errors, vl::vint codeIndex) { vl::parsing::tabling::ParsingState state(input, table, codeIndex); state.Reset(L"XElement"); vl::Ptr parser=vl::parsing::tabling::CreateStrictParser(table); vl::Ptr node=parser->Parse(state, errors); return node; } vl::Ptr XmlParseElementAsParsingTreeNode(const vl::WString& input, vl::Ptr table, vl::vint codeIndex) { vl::collections::List> errors; return XmlParseElementAsParsingTreeNode(input, table, errors, codeIndex); } vl::Ptr XmlParseElement(const vl::WString& input, vl::Ptr table, vl::collections::List>& errors, vl::vint codeIndex) { vl::parsing::tabling::ParsingState state(input, table, codeIndex); state.Reset(L"XElement"); vl::Ptr parser=vl::parsing::tabling::CreateStrictParser(table); vl::Ptr node=parser->Parse(state, errors); if(node && errors.Count()==0) { return XmlConvertParsingTreeNode(node, state.GetTokens()).Cast(); } return 0; } vl::Ptr XmlParseElement(const vl::WString& input, vl::Ptr table, vl::vint codeIndex) { vl::collections::List> errors; return XmlParseElement(input, table, errors, codeIndex); } /*********************************************************************** Table Generation ***********************************************************************/ vl::Ptr XmlLoadTable() { vl::stream::MemoryStream stream; XmlGetParserBuffer(stream); vl::Ptr table=new vl::parsing::tabling::ParsingTable(stream); table->Initialize(); return table; } } } } /*********************************************************************** .\REFLECTION\GUITYPEDESCRIPTOR.CPP ***********************************************************************/ namespace vl { using namespace collections; namespace reflection { /*********************************************************************** DescriptableObject ***********************************************************************/ #ifndef VCZH_DEBUG_NO_REFLECTION bool DescriptableObject::IsAggregated() { return aggregationInfo != nullptr; } vint DescriptableObject::GetAggregationSize() { CHECK_ERROR(IsAggregated(), L"vl::reflection::DescriptableObject::GetAggregationSize()#This function should not be called on non-aggregated objects."); return aggregationSize; } DescriptableObject* DescriptableObject::GetAggregationRoot() { CHECK_ERROR(IsAggregated(), L"vl::reflection::DescriptableObject::GetAggregationRoot()#This function should not be called on non-aggregated objects."); return aggregationInfo[aggregationSize]; } void DescriptableObject::SetAggregationRoot(DescriptableObject* value) { CHECK_ERROR(value != nullptr, L"vl::reflection::DescriptableObject::SetAggregationRoot(Descriptable*)#The root object should not null."); CHECK_ERROR(value->IsAggregated() && value->GetAggregationRoot() == nullptr, L"vl::reflection::DescriptableObject::SetAggregationRoot(Descriptable*)#The root object should not have an aggregation root."); if (!IsAggregated()) { InitializeAggregation(0); } aggregationInfo[aggregationSize] = value; aggregationInfo[aggregationSize + 1] = value; for (vint i = 0; i < aggregationSize; i++) { if (aggregationInfo[i]) { aggregationInfo[i]->SetAggregationRoot(value); } } } DescriptableObject* DescriptableObject::GetAggregationParent(vint index) { CHECK_ERROR(IsAggregated(), L"vl::reflection::DescriptableObject::GetAggregationParent(vint)#This function should not be called on non-aggregated objects."); CHECK_ERROR(0 <= index && index < aggregationSize, L"vl::reflection::DescriptableObject::GetAggregationParent(vint)#Index out of range."); return aggregationInfo[index]; } void DescriptableObject::SetAggregationParent(vint index, DescriptableObject* value) { CHECK_ERROR(IsAggregated(), L"vl::reflection::DescriptableObject::SetAggregationParent(vint, DescriptableObject*)#This function should not be called on non-aggregated objects."); CHECK_ERROR(0 <= index && index < aggregationSize, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, DescriptableObject*)#Index out of range."); CHECK_ERROR(aggregationInfo[index] == nullptr, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, DescriptableObject*)#This index has been used."); CHECK_ERROR(value != nullptr, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, DescriptableObject*)#Parent should not be null."); CHECK_ERROR(!value->IsAggregated() || value->GetAggregationRoot() == nullptr, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, DescriptableObject*)#Parent already has a aggregation root."); CHECK_ERROR(value->referenceCounter == 0, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, DescriptableObject*)#Parent should not be contained in any smart pointer."); value->SetAggregationRoot(this); aggregationInfo[index] = value; } void DescriptableObject::SetAggregationParent(vint index, Ptr& value) { CHECK_ERROR(IsAggregated(), L"vl::reflection::DescriptableObject::SetAggregationParent(vint, Ptr&)#This function should not be called on non-aggregated objects."); CHECK_ERROR(0 <= index && index < aggregationSize, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, Ptr&)#Index out of range."); CHECK_ERROR(aggregationInfo[index] == nullptr, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, Ptr&)#This index has been used."); CHECK_ERROR(value, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, Ptr&)#Parent should not be null"); CHECK_ERROR(!value->IsAggregated() || value->GetAggregationRoot() == nullptr, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, Ptr&)#Parent already has a aggregation root."); CHECK_ERROR(value->referenceCounter == 1, L"vl::reflection::DescriptableObject::SetAggregationParent(vint, Ptr&)#Parent should not be contained in any other smart pointer."); value->SetAggregationRoot(this); auto parent = value.Detach(); aggregationInfo[index] = parent; } void DescriptableObject::InitializeAggregation(vint size) { CHECK_ERROR(!IsAggregated(), L"vl::reflection::DescriptableObject::InitializeAggregation(vint)#This function should not be called on aggregated objects."); CHECK_ERROR(size >= 0, L"vl::reflection::DescriptableObject::InitializeAggregation(vint)#Size shout not be negative."); aggregationSize = size; aggregationInfo = new DescriptableObject*[size + 2]; memset(aggregationInfo, 0, sizeof(*aggregationInfo) * (size + 2)); } #endif void DescriptableObject::FinalizeAggregation() { #ifndef VCZH_DEBUG_NO_REFLECTION if (IsAggregated()) { if (auto root = GetAggregationRoot()) { if (aggregationInfo[aggregationSize + 1] == nullptr) { return; } else { aggregationInfo[aggregationSize + 1] = nullptr; } if (!root->destructing) { destructing = true; delete root; } } } #endif } DescriptableObject::DescriptableObject() :referenceCounter(0) , sharedPtrDestructorProc(0) #ifndef VCZH_DEBUG_NO_REFLECTION , objectSize(0) , typeDescriptor(0) , destructing(false) , aggregationInfo(nullptr) , aggregationSize(-1) #endif { } #if defined(VCZH_GCC) && defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wexceptions" #endif DescriptableObject::~DescriptableObject() { #ifndef VCZH_DEBUG_NO_REFLECTION destructing = true; if (IsAggregated()) { if (auto root = GetAggregationRoot()) { if (aggregationInfo[aggregationSize + 1] != nullptr) { #pragma warning (push) #pragma warning (disable: 4297) // Your class should call FinalizeAggregation in the destructor if it inherits from AggregatableDescription. CHECK_ERROR(!IsAggregated(), L"vl::reflection::DescriptableObject::~DescriptableObject0()#FinalizeAggregation function should be called."); #pragma warning (pop) } } for (vint i = 0; i < aggregationSize; i++) { if (auto parent = GetAggregationParent(i)) { if (!parent->destructing) { delete parent; } } } delete[] aggregationInfo; } #endif } #if defined(VCZH_GCC) && defined(__clang__) #pragma clang diagnostic pop #endif #ifndef VCZH_DEBUG_NO_REFLECTION description::ITypeDescriptor* DescriptableObject::GetTypeDescriptor() { return typeDescriptor?*typeDescriptor:0; } #endif Ptr DescriptableObject::GetInternalProperty(const WString& name) { if(!internalProperties) return 0; vint index=internalProperties->Keys().IndexOf(name); if(index==-1) return 0; return internalProperties->Values().Get(index); } void DescriptableObject::SetInternalProperty(const WString& name, Ptr value) { if(internalProperties) { vint index=internalProperties->Keys().IndexOf(name); if(index==-1) { if(value) { internalProperties->Add(name, value); } } else { if(value) { internalProperties->Set(name, value); } else { internalProperties->Remove(name); if(internalProperties->Count()==0) { internalProperties=0; } } } } else { if(value) { internalProperties=new InternalPropertyMap; internalProperties->Add(name, value); } } } bool DescriptableObject::Dispose(bool forceDisposing) { #ifndef VCZH_DEBUG_NO_REFLECTION if (IsAggregated()) { if (auto root = GetAggregationRoot()) { return root->Dispose(forceDisposing); } } #endif if (referenceCounter > 0 && forceDisposing) { throw description::ValueNotDisposableException(); } if (sharedPtrDestructorProc) { return sharedPtrDestructorProc(this, forceDisposing); } else { delete this; return true; } } #ifndef VCZH_DEBUG_NO_REFLECTION DescriptableObject* DescriptableObject::SafeGetAggregationRoot() { if (IsAggregated()) { if (auto root = GetAggregationRoot()) { return root; } } return this; } #endif /*********************************************************************** description::Value ***********************************************************************/ namespace description { Value::Value(DescriptableObject* value) :valueType(value ? RawPtr :Null) ,rawPtr(nullptr) #ifndef VCZH_DEBUG_NO_REFLECTION ,typeDescriptor(0) #endif { #ifndef VCZH_DEBUG_NO_REFLECTION if (value) { rawPtr = value->SafeGetAggregationRoot(); } #else rawPtr = value; #endif } Value::Value(Ptr value) :valueType(value ? SharedPtr : Null) ,rawPtr(nullptr) #ifndef VCZH_DEBUG_NO_REFLECTION ,typeDescriptor(0) #endif { #ifndef VCZH_DEBUG_NO_REFLECTION if (value) { rawPtr = value->SafeGetAggregationRoot(); sharedPtr = rawPtr; } #else rawPtr = value.Obj(); sharedPtr = value; #endif } Value::Value(Ptr value, ITypeDescriptor* associatedTypeDescriptor) :valueType(value ? BoxedValue : Null) , rawPtr(nullptr) , boxedValue(value) #ifndef VCZH_DEBUG_NO_REFLECTION , typeDescriptor(associatedTypeDescriptor) #endif { } vint Value::Compare(const Value& a, const Value& b)const { switch (a.GetValueType()) { case Value::RawPtr: case Value::SharedPtr: switch (b.GetValueType()) { case Value::RawPtr: case Value::SharedPtr: { auto pa = a.GetRawPtr(); auto pb = b.GetRawPtr(); if (pa < pb) return -1; if (pa > pb) return 1; return 0; } case Value::BoxedValue: return -1; default: return 1; } case Value::BoxedValue: switch (b.GetValueType()) { case Value::RawPtr: case Value::SharedPtr: return 1; case Value::BoxedValue: { #ifndef VCZH_DEBUG_NO_REFLECTION auto aSt = a.GetTypeDescriptor()->GetSerializableType(); auto bSt = b.GetTypeDescriptor()->GetSerializableType(); if (aSt) { if (bSt) { auto aSt = a.GetTypeDescriptor()->GetSerializableType(); auto bSt = b.GetTypeDescriptor()->GetSerializableType(); WString aText; WString bText; aSt->Serialize(a, aText); bSt->Serialize(b, bText); if (aText < bText) return -1; if (aText > bText) return 1; return 0; } else { return 1; } } else { if (bSt) { return -1; } else { if (a.GetTypeDescriptor() != b.GetTypeDescriptor()) { auto aText = a.GetTypeDescriptor()->GetTypeName(); auto bText = b.GetTypeDescriptor()->GetTypeName(); if (aText < bText) return -1; if (aText > bText) return 1; return 0; } switch (a.GetTypeDescriptor()->GetTypeDescriptorFlags()) { case TypeDescriptorFlags::Struct: { auto td = a.GetTypeDescriptor(); vint count = td->GetPropertyCount(); for (vint i = 0; i < count; i++) { auto prop = td->GetProperty(i); auto ap = prop->GetValue(a); auto bp = prop->GetValue(b); vint result = Compare(ap, bp); if (result != 0) { return result; } } } return 0; case TypeDescriptorFlags::FlagEnum: case TypeDescriptorFlags::NormalEnum: { auto ai = a.GetTypeDescriptor()->GetEnumType()->FromEnum(a); auto bi = a.GetTypeDescriptor()->GetEnumType()->FromEnum(b); if (ai < bi) return -1; if (ai > bi) return 1; return 0; } default: return 0; } } } #else auto pa = a.GetBoxedValue(); auto pb = b.GetBoxedValue(); switch (pa->ComparePrimitive(pb)) { case IBoxedValue::Smaller: return -1; case IBoxedValue::Greater: return 1; case IBoxedValue::Equal: return 0; default:; } if (pa.Obj() < pb.Obj()) return -1; if (pa.Obj() > pb.Obj()) return 1; return 0; #endif } default: return 1; } default: switch (b.GetValueType()) { case Value::RawPtr: case Value::SharedPtr: case Value::BoxedValue: return -1; default: return 0; } } } Value::Value() :valueType(Null) ,rawPtr(0) #ifndef VCZH_DEBUG_NO_REFLECTION ,typeDescriptor(0) #endif { } Value::Value(const Value& value) :valueType(value.valueType) ,rawPtr(value.rawPtr) ,sharedPtr(value.sharedPtr) ,boxedValue(value.boxedValue ? value.boxedValue->Copy() : nullptr) #ifndef VCZH_DEBUG_NO_REFLECTION ,typeDescriptor(value.typeDescriptor) #endif { } Value& Value::operator=(const Value& value) { valueType = value.valueType; rawPtr = value.rawPtr; sharedPtr = value.sharedPtr; boxedValue = value.boxedValue ? value.boxedValue->Copy() : nullptr; #ifndef VCZH_DEBUG_NO_REFLECTION typeDescriptor = value.typeDescriptor; #endif return *this; } Value::ValueType Value::GetValueType()const { return valueType; } DescriptableObject* Value::GetRawPtr()const { return rawPtr; } Ptr Value::GetSharedPtr()const { return sharedPtr; } Ptr Value::GetBoxedValue()const { return boxedValue; } bool Value::IsNull()const { return valueType == Null; } #ifndef VCZH_DEBUG_NO_REFLECTION ITypeDescriptor* Value::GetTypeDescriptor()const { switch(valueType) { case RawPtr: case SharedPtr: return rawPtr?rawPtr->GetTypeDescriptor():0; case BoxedValue: return typeDescriptor; default:; } return 0; } WString Value::GetTypeFriendlyName()const { switch(valueType) { case RawPtr: return GetTypeDescriptor()->GetTypeName()+L"*"; case SharedPtr: return L"Ptr<"+GetTypeDescriptor()->GetTypeName()+L">"; case BoxedValue: return GetTypeDescriptor()->GetTypeName(); default: return L"null"; } } bool Value::CanConvertTo(ITypeDescriptor* targetType, ValueType targetValueType)const { if(targetType==GetGlobalTypeManager()->GetRootType()) { return true; } switch(valueType) { case Null: return targetValueType != BoxedValue; case RawPtr: case SharedPtr: if (targetValueType != RawPtr && targetValueType != SharedPtr) return false; break; case BoxedValue: return targetValueType == BoxedValue; } return GetTypeDescriptor()->CanConvertTo(targetType); } bool Value::CanConvertTo(ITypeInfo* targetType)const { if(valueType==Null && targetType->GetDecorator()==ITypeInfo::Nullable) { return true; } ValueType targetValueType=ValueType::Null; { ITypeInfo* currentType=targetType; while(currentType) { switch(targetType->GetDecorator()) { case ITypeInfo::RawPtr: targetValueType=RawPtr; currentType=0; break; case ITypeInfo::SharedPtr: targetValueType=SharedPtr; currentType=0; break; case ITypeInfo::TypeDescriptor: case ITypeInfo::Nullable: targetValueType=BoxedValue; currentType=0; break; default: currentType=currentType->GetElementType(); } } } return CanConvertTo(targetType->GetTypeDescriptor(), targetValueType); } #endif Value Value::From(DescriptableObject* value) { return Value(value); } Value Value::From(Ptr value) { return Value(value); } Value Value::From(Ptr value, ITypeDescriptor* type) { return Value(value, type); } #ifndef VCZH_DEBUG_NO_REFLECTION IMethodInfo* Value::SelectMethod(IMethodGroupInfo* methodGroup, collections::Array& arguments) { if(methodGroup->GetMethodCount()==1) { return methodGroup->GetMethod(0); } List methods; for(vint i=0;iGetMethodCount();i++) { IMethodInfo* method=methodGroup->GetMethod(i); if(method->GetParameterCount()==arguments.Count()) { methods.Add(method); } } if(methods.Count()==0) { throw ArgumentCountMismtatchException(methodGroup); } else if(methods.Count()==1) { return methods[0]; } else { for(vint i=0;iCheckArguments(arguments); return method; } catch(const TypeDescriptorException&) { } } return methods[0]; } } Value Value::Create(ITypeDescriptor* type) { Array arguments; return Create(type, arguments); } Value Value::Create(ITypeDescriptor* type, collections::Array& arguments) { IMethodGroupInfo* methodGroup=type->GetConstructorGroup(); if(!methodGroup) throw ConstructorNotExistsException(type); IMethodInfo* method=SelectMethod(methodGroup, arguments); return method->Invoke(Value(), arguments); } Value Value::Create(const WString& typeName) { Array arguments; return Create(typeName, arguments); } Value Value::Create(const WString& typeName, collections::Array& arguments) { ITypeDescriptor* type = vl::reflection::description::GetTypeDescriptor(typeName); if(!type) throw TypeNotExistsException(typeName); return Create(type, arguments); } Value Value::InvokeStatic(const WString& typeName, const WString& name) { Array arguments; return InvokeStatic(typeName, name, arguments); } Value Value::InvokeStatic(const WString& typeName, const WString& name, collections::Array& arguments) { ITypeDescriptor* type=vl::reflection::description::GetTypeDescriptor(typeName); if(!type) throw TypeNotExistsException(typeName); IMethodGroupInfo* methodGroup=type->GetMethodGroupByName(name, true); if(!methodGroup) throw MemberNotExistsException(name, type); IMethodInfo* method=SelectMethod(methodGroup, arguments); return method->Invoke(Value(), arguments); } Value Value::GetProperty(const WString& name)const { ITypeDescriptor* type=GetTypeDescriptor(); if(!type) throw ArgumentNullException(L"thisObject", name); IPropertyInfo* prop=type->GetPropertyByName(name, true); if(!prop) throw MemberNotExistsException(name, type); return prop->GetValue(*this); } void Value::SetProperty(const WString& name, const Value& newValue) { ITypeDescriptor* type=GetTypeDescriptor(); if(!type) throw ArgumentNullException(L"thisObject", name); IPropertyInfo* prop=type->GetPropertyByName(name, true); if(!prop) throw MemberNotExistsException(name, type); prop->SetValue(*this, newValue); } Value Value::Invoke(const WString& name)const { Array arguments; return Invoke(name, arguments); } Value Value::Invoke(const WString& name, collections::Array& arguments)const { ITypeDescriptor* type=GetTypeDescriptor(); if(!type) throw ArgumentNullException(L"thisObject", name); IMethodGroupInfo* methodGroup=type->GetMethodGroupByName(name, true); if(!methodGroup) throw MemberNotExistsException(name, type); IMethodInfo* method=SelectMethod(methodGroup, arguments); return method->Invoke(*this, arguments); } Ptr Value::AttachEvent(const WString& name, const Value& function)const { ITypeDescriptor* type=GetTypeDescriptor(); if(!type) throw ArgumentNullException(L"thisObject", name); IEventInfo* eventInfo=type->GetEventByName(name, true); if(!eventInfo) throw MemberNotExistsException(name, type); Ptr proxy=UnboxValue>(function, Description::GetAssociatedTypeDescriptor(), L"function"); return eventInfo->Attach(*this, proxy); } bool Value::DetachEvent(const WString& name, Ptr handler)const { ITypeDescriptor* type = GetTypeDescriptor(); if (!type) throw ArgumentNullException(L"thisObject", name); IEventInfo* eventInfo = type->GetEventByName(name, true); if (!eventInfo) throw MemberNotExistsException(name, type); return eventInfo->Detach(*this, handler); } #endif bool Value::DeleteRawPtr() { if(valueType!=RawPtr) return false; if(!rawPtr) return false; rawPtr->Dispose(true); *this=Value(); return true; } #ifndef VCZH_DEBUG_NO_REFLECTION /*********************************************************************** description::TypeManager ***********************************************************************/ class TypeManager : public Object, public ITypeManager { protected: Dictionary> typeDescriptors; List> typeLoaders; ITypeDescriptor* rootType; bool loaded; public: TypeManager() :rootType(0) ,loaded(false) { } ~TypeManager() { Unload(); } vint GetTypeDescriptorCount()override { return typeDescriptors.Values().Count(); } ITypeDescriptor* GetTypeDescriptor(vint index)override { return typeDescriptors.Values().Get(index).Obj(); } ITypeDescriptor* GetTypeDescriptor(const WString& name)override { vint index=typeDescriptors.Keys().IndexOf(name); return index==-1?0:typeDescriptors.Values().Get(index).Obj(); } bool SetTypeDescriptor(const WString& name, Ptr typeDescriptor)override { if(typeDescriptor && name!=typeDescriptor->GetTypeName()) { return false; } if(!typeDescriptors.Keys().Contains(name)) { if(typeDescriptor) { typeDescriptors.Add(name, typeDescriptor); return true; } } else { if(!typeDescriptor) { typeDescriptors.Remove(name); return true; } } return false; } bool AddTypeLoader(Ptr typeLoader)override { vint index=typeLoaders.IndexOf(typeLoader.Obj()); if(index==-1) { typeLoaders.Add(typeLoader); if(loaded) { typeLoader->Load(this); } return true; } else { return false; } } bool RemoveTypeLoader(Ptr typeLoader)override { vint index=typeLoaders.IndexOf(typeLoader.Obj()); if(index!=-1) { if(loaded) { typeLoader->Unload(this); } typeLoaders.RemoveAt(index); return true; } else { return false; } } bool Load()override { if(!loaded) { loaded=true; for(vint i=0;iLoad(this); } return true; } else { return false; } } bool Unload()override { if(loaded) { loaded=false; rootType=0; for(vint i=0;iUnload(this); } typeDescriptors.Clear(); return true; } else { return false; } } bool Reload()override { Unload(); Load(); return true; } bool IsLoaded()override { return loaded; } ITypeDescriptor* GetRootType()override { if (!rootType) { rootType=description::GetTypeDescriptor(); } return rootType; } }; /*********************************************************************** description::TypeManager helper functions ***********************************************************************/ ITypeManager* globalTypeManager=0; bool initializedGlobalTypeManager=false; ITypeManager* GetGlobalTypeManager() { if(!initializedGlobalTypeManager) { initializedGlobalTypeManager=true; globalTypeManager=new TypeManager; } return globalTypeManager; } bool DestroyGlobalTypeManager() { if(initializedGlobalTypeManager && globalTypeManager) { delete globalTypeManager; globalTypeManager=0; return true; } else { return false; } } bool ResetGlobalTypeManager() { if(!DestroyGlobalTypeManager()) return false; initializedGlobalTypeManager=false; return true; } ITypeDescriptor* GetTypeDescriptor(const WString& name) { if(globalTypeManager) { if(!globalTypeManager->IsLoaded()) { globalTypeManager->Load(); } return globalTypeManager->GetTypeDescriptor(name); } return 0; } /*********************************************************************** Cpp Helper Functions ***********************************************************************/ WString CppGetFullName(ITypeDescriptor* type) { if (auto cpp = type->GetCpp()) { if (cpp->GetFullName() == L"void" || cpp->GetFullName() == L"vl::reflection::description::VoidValue") { return L"void"; } else if (cpp->GetFullName() == L"float") { return L"float"; } else if (cpp->GetFullName() == L"double") { return L"double"; } else if (cpp->GetFullName() == L"bool") { return L"bool"; } else if (cpp->GetFullName() == L"wchar_t") { return L"wchar_t"; } else { return L"::" + cpp->GetFullName(); } } else { return L"::vl::" + type->GetTypeName(); } } WString CppGetReferenceTemplate(IPropertyInfo* prop) { if (auto cpp = prop->GetCpp()) { return cpp->GetReferenceTemplate(); } else if ((prop->GetOwnerTypeDescriptor()->GetTypeDescriptorFlags() & TypeDescriptorFlags::ReferenceType) != TypeDescriptorFlags::Undefined) { return WString(L"$This->$Name", false); } else { return WString(L"$This.$Name", false); } } WString CppGetClosureTemplate(IMethodInfo* method) { if (auto cpp = method->GetCpp()) { return cpp->GetClosureTemplate(); } if (method->IsStatic()) { return WString(L"::vl::Func<$Func>(&$Type::$Name)", false); } else { return WString(L"::vl::Func<$Func>($This, &$Type::$Name)", false); } } WString CppGetInvokeTemplate(IMethodInfo* method) { if (auto cpp = method->GetCpp()) { return cpp->GetInvokeTemplate(); } if (method->GetOwnerMethodGroup() == method->GetOwnerTypeDescriptor()->GetConstructorGroup()) { return WString(L"new $Type($Arguments)", false); } else if (method->IsStatic()) { return WString(L"$Type::$Name($Arguments)", false); } else { return WString(L"$This->$Name($Arguments)", false); } } WString CppGetAttachTemplate(IEventInfo* ev) { auto cpp = ev->GetCpp(); return cpp == nullptr ? WString(L"::vl::__vwsn::EventAttach($This->$Name, $Handler)", false) : cpp->GetAttachTemplate(); } WString CppGetDetachTemplate(IEventInfo* ev) { auto cpp = ev->GetCpp(); return cpp == nullptr ? WString(L"::vl::__vwsn::EventDetach($This->$Name, $Handler)", false) : cpp->GetDetachTemplate(); } WString CppGetInvokeTemplate(IEventInfo* ev) { auto cpp = ev->GetCpp(); return cpp == nullptr ? WString(L"::vl::__vwsn::EventInvoke($This->$Name)($Arguments)", false) : cpp->GetInvokeTemplate(); } bool CppExists(ITypeDescriptor* type) { auto cpp = type->GetCpp(); return cpp == nullptr || cpp->GetFullName() != L"*"; } bool CppExists(IPropertyInfo* prop) { if (auto cpp = prop->GetCpp()) { return cpp->GetReferenceTemplate() != L"*"; } else if (auto method = prop->GetGetter()) { return CppExists(method); } else { return true; } } bool CppExists(IMethodInfo* method) { auto cpp = method->GetCpp(); return cpp == nullptr || cpp->GetInvokeTemplate() != L"*"; } bool CppExists(IEventInfo* ev) { auto cpp = ev->GetCpp(); return cpp == nullptr || cpp->GetInvokeTemplate() != L"*"; } #endif } } } /*********************************************************************** .\REFLECTION\GUITYPEDESCRIPTORBUILDER.CPP ***********************************************************************/ namespace vl { using namespace collections; namespace reflection { namespace description { #ifndef VCZH_DEBUG_NO_REFLECTION /*********************************************************************** TypeDescriptorImplBase ***********************************************************************/ const WString& TypeDescriptorImplBase::GetFullName() { return cppFullTypeName; } const TypeInfoContent* TypeDescriptorImplBase::GetTypeInfoContentInternal() { return typeInfoContent; } TypeDescriptorImplBase::TypeDescriptorImplBase(TypeDescriptorFlags _typeDescriptorFlags, const TypeInfoContent* _typeInfoContent) :typeDescriptorFlags(_typeDescriptorFlags) , typeInfoContent(_typeInfoContent) , typeName(_typeInfoContent->typeName, false) { switch (typeInfoContent->cppName) { case TypeInfoContent::VlppType: break; case TypeInfoContent::CppType: cppFullTypeName = WString(typeInfoContent->typeName, false); break; case TypeInfoContent::Renamed: cppFullTypeName = WString(typeInfoContent->cppFullTypeName, false); break; } } TypeDescriptorImplBase::~TypeDescriptorImplBase() { } ITypeDescriptor::ICpp* TypeDescriptorImplBase::GetCpp() { return typeInfoContent->cppName == TypeInfoContent::VlppType ? nullptr : this; } TypeDescriptorFlags TypeDescriptorImplBase::GetTypeDescriptorFlags() { return typeDescriptorFlags; } const WString& TypeDescriptorImplBase::GetTypeName() { return typeName; } /*********************************************************************** ValueTypeDescriptorBase ***********************************************************************/ void ValueTypeDescriptorBase::LoadInternal() { } void ValueTypeDescriptorBase::Load() { if (!loaded) { loaded = true; LoadInternal(); } } ValueTypeDescriptorBase::ValueTypeDescriptorBase(TypeDescriptorFlags _typeDescriptorFlags, const TypeInfoContent* _typeInfoContent) :TypeDescriptorImplBase(_typeDescriptorFlags, _typeInfoContent) , loaded(false) { } ValueTypeDescriptorBase::~ValueTypeDescriptorBase() { } bool ValueTypeDescriptorBase::IsAggregatable() { return false; } IValueType* ValueTypeDescriptorBase::GetValueType() { Load(); return valueType.Obj(); } IEnumType* ValueTypeDescriptorBase::GetEnumType() { Load(); return enumType.Obj(); } ISerializableType* ValueTypeDescriptorBase::GetSerializableType() { Load(); return serializableType.Obj(); } vint ValueTypeDescriptorBase::GetBaseTypeDescriptorCount() { return 0; } ITypeDescriptor* ValueTypeDescriptorBase::GetBaseTypeDescriptor(vint index) { return 0; } bool ValueTypeDescriptorBase::CanConvertTo(ITypeDescriptor* targetType) { return this == targetType; } vint ValueTypeDescriptorBase::GetPropertyCount() { return 0; } IPropertyInfo* ValueTypeDescriptorBase::GetProperty(vint index) { return 0; } bool ValueTypeDescriptorBase::IsPropertyExists(const WString& name, bool inheritable) { return false; } IPropertyInfo* ValueTypeDescriptorBase::GetPropertyByName(const WString& name, bool inheritable) { return 0; } vint ValueTypeDescriptorBase::GetEventCount() { return 0; } IEventInfo* ValueTypeDescriptorBase::GetEvent(vint index) { return 0; } bool ValueTypeDescriptorBase::IsEventExists(const WString& name, bool inheritable) { return false; } IEventInfo* ValueTypeDescriptorBase::GetEventByName(const WString& name, bool inheritable) { return 0; } vint ValueTypeDescriptorBase::GetMethodGroupCount() { return 0; } IMethodGroupInfo* ValueTypeDescriptorBase::GetMethodGroup(vint index) { return 0; } bool ValueTypeDescriptorBase::IsMethodGroupExists(const WString& name, bool inheritable) { return false; } IMethodGroupInfo* ValueTypeDescriptorBase::GetMethodGroupByName(const WString& name, bool inheritable) { return 0; } IMethodGroupInfo* ValueTypeDescriptorBase::GetConstructorGroup() { return 0; } /*********************************************************************** TypeDescriptorTypeInfo ***********************************************************************/ TypeDescriptorTypeInfo::TypeDescriptorTypeInfo(ITypeDescriptor* _typeDescriptor, TypeInfoHint _hint) :typeDescriptor(_typeDescriptor) , hint(_hint) { } TypeDescriptorTypeInfo::~TypeDescriptorTypeInfo() { } ITypeInfo::Decorator TypeDescriptorTypeInfo::GetDecorator() { return ITypeInfo::TypeDescriptor; } TypeInfoHint TypeDescriptorTypeInfo::GetHint() { return hint; } ITypeInfo* TypeDescriptorTypeInfo::GetElementType() { return nullptr; } ITypeDescriptor* TypeDescriptorTypeInfo::GetTypeDescriptor() { return typeDescriptor; } vint TypeDescriptorTypeInfo::GetGenericArgumentCount() { return 0; } ITypeInfo* TypeDescriptorTypeInfo::GetGenericArgument(vint index) { return nullptr; } WString TypeDescriptorTypeInfo::GetTypeFriendlyName() { return typeDescriptor->GetTypeName(); } /*********************************************************************** DecoratedTypeInfo ***********************************************************************/ DecoratedTypeInfo::DecoratedTypeInfo(Ptr _elementType) :elementType(_elementType) { } DecoratedTypeInfo::~DecoratedTypeInfo() { } TypeInfoHint DecoratedTypeInfo::GetHint() { return elementType->GetHint(); } ITypeInfo* DecoratedTypeInfo::GetElementType() { return elementType.Obj(); } ITypeDescriptor* DecoratedTypeInfo::GetTypeDescriptor() { return elementType->GetTypeDescriptor(); } vint DecoratedTypeInfo::GetGenericArgumentCount() { return 0; } ITypeInfo* DecoratedTypeInfo::GetGenericArgument(vint index) { return nullptr; } /*********************************************************************** RawPtrTypeInfo ***********************************************************************/ RawPtrTypeInfo::RawPtrTypeInfo(Ptr _elementType) :DecoratedTypeInfo(_elementType) { } RawPtrTypeInfo::~RawPtrTypeInfo() { } ITypeInfo::Decorator RawPtrTypeInfo::GetDecorator() { return ITypeInfo::RawPtr; } WString RawPtrTypeInfo::GetTypeFriendlyName() { return elementType->GetTypeFriendlyName() + L"*"; } /*********************************************************************** SharedPtrTypeInfo ***********************************************************************/ SharedPtrTypeInfo::SharedPtrTypeInfo(Ptr _elementType) :DecoratedTypeInfo(_elementType) { } SharedPtrTypeInfo::~SharedPtrTypeInfo() { } ITypeInfo::Decorator SharedPtrTypeInfo::GetDecorator() { return ITypeInfo::SharedPtr; } WString SharedPtrTypeInfo::GetTypeFriendlyName() { return elementType->GetTypeFriendlyName() + L"^"; } /*********************************************************************** NullableTypeInfo ***********************************************************************/ NullableTypeInfo::NullableTypeInfo(Ptr _elementType) :DecoratedTypeInfo(_elementType) { } NullableTypeInfo::~NullableTypeInfo() { } ITypeInfo::Decorator NullableTypeInfo::GetDecorator() { return ITypeInfo::Nullable; } WString NullableTypeInfo::GetTypeFriendlyName() { return elementType->GetTypeFriendlyName() + L"?"; } /*********************************************************************** GenericTypeInfo ***********************************************************************/ GenericTypeInfo::GenericTypeInfo(Ptr _elementType) :DecoratedTypeInfo(_elementType) { } GenericTypeInfo::~GenericTypeInfo() { } ITypeInfo::Decorator GenericTypeInfo::GetDecorator() { return ITypeInfo::Generic; } vint GenericTypeInfo::GetGenericArgumentCount() { return genericArguments.Count(); } ITypeInfo* GenericTypeInfo::GetGenericArgument(vint index) { return genericArguments[index].Obj(); } WString GenericTypeInfo::GetTypeFriendlyName() { WString result = elementType->GetTypeFriendlyName() + L"<"; FOREACH_INDEXER(Ptr, type, i, genericArguments) { WString result = elementType->GetTypeFriendlyName() + L"<"; FOREACH_INDEXER(Ptr, type, i, genericArguments) { if (i>0) result += L", "; result += type->GetTypeFriendlyName(); } result += L">"; return result; if (i>0) result += L", "; result += type->GetTypeFriendlyName(); } result += L">"; return result; } void GenericTypeInfo::AddGenericArgument(Ptr value) { genericArguments.Add(value); } /*********************************************************************** ParameterInfoImpl ***********************************************************************/ ParameterInfoImpl::ParameterInfoImpl(IMethodInfo* _ownerMethod, const WString& _name, Ptr _type) :ownerMethod(_ownerMethod) ,name(_name) ,type(_type) { } ParameterInfoImpl::~ParameterInfoImpl() { } ITypeDescriptor* ParameterInfoImpl::GetOwnerTypeDescriptor() { return ownerMethod->GetOwnerTypeDescriptor(); } const WString& ParameterInfoImpl::GetName() { return name; } ITypeInfo* ParameterInfoImpl::GetType() { return type.Obj(); } IMethodInfo* ParameterInfoImpl::GetOwnerMethod() { return ownerMethod; } /*********************************************************************** MethodInfoImpl ***********************************************************************/ MethodInfoImpl::MethodInfoImpl(IMethodGroupInfo* _ownerMethodGroup, Ptr _return, bool _isStatic) :ownerMethodGroup(_ownerMethodGroup) ,ownerProperty(0) ,returnInfo(_return) ,isStatic(_isStatic) { } MethodInfoImpl::~MethodInfoImpl() { } ITypeDescriptor* MethodInfoImpl::GetOwnerTypeDescriptor() { return ownerMethodGroup->GetOwnerTypeDescriptor(); } IPropertyInfo* MethodInfoImpl::GetOwnerProperty() { return ownerProperty; } const WString& MethodInfoImpl::GetName() { return ownerMethodGroup->GetName(); } IMethodGroupInfo* MethodInfoImpl::GetOwnerMethodGroup() { return ownerMethodGroup; } vint MethodInfoImpl::GetParameterCount() { return parameters.Count(); } IParameterInfo* MethodInfoImpl::GetParameter(vint index) { if(0<=index && index& arguments) { if(arguments.Count()!=parameters.Count()) { throw ArgumentCountMismtatchException(ownerMethodGroup); } for(vint i=0;iGetType())) { throw ArgumentTypeMismtatchException(parameters[i]->GetName(), parameters[i]->GetType(), arguments[i]); } } } Value MethodInfoImpl::Invoke(const Value& thisObject, collections::Array& arguments) { if(thisObject.IsNull()) { if(!isStatic) { throw ArgumentNullException(L"thisObject", this); } } else if(!thisObject.CanConvertTo(ownerMethodGroup->GetOwnerTypeDescriptor(), Value::RawPtr)) { throw ArgumentTypeMismtatchException(L"thisObject", ownerMethodGroup->GetOwnerTypeDescriptor(), Value::RawPtr, thisObject); } CheckArguments(arguments); return InvokeInternal(thisObject, arguments); } Value MethodInfoImpl::CreateFunctionProxy(const Value& thisObject) { if(thisObject.IsNull()) { if(!isStatic) { throw ArgumentNullException(L"thisObject", this); } } else if(!thisObject.CanConvertTo(ownerMethodGroup->GetOwnerTypeDescriptor(), Value::RawPtr)) { throw ArgumentTypeMismtatchException(L"thisObject", ownerMethodGroup->GetOwnerTypeDescriptor(), Value::RawPtr, thisObject); } return CreateFunctionProxyInternal(thisObject); } bool MethodInfoImpl::AddParameter(Ptr parameter) { for(vint i=0;iGetName()==parameter->GetName()) { return false; } } parameters.Add(parameter); return true; } bool MethodInfoImpl::SetOwnerMethodgroup(IMethodGroupInfo* _ownerMethodGroup) { if(ownerMethodGroup) return false; ownerMethodGroup=_ownerMethodGroup; return true; } /*********************************************************************** MethodGroupInfoImpl ***********************************************************************/ MethodGroupInfoImpl::MethodGroupInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name) :ownerTypeDescriptor(_ownerTypeDescriptor) ,name(_name) { } MethodGroupInfoImpl::~MethodGroupInfoImpl() { } ITypeDescriptor* MethodGroupInfoImpl::GetOwnerTypeDescriptor() { return ownerTypeDescriptor; } const WString& MethodGroupInfoImpl::GetName() { return name; } vint MethodGroupInfoImpl::GetMethodCount() { return methods.Count(); } IMethodInfo* MethodGroupInfoImpl::GetMethod(vint index) { if(0<=index && index _method) { methods.Add(_method); return true; } /*********************************************************************** EventInfoImpl ***********************************************************************/ EventInfoImpl::EventInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name) :ownerTypeDescriptor(_ownerTypeDescriptor) ,name(_name) { } EventInfoImpl::~EventInfoImpl() { } ITypeDescriptor* EventInfoImpl::GetOwnerTypeDescriptor() { return ownerTypeDescriptor; } ITypeInfo* EventInfoImpl::GetHandlerType() { if(!handlerType) { handlerType=GetHandlerTypeInternal(); } return handlerType.Obj(); } vint EventInfoImpl::GetObservingPropertyCount() { return observingProperties.Count(); } IPropertyInfo* EventInfoImpl::GetObservingProperty(vint index) { return observingProperties[index]; } const WString& EventInfoImpl::GetName() { return name; } Ptr EventInfoImpl::Attach(const Value& thisObject, Ptr handler) { if(thisObject.IsNull()) { throw ArgumentNullException(L"thisObject", this); } else if(!thisObject.CanConvertTo(ownerTypeDescriptor, Value::RawPtr)) { throw ArgumentTypeMismtatchException(L"thisObject", ownerTypeDescriptor, Value::RawPtr, thisObject); } DescriptableObject* rawThisObject=thisObject.GetRawPtr(); if(rawThisObject) { return AttachInternal(rawThisObject, handler); } else { return nullptr; } } bool EventInfoImpl::Detach(const Value& thisObject, Ptr handler) { if (thisObject.IsNull()) { throw ArgumentNullException(L"thisObject", this); } else if (!thisObject.CanConvertTo(ownerTypeDescriptor, Value::RawPtr)) { throw ArgumentTypeMismtatchException(L"thisObject", ownerTypeDescriptor, Value::RawPtr, thisObject); } DescriptableObject* rawThisObject = thisObject.GetRawPtr(); if (rawThisObject) { return DetachInternal(rawThisObject, handler); } else { return false; } } void EventInfoImpl::Invoke(const Value& thisObject, Ptr arguments) { if(thisObject.IsNull()) { throw ArgumentNullException(L"thisObject", this); } else if(!thisObject.CanConvertTo(ownerTypeDescriptor, Value::RawPtr)) { throw ArgumentTypeMismtatchException(L"thisObject", ownerTypeDescriptor, Value::RawPtr, thisObject); } DescriptableObject* rawThisObject=thisObject.GetRawPtr(); if(rawThisObject) { InvokeInternal(rawThisObject, arguments); } else { return; } } /*********************************************************************** PropertyInfoImpl ***********************************************************************/ PropertyInfoImpl::PropertyInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, MethodInfoImpl* _getter, MethodInfoImpl* _setter, EventInfoImpl* _valueChangedEvent) :ownerTypeDescriptor(_ownerTypeDescriptor) ,name(_name) ,getter(_getter) ,setter(_setter) ,valueChangedEvent(_valueChangedEvent) { if(getter) getter->ownerProperty=this; if(setter) setter->ownerProperty=this; if(valueChangedEvent) { valueChangedEvent->observingProperties.Add(this); } } PropertyInfoImpl::~PropertyInfoImpl() { } ITypeDescriptor* PropertyInfoImpl::GetOwnerTypeDescriptor() { return ownerTypeDescriptor; } const WString& PropertyInfoImpl::GetName() { return name; } IPropertyInfo::ICpp* PropertyInfoImpl::GetCpp() { return nullptr; } bool PropertyInfoImpl::IsReadable() { return getter!=0; } bool PropertyInfoImpl::IsWritable() { return setter!=0; } ITypeInfo* PropertyInfoImpl::GetReturn() { return getter?getter->GetReturn():0; } IMethodInfo* PropertyInfoImpl::GetGetter() { return getter; } IMethodInfo* PropertyInfoImpl::GetSetter() { return setter; } IEventInfo* PropertyInfoImpl::GetValueChangedEvent() { return valueChangedEvent; } Value PropertyInfoImpl::GetValue(const Value& thisObject) { if(getter) { Array arguments; return getter->Invoke(thisObject, arguments); } else { throw PropertyIsNotReadableException(this); } } void PropertyInfoImpl::SetValue(Value& thisObject, const Value& newValue) { if(setter) { Array arguments(1); arguments[0]=newValue; setter->Invoke(thisObject, arguments); } else { throw PropertyIsNotWritableException(this); } } /*********************************************************************** PropertyInfoImpl_StaticCpp ***********************************************************************/ const WString& PropertyInfoImpl_StaticCpp::GetReferenceTemplate() { return referenceTemplate; } PropertyInfoImpl_StaticCpp::PropertyInfoImpl_StaticCpp(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, MethodInfoImpl* _getter, MethodInfoImpl* _setter, EventInfoImpl* _valueChangedEvent, const WString& _referenceTemplate) :PropertyInfoImpl(_ownerTypeDescriptor, _name, _getter, _setter, _valueChangedEvent) , referenceTemplate(_referenceTemplate) { } PropertyInfoImpl_StaticCpp::~PropertyInfoImpl_StaticCpp() { } IPropertyInfo::ICpp* PropertyInfoImpl_StaticCpp::GetCpp() { return this; } /*********************************************************************** FieldInfoImpl ***********************************************************************/ FieldInfoImpl::FieldInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, Ptr _returnInfo) :ownerTypeDescriptor(_ownerTypeDescriptor) ,name(_name) ,returnInfo(_returnInfo) { } FieldInfoImpl::~FieldInfoImpl() { } ITypeDescriptor* FieldInfoImpl::GetOwnerTypeDescriptor() { return ownerTypeDescriptor; } const WString& FieldInfoImpl::GetName() { return name; } bool FieldInfoImpl::IsReadable() { return true; } bool FieldInfoImpl::IsWritable() { return true; } ITypeInfo* FieldInfoImpl::GetReturn() { return returnInfo.Obj(); } IMethodInfo* FieldInfoImpl::GetGetter() { return 0; } IMethodInfo* FieldInfoImpl::GetSetter() { return 0; } IEventInfo* FieldInfoImpl::GetValueChangedEvent() { return 0; } Value FieldInfoImpl::GetValue(const Value& thisObject) { if(thisObject.IsNull()) { throw ArgumentNullException(L"thisObject", this); } else { auto td = thisObject.GetTypeDescriptor(); auto valueType = td->GetValueType() ? Value::BoxedValue : Value::RawPtr; if(!thisObject.CanConvertTo(ownerTypeDescriptor, valueType)) { throw ArgumentTypeMismtatchException(L"thisObject", ownerTypeDescriptor, valueType, thisObject); } } return GetValueInternal(thisObject); } void FieldInfoImpl::SetValue(Value& thisObject, const Value& newValue) { if(thisObject.IsNull()) { throw ArgumentNullException(L"thisObject", this); } else { auto td = thisObject.GetTypeDescriptor(); auto valueType = td->GetValueType() ? Value::BoxedValue : Value::RawPtr; if(!thisObject.CanConvertTo(ownerTypeDescriptor, valueType)) { throw ArgumentTypeMismtatchException(L"thisObject", ownerTypeDescriptor, valueType, thisObject); } } if(!newValue.CanConvertTo(returnInfo.Obj())) { throw ArgumentTypeMismtatchException(L"newValue", returnInfo.Obj(), newValue); } SetValueInternal(thisObject, newValue); } /*********************************************************************** TypeDescriptorImpl ***********************************************************************/ MethodGroupInfoImpl* TypeDescriptorImpl::PrepareMethodGroup(const WString& name) { vint index=methodGroups.Keys().IndexOf(name); if(index==-1) { Ptr methodGroup=new MethodGroupInfoImpl(this, name); methodGroups.Add(name, methodGroup); return methodGroup.Obj(); } else { return methodGroups.Values().Get(index).Obj(); } } MethodGroupInfoImpl* TypeDescriptorImpl::PrepareConstructorGroup() { if(!constructorGroup) { constructorGroup=new MethodGroupInfoImpl(this, L""); } return constructorGroup.Obj(); } IPropertyInfo* TypeDescriptorImpl::AddProperty(Ptr value) { properties.Add(value->GetName(), value); return value.Obj(); } IEventInfo* TypeDescriptorImpl::AddEvent(Ptr value) { events.Add(value->GetName(), value); return value.Obj(); } IMethodInfo* TypeDescriptorImpl::AddMethod(const WString& name, Ptr value) { MethodGroupInfoImpl* methodGroup=PrepareMethodGroup(name); value->SetOwnerMethodgroup(methodGroup); methodGroup->AddMethod(value); return value.Obj(); } IMethodInfo* TypeDescriptorImpl::AddConstructor(Ptr value) { MethodGroupInfoImpl* methodGroup=PrepareConstructorGroup(); value->SetOwnerMethodgroup(methodGroup); methodGroup->AddMethod(value); return value.Obj(); } void TypeDescriptorImpl::AddBaseType(ITypeDescriptor* value) { baseTypeDescriptors.Add(value); } void TypeDescriptorImpl::Load() { if(!loaded) { loaded=true; LoadInternal(); } } TypeDescriptorImpl::TypeDescriptorImpl(TypeDescriptorFlags _typeDescriptorFlags, const TypeInfoContent* _typeInfoContent) :TypeDescriptorImplBase(_typeDescriptorFlags, _typeInfoContent) ,loaded(false) { } TypeDescriptorImpl::~TypeDescriptorImpl() { } bool TypeDescriptorImpl::IsAggregatable() { return false; } IValueType* TypeDescriptorImpl::GetValueType() { return nullptr; } IEnumType* TypeDescriptorImpl::GetEnumType() { return nullptr; } ISerializableType* TypeDescriptorImpl::GetSerializableType() { return nullptr; } vint TypeDescriptorImpl::GetBaseTypeDescriptorCount() { Load(); return baseTypeDescriptors.Count(); } ITypeDescriptor* TypeDescriptorImpl::GetBaseTypeDescriptor(vint index) { Load(); if(0<=index && indexCanConvertTo(targetType)) return true; } return false; } vint TypeDescriptorImpl::GetPropertyCount() { Load(); return properties.Count(); } IPropertyInfo* TypeDescriptorImpl::GetProperty(vint index) { Load(); if(0<=index && indexIsPropertyExists(name, true)) { return true; } } } return false; } IPropertyInfo* TypeDescriptorImpl::GetPropertyByName(const WString& name, bool inheritable) { Load(); vint index=properties.Keys().IndexOf(name); if(index!=-1) { return properties.Values().Get(index).Obj(); } if(inheritable) { for(vint i=0;iGetPropertyByName(name, true); if(result) { return result; } } } return 0; } vint TypeDescriptorImpl::GetEventCount() { Load(); return events.Count(); } IEventInfo* TypeDescriptorImpl::GetEvent(vint index) { Load(); if(0<=index && indexIsEventExists(name, true)) { return true; } } } return false; } IEventInfo* TypeDescriptorImpl::GetEventByName(const WString& name, bool inheritable) { Load(); vint index=events.Keys().IndexOf(name); if(index!=-1) { return events.Values().Get(index).Obj(); } if(inheritable) { for(vint i=0;iGetEventByName(name, true); if(result) { return result; } } } return 0; } vint TypeDescriptorImpl::GetMethodGroupCount() { Load(); return methodGroups.Count(); } IMethodGroupInfo* TypeDescriptorImpl::GetMethodGroup(vint index) { Load(); if(0<=index && indexIsMethodGroupExists(name, true)) { return true; } } } return false; } IMethodGroupInfo* TypeDescriptorImpl::GetMethodGroupByName(const WString& name, bool inheritable) { Load(); vint index=methodGroups.Keys().IndexOf(name); if(index!=-1) { return methodGroups.Values().Get(index).Obj(); } if(inheritable) { for(vint i=0;iGetMethodGroupByName(name, true); if(result) { return result; } } } return 0; } IMethodGroupInfo* TypeDescriptorImpl::GetConstructorGroup() { Load(); return constructorGroup.Obj(); } #endif /*********************************************************************** Function Related ***********************************************************************/ namespace internal_helper { void UnboxSpecifiedParameter(Ptr arguments, vint index) { } #ifndef VCZH_DEBUG_NO_REFLECTION void UnboxSpecifiedParameter(MethodInfoImpl* methodInfo, collections::Array& arguments, vint index) { } #endif void AddValueToList(Ptr arguments) { } } } } } /*********************************************************************** .\REFLECTION\GUITYPEDESCRIPTORPREDEFINED.CPP ***********************************************************************/ namespace vl { using namespace collections; namespace reflection { namespace description { /*********************************************************************** IValueEnumerable ***********************************************************************/ Ptr IValueEnumerable::Create(collections::LazyList values) { Ptr> enumerable = new LazyList(values); return new ValueEnumerableWrapper>>(enumerable); } /*********************************************************************** IValueList ***********************************************************************/ Ptr IValueList::Create() { return Create(LazyList()); } Ptr IValueList::Create(Ptr values) { return Create(GetLazyList(values)); } Ptr IValueList::Create(collections::LazyList values) { Ptr> list = new List; CopyFrom(*list.Obj(), values); return new ValueListWrapper>>(list); } /*********************************************************************** IObservableList ***********************************************************************/ class ReversedObservableList : public ObservableListBase { protected: void NotifyUpdateInternal(vint start, vint count, vint newCount)override { if (observableList) { observableList->ItemChanged(start, count, newCount); } } public: IValueObservableList* observableList = nullptr; }; Ptr IValueObservableList::Create() { return Create(LazyList()); } Ptr IValueObservableList::Create(Ptr values) { return Create(GetLazyList(values)); } Ptr IValueObservableList::Create(collections::LazyList values) { auto list = MakePtr(); CopyFrom(*list.Obj(), values); auto wrapper = MakePtr>>(list); list->observableList = wrapper.Obj(); return wrapper; } /*********************************************************************** IValueDictionary ***********************************************************************/ Ptr IValueDictionary::Create() { Ptr> dictionary = new Dictionary; return new ValueDictionaryWrapper>>(dictionary); } Ptr IValueDictionary::Create(Ptr values) { Ptr> dictionary = new Dictionary; CopyFrom(*dictionary.Obj(), GetLazyList(values)); return new ValueDictionaryWrapper>>(dictionary); } Ptr IValueDictionary::Create(collections::LazyList> values) { Ptr> dictionary = new Dictionary; CopyFrom(*dictionary.Obj(), values); return new ValueDictionaryWrapper>>(dictionary); } /*********************************************************************** IValueException ***********************************************************************/ class DefaultValueException : public Object, public IValueException { protected: WString message; public: DefaultValueException(const WString& _message) :message(_message) { } #pragma push_macro("GetMessage") #if defined GetMessage #undef GetMessage #endif WString GetMessage()override { return message; } #pragma pop_macro("GetMessage") bool GetFatal()override { return false; } Ptr GetCallStack()override { return nullptr; } }; Ptr IValueException::Create(const WString& message) { return new DefaultValueException(message); } } } } /*********************************************************************** .\REFLECTION\GUITYPEDESCRIPTORREFLECTION.CPP ***********************************************************************/ #include #include namespace vl { using namespace collections; using namespace regex; namespace reflection { namespace description { /*********************************************************************** TypeName ***********************************************************************/ #ifndef VCZH_DEBUG_NO_REFLECTION IMPL_TYPE_INFO_RENAME(void, system::Void) IMPL_TYPE_INFO_RENAME(vl::reflection::description::VoidValue, system::Void) IMPL_TYPE_INFO_RENAME(vl::reflection::IDescriptable, system::Interface) IMPL_TYPE_INFO_RENAME(vl::reflection::DescriptableObject, system::ReferenceType) IMPL_TYPE_INFO_RENAME(vl::reflection::description::Value, system::Object) IMPL_TYPE_INFO_RENAME(vl::vuint8_t, system::UInt8) IMPL_TYPE_INFO_RENAME(vl::vuint16_t, system::UInt16) IMPL_TYPE_INFO_RENAME(vl::vuint32_t, system::UInt32) IMPL_TYPE_INFO_RENAME(vl::vuint64_t, system::UInt64) IMPL_TYPE_INFO_RENAME(vl::vint8_t, system::Int8) IMPL_TYPE_INFO_RENAME(vl::vint16_t, system::Int16) IMPL_TYPE_INFO_RENAME(vl::vint32_t, system::Int32) IMPL_TYPE_INFO_RENAME(vl::vint64_t, system::Int64) IMPL_TYPE_INFO_RENAME(float, system::Single) IMPL_TYPE_INFO_RENAME(double, system::Double) IMPL_TYPE_INFO_RENAME(bool, system::Boolean) IMPL_TYPE_INFO_RENAME(wchar_t, system::Char) IMPL_TYPE_INFO_RENAME(vl::WString, system::String) IMPL_TYPE_INFO_RENAME(vl::DateTime, system::DateTime) IMPL_TYPE_INFO_RENAME(vl::Locale, system::Locale) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueEnumerator, system::Enumerator) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueEnumerable, system::Enumerable) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueReadonlyList, system::ReadonlyList) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueList, system::List) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueObservableList, system::ObservableList) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueReadonlyDictionary, system::ReadonlyDictionary) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueDictionary, system::Dictionary) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueInterfaceProxy, system::InterfaceProxy) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueFunctionProxy, system::Function) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueSubscription, system::Subscription) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueCallStack, system::CallStack) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueException, system::Exception) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IBoxedValue, system::reflection::BoxedValue) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IBoxedValue::CompareResult, system::reflection::ValueType::CompareResult) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IValueType, system::reflection::ValueType) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IEnumType, system::reflection::EnumType) IMPL_TYPE_INFO_RENAME(vl::reflection::description::ISerializableType, system::reflection::SerializableType) IMPL_TYPE_INFO_RENAME(vl::reflection::description::ITypeInfo, system::reflection::TypeInfo) IMPL_TYPE_INFO_RENAME(vl::reflection::description::ITypeInfo::Decorator, system::reflection::TypeInfo::Decorator) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IMemberInfo, system::reflection::MemberInfo) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IEventHandler, system::reflection::EventHandler) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IEventInfo, system::reflection::EventInfo) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IPropertyInfo, system::reflection::PropertyInfo) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IParameterInfo, system::reflection::ParameterInfo) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IMethodInfo, system::reflection::MethodInfo) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IMethodGroupInfo, system::reflection::MethodGroupInfo) IMPL_TYPE_INFO_RENAME(vl::reflection::description::TypeDescriptorFlags, system::reflection::TypeDescriptorFlags) IMPL_TYPE_INFO_RENAME(vl::reflection::description::ITypeDescriptor, system::reflection::TypeDescriptor) #endif /*********************************************************************** TypedValueSerializerProvider ***********************************************************************/ #define DEFINE_COMPARE(TYPENAME)\ IBoxedValue::CompareResult TypedValueSerializerProvider::Compare(const TYPENAME& a, const TYPENAME& b)\ {\ if (a < b) return IBoxedValue::Smaller;\ if (a > b) return IBoxedValue::Greater;\ return IBoxedValue::Equal;\ }\ REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_COMPARE) #undef DEFINE_COMPARE vuint8_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const vuint8_t& input, WString& output) { output = u64tow(input); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, vuint8_t& output) { bool success = false; vuint64_t result = wtou64_test(input, success); if (!success) return false; if (result>_UI8_MAX) return false; output = (vuint8_t)result; return true; } //--------------------------------------- vuint16_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const vuint16_t& input, WString& output) { output = u64tow(input); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, vuint16_t& output) { bool success = false; vuint64_t result = wtou64_test(input, success); if (!success) return false; if (result>_UI16_MAX) return false; output = (vuint16_t)result; return true; } //--------------------------------------- vuint32_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const vuint32_t& input, WString& output) { output = u64tow(input); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, vuint32_t& output) { bool success = false; vuint64_t result = wtou64_test(input, success); if (!success) return false; if (result>_UI32_MAX) return false; output = (vuint32_t)result; return true; } //--------------------------------------- vuint64_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const vuint64_t& input, WString& output) { output = u64tow(input); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, vuint64_t& output) { bool success = false; vuint64_t result = wtou64_test(input, success); if (!success) return false; output = result; return true; } //--------------------------------------- vint8_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const vint8_t& input, WString& output) { output = i64tow(input); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, vint8_t& output) { bool success = false; vint64_t result = wtoi64_test(input, success); if (!success) return false; if (result<_I8_MIN || result>_I8_MAX) return false; output = (vint8_t)result; return true; } //--------------------------------------- vint16_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const vint16_t& input, WString& output) { output = i64tow(input); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, vint16_t& output) { bool success = false; vint64_t result = wtoi64_test(input, success); if (!success) return false; if (result<_I16_MIN || result>_I16_MAX) return false; output = (vint16_t)result; return true; } //--------------------------------------- vint32_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const vint32_t& input, WString& output) { output = i64tow(input); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, vint32_t& output) { bool success = false; vint64_t result = wtoi64_test(input, success); if (!success) return false; if (result<_I32_MIN || result>_I32_MAX) return false; output = (vint32_t)result; return true; } //--------------------------------------- vint64_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const vint64_t& input, WString& output) { output = i64tow(input); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, vint64_t& output) { bool success = false; vint64_t result = wtoi64_test(input, success); if (!success) return false; output = result; return true; } //--------------------------------------- float TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const float& input, WString& output) { output = ftow(input); if (output == L"-0") output = L"0"; return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, float& output) { bool success = false; double result = wtof_test(input, success); if (!success) return false; if (result<-FLT_MAX || result>FLT_MAX) return false; output = (float)result; return true; } //--------------------------------------- double TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const double& input, WString& output) { output = ftow(input); if (output == L"-0") output = L"0"; return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, double& output) { bool success = false; double result = wtof_test(input, success); if (!success) return false; output = result; return true; } //--------------------------------------- wchar_t TypedValueSerializerProvider::GetDefaultValue() { return 0; } bool TypedValueSerializerProvider::Serialize(const wchar_t& input, WString& output) { output = input ? WString(input) : L""; return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, wchar_t& output) { if (input.Length()>1) return false; output = input.Length() == 0 ? 0 : input[0]; return true; } //--------------------------------------- WString TypedValueSerializerProvider::GetDefaultValue() { return L""; } bool TypedValueSerializerProvider::Serialize(const WString& input, WString& output) { output = input; return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, WString& output) { output = input; return true; } //--------------------------------------- bool TypedValueSerializerProvider::GetDefaultValue() { return false; } bool TypedValueSerializerProvider::Serialize(const bool& input, WString& output) { output = input ? L"true" : L"false"; return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, bool& output) { output = input == L"true"; return input == L"true" || input == L"false"; } //--------------------------------------- Locale TypedValueSerializerProvider::GetDefaultValue() { return Locale(); } bool TypedValueSerializerProvider::Serialize(const Locale& input, WString& output) { output = input.GetName(); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, Locale& output) { output = Locale(input); return true; } /*********************************************************************** DateTimeValueSerializer ***********************************************************************/ BEGIN_GLOBAL_STORAGE_CLASS(DateTimeSerializerStorage) Regex* regexDateTime = nullptr; INITIALIZE_GLOBAL_STORAGE_CLASS regexDateTime = new Regex(L"(/d/d/d/d)-(/d/d)-(/d/d) (/d/d):(/d/d):(/d/d).(/d/d/d)"); FINALIZE_GLOBAL_STORAGE_CLASS delete regexDateTime; regexDateTime = nullptr; END_GLOBAL_STORAGE_CLASS(DateTimeSerializerStorage) DateTime TypedValueSerializerProvider::GetDefaultValue() { return DateTime(); } WString FormatDigits(vint number, vint length) { WString result = itow(number); while (result.Length() < length) { result = L"0" + result; } return result; } bool TypedValueSerializerProvider::Serialize(const DateTime& input, WString& output) { output = FormatDigits(input.year, 4) + L"-" + FormatDigits(input.month, 2) + L"-" + FormatDigits(input.day, 2) + L" " + FormatDigits(input.hour, 2) + L":" + FormatDigits(input.minute, 2) + L":" + FormatDigits(input.second, 2) + L"." + FormatDigits(input.milliseconds, 3); return true; } bool TypedValueSerializerProvider::Deserialize(const WString& input, DateTime& output) { Ptr match = GetDateTimeSerializerStorage().regexDateTime->Match(input); if (!match) return false; if (!match->Success()) return false; if (match->Result().Start() != 0) return false; if (match->Result().Length() != input.Length()) return false; vint year = wtoi(match->Groups()[L"Y"].Get(0).Value()); vint month = wtoi(match->Groups()[L"M"].Get(0).Value()); vint day = wtoi(match->Groups()[L"D"].Get(0).Value()); vint hour = wtoi(match->Groups()[L"h"].Get(0).Value()); vint minute = wtoi(match->Groups()[L"m"].Get(0).Value()); vint second = wtoi(match->Groups()[L"s"].Get(0).Value()); vint milliseconds = wtoi(match->Groups()[L"ms"].Get(0).Value()); output = DateTime::FromDateTime(year, month, day, hour, minute, second, milliseconds); return true; } IBoxedValue::CompareResult TypedValueSerializerProvider::Compare(const DateTime& a, const DateTime& b) { auto ta = a.filetime; auto tb = b.filetime; if (ta < tb) return IBoxedValue::Smaller; if (ta > tb) return IBoxedValue::Greater; return IBoxedValue::Equal; } /*********************************************************************** Helper Functions ***********************************************************************/ #ifndef VCZH_DEBUG_NO_REFLECTION vint ITypeDescriptor_GetTypeDescriptorCount() { return GetGlobalTypeManager()->GetTypeDescriptorCount(); } ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(vint index) { return GetGlobalTypeManager()->GetTypeDescriptor(index); } ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(const WString& name) { return GetGlobalTypeManager()->GetTypeDescriptor(name); } ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(const Value& value) { return value.GetTypeDescriptor(); } #else vint ITypeDescriptor_GetTypeDescriptorCount() { return 0; } ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(vint index) { return nullptr; } ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(const WString& name) { return nullptr; } ITypeDescriptor* ITypeDescriptor_GetTypeDescriptor(const Value& value) { return nullptr; } #endif /*********************************************************************** LoadPredefinedTypes ***********************************************************************/ #ifndef VCZH_DEBUG_NO_REFLECTION #define _ , template<> struct CustomTypeDescriptorSelector { public: class CustomTypeDescriptorImpl : public TypeDescriptorImpl { public: CustomTypeDescriptorImpl() :TypeDescriptorImpl(TypeDescriptorFlags::Class, &TypeInfo::content) { Description::SetAssociatedTypeDescroptor(this); } ~CustomTypeDescriptorImpl() { Description::SetAssociatedTypeDescroptor(0); } protected: void LoadInternal()override { } }; }; BEGIN_STRUCT_MEMBER_FLAG(VoidValue, TypeDescriptorFlags::Primitive) END_STRUCT_MEMBER(VoidValue) BEGIN_INTERFACE_MEMBER_NOPROXY_FLAG(IDescriptable, TypeDescriptorFlags::IDescriptable) END_INTERFACE_MEMBER(IDescriptable) BEGIN_STRUCT_MEMBER(DateTime) valueType = new SerializableValueType(); serializableType = new SerializableType(); STRUCT_MEMBER(year) STRUCT_MEMBER(month) STRUCT_MEMBER(dayOfWeek) STRUCT_MEMBER(day) STRUCT_MEMBER(hour) STRUCT_MEMBER(minute) STRUCT_MEMBER(second) STRUCT_MEMBER(milliseconds) STRUCT_MEMBER(totalMilliseconds) STRUCT_MEMBER(filetime) END_STRUCT_MEMBER(DateTime) BEGIN_INTERFACE_MEMBER(IValueEnumerator) CLASS_MEMBER_PROPERTY_READONLY_FAST(Current) CLASS_MEMBER_PROPERTY_READONLY_FAST(Index) CLASS_MEMBER_METHOD(Next, NO_PARAMETER) END_INTERFACE_MEMBER(IValueEnumerator) BEGIN_INTERFACE_MEMBER(IValueEnumerable) CLASS_MEMBER_METHOD(CreateEnumerator, NO_PARAMETER) END_INTERFACE_MEMBER(IValueEnumerable) BEGIN_INTERFACE_MEMBER(IValueReadonlyList) CLASS_MEMBER_BASE(IValueEnumerable) CLASS_MEMBER_PROPERTY_READONLY_FAST(Count) CLASS_MEMBER_METHOD(Get, { L"index" }) CLASS_MEMBER_METHOD(Contains, { L"value" }) CLASS_MEMBER_METHOD(IndexOf, { L"value" }) END_INTERFACE_MEMBER(IValueReadonlyList) BEGIN_INTERFACE_MEMBER(IValueList) CLASS_MEMBER_BASE(IValueReadonlyList) CLASS_MEMBER_EXTERNALCTOR(Ptr(), NO_PARAMETER, vl::reflection::description::IValueList::Create) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), { L"values" }, vl::reflection::description::IValueList::Create) CLASS_MEMBER_METHOD(Set, { L"index" _ L"value" }) CLASS_MEMBER_METHOD(Add, { L"value" }) CLASS_MEMBER_METHOD(Insert, { L"index" _ L"value" }) CLASS_MEMBER_METHOD(Remove, { L"value" }) CLASS_MEMBER_METHOD(RemoveAt, { L"index" }) CLASS_MEMBER_METHOD(Clear, NO_PARAMETER) END_INTERFACE_MEMBER(IValueList) BEGIN_INTERFACE_MEMBER(IValueObservableList) CLASS_MEMBER_BASE(IValueList) CLASS_MEMBER_EXTERNALCTOR(Ptr(), NO_PARAMETER, vl::reflection::description::IValueObservableList::Create) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), { L"values" }, vl::reflection::description::IValueObservableList::Create) CLASS_MEMBER_EVENT(ItemChanged) END_INTERFACE_MEMBER(IValueObservableList) BEGIN_INTERFACE_MEMBER(IValueReadonlyDictionary) CLASS_MEMBER_PROPERTY_READONLY_FAST(Keys) CLASS_MEMBER_PROPERTY_READONLY_FAST(Values) CLASS_MEMBER_PROPERTY_READONLY_FAST(Count) CLASS_MEMBER_METHOD(Get, { L"key" }) END_INTERFACE_MEMBER(IValueReadonlyDictionary) BEGIN_INTERFACE_MEMBER(IValueDictionary) CLASS_MEMBER_BASE(IValueReadonlyDictionary) CLASS_MEMBER_EXTERNALCTOR(Ptr(), NO_PARAMETER, vl::reflection::description::IValueDictionary::Create) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), { L"values" }, vl::reflection::description::IValueDictionary::Create) CLASS_MEMBER_METHOD(Set, { L"key" _ L"value" }) CLASS_MEMBER_METHOD(Remove, { L"key" }) CLASS_MEMBER_METHOD(Clear, NO_PARAMETER) END_INTERFACE_MEMBER(IValueDictionary) BEGIN_INTERFACE_MEMBER_NOPROXY(IValueInterfaceProxy) CLASS_MEMBER_METHOD(Invoke, { L"methodInfo" _ L"arguments" }) END_INTERFACE_MEMBER(IValueInterfaceProxy) BEGIN_INTERFACE_MEMBER_NOPROXY(IValueFunctionProxy) CLASS_MEMBER_METHOD(Invoke, { L"arguments" }) END_INTERFACE_MEMBER(IValueFunctionProxy) BEGIN_INTERFACE_MEMBER(IValueSubscription) CLASS_MEMBER_EVENT(ValueChanged) CLASS_MEMBER_METHOD(Open, NO_PARAMETER) CLASS_MEMBER_METHOD(Update, NO_PARAMETER) CLASS_MEMBER_METHOD(Close, NO_PARAMETER) END_CLASS_MEMBER(IValueSubscription) BEGIN_INTERFACE_MEMBER_NOPROXY(IValueCallStack) CLASS_MEMBER_PROPERTY_READONLY_FAST(LocalVariables) CLASS_MEMBER_PROPERTY_READONLY_FAST(LocalArguments) CLASS_MEMBER_PROPERTY_READONLY_FAST(CapturedVariables) CLASS_MEMBER_PROPERTY_READONLY_FAST(GlobalVariables) CLASS_MEMBER_PROPERTY_READONLY_FAST(FunctionName) CLASS_MEMBER_PROPERTY_READONLY_FAST(SourceCodeBeforeCodegen) CLASS_MEMBER_PROPERTY_READONLY_FAST(SourceCodeAfterCodegen) CLASS_MEMBER_PROPERTY_READONLY_FAST(RowBeforeCodegen) CLASS_MEMBER_PROPERTY_READONLY_FAST(RowAfterCodegen) END_INTERFACE_MEMBER(IValueCallStack) BEGIN_INTERFACE_MEMBER_NOPROXY(IValueException) #pragma push_macro("GetMessage") #if defined GetMessage #undef GetMessage #endif CLASS_MEMBER_PROPERTY_READONLY_FAST(Message) #pragma pop_macro("GetMessage") CLASS_MEMBER_PROPERTY_READONLY_FAST(Fatal) CLASS_MEMBER_PROPERTY_READONLY_FAST(CallStack) END_INTERFACE_MEMBER(IValueException) BEGIN_INTERFACE_MEMBER_NOPROXY(IBoxedValue) CLASS_MEMBER_METHOD(Copy, NO_PARAMETER) END_INTERFACE_MEMBER(IBoxedValue) BEGIN_ENUM_ITEM(IBoxedValue::CompareResult) ENUM_ITEM_NAMESPACE(IBoxedValue) ENUM_NAMESPACE_ITEM(Smaller) ENUM_NAMESPACE_ITEM(Greater) ENUM_NAMESPACE_ITEM(Equal) ENUM_NAMESPACE_ITEM(NotComparable) END_ENUM_ITEM(ITypeInfo::Decorator) BEGIN_INTERFACE_MEMBER_NOPROXY(IValueType) CLASS_MEMBER_METHOD(CreateDefault, NO_PARAMETER) CLASS_MEMBER_METHOD(Compare, { L"a" _ L"b" }) END_INTERFACE_MEMBER(IValueType) BEGIN_INTERFACE_MEMBER_NOPROXY(IEnumType) CLASS_MEMBER_METHOD(IsFlagEnum, NO_PARAMETER) CLASS_MEMBER_METHOD(GetItemCount, NO_PARAMETER) CLASS_MEMBER_METHOD(GetItemName, { L"index" }) CLASS_MEMBER_METHOD(GetItemValue, { L"index" }) CLASS_MEMBER_METHOD(IndexOfItem, { L"name" }) CLASS_MEMBER_METHOD(ToEnum, { L"value" }) CLASS_MEMBER_METHOD(FromEnum, { L"value" }) END_INTERFACE_MEMBER(IEnumType) BEGIN_INTERFACE_MEMBER_NOPROXY(ISerializableType) CLASS_MEMBER_METHOD(Serialize, { L"input" _ L"output" }) CLASS_MEMBER_METHOD(Deserialize, { L"input" _ L"output" }) END_INTERFACE_MEMBER(ISerializableType) BEGIN_INTERFACE_MEMBER_NOPROXY(ITypeInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(Decorator) CLASS_MEMBER_PROPERTY_READONLY_FAST(ElementType) CLASS_MEMBER_PROPERTY_READONLY_FAST(TypeDescriptor) CLASS_MEMBER_PROPERTY_READONLY_FAST(GenericArgumentCount) CLASS_MEMBER_PROPERTY_READONLY_FAST(TypeFriendlyName) CLASS_MEMBER_METHOD(GetGenericArgument, { L"index" }) END_INTERFACE_MEMBER(ITypeInfo) BEGIN_ENUM_ITEM(ITypeInfo::Decorator) ENUM_ITEM_NAMESPACE(ITypeInfo) ENUM_NAMESPACE_ITEM(RawPtr) ENUM_NAMESPACE_ITEM(SharedPtr) ENUM_NAMESPACE_ITEM(Nullable) ENUM_NAMESPACE_ITEM(TypeDescriptor) ENUM_NAMESPACE_ITEM(Generic) END_ENUM_ITEM(ITypeInfo::Decorator) BEGIN_INTERFACE_MEMBER_NOPROXY(IMemberInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerTypeDescriptor) CLASS_MEMBER_PROPERTY_READONLY_FAST(Name) END_INTERFACE_MEMBER(IMemberInfo) BEGIN_INTERFACE_MEMBER_NOPROXY(IEventHandler) CLASS_MEMBER_METHOD(IsAttached, NO_PARAMETER) END_INTERFACE_MEMBER(IEventHandler) BEGIN_INTERFACE_MEMBER_NOPROXY(IEventInfo) CLASS_MEMBER_BASE(IMemberInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(HandlerType) CLASS_MEMBER_PROPERTY_READONLY_FAST(ObservingPropertyCount) CLASS_MEMBER_METHOD(GetObservingProperty, { L"index" }) CLASS_MEMBER_METHOD(Attach, { L"thisObject" _ L"handler" }) CLASS_MEMBER_METHOD(Invoke, { L"thisObject" _ L"arguments" }) END_INTERFACE_MEMBER(IEventInfo) BEGIN_INTERFACE_MEMBER_NOPROXY(IPropertyInfo) CLASS_MEMBER_BASE(IMemberInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(Return) CLASS_MEMBER_PROPERTY_READONLY_FAST(Getter) CLASS_MEMBER_PROPERTY_READONLY_FAST(Setter) CLASS_MEMBER_PROPERTY_READONLY_FAST(ValueChangedEvent) CLASS_MEMBER_METHOD(IsReadable, NO_PARAMETER) CLASS_MEMBER_METHOD(IsWritable, NO_PARAMETER) CLASS_MEMBER_METHOD(GetValue, { L"thisObject" }) CLASS_MEMBER_METHOD(SetValue, { L"thisObject" _ L"newValue" }) END_INTERFACE_MEMBER(IPropertyInfo) BEGIN_INTERFACE_MEMBER_NOPROXY(IParameterInfo) CLASS_MEMBER_BASE(IMemberInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(Type) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerMethod) END_CLASS_MEMBER(IParameterInfo) BEGIN_INTERFACE_MEMBER_NOPROXY(IMethodInfo) CLASS_MEMBER_BASE(IMemberInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerMethodGroup) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerProperty) CLASS_MEMBER_PROPERTY_READONLY_FAST(ParameterCount) CLASS_MEMBER_PROPERTY_READONLY_FAST(Return) CLASS_MEMBER_METHOD(GetParameter, { L"index" }) CLASS_MEMBER_METHOD(IsStatic, NO_PARAMETER) CLASS_MEMBER_METHOD(CheckArguments, { L"arguments" }) CLASS_MEMBER_METHOD(Invoke, { L"thisObject" _ L"arguments" }) CLASS_MEMBER_BASE(IMemberInfo) END_INTERFACE_MEMBER(IMethodInfo) BEGIN_INTERFACE_MEMBER_NOPROXY(IMethodGroupInfo) CLASS_MEMBER_BASE(IMemberInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(MethodCount) CLASS_MEMBER_METHOD(GetMethod, { L"index" }) END_INTERFACE_MEMBER(IMethodGroupInfo) BEGIN_ENUM_ITEM_MERGABLE(TypeDescriptorFlags) ENUM_CLASS_ITEM(Object) ENUM_CLASS_ITEM(IDescriptable) ENUM_CLASS_ITEM(Class) ENUM_CLASS_ITEM(Interface) ENUM_CLASS_ITEM(Primitive) ENUM_CLASS_ITEM(Struct) ENUM_CLASS_ITEM(FlagEnum) ENUM_CLASS_ITEM(NormalEnum) END_ENUM_ITEM(TypeDescriptorFlags) BEGIN_INTERFACE_MEMBER_NOPROXY(ITypeDescriptor) CLASS_MEMBER_PROPERTY_READONLY_FAST(TypeDescriptorFlags) CLASS_MEMBER_PROPERTY_READONLY_FAST(TypeName) CLASS_MEMBER_PROPERTY_READONLY_FAST(ValueType) CLASS_MEMBER_PROPERTY_READONLY_FAST(EnumType) CLASS_MEMBER_PROPERTY_READONLY_FAST(SerializableType) CLASS_MEMBER_PROPERTY_READONLY_FAST(BaseTypeDescriptorCount) CLASS_MEMBER_PROPERTY_READONLY_FAST(PropertyCount) CLASS_MEMBER_PROPERTY_READONLY_FAST(EventCount) CLASS_MEMBER_PROPERTY_READONLY_FAST(MethodGroupCount) CLASS_MEMBER_PROPERTY_READONLY_FAST(ConstructorGroup) CLASS_MEMBER_METHOD(GetBaseTypeDescriptor, { L"index" }) CLASS_MEMBER_METHOD(CanConvertTo, { L"targetType" }) CLASS_MEMBER_METHOD(GetProperty, { L"index" }) CLASS_MEMBER_METHOD(IsPropertyExists, { L"name" _ L"inheritable" }) CLASS_MEMBER_METHOD(GetPropertyByName, { L"name" _ L"inheritable" }) CLASS_MEMBER_METHOD(GetEvent, { L"index" }) CLASS_MEMBER_METHOD(IsEventExists, { L"name" _ L"inheritable" }) CLASS_MEMBER_METHOD(GetEventByName, { L"name" _ L"inheritable" }) CLASS_MEMBER_METHOD(GetMethodGroup, { L"index" }) CLASS_MEMBER_METHOD(IsMethodGroupExists, { L"name" _ L"inheritable" }) CLASS_MEMBER_METHOD(GetMethodGroupByName, { L"name" _ L"inheritable" }) CLASS_MEMBER_STATIC_EXTERNALMETHOD(GetTypeDescriptorCount, NO_PARAMETER, vint(*)(), vl::reflection::description::ITypeDescriptor_GetTypeDescriptorCount) CLASS_MEMBER_STATIC_EXTERNALMETHOD(GetTypeDescriptor, { L"index" }, ITypeDescriptor*(*)(vint), vl::reflection::description::ITypeDescriptor_GetTypeDescriptor) CLASS_MEMBER_STATIC_EXTERNALMETHOD(GetTypeDescriptor, { L"name" }, ITypeDescriptor*(*)(const WString&), vl::reflection::description::ITypeDescriptor_GetTypeDescriptor) CLASS_MEMBER_STATIC_EXTERNALMETHOD(GetTypeDescriptor, { L"value" }, ITypeDescriptor*(*)(const Value&), vl::reflection::description::ITypeDescriptor_GetTypeDescriptor) END_INTERFACE_MEMBER(ITypeDescriptor) #undef _ class PredefinedTypeLoader : public Object, public ITypeLoader { public: void Load(ITypeManager* manager)override { manager->SetTypeDescriptor(TypeInfo::content.typeName, new TypedValueTypeDescriptorBase); #define ADD_PRIMITIVE_TYPE(TYPE) manager->SetTypeDescriptor(TypeInfo::content.typeName, new PrimitiveTypeDescriptor()); REFLECTION_PREDEFINED_PRIMITIVE_TYPES(ADD_PRIMITIVE_TYPE) #undef ADD_PRIMITIVE_TYPE REFLECTION_PREDEFINED_COMPLEX_TYPES(ADD_TYPE_INFO, VoidValue) } void Unload(ITypeManager* manager)override { } }; #endif bool LoadPredefinedTypes() { #ifndef VCZH_DEBUG_NO_REFLECTION ITypeManager* manager = GetGlobalTypeManager(); if (manager) { Ptr loader = new PredefinedTypeLoader; return manager->AddTypeLoader(loader); } #endif return false; } } } } /*********************************************************************** .\REFLECTION\GUITYPEDESCRIPTOR_LOG.CPP ***********************************************************************/ namespace vl { namespace reflection { namespace description { using namespace collections; #ifndef VCZH_DEBUG_NO_REFLECTION /*********************************************************************** LogTypeManager (enum) ***********************************************************************/ void LogTypeManager_Enum(stream::TextWriter& writer, ITypeDescriptor* type) { writer.WriteLine((type->GetTypeDescriptorFlags() == TypeDescriptorFlags::FlagEnum ? L"flags " : L"enum ") + type->GetTypeName()); writer.WriteLine(L"{"); auto enumType = type->GetEnumType(); for (vint j = 0; j < enumType->GetItemCount(); j++) { writer.WriteLine(L" " + enumType->GetItemName(j) + L" = " + u64tow(enumType->GetItemValue(j)) + L","); } writer.WriteLine(L"}"); } /*********************************************************************** LogTypeManager (struct) ***********************************************************************/ void LogTypeManager_Struct(stream::TextWriter& writer, ITypeDescriptor* type) { writer.WriteLine(L"struct " + type->GetTypeName()); writer.WriteLine(L"{"); for (vint j = 0; jGetPropertyCount(); j++) { IPropertyInfo* info = type->GetProperty(j); writer.WriteLine(L" " + info->GetReturn()->GetTypeFriendlyName() + L" " + info->GetName() + L";"); } writer.WriteLine(L"}"); } /*********************************************************************** LogTypeManager (data) ***********************************************************************/ void LogTypeManager_Data(stream::TextWriter& writer, ITypeDescriptor* type) { writer.WriteLine(L"primitive " + type->GetTypeName() + L";"); } /*********************************************************************** LogTypeManager (class) ***********************************************************************/ void LogTypeManager_PrintEvents(stream::TextWriter& writer, ITypeDescriptor* type) { bool printed = false; for (vint j = 0; jGetEventCount(); j++) { printed = true; IEventInfo* info = type->GetEvent(j); writer.WriteString(L" event " + info->GetHandlerType()->GetTypeFriendlyName() + L" " + info->GetName() + L"{"); if (info->GetObservingPropertyCount()>0) { writer.WriteString(L" observing "); vint count = +info->GetObservingPropertyCount(); for (vint i = 0; i0) writer.WriteString(L", "); writer.WriteString(info->GetObservingProperty(i)->GetName()); } writer.WriteString(L";"); } writer.WriteLine(L"};"); } if (printed) { writer.WriteLine(L""); } } void LogTypeManager_PrintProperties(stream::TextWriter& writer, ITypeDescriptor* type, List& propertyAccessors) { bool printed = false; for (vint j = 0; jGetPropertyCount(); j++) { printed = true; IPropertyInfo* info = type->GetProperty(j); writer.WriteString(L" property " + info->GetReturn()->GetTypeFriendlyName() + L" " + info->GetName() + L"{"); if (info->GetGetter()) { propertyAccessors.Add(info->GetGetter()); writer.WriteString(L" getter " + info->GetGetter()->GetName() + L";"); } if (info->GetSetter()) { propertyAccessors.Add(info->GetSetter()); writer.WriteString(L" setter " + info->GetSetter()->GetName() + L";"); } if (info->GetValueChangedEvent()) { writer.WriteString(L" raising " + info->GetValueChangedEvent()->GetName() + L";"); } writer.WriteLine(L"}"); } if (printed) { writer.WriteLine(L""); } } void LogTypeManager_PrintMethods(stream::TextWriter& writer, ITypeDescriptor* type, const List& propertyAccessors, bool isPropertyAccessor) { bool printed = false; for (vint j = 0; jGetMethodGroupCount(); j++) { IMethodGroupInfo* group = type->GetMethodGroup(j); for (vint k = 0; kGetMethodCount(); k++) { IMethodInfo* info = group->GetMethod(k); if (propertyAccessors.Contains(info) == isPropertyAccessor) { printed = true; writer.WriteString(WString(L" ") + (info->IsStatic() ? L"static " : L"") + (isPropertyAccessor ? L"accessor " : L"function ") + info->GetReturn()->GetTypeFriendlyName()); writer.WriteString(L" " + info->GetName() + L"("); for (vint l = 0; lGetParameterCount(); l++) { if (l>0) writer.WriteString(L", "); IParameterInfo* parameter = info->GetParameter(l); writer.WriteString(parameter->GetType()->GetTypeFriendlyName() + L" " + parameter->GetName()); } writer.WriteLine(L");"); } } } if (printed) { writer.WriteLine(L""); } } void LogTypeManager_PrintConstructors(stream::TextWriter& writer, ITypeDescriptor* type) { if (IMethodGroupInfo* group = type->GetConstructorGroup()) { for (vint k = 0; kGetMethodCount(); k++) { IMethodInfo* info = group->GetMethod(k); writer.WriteString(L" constructor " + info->GetReturn()->GetTypeFriendlyName()); writer.WriteString(L" " + info->GetName() + L"("); for (vint l = 0; lGetParameterCount(); l++) { if (l>0) writer.WriteString(L", "); IParameterInfo* parameter = info->GetParameter(l); writer.WriteString(parameter->GetType()->GetTypeFriendlyName() + L" " + parameter->GetName()); } writer.WriteLine(L");"); } } } void LogTypeManager_Class(stream::TextWriter& writer, ITypeDescriptor* type) { bool acceptProxy = false; bool isInterface = (type->GetTypeDescriptorFlags() & TypeDescriptorFlags::InterfaceType) != TypeDescriptorFlags::Undefined; writer.WriteString((isInterface ? L"interface " : L"class ") + type->GetTypeName()); for (vint j = 0; jGetBaseTypeDescriptorCount(); j++) { writer.WriteString(j == 0 ? L" : " : L", "); writer.WriteString(type->GetBaseTypeDescriptor(j)->GetTypeName()); } writer.WriteLine(L""); writer.WriteLine(L"{"); List propertyAccessors; LogTypeManager_PrintEvents(writer, type); LogTypeManager_PrintProperties(writer, type, propertyAccessors); LogTypeManager_PrintMethods(writer, type, propertyAccessors, false); LogTypeManager_PrintMethods(writer, type, propertyAccessors, true); LogTypeManager_PrintConstructors(writer, type); writer.WriteLine(L"}"); } /*********************************************************************** LogTypeManager ***********************************************************************/ bool IsInterfaceType(ITypeDescriptor* typeDescriptor, bool& acceptProxy) { bool containsConstructor = false; if (IMethodGroupInfo* group = typeDescriptor->GetConstructorGroup()) { containsConstructor = group->GetMethodCount() > 0; if (group->GetMethodCount() == 1) { if (IMethodInfo* info = group->GetMethod(0)) { if (info->GetParameterCount() == 1 && info->GetParameter(0)->GetType()->GetTypeDescriptor()->GetTypeName() == TypeInfo::content.typeName) { acceptProxy = true; return true; } } } } if (!containsConstructor) { if (typeDescriptor->GetTypeName() == TypeInfo::content.typeName) { return true; } else { for (vint i = 0; i < typeDescriptor->GetBaseTypeDescriptorCount(); i++) { bool _acceptProxy = false; if (!IsInterfaceType(typeDescriptor->GetBaseTypeDescriptor(i), _acceptProxy)) { return false; } } const wchar_t* name = typeDescriptor->GetTypeName().Buffer(); while (const wchar_t* next = ::wcschr(name, L':')) { name = next + 1; } return name[0] == L'I' && (L'A' <= name[1] && name[1] <= L'Z'); } } return false; } void LogTypeManager(stream::TextWriter& writer) { for (vint i = 0; i < GetGlobalTypeManager()->GetTypeDescriptorCount(); i++) { ITypeDescriptor* type = GetGlobalTypeManager()->GetTypeDescriptor(i); switch (type->GetTypeDescriptorFlags()) { case TypeDescriptorFlags::Object: case TypeDescriptorFlags::IDescriptable: case TypeDescriptorFlags::Class: case TypeDescriptorFlags::Interface: LogTypeManager_Class(writer, type); break; case TypeDescriptorFlags::FlagEnum: case TypeDescriptorFlags::NormalEnum: LogTypeManager_Enum(writer, type); break; case TypeDescriptorFlags::Primitive: LogTypeManager_Data(writer, type); break; case TypeDescriptorFlags::Struct: LogTypeManager_Struct(writer, type); break; default:; } writer.WriteLine(L""); } } #endif } } } /*********************************************************************** .\REGEX\REGEX.CPP ***********************************************************************/ namespace vl { namespace regex { using namespace collections; using namespace regex_internal; /*********************************************************************** RegexString ***********************************************************************/ RegexString::RegexString(vint _start) :start(_start) ,length(0) { } RegexString::RegexString(const WString& _string, vint _start, vint _length) :value(_length==0?L"":_string.Sub(_start, _length)) ,start(_start) ,length(_length) { } vint RegexString::Start()const { return start; } vint RegexString::Length()const { return length; } const WString& RegexString::Value()const { return value; } bool RegexString::operator==(const RegexString& string)const { return start==string.start && length==string.length && value==string.value; } /*********************************************************************** RegexMatch ***********************************************************************/ RegexMatch::RegexMatch(const WString& _string, PureResult* _result) :success(true) ,result(_string, _result->start, _result->length) { } RegexMatch::RegexMatch(const WString& _string, RichResult* _result, RichInterpretor* _rich) :success(true) ,result(_string, _result->start, _result->length) { for(vint i=0;i<_result->captures.Count();i++) { CaptureRecord& capture=_result->captures[i]; if(capture.capture==-1) { captures.Add(RegexString(_string, capture.start, capture.length)); } else { groups.Add(_rich->CaptureNames().Get(capture.capture), RegexString(_string, capture.start, capture.length)); } } } RegexMatch::RegexMatch(const RegexString& _result) :success(false) ,result(_result) { } bool RegexMatch::Success()const { return success; } const RegexString& RegexMatch::Result()const { return result; } const RegexMatch::CaptureList& RegexMatch::Captures()const { return captures; } const RegexMatch::CaptureGroup& RegexMatch::Groups()const { return groups; } /*********************************************************************** Regex ***********************************************************************/ void Regex::Process(const WString& text, bool keepEmpty, bool keepSuccess, bool keepFail, RegexMatch::List& matches)const { if(rich) { const wchar_t* start=text.Buffer(); const wchar_t* input=start; RichResult result; while(rich->Match(input, start, result)) { vint offset=input-start; if(keepFail) { if(result.start>offset || keepEmpty) { matches.Add(new RegexMatch(RegexString(text, offset, result.start-offset))); } } if(keepSuccess) { matches.Add(new RegexMatch(text, &result, rich)); } input=start+result.start+result.length; } if(keepFail) { vint remain=input-start; vint length=text.Length()-remain; if(length || keepEmpty) { matches.Add(new RegexMatch(RegexString(text, remain, length))); } } } else { const wchar_t* start=text.Buffer(); const wchar_t* input=start; PureResult result; while(pure->Match(input, start, result)) { vint offset=input-start; if(keepFail) { if(result.start>offset || keepEmpty) { matches.Add(new RegexMatch(RegexString(text, offset, result.start-offset))); } } if(keepSuccess) { matches.Add(new RegexMatch(text, &result)); } input=start+result.start+result.length; } if(keepFail) { vint remain=input-start; vint length=text.Length()-remain; if(length || keepEmpty) { matches.Add(new RegexMatch(RegexString(text, remain, length))); } } } } Regex::Regex(const WString& code, bool preferPure) :pure(0) ,rich(0) { CharRange::List subsets; RegexExpression::Ref regex=ParseRegexExpression(code); Expression::Ref expression=regex->Merge(); expression->NormalizeCharSet(subsets); bool pureRequired=false; bool richRequired=false; if(preferPure) { if(expression->HasNoExtension()) { pureRequired=true; } else { if(expression->CanTreatAsPure()) { pureRequired=true; richRequired=true; } else { richRequired=true; } } } else { richRequired=true; } try { if(pureRequired) { Dictionary nfaStateMap; Group dfaStateMap; Automaton::Ref eNfa=expression->GenerateEpsilonNfa(); Automaton::Ref nfa=EpsilonNfaToNfa(eNfa, PureEpsilonChecker, nfaStateMap); Automaton::Ref dfa=NfaToDfa(nfa, dfaStateMap); pure=new PureInterpretor(dfa, subsets); } if(richRequired) { Dictionary nfaStateMap; Group dfaStateMap; Automaton::Ref eNfa=expression->GenerateEpsilonNfa(); Automaton::Ref nfa=EpsilonNfaToNfa(eNfa, RichEpsilonChecker, nfaStateMap); Automaton::Ref dfa=NfaToDfa(nfa, dfaStateMap); rich=new RichInterpretor(dfa); } } catch(...) { if(pure)delete pure; if(rich)delete rich; throw; } } Regex::~Regex() { if(pure)delete pure; if(rich)delete rich; } bool Regex::IsPureMatch()const { return rich?false:true; } bool Regex::IsPureTest()const { return pure?true:false; } RegexMatch::Ref Regex::MatchHead(const WString& text)const { if(rich) { RichResult result; if(rich->MatchHead(text.Buffer(), text.Buffer(), result)) { return new RegexMatch(text, &result, rich); } else { return 0; } } else { PureResult result; if(pure->MatchHead(text.Buffer(), text.Buffer(), result)) { return new RegexMatch(text, &result); } else { return 0; } } } RegexMatch::Ref Regex::Match(const WString& text)const { if(rich) { RichResult result; if(rich->Match(text.Buffer(), text.Buffer(), result)) { return new RegexMatch(text, &result, rich); } else { return 0; } } else { PureResult result; if(pure->Match(text.Buffer(), text.Buffer(), result)) { return new RegexMatch(text, &result); } else { return 0; } } } bool Regex::TestHead(const WString& text)const { if(pure) { PureResult result; return pure->MatchHead(text.Buffer(), text.Buffer(), result); } else { RichResult result; return rich->MatchHead(text.Buffer(), text.Buffer(), result); } } bool Regex::Test(const WString& text)const { if(pure) { PureResult result; return pure->Match(text.Buffer(), text.Buffer(), result); } else { RichResult result; return rich->Match(text.Buffer(), text.Buffer(), result); } } void Regex::Search(const WString& text, RegexMatch::List& matches)const { Process(text, false, true, false, matches); } void Regex::Split(const WString& text, bool keepEmptyMatch, RegexMatch::List& matches)const { Process(text, keepEmptyMatch, false, true, matches); } void Regex::Cut(const WString& text, bool keepEmptyMatch, RegexMatch::List& matches)const { Process(text, keepEmptyMatch, true, true, matches); } /*********************************************************************** RegexTokens ***********************************************************************/ bool RegexToken::operator==(const RegexToken& _token)const { return length==_token.length && token==_token.token && reading==_token.reading; } bool RegexToken::operator==(const wchar_t* _token)const { return wcslen(_token)==length && wcsncmp(reading, _token, length)==0; } class RegexTokenEnumerator : public Object, public IEnumerator { protected: RegexToken token; vint index; PureInterpretor* pure; const Array& stateTokens; const wchar_t* start; vint codeIndex; const wchar_t* reading; vint rowStart; vint columnStart; bool cacheAvailable; RegexToken cacheToken; public: RegexTokenEnumerator(const RegexTokenEnumerator& enumerator) :token(enumerator.token) ,index(enumerator.index) ,pure(enumerator.pure) ,stateTokens(enumerator.stateTokens) ,reading(enumerator.reading) ,start(enumerator.start) ,rowStart(enumerator.rowStart) ,columnStart(enumerator.columnStart) ,codeIndex(enumerator.codeIndex) ,cacheAvailable(enumerator.cacheAvailable) ,cacheToken(enumerator.cacheToken) { } RegexTokenEnumerator(PureInterpretor* _pure, const Array& _stateTokens, const wchar_t* _start, vint _codeIndex) :index(-1) ,pure(_pure) ,stateTokens(_stateTokens) ,reading(_start) ,start(_start) ,rowStart(0) ,columnStart(0) ,codeIndex(_codeIndex) ,cacheAvailable(false) { } IEnumerator* Clone()const { return new RegexTokenEnumerator(*this); } const RegexToken& Current()const { return token; } vint Index()const { return index; } bool Next() { if(!cacheAvailable && !*reading) return false; if(cacheAvailable) { token=cacheToken; cacheAvailable=false; } else { token.reading=reading; token.start=0; token.length=0; token.token=-2; token.completeToken=true; } token.rowStart=rowStart; token.columnStart=columnStart; token.rowEnd=rowStart; token.columnEnd=columnStart; token.codeIndex=codeIndex; PureResult result; while(*reading) { vint id=-1; bool completeToken=true; if(!pure->MatchHead(reading, start, result)) { result.start=reading-start; if(id==-1 && result.terminateState!=-1) { vint state=pure->GetRelatedFinalState(result.terminateState); if(state!=-1) { id=stateTokens[state]; } } if(id==-1) { result.length=1; } else { completeToken=false; } } else { id=stateTokens.Get(result.finalState); } if(token.token==-2) { token.start=result.start; token.length=result.length; token.token=id; token.completeToken=completeToken; } else if(token.token==id && id==-1) { token.length+=result.length; } else { cacheAvailable=true; cacheToken.reading=reading; cacheToken.start=result.start; cacheToken.length=result.length; cacheToken.codeIndex=codeIndex; cacheToken.token=id; cacheToken.completeToken=completeToken; } reading+=result.length; if(cacheAvailable) { break; } } index++; for(vint i=0;i& tokens, bool(*discard)(vint)) { while(Next()) { if(!discard(token.token)) { tokens.Add(token); } } } }; RegexTokens::RegexTokens(PureInterpretor* _pure, const Array& _stateTokens, const WString& _code, vint _codeIndex) :pure(_pure) ,stateTokens(_stateTokens) ,code(_code) ,codeIndex(_codeIndex) { } RegexTokens::RegexTokens(const RegexTokens& tokens) :pure(tokens.pure) ,stateTokens(tokens.stateTokens) ,code(tokens.code) ,codeIndex(tokens.codeIndex) { } IEnumerator* RegexTokens::CreateEnumerator()const { return new RegexTokenEnumerator(pure, stateTokens, code.Buffer(), codeIndex); } bool DefaultDiscard(vint token) { return false; } void RegexTokens::ReadToEnd(collections::List& tokens, bool(*discard)(vint))const { if(discard==0) { discard=&DefaultDiscard; } RegexTokenEnumerator(pure, stateTokens, code.Buffer(), codeIndex).ReadToEnd(tokens, discard); } /*********************************************************************** RegexLexerWalker ***********************************************************************/ RegexLexerWalker::RegexLexerWalker(PureInterpretor* _pure, const Array& _stateTokens) :pure(_pure) ,stateTokens(_stateTokens) { } RegexLexerWalker::RegexLexerWalker(const RegexLexerWalker& walker) :pure(walker.pure) ,stateTokens(walker.stateTokens) { } RegexLexerWalker::~RegexLexerWalker() { } vint RegexLexerWalker::GetStartState()const { return pure->GetStartState(); } vint RegexLexerWalker::GetRelatedToken(vint state)const { vint finalState=pure->GetRelatedFinalState(state); return finalState==-1?-1:stateTokens.Get(finalState); } void RegexLexerWalker::Walk(wchar_t input, vint& state, vint& token, bool& finalState, bool& previousTokenStop)const { vint previousState=state; token=-1; finalState=false; previousTokenStop=false; if(state==-1) { state=pure->GetStartState(); previousTokenStop=true; } state=pure->Transit(input, state); if(state==-1) { previousTokenStop=true; if(previousState==-1) { finalState=true; return; } else if(pure->IsFinalState(previousState)) { state=pure->Transit(input, pure->GetStartState()); } } if(pure->IsFinalState(state)) { token=stateTokens.Get(state); finalState=true; return; } else { finalState=state==-1; return; } } vint RegexLexerWalker::Walk(wchar_t input, vint state)const { vint token=-1; bool finalState=false; bool previousTokenStop=false; Walk(input, state, token, finalState, previousTokenStop); return state; } bool RegexLexerWalker::IsClosedToken(const wchar_t* input, vint length)const { vint state=pure->GetStartState(); for(vint i=0;iTransit(input[i], state); if(state==-1) return true; if(pure->IsDeadState(state)) return true; } return false; } bool RegexLexerWalker::IsClosedToken(const WString& input)const { return IsClosedToken(input.Buffer(), input.Length()); } /*********************************************************************** RegexLexerColorizer ***********************************************************************/ RegexLexerColorizer::RegexLexerColorizer(const RegexLexerWalker& _walker) :walker(_walker) ,currentState(_walker.GetStartState()) { } RegexLexerColorizer::RegexLexerColorizer(const RegexLexerColorizer& colorizer) :walker(colorizer.walker) ,currentState(colorizer.currentState) { } RegexLexerColorizer::~RegexLexerColorizer() { } void RegexLexerColorizer::Reset(vint state) { currentState=state; } void RegexLexerColorizer::Pass(wchar_t input) { currentState=walker.Walk(input, currentState); } vint RegexLexerColorizer::GetStartState()const { return walker.GetStartState(); } vint RegexLexerColorizer::GetCurrentState()const { return currentState; } void RegexLexerColorizer::Colorize(const wchar_t* input, vint length, TokenProc tokenProc, void* tokenProcArgument) { vint start=0; vint stop=0; vint state=-1; vint token=-1; vint index=0; vint currentToken=-1; bool finalState=false; bool previousTokenStop=false; while(index0) { tokenProc(tokenProcArgument, start, tokenLength, token); currentState=state; start=stop; index=stop-1; state=-1; token=-1; finalState=false; } else if(stop& tokens) :pure(0) { // Build DFA for all tokens List expressions; List dfas; CharRange::List subsets; Ptr> enumerator=tokens.CreateEnumerator(); while(enumerator->Next()) { const WString& code=enumerator->Current(); RegexExpression::Ref regex=ParseRegexExpression(code); Expression::Ref expression=regex->Merge(); expression->CollectCharSet(subsets); expressions.Add(expression); } for(vint i=0;i nfaStateMap; Group dfaStateMap; Expression::Ref expression=expressions[i]; expression->ApplyCharSet(subsets); Automaton::Ref eNfa=expression->GenerateEpsilonNfa(); Automaton::Ref nfa=EpsilonNfaToNfa(eNfa, PureEpsilonChecker, nfaStateMap); Automaton::Ref dfa=NfaToDfa(nfa, dfaStateMap); dfas.Add(dfa); } // Mark all states in DFAs for(vint i=0;istates.Count();j++) { if(dfa->states[j]->finalState) { dfa->states[j]->userData=(void*)i; } else { dfa->states[j]->userData=(void*)dfas.Count(); } } } // Connect all DFAs to an e-NFA Automaton::Ref bigEnfa=new Automaton; for(vint i=0;istates, dfas[i]->states); CopyFrom(bigEnfa->transitions, dfas[i]->transitions); } bigEnfa->startState=bigEnfa->NewState(); for(vint i=0;iNewEpsilon(bigEnfa->startState, dfas[i]->startState); } // Build a single DFA out of the e-NFA Dictionary nfaStateMap; Group dfaStateMap; Automaton::Ref bigNfa=EpsilonNfaToNfa(bigEnfa, PureEpsilonChecker, nfaStateMap); for(vint i=0;iuserData; nfaStateMap.Keys()[i]->userData=userData; } Automaton::Ref bigDfa=NfaToDfa(bigNfa, dfaStateMap); for(vint i=0;iuserData; for(vint j=1;juserData; if(userData>newData) { userData=newData; } } dfaStateMap.Keys()[i]->userData=userData; } // Build state machine pure=new PureInterpretor(bigDfa, subsets); stateTokens.Resize(bigDfa->states.Count()); for(vint i=0;istates[i]->userData; stateTokens[i]=(vint)userData; } } RegexLexer::~RegexLexer() { if(pure)delete pure; } RegexTokens RegexLexer::Parse(const WString& code, vint codeIndex)const { pure->PrepareForRelatedFinalStateTable(); return RegexTokens(pure, stateTokens, code, codeIndex); } RegexLexerWalker RegexLexer::Walk()const { pure->PrepareForRelatedFinalStateTable(); return RegexLexerWalker(pure, stateTokens); } RegexLexerColorizer RegexLexer::Colorize()const { return RegexLexerColorizer(Walk()); } } } /*********************************************************************** .\REGEX\REGEXAUTOMATON.CPP ***********************************************************************/ namespace vl { namespace regex_internal { using namespace collections; /*********************************************************************** Automaton ***********************************************************************/ Automaton::Automaton() { startState=0; } State* Automaton::NewState() { State* state=new State; state->finalState=false; state->userData=0; states.Add(state); return state; } Transition* Automaton::NewTransition(State* start, State* end) { Transition* transition=new Transition; transition->source=start; transition->target=end; start->transitions.Add(transition); end->inputs.Add(transition); transitions.Add(transition); return transition; } Transition* Automaton::NewChars(State* start, State* end, CharRange range) { Transition* transition=NewTransition(start, end); transition->type=Transition::Chars; transition->range=range; return transition; } Transition* Automaton::NewEpsilon(State* start, State* end) { Transition* transition=NewTransition(start, end); transition->type=Transition::Epsilon; return transition; } Transition* Automaton::NewBeginString(State* start, State* end) { Transition* transition=NewTransition(start, end); transition->type=Transition::BeginString; return transition; } Transition* Automaton::NewEndString(State* start, State* end) { Transition* transition=NewTransition(start, end); transition->type=Transition::EndString; return transition; } Transition* Automaton::NewNop(State* start, State* end) { Transition* transition=NewTransition(start, end); transition->type=Transition::Nop; return transition; } Transition* Automaton::NewCapture(State* start, State* end, vint capture) { Transition* transition=NewTransition(start, end); transition->type=Transition::Capture; transition->capture=capture; return transition; } Transition* Automaton::NewMatch(State* start, State* end, vint capture, vint index) { Transition* transition=NewTransition(start, end); transition->type=Transition::Match; transition->capture=capture; transition->index=index; return transition; } Transition* Automaton::NewPositive(State* start, State* end) { Transition* transition=NewTransition(start, end); transition->type=Transition::Positive; return transition; } Transition* Automaton::NewNegative(State* start, State* end) { Transition* transition=NewTransition(start, end); transition->type=Transition::Negative; return transition; } Transition* Automaton::NewNegativeFail(State* start, State* end) { Transition* transition=NewTransition(start, end); transition->type=Transition::NegativeFail; return transition; } Transition* Automaton::NewEnd(State* start, State* end) { Transition* transition=NewTransition(start, end); transition->type=Transition::End; return transition; } /*********************************************************************** Helpers ***********************************************************************/ bool PureEpsilonChecker(Transition* transition) { switch(transition->type) { case Transition::Epsilon: case Transition::Nop: case Transition::Capture: case Transition::End: return true; default: return false; } } bool RichEpsilonChecker(Transition* transition) { switch(transition->type) { case Transition::Epsilon: return true; default: return false; } } bool AreEqual(Transition* transA, Transition* transB) { if(transA->type!=transB->type)return false; switch(transA->type) { case Transition::Chars: return transA->range==transB->range; case Transition::Capture: return transA->capture==transB->capture; case Transition::Match: return transA->capture==transB->capture && transA->index==transB->index; default: return true; } } // Collect epsilon states and non-epsilon transitions, their order are maintained to match the e-NFA void CollectEpsilon(State* targetState, State* sourceState, bool(*epsilonChecker)(Transition*), List& epsilonStates, List& transitions) { if(!epsilonStates.Contains(sourceState)) { epsilonStates.Add(sourceState); for(vint i=0;itransitions.Count();i++) { Transition* transition=sourceState->transitions[i]; if(epsilonChecker(transition)) { if(!epsilonStates.Contains(transition->target)) { if(transition->target->finalState) { targetState->finalState=true; } CollectEpsilon(targetState, transition->target, epsilonChecker, epsilonStates, transitions); } } else { transitions.Add(transition); } } } } Automaton::Ref EpsilonNfaToNfa(Automaton::Ref source, bool(*epsilonChecker)(Transition*), Dictionary& nfaStateMap) { Automaton::Ref target=new Automaton; Dictionary stateMap; // source->target List epsilonStates; // current epsilon closure List transitions; // current non-epsilon transitions stateMap.Add(source->startState, target->NewState()); nfaStateMap.Add(stateMap[source->startState], source->startState); target->startState=target->states[0].Obj(); CopyFrom(target->captureNames, source->captureNames); for(vint i=0;istates.Count();i++) { // Clear cache State* targetState=target->states[i].Obj(); State* sourceState=nfaStateMap[targetState]; if(sourceState->finalState) { targetState->finalState=true; } epsilonStates.Clear(); transitions.Clear(); // Collect epsilon states and non-epsilon transitions CollectEpsilon(targetState, sourceState, epsilonChecker, epsilonStates, transitions); // Iterate through all non-epsilon transitions for(vint j=0;jtarget)) { stateMap.Add(transition->target, target->NewState()); nfaStateMap.Add(stateMap[transition->target], transition->target); } // Copy transition to connect between two non-epsilon state Transition* newTransition=target->NewTransition(targetState, stateMap[transition->target]); newTransition->capture=transition->capture; newTransition->index=transition->index; newTransition->range=transition->range; newTransition->type=transition->type; } } return target; } Automaton::Ref NfaToDfa(Automaton::Ref source, Group& dfaStateMap) { Automaton::Ref target=new Automaton; Group nfaTransitions; List transitionClasses; // Maintain order for nfaTransitions.Keys CopyFrom(target->captureNames, source->captureNames); State* startState=target->NewState(); target->startState=startState; dfaStateMap.Add(startState, source->startState); SortedList transitionTargets; SortedList relativeStates; transitionTargets.SetLessMemoryMode(false); relativeStates.SetLessMemoryMode(false); for(vint i=0;istates.Count();i++) { State* currentState=target->states[i].Obj(); nfaTransitions.Clear(); transitionClasses.Clear(); // Iterate through all NFA states which represent the DFA state const List& nfaStates=dfaStateMap[currentState]; for(vint j=0;jtransitions.Count();k++) { Transition* nfaTransition=nfaState->transitions[k]; // Check if there is any key in nfaTransitions that has the same input as the current transition Transition* transitionClass=0; for(vint l=0;l& transitionSet=nfaTransitions[transitionClasses[j]]; // Sort all target states and keep unique transitionTargets.Clear(); for(vint l=0;ltarget; if(!transitionTargets.Contains(nfaState)) { transitionTargets.Add(nfaState); } } // Check if these NFA states represent a created DFA state State* dfaState=0; for(vint k=0;kNewState(); for(vint k=0;kfinalState) { dfaState->finalState=true; } } } // Create corresponding DFA transition Transition* transitionClass=transitionClasses[j]; Transition* newTransition=target->NewTransition(currentState, dfaState); newTransition->capture=transitionClass->capture; newTransition->index=transitionClass->index; newTransition->range=transitionClass->range; newTransition->type=transitionClass->type; } } return target; } } } /*********************************************************************** .\REGEX\REGEXDATA.CPP ***********************************************************************/ namespace vl { namespace regex_internal { /*********************************************************************** CharRange ***********************************************************************/ CharRange::CharRange() :begin(L'\0') ,end(L'\0') { } CharRange::CharRange(wchar_t _begin, wchar_t _end) :begin(_begin) ,end(_end) { } bool CharRange::operator<(CharRange item)const { return end(CharRange item)const { return item.end=(CharRange item)const { return *this>item || *this==item; } bool CharRange::operator==(CharRange item)const { return begin==item.begin && end==item.end; } bool CharRange::operator!=(CharRange item)const { return begin!=item.begin || item.end!=end; } bool CharRange::operator<(wchar_t item)const { return end(wchar_t item)const { return item=(wchar_t item)const { return item<=end; } bool CharRange::operator==(wchar_t item)const { return begin<=item && item<=end; } bool CharRange::operator!=(wchar_t item)const { return item { public: bool Apply(CharSetExpression* expression, Expression* target) { CharSetExpression* expected=dynamic_cast(target); if(expected) { if(expression->reverse!=expected->reverse)return false; if(expression->ranges.Count()!=expected->ranges.Count())return false; for(vint i=0;iranges.Count();i++) { if(expression->ranges[i]!=expected->ranges[i])return false; } return true; } return false; } bool Apply(LoopExpression* expression, Expression* target) { LoopExpression* expected=dynamic_cast(target); if(expected) { if(expression->min!=expected->min)return false; if(expression->max!=expected->max)return false; if(expression->preferLong!=expected->preferLong)return false; if(!Invoke(expression->expression, expected->expression.Obj()))return false; return true; } return false; } bool Apply(SequenceExpression* expression, Expression* target) { SequenceExpression* expected=dynamic_cast(target); if(expected) { if(!Invoke(expression->left, expected->left.Obj()))return false; if(!Invoke(expression->right, expected->right.Obj()))return false; return true; } return false; } bool Apply(AlternateExpression* expression, Expression* target) { AlternateExpression* expected=dynamic_cast(target); if(expected) { if(!Invoke(expression->left, expected->left.Obj()))return false; if(!Invoke(expression->right, expected->right.Obj()))return false; return true; } return false; } bool Apply(BeginExpression* expression, Expression* target) { BeginExpression* expected=dynamic_cast(target); if(expected) { return true; } return false; } bool Apply(EndExpression* expression, Expression* target) { EndExpression* expected=dynamic_cast(target); if(expected) { return true; } return false; } bool Apply(CaptureExpression* expression, Expression* target) { CaptureExpression* expected=dynamic_cast(target); if(expected) { if(expression->name!=expected->name)return false; if(!Invoke(expression->expression, expected->expression.Obj()))return false; return true; } return false; } bool Apply(MatchExpression* expression, Expression* target) { MatchExpression* expected=dynamic_cast(target); if(expected) { if(expression->name!=expected->name)return false; if(expression->index!=expected->index)return false; return true; } return false; } bool Apply(PositiveExpression* expression, Expression* target) { PositiveExpression* expected=dynamic_cast(target); if(expected) { if(!Invoke(expression->expression, expected->expression.Obj()))return false; return true; } return false; } bool Apply(NegativeExpression* expression, Expression* target) { NegativeExpression* expected=dynamic_cast(target); if(expected) { if(!Invoke(expression->expression, expected->expression.Obj()))return false; return true; } return false; } bool Apply(UsingExpression* expression, Expression* target) { UsingExpression* expected=dynamic_cast(target); if(expected) { if(expression->name!=expected->name)return false; return true; } return false; } }; /*********************************************************************** HasNoExtensionAlgorithm ***********************************************************************/ class HasNoExtensionAlgorithm : public RegexExpressionAlgorithm { public: bool Apply(CharSetExpression* expression, void* target) { return true; } bool Apply(LoopExpression* expression, void* target) { return expression->preferLong && Invoke(expression->expression, 0); } bool Apply(SequenceExpression* expression, void* target) { return Invoke(expression->left, 0) && Invoke(expression->right, 0); } bool Apply(AlternateExpression* expression, void* target) { return Invoke(expression->left, 0) && Invoke(expression->right, 0); } bool Apply(BeginExpression* expression, void* target) { return false; } bool Apply(EndExpression* expression, void* target) { return false; } bool Apply(CaptureExpression* expression, void* target) { return false; } bool Apply(MatchExpression* expression, void* target) { return false; } bool Apply(PositiveExpression* expression, void* target) { return false; } bool Apply(NegativeExpression* expression, void* target) { return false; } bool Apply(UsingExpression* expression, void* target) { return false; } }; /*********************************************************************** CanTreatAsPureAlgorithm ***********************************************************************/ class CanTreatAsPureAlgorithm : public RegexExpressionAlgorithm { public: bool Apply(CharSetExpression* expression, void* target) { return true; } bool Apply(LoopExpression* expression, void* target) { return expression->preferLong && Invoke(expression->expression, 0); } bool Apply(SequenceExpression* expression, void* target) { return Invoke(expression->left, 0) && Invoke(expression->right, 0); } bool Apply(AlternateExpression* expression, void* target) { return Invoke(expression->left, 0) && Invoke(expression->right, 0); } bool Apply(BeginExpression* expression, void* target) { return false; } bool Apply(EndExpression* expression, void* target) { return false; } bool Apply(CaptureExpression* expression, void* target) { return Invoke(expression->expression, 0); } bool Apply(MatchExpression* expression, void* target) { return false; } bool Apply(PositiveExpression* expression, void* target) { return false; } bool Apply(NegativeExpression* expression, void* target) { return false; } bool Apply(UsingExpression* expression, void* target) { return false; } }; /*********************************************************************** CharSetNormalizationAlgorithm ***********************************************************************/ class NormalizedCharSet { public: CharRange::List ranges; }; class CharSetAlgorithm : public RegexExpressionAlgorithm { public: virtual void Process(CharSetExpression* expression, NormalizedCharSet* target, CharRange range)=0; void Loop(CharSetExpression* expression, CharRange::List& ranges, NormalizedCharSet* target) { if(expression->reverse) { wchar_t begin=1; for(vint i=0;ibegin) { Process(expression, target, CharRange(begin, range.begin-1)); } begin=range.end+1; } if(begin<=65535) { Process(expression, target, CharRange(begin, 65535)); } } else { for(vint i=0;iexpression, target); } void Apply(SequenceExpression* expression, NormalizedCharSet* target) { Invoke(expression->left, target); Invoke(expression->right, target); } void Apply(AlternateExpression* expression, NormalizedCharSet* target) { Invoke(expression->left, target); Invoke(expression->right, target); } void Apply(BeginExpression* expression, NormalizedCharSet* target) { } void Apply(EndExpression* expression, NormalizedCharSet* target) { } void Apply(CaptureExpression* expression, NormalizedCharSet* target) { Invoke(expression->expression, target); } void Apply(MatchExpression* expression, NormalizedCharSet* target) { } void Apply(PositiveExpression* expression, NormalizedCharSet* target) { Invoke(expression->expression, target); } void Apply(NegativeExpression* expression, NormalizedCharSet* target) { Invoke(expression->expression, target); } void Apply(UsingExpression* expression, NormalizedCharSet* target) { } }; class BuildNormalizedCharSetAlgorithm : public CharSetAlgorithm { public: void Process(CharSetExpression* expression, NormalizedCharSet* target, CharRange range) { vint index=0; while(indexranges.Count()) { CharRange current=target->ranges[index]; if(currentrange) { index++; } else if(current.beginranges.RemoveAt(index); target->ranges.Add(CharRange(current.begin, range.begin-1)); target->ranges.Add(CharRange(range.begin, current.end)); index++; } else if(current.begin>range.begin) { // range : [ ] // current : [ ? target->ranges.Add(CharRange(range.begin, current.begin-1)); range.begin=current.begin; } else if(current.endrange.end) { // range : [ ] // current : [ ] target->ranges.RemoveAt(index); target->ranges.Add(range); target->ranges.Add(CharRange(range.end+1, current.end)); return; } else { // range : [ ] // current : [ ] return; } } target->ranges.Add(range); } void Apply(CharSetExpression* expression, NormalizedCharSet* target) { Loop(expression, expression->ranges, target); } }; class SetNormalizedCharSetAlgorithm : public CharSetAlgorithm { public: void Process(CharSetExpression* expression, NormalizedCharSet* target, CharRange range) { for(vint j=0;jranges.Count();j++) { CharRange targetRange=target->ranges[j]; if(range.begin<=targetRange.begin && targetRange.end<=range.end) { expression->ranges.Add(targetRange); } } } void Apply(CharSetExpression* expression, NormalizedCharSet* target) { CharRange::List source; CopyFrom(source, expression->ranges); expression->ranges.Clear(); Loop(expression, source, target); expression->reverse=false; } }; /*********************************************************************** MergeAlgorithm ***********************************************************************/ class MergeParameter { public: Expression::Map definitions; RegexExpression* regex; }; class MergeAlgorithm : public RegexExpressionAlgorithm { public: Expression::Ref Apply(CharSetExpression* expression, MergeParameter* target) { Ptr result=new CharSetExpression; CopyFrom(result->ranges, expression->ranges); result->reverse=expression->reverse; return result; } Expression::Ref Apply(LoopExpression* expression, MergeParameter* target) { Ptr result=new LoopExpression; result->max=expression->max; result->min=expression->min; result->preferLong=expression->preferLong; result->expression=Invoke(expression->expression, target); return result; } Expression::Ref Apply(SequenceExpression* expression, MergeParameter* target) { Ptr result=new SequenceExpression; result->left=Invoke(expression->left, target); result->right=Invoke(expression->right, target); return result; } Expression::Ref Apply(AlternateExpression* expression, MergeParameter* target) { Ptr result=new AlternateExpression; result->left=Invoke(expression->left, target); result->right=Invoke(expression->right, target); return result; } Expression::Ref Apply(BeginExpression* expression, MergeParameter* target) { return new BeginExpression; } Expression::Ref Apply(EndExpression* expression, MergeParameter* target) { return new EndExpression; } Expression::Ref Apply(CaptureExpression* expression, MergeParameter* target) { Ptr result=new CaptureExpression; result->expression=Invoke(expression->expression, target); result->name=expression->name; return result; } Expression::Ref Apply(MatchExpression* expression, MergeParameter* target) { Ptr result=new MatchExpression; result->name=expression->name; result->index=expression->index; return result; } Expression::Ref Apply(PositiveExpression* expression, MergeParameter* target) { Ptr result=new PositiveExpression; result->expression=Invoke(expression->expression, target); return result; } Expression::Ref Apply(NegativeExpression* expression, MergeParameter* target) { Ptr result=new NegativeExpression; result->expression=Invoke(expression->expression, target); return result; } Expression::Ref Apply(UsingExpression* expression, MergeParameter* target) { if(target->definitions.Keys().Contains(expression->name)) { Expression::Ref reference=target->definitions[expression->name]; if(reference) { return reference; } else { throw ArgumentException(L"Regular expression syntax error: Found reference loops in\""+expression->name+L"\".", L"vl::regex_internal::RegexExpression::Merge", L""); } } else if(target->regex->definitions.Keys().Contains(expression->name)) { target->definitions.Add(expression->name, 0); Expression::Ref result=Invoke(target->regex->definitions[expression->name], target); target->definitions.Set(expression->name, result); return result; } else { throw ArgumentException(L"Regular expression syntax error: Cannot find sub expression reference\""+expression->name+L"\".", L"vl::regex_internal::RegexExpression::Merge", L""); } } }; /*********************************************************************** EpsilonNfaAlgorithm ***********************************************************************/ class EpsilonNfaInfo { public: Automaton::Ref automaton; }; class EpsilonNfa { public: State* start; State* end; EpsilonNfa() { start=0; end=0; } }; class EpsilonNfaAlgorithm : public RegexExpressionAlgorithm { public: EpsilonNfa Connect(EpsilonNfa a, EpsilonNfa b, Automaton* target) { if(a.start) { target->NewEpsilon(a.end, b.start); a.end=b.end; return a; } else { return b; } } EpsilonNfa Apply(CharSetExpression* expression, Automaton* target) { EpsilonNfa nfa; nfa.start=target->NewState(); nfa.end=target->NewState(); for(vint i=0;iranges.Count();i++) { target->NewChars(nfa.start, nfa.end, expression->ranges[i]); } return nfa; } EpsilonNfa Apply(LoopExpression* expression, Automaton* target) { EpsilonNfa head; for(vint i=0;imin;i++) { EpsilonNfa body=Invoke(expression->expression, target); head=Connect(head, body, target); } if(expression->max==-1) { EpsilonNfa body=Invoke(expression->expression, target); if(!head.start) { head.start=head.end=target->NewState(); } State* loopBegin=head.end; State* loopEnd=target->NewState(); if(expression->preferLong) { target->NewEpsilon(loopBegin, body.start); target->NewEpsilon(body.end, loopBegin); target->NewNop(loopBegin, loopEnd); } else { target->NewNop(loopBegin, loopEnd); target->NewEpsilon(loopBegin, body.start); target->NewEpsilon(body.end, loopBegin); } head.end=loopEnd; } else if(expression->max>expression->min) { for(vint i=expression->min;imax;i++) { EpsilonNfa body=Invoke(expression->expression, target); State* start=target->NewState(); State* end=target->NewState(); if(expression->preferLong) { target->NewEpsilon(start, body.start); target->NewEpsilon(body.end, end); target->NewNop(start, end); } else { target->NewNop(start, end); target->NewEpsilon(start, body.start); target->NewEpsilon(body.end, end); } body.start=start; body.end=end; head=Connect(head, body, target); } } return head; } EpsilonNfa Apply(SequenceExpression* expression, Automaton* target) { EpsilonNfa a=Invoke(expression->left, target); EpsilonNfa b=Invoke(expression->right, target); return Connect(a, b, target); } EpsilonNfa Apply(AlternateExpression* expression, Automaton* target) { EpsilonNfa result; result.start=target->NewState(); result.end=target->NewState(); EpsilonNfa a=Invoke(expression->left, target); EpsilonNfa b=Invoke(expression->right, target); target->NewEpsilon(result.start, a.start); target->NewEpsilon(a.end, result.end); target->NewEpsilon(result.start, b.start); target->NewEpsilon(b.end, result.end); return result; } EpsilonNfa Apply(BeginExpression* expression, Automaton* target) { EpsilonNfa result; result.start=target->NewState(); result.end=target->NewState(); target->NewBeginString(result.start, result.end); return result; } EpsilonNfa Apply(EndExpression* expression, Automaton* target) { EpsilonNfa result; result.start=target->NewState(); result.end=target->NewState(); target->NewEndString(result.start, result.end); return result; } EpsilonNfa Apply(CaptureExpression* expression, Automaton* target) { EpsilonNfa result; result.start=target->NewState(); result.end=target->NewState(); vint capture=-1; if(expression->name!=L"") { capture=target->captureNames.IndexOf(expression->name); if(capture==-1) { capture=target->captureNames.Count(); target->captureNames.Add(expression->name); } } EpsilonNfa body=Invoke(expression->expression, target); target->NewCapture(result.start, body.start, capture); target->NewEnd(body.end, result.end); return result; } EpsilonNfa Apply(MatchExpression* expression, Automaton* target) { vint capture=-1; if(expression->name!=L"") { capture=target->captureNames.IndexOf(expression->name); if(capture==-1) { capture=target->captureNames.Count(); target->captureNames.Add(expression->name); } } EpsilonNfa result; result.start=target->NewState(); result.end=target->NewState(); target->NewMatch(result.start, result.end, capture, expression->index); return result; } EpsilonNfa Apply(PositiveExpression* expression, Automaton* target) { EpsilonNfa result; result.start=target->NewState(); result.end=target->NewState(); EpsilonNfa body=Invoke(expression->expression, target); target->NewPositive(result.start, body.start); target->NewEnd(body.end, result.end); return result; } EpsilonNfa Apply(NegativeExpression* expression, Automaton* target) { EpsilonNfa result; result.start=target->NewState(); result.end=target->NewState(); EpsilonNfa body=Invoke(expression->expression, target); target->NewNegative(result.start, body.start); target->NewEnd(body.end, result.end); target->NewNegativeFail(result.start, result.end); return result; } EpsilonNfa Apply(UsingExpression* expression, Automaton* target) { CHECK_FAIL(L"RegexExpression::GenerateEpsilonNfa()#UsingExpression cannot create state machine."); } }; /*********************************************************************** Expression ***********************************************************************/ bool Expression::IsEqual(vl::regex_internal::Expression *expression) { return IsEqualAlgorithm().Invoke(this, expression); } bool Expression::HasNoExtension() { return HasNoExtensionAlgorithm().Invoke(this, 0); } bool Expression::CanTreatAsPure() { return CanTreatAsPureAlgorithm().Invoke(this, 0); } void Expression::NormalizeCharSet(CharRange::List& subsets) { NormalizedCharSet normalized; BuildNormalizedCharSetAlgorithm().Invoke(this, &normalized); SetNormalizedCharSetAlgorithm().Invoke(this, &normalized); CopyFrom(subsets, normalized.ranges); } void Expression::CollectCharSet(CharRange::List& subsets) { NormalizedCharSet normalized; CopyFrom(normalized.ranges, subsets); BuildNormalizedCharSetAlgorithm().Invoke(this, &normalized); CopyFrom(subsets, normalized.ranges); } void Expression::ApplyCharSet(CharRange::List& subsets) { NormalizedCharSet normalized; CopyFrom(normalized.ranges, subsets); SetNormalizedCharSetAlgorithm().Invoke(this, &normalized); } Automaton::Ref Expression::GenerateEpsilonNfa() { Automaton::Ref automaton=new Automaton; EpsilonNfa result=EpsilonNfaAlgorithm().Invoke(this, automaton.Obj()); automaton->startState=result.start; result.end->finalState=true; return automaton; } /*********************************************************************** CharSetExpression ***********************************************************************/ bool CharSetExpression::AddRangeWithConflict(CharRange range) { if(range.begin>range.end) { wchar_t t=range.begin; range.begin=range.end; range.end=t; } for(vint i=0;iranges[i])) { return false; } } ranges.Add(range); return true; } /*********************************************************************** RegexExpression ***********************************************************************/ Expression::Ref RegexExpression::Merge() { MergeParameter merge; merge.regex=this; return MergeAlgorithm().Invoke(expression, &merge); } /*********************************************************************** Expression::Apply ***********************************************************************/ void CharSetExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void LoopExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void SequenceExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void AlternateExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void BeginExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void EndExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void CaptureExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void MatchExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void PositiveExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void NegativeExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } void UsingExpression::Apply(IRegexExpressionAlgorithm& algorithm) { algorithm.Visit(this); } } } /*********************************************************************** .\REGEX\REGEXPARSER.CPP ***********************************************************************/ namespace vl { namespace regex_internal { /*********************************************************************** Helper Functions ***********************************************************************/ bool IsChar(const wchar_t*& input, wchar_t c) { if(*input==c) { input++; return true; } else { return false; } } bool IsChars(const wchar_t*& input, const wchar_t* chars, wchar_t& c) { const wchar_t* position=::wcschr(chars, *input); if(position) { c=*input++; return true; } else { return false; } } bool IsStr(const wchar_t*& input, const wchar_t* str) { size_t len=wcslen(str); if(wcsncmp(input, str, len)==0) { input+=len; return true; } else { return false; } } bool IsChars(const wchar_t*& input, const wchar_t* chars) { wchar_t c; return IsChars(input, chars, c); } bool IsPositiveInteger(const wchar_t*& input, vint& number) { bool readed=false; number=0; while(L'0'<=*input && *input<=L'9') { number=number*10+(*input++)-L'0'; readed=true; } return readed; } bool IsName(const wchar_t*& input, WString& name) { const wchar_t* read=input; if((L'A'<=*read && *read<=L'Z') || (L'a'<=*read && *read<=L'z') || *read==L'_') { read++; while((L'A'<=*read && *read<=L'Z') || (L'a'<=*read && *read<=L'z') || (L'0'<=*read && *read<=L'9') || *read==L'_') { read++; } } if(input==read) { return false; } else { name=WString(input, vint(read-input)); input=read; return true; } } Ptr ParseLoop(const wchar_t*& input) { vint min=0; vint max=0; if(!*input) { return 0; } else if(IsChar(input, L'+')) { min=1; max=-1; } else if(IsChar(input, L'*')) { min=0; max=-1; } else if(IsChar(input, L'?')) { min=0; max=1; } else if(IsChar(input, L'{')) { if(IsPositiveInteger(input, min)) { if(IsChar(input, L',')) { if(!IsPositiveInteger(input, max)) { max=-1; } } else { max=min; } if(!IsChar(input, L'}')) { goto THROW_EXCEPTION; } } else { goto THROW_EXCEPTION; } } else { return 0; } { LoopExpression* expression=new LoopExpression; expression->min=min; expression->max=max; expression->preferLong=!IsChar(input, L'?'); return expression; } THROW_EXCEPTION: throw ArgumentException(L"Regular expression syntax error: Illegal loop expression.", L"vl::regex_internal::ParseLoop", L"input"); } Ptr ParseCharSet(const wchar_t*& input) { if(!*input) { return 0; } else if(IsChar(input, L'^')) { return new BeginExpression; } else if(IsChar(input, L'$')) { return new EndExpression; } else if(IsChar(input, L'\\') || IsChar(input, L'/')) { Ptr expression=new CharSetExpression; expression->reverse=false; switch(*input) { case L'.': expression->ranges.Add(CharRange(1, 65535)); break; case L'r': expression->ranges.Add(CharRange(L'\r', L'\r')); break; case L'n': expression->ranges.Add(CharRange(L'\n', L'\n')); break; case L't': expression->ranges.Add(CharRange(L'\t', L'\t')); break; case L'\\':case L'/':case L'(':case L')':case L'+':case L'*':case L'?':case L'|': case L'{':case L'}':case L'[':case L']':case L'<':case L'>': case L'^':case L'$':case L'!':case L'=': expression->ranges.Add(CharRange(*input, *input)); break; case L'S': expression->reverse=true; case L's': expression->ranges.Add(CharRange(L' ', L' ')); expression->ranges.Add(CharRange(L'\r', L'\r')); expression->ranges.Add(CharRange(L'\n', L'\n')); expression->ranges.Add(CharRange(L'\t', L'\t')); break; case L'D': expression->reverse=true; case L'd': expression->ranges.Add(CharRange(L'0', L'9')); break; case L'L': expression->reverse=true; case L'l': expression->ranges.Add(CharRange(L'_', L'_')); expression->ranges.Add(CharRange(L'A', L'Z')); expression->ranges.Add(CharRange(L'a', L'z')); break; case L'W': expression->reverse=true; case L'w': expression->ranges.Add(CharRange(L'_', L'_')); expression->ranges.Add(CharRange(L'0', L'9')); expression->ranges.Add(CharRange(L'A', L'Z')); expression->ranges.Add(CharRange(L'a', L'z')); break; default: throw ArgumentException(L"Regular expression syntax error: Illegal character escaping.", L"vl::regex_internal::ParseCharSet", L"input"); } input++; return expression; } else if(IsChar(input, L'[')) { Ptr expression=new CharSetExpression; if(IsChar(input, L'^')) { expression->reverse=true; } else { expression->reverse=false; } bool midState=false; wchar_t a=L'\0'; wchar_t b=L'\0'; while(true) { if(IsChar(input, L'\\') || IsChar(input, L'/')) { wchar_t c=L'\0'; switch(*input) { case L'r': c=L'\r'; break; case L'n': c=L'\n'; break; case L't': c=L'\t'; break; case L'-':case L'[':case L']':case L'\\':case L'/':case L'^':case L'$': c=*input; break; default: throw ArgumentException(L"Regular expression syntax error: Illegal character escaping, only \"rnt-[]\\/\" are legal escaped characters in [].", L"vl::regex_internal::ParseCharSet", L"input"); } input++; midState?b=c:a=c; midState=!midState; } else if(IsChars(input, L"-]")) { goto THROW_EXCEPTION; } else if(*input) { midState?b=*input++:a=*input++; midState=!midState; } else { goto THROW_EXCEPTION; } if(IsChar(input, L']')) { if(midState) { b=a; } if(!expression->AddRangeWithConflict(CharRange(a, b))) { goto THROW_EXCEPTION; } break; } else if(IsChar(input, L'-')) { if(!midState) { goto THROW_EXCEPTION; } } else { if(midState) { b=a; } if(expression->AddRangeWithConflict(CharRange(a, b))) { midState=false; } else { goto THROW_EXCEPTION; } } } return expression; THROW_EXCEPTION: throw ArgumentException(L"Regular expression syntax error: Illegal character set definition."); } else if(IsChars(input, L"()+*?{}|")) { input--; return 0; } else { CharSetExpression* expression=new CharSetExpression; expression->reverse=false; expression->ranges.Add(CharRange(*input, *input)); input++; return expression; } } Ptr ParseFunction(const wchar_t*& input) { if(IsStr(input, L"(=")) { Ptr sub=ParseExpression(input); if(!IsChar(input, L')')) { goto NEED_RIGHT_BRACKET; } PositiveExpression* expression=new PositiveExpression; expression->expression=sub; return expression; } else if(IsStr(input, L"(!")) { Ptr sub=ParseExpression(input); if(!IsChar(input, L')')) { goto NEED_RIGHT_BRACKET; } NegativeExpression* expression=new NegativeExpression; expression->expression=sub; return expression; } else if(IsStr(input, L"(<&")) { WString name; if(!IsName(input, name)) { goto NEED_NAME; } if(!IsChar(input, L'>')) { goto NEED_GREATER; } if(!IsChar(input, L')')) { goto NEED_RIGHT_BRACKET; } UsingExpression* expression=new UsingExpression; expression->name=name; return expression; } else if(IsStr(input, L"(<$")) { WString name; vint index=-1; if(IsName(input, name)) { if(IsChar(input, L';')) { if(!IsPositiveInteger(input, index)) { goto NEED_NUMBER; } } } else if(!IsPositiveInteger(input, index)) { goto NEED_NUMBER; } if(!IsChar(input, L'>')) { goto NEED_GREATER; } if(!IsChar(input, L')')) { goto NEED_RIGHT_BRACKET; } MatchExpression* expression=new MatchExpression; expression->name=name; expression->index=index; return expression; } else if(IsStr(input, L"(<")) { WString name; if(!IsName(input, name)) { goto NEED_NAME; } if(!IsChar(input, L'>')) { goto NEED_GREATER; } Ptr sub=ParseExpression(input); if(!IsChar(input, L')')) { goto NEED_RIGHT_BRACKET; } CaptureExpression* expression=new CaptureExpression; expression->name=name; expression->expression=sub; return expression; } else if(IsStr(input, L"(?")) { Ptr sub=ParseExpression(input); if(!IsChar(input, L')')) { goto NEED_RIGHT_BRACKET; } CaptureExpression* expression=new CaptureExpression; expression->expression=sub; return expression; } else if(IsChar(input, L'(')) { Ptr sub=ParseExpression(input); if(!IsChar(input, L')')) { goto NEED_RIGHT_BRACKET; } return sub; } else { return 0; } NEED_RIGHT_BRACKET: throw ArgumentException(L"Regular expression syntax error: \")\" expected.", L"vl::regex_internal::ParseFunction", L"input"); NEED_GREATER: throw ArgumentException(L"Regular expression syntax error: \">\" expected.", L"vl::regex_internal::ParseFunction", L"input"); NEED_NAME: throw ArgumentException(L"Regular expression syntax error: Identifier expected.", L"vl::regex_internal::ParseFunction", L"input"); NEED_NUMBER: throw ArgumentException(L"Regular expression syntax error: Number expected.", L"vl::regex_internal::ParseFunction", L"input"); } Ptr ParseUnit(const wchar_t*& input) { Ptr unit=ParseCharSet(input); if(!unit) { unit=ParseFunction(input); } if(!unit) { return 0; } Ptr loop; while((loop=ParseLoop(input))) { loop->expression=unit; unit=loop; } return unit; } Ptr ParseJoin(const wchar_t*& input) { Ptr expression=ParseUnit(input); while(true) { Ptr right=ParseUnit(input); if(right) { SequenceExpression* sequence=new SequenceExpression; sequence->left=expression; sequence->right=right; expression=sequence; } else { break; } } return expression; } Ptr ParseAlt(const wchar_t*& input) { Ptr expression=ParseJoin(input); while(true) { if(IsChar(input, L'|')) { Ptr right=ParseJoin(input); if(right) { AlternateExpression* alternate=new AlternateExpression; alternate->left=expression; alternate->right=right; expression=alternate; } else { throw ArgumentException(L"Regular expression syntax error: Expression expected.", L"vl::regex_internal::ParseAlt", L"input"); } } else { break; } } return expression; } Ptr ParseExpression(const wchar_t*& input) { return ParseAlt(input); } RegexExpression::Ref ParseRegexExpression(const WString& code) { RegexExpression::Ref regex=new RegexExpression; const wchar_t* start=code.Buffer(); const wchar_t* input=start; try { while(IsStr(input, L"(<#")) { WString name; if(!IsName(input, name)) { throw ArgumentException(L"Regular expression syntax error: Identifier expected.", L"vl::regex_internal::ParseRegexExpression", L"code"); } if(!IsChar(input, L'>')) { throw ArgumentException(L"Regular expression syntax error: \">\" expected.", L"vl::regex_internal::ParseFunction", L"input"); } Ptr sub=ParseExpression(input); if(!IsChar(input, L')')) { throw ArgumentException(L"Regular expression syntax error: \")\" expected.", L"vl::regex_internal::ParseFunction", L"input"); } if(regex->definitions.Keys().Contains(name)) { throw ArgumentException(L"Regular expression syntax error: Found duplicated sub expression name: \""+name+L"\". ", L"vl::regex_internal::ParseFunction", L"input"); } else { regex->definitions.Add(name, sub); } } regex->expression=ParseExpression(input); if(!regex->expression) { throw ArgumentException(L"Regular expression syntax error: Expression expected.", L"vl::regex_internal::ParseUnit", L"input"); } if(*input) { throw ArgumentException(L"Regular expression syntax error: Found unnecessary tokens.", L"vl::regex_internal::ParseUnit", L"input"); } return regex; } catch(const ArgumentException& e) { throw ParsingException(e.Message(), code, input-start); } } WString EscapeTextForRegex(const WString& literalString) { WString result; for(vint i=0;i': case L'^':case L'$':case L'!':case L'=': result+=WString(L"\\")+c; break; case L'\r': result+=L"\\r"; break; case L'\n': result+=L"\\n"; break; case L'\t': result+=L"\\t"; break; default: result+=c; } } return result; } WString UnescapeTextForRegex(const WString& escapedText) { WString result; for(vint i=0;i': case L'^':case L'$':case L'!':case L'=': return false; } } } return true; } } } /*********************************************************************** .\REGEX\REGEXPURE.CPP ***********************************************************************/ namespace vl { namespace regex_internal { /*********************************************************************** PureInterpretor ***********************************************************************/ PureInterpretor::PureInterpretor(Automaton::Ref dfa, CharRange::List& subsets) :transition(0) ,finalState(0) ,relatedFinalState(0) { stateCount=dfa->states.Count(); charSetCount=subsets.Count()+1; startState=dfa->states.IndexOf(dfa->startState); // Map char to input index (equivalent char class) for(vint i=0;istates[i].Obj(); for(vint j=0;jtransitions.Count();j++) { Transition* dfaTransition=state->transitions[j]; switch(dfaTransition->type) { case Transition::Chars: { vint index=subsets.IndexOf(dfaTransition->range); if(index==-1) { CHECK_ERROR(false, L"PureInterpretor::PureInterpretor(Automaton::Ref, CharRange::List&)#Specified chars don't appear in the normalized char ranges."); } transition[i][index]=dfa->states.IndexOf(dfaTransition->target); } break; default: CHECK_ERROR(false, L"PureInterpretor::PureInterpretor(Automaton::Ref, CharRange::List&)#PureInterpretor only accepts Transition::Chars transitions."); } } } // Mark final states finalState=new bool[stateCount]; for(vint i=0;istates[i]->finalState; } } PureInterpretor::~PureInterpretor() { if(relatedFinalState) delete[] relatedFinalState; delete[] finalState; for(vint i=0;i=SupportedCharCount)break; #endif vint charIndex=charMap[*read++]; currentState=transition[currentState][charIndex]; } if(result.finalState==-1) { if(terminateLength>0) { result.terminateState=terminateState; } result.length=terminateLength; return false; } else { return true; } } bool PureInterpretor::Match(const wchar_t* input, const wchar_t* start, PureResult& result) { const wchar_t* read=input; while(*read) { if(MatchHead(read, start, result)) { return true; } read++; } return false; } vint PureInterpretor::GetStartState() { return startState; } vint PureInterpretor::Transit(wchar_t input, vint state) { if(0<=state && state struct POD { static const bool Result = true; }; template<> struct POD { static const bool Result = true; }; namespace regex_internal { using namespace collections; void Push(List& elements, vint& available, vint& count, const ExtensionSaver& element) { if(elements.Count()==count) { elements.Add(element); } else { elements[count]=element; } ExtensionSaver& current=elements[count]; current.previous=available; available=count++; } ExtensionSaver Pop(List& elements, vint& available, vint& count) { ExtensionSaver& current=elements[available]; available=current.previous; return current; } template void PushNonSaver(List& elements, vint& count, const T& element) { if(elements.Count()==count) { elements.Add(element); } else { elements[count]=element; } count++; } template T PopNonSaver(List& elements, vint& count) { return elements[--count]; } } namespace regex_internal { /*********************************************************************** CaptureRecord ***********************************************************************/ bool CaptureRecord::operator==(const CaptureRecord& record)const { return capture==record.capture && start==record.start && length==record.length; } /*********************************************************************** RichInterpretor ***********************************************************************/ RichInterpretor::RichInterpretor(Automaton::Ref _dfa) :dfa(_dfa) { datas=new UserData[dfa->states.Count()]; for(vint i=0;istates.Count();i++) { State* state=dfa->states[i].Obj(); vint charEdges=0; vint nonCharEdges=0; bool mustSave=false; for(vint j=0;jtransitions.Count();j++) { if(state->transitions[j]->type==Transition::Chars) { charEdges++; } else { if(state->transitions[j]->type==Transition::Negative || state->transitions[j]->type==Transition::Positive) { mustSave=true; } nonCharEdges++; } } datas[i].NeedKeepState=mustSave || nonCharEdges>1 || (nonCharEdges!=0 && charEdges!=0); state->userData=&datas[i]; } } RichInterpretor::~RichInterpretor() { delete[] datas; } bool RichInterpretor::MatchHead(const wchar_t* input, const wchar_t* start, RichResult& result) { List stateSavers; List extensionSavers; StateSaver currentState; currentState.captureCount=0; currentState.currentState=dfa->startState; currentState.extensionSaverAvailable=-1; currentState.extensionSaverCount=0; currentState.minTransition=0; currentState.reading=input; currentState.stateSaverCount=0; currentState.storeType=StateSaver::Other; while (!currentState.currentState->finalState) { bool found = false; // true means at least one transition matches the input StateSaver oldState = currentState; // Iterate through all transitions from the current state for (vint i = currentState.minTransition; i < currentState.currentState->transitions.Count(); i++) { Transition* transition = currentState.currentState->transitions[i]; switch (transition->type) { case Transition::Chars: { // match the input if the current character fall into the range CharRange range = transition->range; found = range.begin <= *currentState.reading && range.end >= *currentState.reading; if (found) { currentState.reading++; } } break; case Transition::BeginString: { // match the input if this is the first character, and it is not consumed found = currentState.reading == start; } break; case Transition::EndString: { // match the input if this is after the last character, and it is not consumed found = *currentState.reading == L'\0'; } break; case Transition::Nop: { // match without any condition found = true; } break; case Transition::Capture: { // Push the capture information ExtensionSaver saver; saver.captureListIndex = currentState.captureCount; saver.reading = currentState.reading; saver.transition = transition; Push(extensionSavers, currentState.extensionSaverAvailable, currentState.extensionSaverCount, saver); // Push the capture record, and it will be written if the input matches the regex CaptureRecord capture; capture.capture = transition->capture; capture.start = currentState.reading - start; capture.length = -1; PushNonSaver(result.captures, currentState.captureCount, capture); found = true; } break; case Transition::Match: { vint index = 0; for (vint j = 0; j < currentState.captureCount; j++) { CaptureRecord& capture = result.captures[j]; // If the capture name matched if (capture.capture == transition->capture) { // If the capture index matched, or it is -1 if (capture.length != -1 && (transition->index == -1 || transition->index == index)) { // If the captured text matched if (wcsncmp(start + capture.start, currentState.reading, capture.length) == 0) { // Consume so much input currentState.reading += capture.length; found = true; break; } } // Fail if f the captured text with the specified name and index doesn't match if (transition->index != -1 && index == transition->index) { break; } else { index++; } } } } break; case Transition::Positive: { // Push the positive lookahead information ExtensionSaver saver; saver.captureListIndex = -1; saver.reading = currentState.reading; saver.transition = transition; Push(extensionSavers, currentState.extensionSaverAvailable, currentState.extensionSaverCount, saver); // Set found = true so that PushNonSaver(oldState) happens later oldState.storeType = StateSaver::Positive; found = true; } break; case Transition::Negative: { // Push the positive lookahead information ExtensionSaver saver; saver.captureListIndex = -1; saver.reading = currentState.reading; saver.transition = transition; Push(extensionSavers, currentState.extensionSaverAvailable, currentState.extensionSaverCount, saver); // Set found = true so that PushNonSaver(oldState) happens later oldState.storeType = StateSaver::Negative; found = true; } break; case Transition::NegativeFail: { // NegativeFail will be used when the nagative lookahead failed } break; case Transition::End: { // Find the corresponding extension saver so that we can know how to deal with a matched sub regex that ends here ExtensionSaver extensionSaver = Pop(extensionSavers, currentState.extensionSaverAvailable, currentState.extensionSaverCount); switch (extensionSaver.transition->type) { case Transition::Capture: { // Write the captured text CaptureRecord& capture = result.captures[extensionSaver.captureListIndex]; capture.length = (currentState.reading - start) - capture.start; found = true; } break; case Transition::Positive: // Find the last positive lookahead state saver for (vint j = currentState.stateSaverCount - 1; j >= 0; j--) { StateSaver& stateSaver = stateSavers[j]; if (stateSaver.storeType == StateSaver::Positive) { // restore the parsing state just before matching the positive lookahead, since positive lookahead doesn't consume input oldState.reading = stateSaver.reading; oldState.stateSaverCount = j; currentState.reading = stateSaver.reading; currentState.stateSaverCount = j; break; } } found = true; break; case Transition::Negative: // Find the last negative lookahead state saver for (vint j = currentState.stateSaverCount - 1; j >= 0; j--) { StateSaver& stateSaver = stateSavers[j]; if (stateSaver.storeType == StateSaver::Negative) { // restore the parsing state just before matching the negative lookahead, since positive lookahead doesn't consume input oldState = stateSaver; oldState.storeType = StateSaver::Other; currentState = stateSaver; currentState.storeType = StateSaver::Other; i = currentState.minTransition - 1; break; } } break; default:; } } break; default:; } // Save the parsing state when necessary if (found) { UserData* data = (UserData*)currentState.currentState->userData; if (data->NeedKeepState) { oldState.minTransition = i + 1; PushNonSaver(stateSavers, currentState.stateSaverCount, oldState); } currentState.currentState = transition->target; currentState.minTransition = 0; break; } } // If no transition from the current state can be used if (!found) { // If there is a chance to do backtracking if (currentState.stateSaverCount) { currentState = PopNonSaver(stateSavers, currentState.stateSaverCount); // minTransition - 1 is always valid since the value is stored with adding 1 // So minTransition - 1 record the transition, which is the reason the parsing state is saved if (currentState.currentState->transitions[currentState.minTransition - 1]->type == Transition::Negative) { // Find the next NegativeFail transition // Because when a negative lookahead regex failed to match, it is actually succeeded // Since a negative lookahead means we don't want to match this regex for (vint i = 0; i < currentState.currentState->transitions.Count(); i++) { Transition* transition = currentState.currentState->transitions[i]; if (transition->type == Transition::NegativeFail) { // Restore the state to the target of NegativeFail to let the parsing continue currentState.currentState = transition->target; currentState.minTransition = 0; currentState.storeType = StateSaver::Other; break; } } } } else { break; } } } if (currentState.currentState->finalState) { // Keep available captures if succeeded result.start = input - start; result.length = (currentState.reading - start) - result.start; for (vint i = result.captures.Count() - 1; i >= currentState.captureCount; i--) { result.captures.RemoveAt(i); } return true; } else { // Clear captures if failed result.captures.Clear(); return false; } } bool RichInterpretor::Match(const wchar_t* input, const wchar_t* start, RichResult& result) { const wchar_t* read=input; while(*read) { if(MatchHead(read, start, result)) { return true; } read++; } return false; } const List& RichInterpretor::CaptureNames() { return dfa->captureNames; } } } /*********************************************************************** .\REGEX\REGEXWRITER.CPP ***********************************************************************/ namespace vl { namespace regex { using namespace vl::regex_internal; /*********************************************************************** RegexNode ***********************************************************************/ RegexNode::RegexNode(vl::regex_internal::Expression::Ref _expression) :expression(_expression) { } RegexNode RegexNode::Some()const { return Loop(1, -1); } RegexNode RegexNode::Any()const { return Loop(0, -1); } RegexNode RegexNode::Opt()const { return Loop(0, 1); } RegexNode RegexNode::Loop(vint min, vint max)const { LoopExpression* target=new LoopExpression; target->min=min; target->max=max; target->preferLong=true; target->expression=expression; return RegexNode(target); } RegexNode RegexNode::AtLeast(vint min)const { return Loop(min, -1); } RegexNode RegexNode::operator+(const RegexNode& node)const { SequenceExpression* target=new SequenceExpression; target->left=expression; target->right=node.expression; return RegexNode(target); } RegexNode RegexNode::operator|(const RegexNode& node)const { AlternateExpression* target=new AlternateExpression; target->left=expression; target->right=node.expression; return RegexNode(target); } RegexNode RegexNode::operator+()const { PositiveExpression* target=new PositiveExpression; target->expression=expression; return RegexNode(target); } RegexNode RegexNode::operator-()const { NegativeExpression* target=new NegativeExpression; target->expression=expression; return RegexNode(target); } RegexNode RegexNode::operator!()const { CharSetExpression* source=dynamic_cast(expression.Obj()); CHECK_ERROR(source, L"RegexNode::operator!()#operator ! can only applies on charset expressions."); Ptr target=new CharSetExpression; CopyFrom(target->ranges, source->ranges); target->reverse=!source->reverse; return RegexNode(target); } RegexNode RegexNode::operator%(const RegexNode& node)const { CharSetExpression* left=dynamic_cast(expression.Obj()); CharSetExpression* right=dynamic_cast(node.expression.Obj()); CHECK_ERROR(left && right && !left->reverse && !right->reverse, L"RegexNode::operator%(const RegexNode&)#operator % only connects non-reverse charset expressions."); Ptr target=new CharSetExpression; target->reverse=false; CopyFrom(target->ranges, left->ranges); for(vint i=0;iranges.Count();i++) { if(!target->AddRangeWithConflict(right->ranges[i])) { CHECK_ERROR(false, L"RegexNode::operator%(const RegexNode&)#Failed to create charset expression from operator %."); } } return RegexNode(target); } /*********************************************************************** Regex Writer ***********************************************************************/ RegexNode rCapture(const WString& name, const RegexNode& node) { CaptureExpression* target=new CaptureExpression; target->name=name; target->expression=node.expression; return RegexNode(target); } RegexNode rUsing(const WString& name) { UsingExpression* target=new UsingExpression; target->name=name; return RegexNode(target); } RegexNode rMatch(const WString& name, vint index) { MatchExpression* target=new MatchExpression; target->name=name; target->index=index; return RegexNode(target); } RegexNode rMatch(vint index) { MatchExpression* target=new MatchExpression; target->index=index; return RegexNode(target); } RegexNode rBegin() { return RegexNode(new BeginExpression); } RegexNode rEnd() { return RegexNode(new EndExpression); } RegexNode rC(wchar_t a, wchar_t b) { if(!b)b=a; CharSetExpression* target=new CharSetExpression; target->reverse=false; target->AddRangeWithConflict(CharRange(a, b)); return RegexNode(target); } RegexNode r_d() { return rC(L'0', L'9'); } RegexNode r_l() { return rC(L'a', L'z')%rC(L'A', L'Z')%rC(L'_'); } RegexNode r_w() { return rC(L'0', L'9')%rC(L'a', L'z')%rC(L'A', L'Z')%rC(L'_'); } RegexNode rAnyChar() { return rC(1, 65535); } } } /*********************************************************************** .\STREAM\ACCESSOR.CPP ***********************************************************************/ namespace vl { namespace stream { using namespace collections; /*********************************************************************** TextReader ***********************************************************************/ WString TextReader::ReadString(vint length) { wchar_t* buffer=new wchar_t[length+1]; vint i=0; for(;i0 && result[result.Length()-1]==L'\r') { return result.Left(result.Length()-1); } else { return result; } } WString TextReader::ReadToEnd() { WString result; auto buffer = new wchar_t[65537]; buffer[0]=L'\0'; vint i=0; while(true) { wchar_t c=ReadChar(); if(c==L'\0') { buffer[i]=L'\0'; result+=buffer; buffer[0]=L'\0'; i=0; break; } else { if(i==65536) { buffer[i]=L'\0'; result+=buffer; buffer[0]=L'\0'; i=0; } buffer[i++]=c; } } result+=buffer; delete[] buffer; return result; } /*********************************************************************** TextWriter ***********************************************************************/ void TextWriter::WriteString(const wchar_t* string, vint charCount) { while(*string) { WriteChar(*string++); } } void TextWriter::WriteString(const wchar_t* string) { WriteString(string, (vint)wcslen(string)); } void TextWriter::WriteString(const WString& string) { if(string.Length()) { WriteString(string.Buffer(), string.Length()); } } void TextWriter::WriteLine(const wchar_t* string, vint charCount) { WriteString(string, charCount); WriteString(L"\r\n", 2); } void TextWriter::WriteLine(const wchar_t* string) { WriteString(string); WriteString(L"\r\n", 2); } void TextWriter::WriteLine(const WString& string) { WriteString(string); WriteString(L"\r\n", 2); } namespace monospace_tabling { void WriteBorderLine(TextWriter& writer, Array& columnWidths, vint columns) { writer.WriteChar(L'+'); for(vint i=0;i& columnWidths, vint rowHeight, vint columns, Array& tableByRow, vint startRow) { vint cellStart=startRow*columns; for(vint r=0;r=length;i--) { writer.WriteChar(L' '); } writer.WriteChar(L'|'); } writer.WriteLine(L""); } } } using namespace monospace_tabling; void TextWriter::WriteMonospacedEnglishTable(collections::Array& tableByRow, vint rows, vint columns) { Array rowHeights(rows); Array columnWidths(columns); for(vint i=0;iremain) length=remain; WString result=string.Sub(current, length); current+=length; return result; } } WString StringReader::ReadLine() { PrepareIfLastCallIsReadLine(); if(IsEnd()) { return L""; } else { vint lineEnd=current; while(lineEndRead(&buffer, sizeof(buffer))==0) { stream=0; return 0; } else { return buffer; } } else { return L'\0'; } } /*********************************************************************** StreamWriter ***********************************************************************/ StreamWriter::StreamWriter(IStream& _stream) :stream(&_stream) { } void StreamWriter::WriteChar(wchar_t c) { stream->Write(&c, sizeof(c)); } void StreamWriter::WriteString(const wchar_t* string, vint charCount) { stream->Write((void*)string, charCount*sizeof(*string)); } /*********************************************************************** EncoderStream ***********************************************************************/ EncoderStream::EncoderStream(IStream& _stream, IEncoder& _encoder) :stream(&_stream) ,encoder(&_encoder) ,position(0) { encoder->Setup(stream); } EncoderStream::~EncoderStream() { Close(); } bool EncoderStream::CanRead()const { return false; } bool EncoderStream::CanWrite()const { return IsAvailable(); } bool EncoderStream::CanSeek()const { return false; } bool EncoderStream::CanPeek()const { return false; } bool EncoderStream::IsLimited()const { return stream!=0 && stream->IsLimited(); } bool EncoderStream::IsAvailable()const { return stream!=0 && stream->IsAvailable(); } void EncoderStream::Close() { encoder->Close(); stream=0; } pos_t EncoderStream::Position()const { return IsAvailable()?position:-1; } pos_t EncoderStream::Size()const { return -1; } void EncoderStream::Seek(pos_t _size) { CHECK_FAIL(L"EncoderStream::Seek(pos_t)#Operation not supported."); } void EncoderStream::SeekFromBegin(pos_t _size) { CHECK_FAIL(L"EncoderStream::SeekFromBegin(pos_t)#Operation not supported."); } void EncoderStream::SeekFromEnd(pos_t _size) { CHECK_FAIL(L"EncoderStream::SeekFromEnd(pos_t)#Operation not supported."); } vint EncoderStream::Read(void* _buffer, vint _size) { CHECK_FAIL(L"EncoderStream::Read(void*, vint)#Operation not supported."); } vint EncoderStream::Write(void* _buffer, vint _size) { vint result=encoder->Write(_buffer, _size); if(result>=0) { position+=result; } return result; } vint EncoderStream::Peek(void* _buffer, vint _size) { CHECK_FAIL(L"EncoderStream::Peek(void*, vint)#Operation not supported."); } /*********************************************************************** DecoderStream ***********************************************************************/ DecoderStream::DecoderStream(IStream& _stream, IDecoder& _decoder) :stream(&_stream) ,decoder(&_decoder) ,position(0) { decoder->Setup(stream); } DecoderStream::~DecoderStream() { Close(); } bool DecoderStream::CanRead()const { return IsAvailable(); } bool DecoderStream::CanWrite()const { return false; } bool DecoderStream::CanSeek()const { return false; } bool DecoderStream::CanPeek()const { return false; } bool DecoderStream::IsLimited()const { return stream!=0 && stream->IsLimited(); } bool DecoderStream::IsAvailable()const { return stream!=0 && stream->IsAvailable(); } void DecoderStream::Close() { decoder->Close(); stream=0; } pos_t DecoderStream::Position()const { return IsAvailable()?position:-1; } pos_t DecoderStream::Size()const { return -1; } void DecoderStream::Seek(pos_t _size) { CHECK_FAIL(L"DecoderStream::Seek(pos_t)#Operation not supported."); } void DecoderStream::SeekFromBegin(pos_t _size) { CHECK_FAIL(L"DecoderStream::SeekFromBegin(pos_t)#Operation not supported."); } void DecoderStream::SeekFromEnd(pos_t _size) { CHECK_FAIL(L"DecoderStream::SeekFromEnd(pos_t)#Operation not supported."); } vint DecoderStream::Read(void* _buffer, vint _size) { vint result=decoder->Read(_buffer, _size); if(result>=0) { position+=result; } return result; } vint DecoderStream::Write(void* _buffer, vint _size) { CHECK_FAIL(L"DecoderStream::Write(void*, vint)#Operation not supported."); } vint DecoderStream::Peek(void* _buffer, vint _size) { CHECK_FAIL(L"DecoderStream::Peek(void*, vint)#Operation not supported."); } } } /*********************************************************************** .\STREAM\BROADCASTSTREAM.CPP ***********************************************************************/ namespace vl { namespace stream { /*********************************************************************** BroadcastStream ***********************************************************************/ BroadcastStream::BroadcastStream() :closed(false) ,position(0) { } BroadcastStream::~BroadcastStream() { } BroadcastStream::StreamList& BroadcastStream::Targets() { return streams; } bool BroadcastStream::CanRead()const { return false; } bool BroadcastStream::CanWrite()const { return !closed; } bool BroadcastStream::CanSeek()const { return false; } bool BroadcastStream::CanPeek()const { return false; } bool BroadcastStream::IsLimited()const { return false; } bool BroadcastStream::IsAvailable()const { return !closed; } void BroadcastStream::Close() { closed=true; position=-1; } pos_t BroadcastStream::Position()const { return position; } pos_t BroadcastStream::Size()const { return position; } void BroadcastStream::Seek(pos_t _size) { CHECK_FAIL(L"BroadcastStream::Seek(pos_t)#Operation not supported."); } void BroadcastStream::SeekFromBegin(pos_t _size) { CHECK_FAIL(L"BroadcastStream::SeekFromBegin(pos_t)#Operation not supported."); } void BroadcastStream::SeekFromEnd(pos_t _size) { CHECK_FAIL(L"BroadcastStream::SeekFromEnd(pos_t)#Operation not supported."); } vint BroadcastStream::Read(void* _buffer, vint _size) { CHECK_FAIL(L"BroadcastStream::Read(void*, vint)#Operation not supported."); } vint BroadcastStream::Write(void* _buffer, vint _size) { for(vint i=0;iWrite(_buffer, _size); } position+=_size; return _size; } vint BroadcastStream::Peek(void* _buffer, vint _size) { CHECK_FAIL(L"BroadcastStream::Peek(void*, vint)#Operation not supported."); } } } /*********************************************************************** .\STREAM\CACHESTREAM.CPP ***********************************************************************/ namespace vl { namespace stream { /*********************************************************************** CacheStream ***********************************************************************/ void CacheStream::Flush() { if(dirtyLength>0) { if(target->Position()!=start+dirtyStart) { target->SeekFromBegin(start+dirtyStart); } target->Write(buffer+dirtyStart, dirtyLength); } dirtyStart=0; dirtyLength=0; availableLength=0; } void CacheStream::Load(pos_t _position) { if(target->Position()!=_position) { target->SeekFromBegin(_position); } start=_position; if(target->CanRead()) { availableLength=target->Read(buffer, block); } } vint CacheStream::InternalRead(void* _buffer, vint _size) { vint readed=0; if(position>=start && positionreaded) { Flush(); if(_size-readed>=block) { if(CanSeek()) { target->SeekFromBegin(position+readed); } vint additional=target->Read(_buffer, _size-readed); if(additional!=-1) { readed+=additional; } } else { Load(position+readed); vint remain=_size-readed; vint min=availableLength=start && position0) { availableLength+=availableOffset; } } if(_size>written) { Flush(); if(_size-written>=block) { if(CanSeek()) { target->SeekFromBegin(position+written); } vint additional=target->Write(_buffer, _size-written); if(additional!=-1) { written+=additional; } } else { Load(position+written); dirtyLength=_size-written; memcpy(buffer, _buffer, dirtyLength); written+=dirtyLength; } } return written; } CacheStream::CacheStream(IStream& _target, vint _block) :target(&_target) ,block(_block) ,start(0) ,position(0) ,dirtyStart(0) ,dirtyLength(0) ,availableLength(0) ,operatedSize(0) { if(block<=0) { block=65536; } buffer=new char[block]; } CacheStream::~CacheStream() { Close(); } bool CacheStream::CanRead()const { return target!=0 && target->CanRead(); } bool CacheStream::CanWrite()const { return target!=0 && target->CanWrite(); } bool CacheStream::CanSeek()const { return target!=0 && target->CanSeek(); } bool CacheStream::CanPeek()const { return target!=0 && target->CanPeek(); } bool CacheStream::IsLimited()const { return target!=0 && target->IsLimited(); } bool CacheStream::IsAvailable()const { return target!=0 && target->IsAvailable(); } void CacheStream::Close() { Flush(); target=0; delete[] buffer; buffer=0; position=-1; dirtyStart=0; dirtyLength=0; availableLength=0; operatedSize=-1; } pos_t CacheStream::Position()const { return position; } pos_t CacheStream::Size()const { if(target!=0) { if(IsLimited()) { return target->Size(); } else { return operatedSize; } } else { return -1; } } void CacheStream::Seek(pos_t _size) { SeekFromBegin(position+_size); } void CacheStream::SeekFromBegin(pos_t _size) { if(CanSeek()) { if(_size<0) { position=0; } else if(_size>Size()) { position=Size(); } else { position=_size; } } } void CacheStream::SeekFromEnd(pos_t _size) { SeekFromBegin(Size()-_size); } vint CacheStream::Read(void* _buffer, vint _size) { CHECK_ERROR(CanRead(), L"CacheStream::Read(void*, vint)#Stream is closed or operation not supported."); CHECK_ERROR(_size>=0, L"CacheStream::Read(void*, vint)#Argument size cannot be negative."); _size=InternalRead(_buffer, _size); position+=_size; if(operatedSize=0, L"CacheStream::Read(void*, vint)#Argument size cannot be negative."); if(IsLimited()) { pos_t size=Size(); if(size!=-1) { vint remain=(vint)(size-(position+_size)); if(remain<0) { _size-=remain; } } } _size=InternalWrite(_buffer, _size); position+=_size; if(operatedSize=0, L"CacheStream::Read(void*, vint)#Argument size cannot be negative."); return InternalRead(_buffer, _size); } } } /*********************************************************************** .\STREAM\CHARFORMAT.CPP ***********************************************************************/ #if defined VCZH_MSVC #include #elif defined VCZH_GCC #endif namespace vl { namespace stream { /*********************************************************************** CharEncoder ***********************************************************************/ CharEncoder::CharEncoder() :stream(0) ,cacheSize(0) { } void CharEncoder::Setup(IStream* _stream) { stream=_stream; } void CharEncoder::Close() { } vint CharEncoder::Write(void* _buffer, vint _size) { const vint all=cacheSize+_size; const vint chars=all/sizeof(wchar_t); const vint bytes=chars*sizeof(wchar_t); wchar_t* unicode=0; bool needToFree=false; vint result=0; if(chars) { if(cacheSize>0) { unicode=new wchar_t[chars]; memcpy(unicode, cacheBuffer, cacheSize); memcpy(((vuint8_t*)unicode)+cacheSize, _buffer, bytes-cacheSize); needToFree=true; } else { unicode=(wchar_t*)_buffer; } result=WriteString(unicode, chars)*sizeof(wchar_t)-cacheSize; cacheSize=0; } if(needToFree) { delete[] unicode; } if(all-bytes>0) { cacheSize=all-bytes; memcpy(cacheBuffer, (vuint8_t*)_buffer+_size-cacheSize, cacheSize); result+=cacheSize; } return result; } /*********************************************************************** CharDecoder ***********************************************************************/ CharDecoder::CharDecoder() :stream(0) ,cacheSize(0) { } void CharDecoder::Setup(IStream* _stream) { stream=_stream; } void CharDecoder::Close() { } vint CharDecoder::Read(void* _buffer, vint _size) { vuint8_t* unicode=(vuint8_t*)_buffer; vint result=0; { vint index=0; while(cacheSize>0 && _size>0) { *unicode++=cacheBuffer[index]++; cacheSize--; _size--; result++; } } const vint chars=_size/sizeof(wchar_t); vint bytes=ReadString((wchar_t*)unicode, chars)*sizeof(wchar_t); result+=bytes; _size-=bytes; unicode+=bytes; if(_size>0) { wchar_t c; if(ReadString(&c, 1)==1) { cacheSize=sizeof(wchar_t)-_size; memcpy(unicode, &c, _size); memcpy(cacheBuffer, (vuint8_t*)&c+_size, cacheSize); result+=_size; } } return result; } /*********************************************************************** Mbcs ***********************************************************************/ vint MbcsEncoder::WriteString(wchar_t* _buffer, vint chars) { #if defined VCZH_MSVC vint length=WideCharToMultiByte(CP_THREAD_ACP, 0, _buffer, (int)chars, NULL, NULL, NULL, NULL); char* mbcs=new char[length]; WideCharToMultiByte(CP_THREAD_ACP, 0, _buffer, (int)chars, mbcs, (int)length, NULL, NULL); vint result=stream->Write(mbcs, length); delete[] mbcs; #elif defined VCZH_GCC WString w(_buffer, chars); AString a=wtoa(w); vint length=a.Length(); vint result=stream->Write((void*)a.Buffer(), length); #endif if(result==length) { return chars; } else { Close(); return 0; } } vint MbcsDecoder::ReadString(wchar_t* _buffer, vint chars) { char* source=new char[chars*2]; char* reading=source; vint readed=0; while(readedRead(reading, 1)!=1) { break; } #if defined VCZH_MSVC if(IsDBCSLeadByte(*reading)) #elif defined VCZH_GCC if((vint8_t)*reading<0) #endif { if(stream->Read(reading+1, 1)!=1) { break; } reading+=2; } else { reading++; } readed++; } #if defined VCZH_MSVC MultiByteToWideChar(CP_THREAD_ACP, 0, source, (int)(reading-source), _buffer, (int)chars); #elif defined VCZH_GCC AString a(source, (vint)(reading-source)); WString w=atow(a); memcpy(_buffer, w.Buffer(), readed*sizeof(wchar_t)); #endif delete[] source; return readed; } /*********************************************************************** Utf-16 ***********************************************************************/ vint Utf16Encoder::WriteString(wchar_t* _buffer, vint chars) { #if defined VCZH_MSVC return stream->Write(_buffer, chars*sizeof(wchar_t))/sizeof(wchar_t); #elif defined VCZH_GCC vint writed = 0; vuint16_t utf16 = 0; vuint8_t* utf16buf = (vuint8_t*)&utf16; while (writed < chars) { wchar_t w = *_buffer++; if (w < 0x10000) { utf16 = (vuint16_t)w; if (stream->Write(&utf16buf[0], 1) != 1) break; if (stream->Write(&utf16buf[1], 1) != 1) break; } else if (w < 0x110000) { wchar_t inc = w - 0x10000; utf16 = (vuint16_t)(inc / 0x400) + 0xD800; if (stream->Write(&utf16buf[0], 1) != 1) break; if (stream->Write(&utf16buf[1], 1) != 1) break; utf16 = (vuint16_t)(inc % 0x400) + 0xDC00; if (stream->Write(&utf16buf[0], 1) != 1) break; if (stream->Write(&utf16buf[1], 1) != 1) break; } else { break; } writed++; } if(writed!=chars) { Close(); } return writed; #endif } vint Utf16Decoder::ReadString(wchar_t* _buffer, vint chars) { #if defined VCZH_MSVC return stream->Read(_buffer, chars*sizeof(wchar_t))/sizeof(wchar_t); #elif defined VCZH_GCC wchar_t* writing = _buffer; while (writing - _buffer < chars) { vuint16_t utf16_1 = 0; vuint16_t utf16_2 = 0; if (stream->Read(&utf16_1, 2) != 2) break; if (utf16_1 < 0xD800 || utf16_1 > 0xDFFF) { *writing++ = (wchar_t)utf16_1; } else if (utf16_1 < 0xDC00) { if (stream->Read(&utf16_2, 2) != 2) break; if (0xDC00 <= utf16_2 && utf16_2 <= 0xDFFF) { *writing++ = (wchar_t)(utf16_1 - 0xD800) * 0x400 + (wchar_t)(utf16_2 - 0xDC00) + 0x10000; } else { break; } } else { break; } } return writing - _buffer; #endif } /*********************************************************************** Utf-16-be ***********************************************************************/ vint Utf16BEEncoder::WriteString(wchar_t* _buffer, vint chars) { #if defined VCZH_MSVC vint writed=0; while(writedWrite(((unsigned char*)_buffer)+1, 1)!=1) { break; } if(stream->Write(_buffer, 1)!=1) { break; } _buffer++; writed++; } if(writed!=chars) { Close(); } return writed; #elif defined VCZH_GCC vint writed = 0; vuint16_t utf16 = 0; vuint8_t* utf16buf = (vuint8_t*)&utf16; while (writed < chars) { wchar_t w = *_buffer++; if (w < 0x10000) { utf16 = (vuint16_t)w; if (stream->Write(&utf16buf[1], 1) != 1) break; if (stream->Write(&utf16buf[0], 1) != 1) break; } else if (w < 0x110000) { wchar_t inc = w - 0x10000; utf16 = (vuint16_t)(inc / 0x400) + 0xD800; if (stream->Write(&utf16buf[1], 1) != 1) break; if (stream->Write(&utf16buf[0], 1) != 1) break; utf16 = (vuint16_t)(inc % 0x400) + 0xDC00; if (stream->Write(&utf16buf[1], 1) != 1) break; if (stream->Write(&utf16buf[0], 1) != 1) break; } else { break; } writed++; } if(writed!=chars) { Close(); } return writed; #endif } vint Utf16BEDecoder::ReadString(wchar_t* _buffer, vint chars) { #if defined VCZH_MSVC chars=stream->Read(_buffer, chars*sizeof(wchar_t))/sizeof(wchar_t); unsigned char* unicode=(unsigned char*)_buffer; for(vint i=0;iRead(&utf16_1, 2) != 2) break; utf16buf = (vuint8_t*)&utf16_1; utf16buf_temp = utf16buf[0]; utf16buf[0] = utf16buf[1]; utf16buf[1] = utf16buf_temp; if (utf16_1 < 0xD800 || utf16_1 > 0xDFFF) { *writing++ = (wchar_t)utf16_1; } else if (utf16_1 < 0xDC00) { if (stream->Read(&utf16_2, 2) != 2) break; utf16buf = (vuint8_t*)&utf16_2; utf16buf_temp = utf16buf[0]; utf16buf[0] = utf16buf[1]; utf16buf[1] = utf16buf_temp; if (0xDC00 <= utf16_2 && utf16_2 <= 0xDFFF) { *writing++ = (wchar_t)(utf16_1 - 0xD800) * 0x400 + (wchar_t)(utf16_2 - 0xDC00) + 0x10000; } else { break; } } else { break; } } return writing - _buffer; #endif } /*********************************************************************** Utf8 ***********************************************************************/ vint Utf8Encoder::WriteString(wchar_t* _buffer, vint chars) { #if defined VCZH_MSVC vint length=WideCharToMultiByte(CP_UTF8, 0, _buffer, (int)chars, NULL, NULL, NULL, NULL); char* mbcs=new char[length]; WideCharToMultiByte(CP_UTF8, 0, _buffer, (int)chars, mbcs, (int)length, NULL, NULL); vint result=stream->Write(mbcs, length); delete[] mbcs; if(result==length) { return chars; } else { Close(); return 0; } #elif defined VCZH_GCC vint writed = 0; while (writed < chars) { wchar_t w = *_buffer++; vuint8_t utf8[4]; if (w < 0x80) { utf8[0] = (vuint8_t)w; if (stream->Write(utf8, 1) != 1) break; } else if (w < 0x800) { utf8[0] = 0xC0 + ((w & 0x7C0) >> 6); utf8[1] = 0x80 + (w & 0x3F); if (stream->Write(utf8, 2) != 2) break; } else if (w < 0x10000) { utf8[0] = 0xE0 + ((w & 0xF000) >> 12); utf8[1] = 0x80 + ((w & 0xFC0) >> 6); utf8[2] = 0x80 + (w & 0x3F); if (stream->Write(utf8, 3) != 3) break; } else if (w < 0x110000) // only accept UTF-16 range { utf8[0] = 0xF0 + ((w & 0x1C0000) >> 18); utf8[1] = 0x80 + ((w & 0x3F000) >> 12); utf8[2] = 0x80 + ((w & 0xFC0) >> 6); utf8[3] = 0x80 + (w & 0x3F); if (stream->Write(utf8, 4) != 4) break; } else { break; } writed++; } if(writed!=chars) { Close(); } return writed; #endif } Utf8Decoder::Utf8Decoder() #if defined VCZH_MSVC :cache(0) ,cacheAvailable(false) #endif { } vint Utf8Decoder::ReadString(wchar_t* _buffer, vint chars) { vuint8_t source[4]; #if defined VCZH_MSVC wchar_t target[2]; #endif wchar_t* writing=_buffer; vint readed=0; vint sourceCount=0; while(readedRead(source, 1)!=1) { break; } if((*source & 0xF0) == 0xF0) { if(stream->Read(source+1, 3)!=3) { break; } sourceCount=4; } else if((*source & 0xE0) == 0xE0) { if(stream->Read(source+1, 2)!=2) { break; } sourceCount=3; } else if((*source & 0xC0) == 0xC0) { if(stream->Read(source+1, 1)!=1) { break; } sourceCount=2; } else { sourceCount=1; } #if defined VCZH_MSVC int targetCount=MultiByteToWideChar(CP_UTF8, 0, (char*)source, (int)sourceCount, target, 2); if(targetCount==1) { *writing++=target[0]; } else if(targetCount==2) { *writing++=target[0]; cache=target[1]; cacheAvailable=true; } else { break; } } #elif defined VCZH_GCC if (sourceCount == 1) { *writing++ = (wchar_t)source[0]; } else if (sourceCount == 2) { *writing++ = (((wchar_t)source[0] & 0x1F) << 6) + ((wchar_t)source[1] & 0x3F); } else if (sourceCount == 3) { *writing++ = (((wchar_t)source[0] & 0xF) << 12) + (((wchar_t)source[1] & 0x3F) << 6) + ((wchar_t)source[2] & 0x3F); } else if (sourceCount == 4) { *writing++ = (((wchar_t)source[0] & 0x7) << 18) + (((wchar_t)source[1] & 0x3F) << 12) + (((wchar_t)source[2] & 0x3F) << 6) + ((wchar_t)source[3] & 0x3F); } else { break; } #endif readed++; } return readed; } /*********************************************************************** BomEncoder ***********************************************************************/ BomEncoder::BomEncoder(Encoding _encoding) :encoding(_encoding) ,encoder(0) { switch(encoding) { case Mbcs: encoder=new MbcsEncoder; break; case Utf8: encoder=new Utf8Encoder; break; case Utf16: encoder=new Utf16Encoder; break; case Utf16BE: encoder=new Utf16BEEncoder; break; } } BomEncoder::~BomEncoder() { Close(); } void BomEncoder::Setup(IStream* _stream) { switch(encoding) { case Mbcs: break; case Utf8: _stream->Write((void*)"\xEF\xBB\xBF", 3); break; case Utf16: _stream->Write((void*)"\xFF\xFE", 2); break; case Utf16BE: _stream->Write((void*)"\xFE\xFF", 2); break; } encoder->Setup(_stream); } void BomEncoder::Close() { if(encoder) { encoder->Close(); delete encoder; encoder=0; } } vint BomEncoder::Write(void* _buffer, vint _size) { return encoder->Write(_buffer, _size); } /*********************************************************************** BomDecoder ***********************************************************************/ BomDecoder::BomStream::BomStream(IStream* _stream, char* _bom, vint _bomLength) :stream(_stream) ,bomPosition(0) ,bomLength(_bomLength) { memcpy(bom, _bom, bomLength); } bool BomDecoder::BomStream::CanRead()const { return IsAvailable(); } bool BomDecoder::BomStream::CanWrite()const { return false; } bool BomDecoder::BomStream::CanSeek()const { return false; } bool BomDecoder::BomStream::CanPeek()const { return false; } bool BomDecoder::BomStream::IsLimited()const { return stream!=0 && stream->IsLimited(); } bool BomDecoder::BomStream::IsAvailable()const { return stream!=0 && stream->IsAvailable(); } void BomDecoder::BomStream::Close() { stream=0; } pos_t BomDecoder::BomStream::Position()const { return IsAvailable()?bomPosition+stream->Position():-1; } pos_t BomDecoder::BomStream::Size()const { return -1; } void BomDecoder::BomStream::Seek(pos_t _size) { CHECK_FAIL(L"BomDecoder::BomStream::Seek(pos_t)#Operation not supported."); } void BomDecoder::BomStream::SeekFromBegin(pos_t _size) { CHECK_FAIL(L"BomDecoder::BomStream::SeekFromBegin(pos_t)#Operation not supported."); } void BomDecoder::BomStream::SeekFromEnd(pos_t _size) { CHECK_FAIL(L"BomDecoder::BomStream::SeekFromEnd(pos_t)#Operation not supported."); } vint BomDecoder::BomStream::Read(void* _buffer, vint _size) { vint result=0; unsigned char* buffer=(unsigned char*)_buffer; if(bomPositionRead(buffer, _size); } return result; } vint BomDecoder::BomStream::Write(void* _buffer, vint _size) { CHECK_FAIL(L"BomDecoder::BomStream::Write(void*, vint)#Operation not supported."); } vint BomDecoder::BomStream::Peek(void* _buffer, vint _size) { CHECK_FAIL(L"BomDecoder::BomStream::Peek(void*, vint)#Operation not supported."); } BomDecoder::BomDecoder() :decoder(0) { } BomDecoder::~BomDecoder() { Close(); } void BomDecoder::Setup(IStream* _stream) { char bom[3]={0}; vint length=_stream->Read(bom, sizeof(bom)); if(strncmp(bom, "\xEF\xBB\xBF", 3)==0) { decoder=new Utf8Decoder; stream=new BomStream(_stream, bom+3, 0); } else if(strncmp(bom, "\xFF\xFE", 2)==0) { decoder=new Utf16Decoder; stream=new BomStream(_stream, bom+2, 1); } else if(strncmp(bom, "\xFE\xFF", 2)==0) { decoder=new Utf16BEDecoder; stream=new BomStream(_stream, bom+2, 1); } else { decoder=new MbcsDecoder; stream=new BomStream(_stream, bom, 3); } decoder->Setup(stream); } void BomDecoder::Close() { if(decoder) { decoder->Close(); delete decoder; decoder=0; stream->Close(); delete stream; stream=0; } } vint BomDecoder::Read(void* _buffer, vint _size) { return decoder->Read(_buffer, _size); } /*********************************************************************** CharEncoder ***********************************************************************/ bool CanBeMbcs(unsigned char* buffer, vint size) { for(vint i=0;i bool GetEncodingResult(int(&tests)[Count], bool(&results)[Count], int test) { for (vint i = 0; i < Count; i++) { if (tests[i] & test) { if (results[i]) return true; } } return false; } #endif void TestEncoding(unsigned char* buffer, vint size, BomEncoder::Encoding& encoding, bool& containsBom) { if (size >= 3 && strncmp((char*)buffer, "\xEF\xBB\xBF", 3) == 0) { encoding = BomEncoder::Utf8; containsBom = true; } else if (size >= 2 && strncmp((char*)buffer, "\xFF\xFE", 2) == 0) { encoding = BomEncoder::Utf16; containsBom = true; } else if (size >= 2 && strncmp((char*)buffer, "\xFE\xFF", 2) == 0) { encoding = BomEncoder::Utf16BE; containsBom = true; } else { encoding = BomEncoder::Mbcs; containsBom = false; bool utf16HitSurrogatePairs = false; bool utf16BEHitSurrogatePairs = false; bool roughMbcs = CanBeMbcs(buffer, size); bool roughUtf8 = CanBeUtf8(buffer, size); bool roughUtf16 = CanBeUtf16(buffer, size, utf16HitSurrogatePairs); bool roughUtf16BE = CanBeUtf16BE(buffer, size, utf16BEHitSurrogatePairs); vint roughCount = (roughMbcs ? 1 : 0) + (roughUtf8 ? 1 : 0) + (roughUtf16 ? 1 : 0) + (roughUtf16BE ? 1 : 0); if (roughCount == 1) { if (roughUtf8) encoding = BomEncoder::Utf8; else if (roughUtf16) encoding = BomEncoder::Utf16; else if (roughUtf16BE) encoding = BomEncoder::Utf16BE; } else if (roughCount > 1) { #if defined VCZH_MSVC int tests[] = { IS_TEXT_UNICODE_REVERSE_ASCII16, IS_TEXT_UNICODE_REVERSE_STATISTICS, IS_TEXT_UNICODE_REVERSE_CONTROLS, IS_TEXT_UNICODE_ASCII16, IS_TEXT_UNICODE_STATISTICS, IS_TEXT_UNICODE_CONTROLS, IS_TEXT_UNICODE_ILLEGAL_CHARS, IS_TEXT_UNICODE_ODD_LENGTH, IS_TEXT_UNICODE_NULL_BYTES, }; const vint TestCount = sizeof(tests) / sizeof(*tests); bool results[TestCount]; for (vint i = 0; i < TestCount; i++) { int test = tests[i]; results[i] = IsTextUnicode(buffer, (int)size, &test) != 0; } if (size % 2 == 0 && !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_ASCII16) && !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_STATISTICS) && !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_CONTROLS) ) { for (vint i = 0; i < size; i += 2) { unsigned char c = buffer[i]; buffer[i] = buffer[i + 1]; buffer[i + 1] = c; } // 3 = (count of reverse group) = (count of unicode group) for (vint i = 0; i < 3; i++) { int test = tests[i + 3]; results[i] = IsTextUnicode(buffer, (int)size, &test) != 0; } for (vint i = 0; i < size; i += 2) { unsigned char c = buffer[i]; buffer[i] = buffer[i + 1]; buffer[i + 1] = c; } } if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_UNICODE_MASK)) { if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_ASCII_MASK)) { encoding = BomEncoder::Utf8; } else if (roughUtf8 || !roughMbcs) { encoding = BomEncoder::Utf8; } } else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_ASCII16)) { encoding = BomEncoder::Utf16; } else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_ASCII16)) { encoding = BomEncoder::Utf16BE; } else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_CONTROLS)) { encoding = BomEncoder::Utf16; } else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_CONTROLS)) { encoding = BomEncoder::Utf16BE; } else { if (!roughUtf8) { if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_STATISTICS)) { encoding = BomEncoder::Utf16; } else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_STATISTICS)) { encoding = BomEncoder::Utf16BE; } } else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_UNICODE_MASK)) { encoding = BomEncoder::Utf8; } else if (roughUtf8 || !roughMbcs) { encoding = BomEncoder::Utf8; } } #elif defined VCZH_GCC if (roughUtf16 && roughUtf16BE && !roughUtf8) { if (utf16BEHitSurrogatePairs && !utf16HitSurrogatePairs) { encoding = BomEncoder::Utf16BE; } else { encoding = BomEncoder::Utf16; } } else { encoding = BomEncoder::Utf8; } #endif } } } } } /*********************************************************************** .\STREAM\COMPRESSIONSTREAM.CPP ***********************************************************************/ namespace vl { namespace stream { using namespace collections; using namespace lzw; /*********************************************************************** LzwBase ***********************************************************************/ void LzwBase::UpdateIndexBits() { if (nextIndex >=2 && (nextIndex & (nextIndex - 1)) == 0) { indexBits++; } } lzw::Code* LzwBase::CreateCode(lzw::Code* prefix, vuint8_t byte) { if (nextIndex < MaxDictionarySize) { Code* code = codeAllocator.Create(); code->byte = byte; code->code = nextIndex; code->parent = prefix; code->size = prefix->size + 1; prefix->children.Set(byte, code, mapAllocator); nextIndex++; return code; } else { return 0; } } LzwBase::LzwBase() :codeAllocator(65536) , mapAllocator(1048576) { root = codeAllocator.Create(); for (vint i = 0; i < 256; i++) { UpdateIndexBits(); CreateCode(root, (vuint8_t)i); } } LzwBase::LzwBase(bool (&existingBytes)[256]) { root = codeAllocator.Create(); for (vint i = 0; i < 256; i++) { if (existingBytes[i]) { UpdateIndexBits(); CreateCode(root, (vuint8_t)i); } } if (indexBits < 8) { eofIndex = nextIndex++; } } LzwBase::~LzwBase() { } /*********************************************************************** LzwEncoder ***********************************************************************/ void LzwEncoder::Flush() { vint written = 0; vint bufferUsedSize = bufferUsedBits / 8; if (bufferUsedBits % 8 != 0) { bufferUsedSize++; } while (written < bufferUsedSize) { vint size = stream->Write(buffer + written, bufferUsedSize - written); CHECK_ERROR(size != 0, L"LzwEncoder::Flush()#Failed to flush the lzw buffer."); written += size; } bufferUsedBits = 0; } vuint8_t highMarks[9] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF }; vuint8_t lowMarks[9] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF }; void LzwEncoder::WriteNumber(vint number, vint bitSize) { vint bitStart = 0; vint bitStep = 8 - bufferUsedBits % 8; if (bitStep > bitSize) { bitStep = bitSize; } while (bitStart < bitSize) { if(bufferUsedBits == BufferSize * 8) { Flush(); } vint writeStart = bufferUsedBits % 8; vint byteIndex = bufferUsedBits / 8; vuint8_t byte = buffer[byteIndex]; byte &= highMarks[writeStart]; vuint8_t content = (vuint8_t)((number >> bitStart)&lowMarks[bitStep]) << (8 - writeStart - bitStep); byte |= content; buffer[byteIndex] = byte; bufferUsedBits += bitStep; bitStart += bitStep; vint remain = bitSize - bitStart; bitStep = remain < 8 ? remain : 8; } } LzwEncoder::LzwEncoder() { prefix = root; } LzwEncoder::LzwEncoder(bool (&existingBytes)[256]) :LzwBase(existingBytes) { prefix = root; } LzwEncoder::~LzwEncoder() { } void LzwEncoder::Setup(IStream* _stream) { stream = _stream; } void LzwEncoder::Close() { if (prefix != root) { WriteNumber(prefix->code, indexBits); prefix = root; } vint remain = 8 - bufferUsedBits % 8; if (remain != 8 && remain >= indexBits) { CHECK_ERROR(eofIndex != -1, L"LzwEncoder::Close()#Internal error."); WriteNumber(eofIndex, indexBits); } Flush(); } vint LzwEncoder::Write(void* _buffer, vint _size) { vuint8_t* bytes = (vuint8_t*)_buffer; for (vint i = 0; i < _size; i++) { vuint8_t byte = bytes[i]; Code* next = prefix->children.Get(byte); if (next) { prefix = next; } else { WriteNumber(prefix->code, indexBits); if (nextIndex < MaxDictionarySize) { UpdateIndexBits(); CreateCode(prefix, byte); } prefix = root->children.Get(byte); } } return _size; } /*********************************************************************** LzwDecoder ***********************************************************************/ bool LzwDecoder::ReadNumber(vint& number, vint bitSize) { number = 0; if (inputBufferSize == -1) { return false; } vint remainBits = inputBufferSize * 8 - inputBufferUsedBits; vint writtenBits = 0; vint bitStep = 8 - inputBufferUsedBits % 8; if (bitStep > bitSize) { bitStep = bitSize; } while (writtenBits < bitSize) { if (remainBits == 0) { inputBufferSize = stream->Read(inputBuffer, BufferSize); if (inputBufferSize == 0) { inputBufferSize = -1; return false; } remainBits = inputBufferSize * 8; inputBufferUsedBits = 0; } vuint8_t byte = inputBuffer[inputBufferUsedBits / 8]; byte >>= (8 - inputBufferUsedBits % 8 - bitStep); byte &= lowMarks[bitStep]; number |= byte << writtenBits; inputBufferUsedBits += bitStep; remainBits -= bitStep; writtenBits += bitStep; vint remain = bitSize - writtenBits; bitStep = remain < 8 ? remain : 8; } return true; } void LzwDecoder::PrepareOutputBuffer(vint size) { if (outputBuffer.Count() < size) { outputBuffer.Resize(size); } outputBufferSize = size; } void LzwDecoder::ExpandCodeToOutputBuffer(lzw::Code* code) { vuint8_t* outputByte = &outputBuffer[0] + code->size; Code* current = code; while (current != root) { *(--outputByte) = current->byte; current = current->parent; } outputBufferUsedBytes = 0; } LzwDecoder::LzwDecoder() { for (vint i = 0; i < 256; i++) { dictionary.Add(root->children.Get((vuint8_t)i)); } } LzwDecoder::LzwDecoder(bool (&existingBytes)[256]) :LzwBase(existingBytes) { for (vint i = 0; i < 256; i++) { if (existingBytes[i]) { dictionary.Add(root->children.Get((vuint8_t)i)); } } if (eofIndex != -1) { dictionary.Add(0); } } LzwDecoder::~LzwDecoder() { } void LzwDecoder::Setup(IStream* _stream) { stream = _stream; } void LzwDecoder::Close() { } vint LzwDecoder::Read(void* _buffer, vint _size) { vint written = 0; vuint8_t* bytes = (vuint8_t*)_buffer; while (written < _size) { vint expect = _size - written; vint remain = outputBufferSize - outputBufferUsedBytes; if (remain == 0) { vint index = 0; if (!ReadNumber(index, indexBits) || index == eofIndex) { break; } Code* prefix = 0; if (index == dictionary.Count()) { prefix = lastCode; PrepareOutputBuffer(prefix->size + 1); ExpandCodeToOutputBuffer(prefix); outputBuffer[outputBufferSize - 1] = outputBuffer[0]; } else { prefix = dictionary[index]; PrepareOutputBuffer(prefix->size); ExpandCodeToOutputBuffer(prefix); } if (nextIndex < MaxDictionarySize) { if (lastCode) { dictionary.Add(CreateCode(lastCode, outputBuffer[0])); } UpdateIndexBits(); } lastCode = dictionary[index]; } else { if (remain > expect) { remain = expect; } memcpy(bytes + written, &outputBuffer[outputBufferUsedBytes], remain); outputBufferUsedBytes += remain; written += remain; } } return written; } /*********************************************************************** Helper Functions ***********************************************************************/ vint CopyStream(stream::IStream& inputStream, stream::IStream& outputStream) { vint totalSize = 0; while (true) { char buffer[1024]; vint copied = inputStream.Read(buffer, (vint)sizeof(buffer)); if (copied == 0) { break; } totalSize += outputStream.Write(buffer, copied); } return totalSize; } const vint CompressionFragmentSize = 1048576; void CompressStream(stream::IStream& inputStream, stream::IStream& outputStream) { Array buffer(CompressionFragmentSize); while (true) { vint size = inputStream.Read(&buffer[0], buffer.Count()); if (size == 0) break; MemoryStream compressedStream; { LzwEncoder encoder; EncoderStream encoderStream(compressedStream, encoder); encoderStream.Write(&buffer[0], size); } compressedStream.SeekFromBegin(0); { { vint32_t bufferSize = (vint32_t)size; outputStream.Write(&bufferSize, (vint)sizeof(bufferSize)); } { vint32_t compressedSize = (vint32_t)compressedStream.Size(); outputStream.Write(&compressedSize, (vint)sizeof(compressedSize)); } CopyStream(compressedStream, outputStream); } } } void DecompressStream(stream::IStream& inputStream, stream::IStream& outputStream) { vint totalSize = 0; vint totalWritten = 0; while (true) { vint32_t bufferSize = 0; if (inputStream.Read(&bufferSize, (vint)sizeof(bufferSize)) != sizeof(bufferSize)) { break; } vint32_t compressedSize = 0; CHECK_ERROR(inputStream.Read(&compressedSize, (vint)sizeof(compressedSize)) == sizeof(compressedSize), L"vl::stream::DecompressStream(MemoryStream&, MemoryStream&)#Incomplete input"); Array buffer(compressedSize); CHECK_ERROR(inputStream.Read(&buffer[0], compressedSize) == compressedSize, L"vl::stream::DecompressStream(MemoryStream&, MemoryStream&)#Incomplete input"); MemoryWrapperStream compressedStream(&buffer[0], compressedSize); LzwDecoder decoder; DecoderStream decoderStream(compressedStream, decoder); totalWritten += CopyStream(decoderStream, outputStream); totalSize += bufferSize; } CHECK_ERROR(outputStream.Size() == totalSize, L"vl::stream::DecompressStream(MemoryStream&, MemoryStream&)#Incomplete input"); } } } /*********************************************************************** .\STREAM\FILESTREAM.CPP ***********************************************************************/ #if defined VCZH_GCC #endif namespace vl { namespace stream { #if defined VCZH_GCC void _fseeki64(FILE* file, pos_t offset, int origin) { fseek(file, (long)offset, origin); } #endif /*********************************************************************** FileStream ***********************************************************************/ FileStream::FileStream(const WString& fileName, AccessRight _accessRight) :accessRight(_accessRight) { const wchar_t* mode=L"rb"; switch(accessRight) { case ReadOnly: mode=L"rb"; break; case WriteOnly: mode=L"wb"; break; case ReadWrite: mode=L"w+b"; break; } #if defined VCZH_MSVC if(_wfopen_s(&file, fileName.Buffer(), mode)!=0) { file=0; } #elif defined VCZH_GCC AString fileNameA = wtoa(fileName); AString modeA = wtoa(mode); file = fopen(fileNameA.Buffer(), modeA.Buffer()); #endif } FileStream::~FileStream() { Close(); } bool FileStream::CanRead()const { return file!=0 && (accessRight==ReadOnly || accessRight==ReadWrite); } bool FileStream::CanWrite()const { return file!=0 && (accessRight==WriteOnly || accessRight==ReadWrite); } bool FileStream::CanSeek()const { return file!=0; } bool FileStream::CanPeek()const { return file!=0 && (accessRight==ReadOnly || accessRight==ReadWrite); } bool FileStream::IsLimited()const { return file!=0 && accessRight==ReadOnly; } bool FileStream::IsAvailable()const { return file!=0; } void FileStream::Close() { if(file!=0) { fclose(file); file=0; } } pos_t FileStream::Position()const { if(file!=0) { #if defined VCZH_MSVC fpos_t position=0; if(fgetpos(file, &position)==0) { return position; } #elif defined VCZH_GCC return (pos_t)ftell(file); #endif } return -1; } pos_t FileStream::Size()const { if(file!=0) { #if defined VCZH_MSVC fpos_t position=0; if(fgetpos(file, &position)==0) { if(fseek(file, 0, SEEK_END)==0) { pos_t size=Position(); if(fsetpos(file, &position)==0) { return size; } } } #elif defined VCZH_GCC long position = ftell(file); fseek(file, 0, SEEK_END); long size=ftell(file); fseek(file, position, SEEK_SET); return (pos_t)size; #endif } return -1; } void FileStream::Seek(pos_t _size) { if(Position()+_size>Size()) { _fseeki64(file, 0, SEEK_END); } else if(Position()+_size<0) { _fseeki64(file, 0, SEEK_SET); } else { _fseeki64(file, _size, SEEK_CUR); } } void FileStream::SeekFromBegin(pos_t _size) { if(_size>Size()) { _fseeki64(file, 0, SEEK_END); } else if(_size<0) { _fseeki64(file, 0, SEEK_SET); } else { _fseeki64(file, _size, SEEK_SET); } } void FileStream::SeekFromEnd(pos_t _size) { if(_size<0) { _fseeki64(file, 0, SEEK_END); } else if(_size>Size()) { _fseeki64(file, 0, SEEK_SET); } else { _fseeki64(file, -_size, SEEK_END); } } vint FileStream::Read(void* _buffer, vint _size) { CHECK_ERROR(file!=0, L"FileStream::Read(pos_t)#Stream is closed, cannot perform this operation."); CHECK_ERROR(_size>=0, L"FileStream::Read(void*, vint)#Argument size cannot be negative."); return fread(_buffer, 1, _size, file); } vint FileStream::Write(void* _buffer, vint _size) { CHECK_ERROR(file!=0, L"FileStream::Write(pos_t)#Stream is closed, cannot perform this operation."); CHECK_ERROR(_size>=0, L"FileStream::Write(void*, vint)#Argument size cannot be negative."); return fwrite(_buffer, 1, _size, file); } vint FileStream::Peek(void* _buffer, vint _size) { CHECK_ERROR(file!=0, L"FileStream::Peek(pos_t)#Stream is closed, cannot perform this operation."); CHECK_ERROR(_size>=0, L"FileStream::Peek(void*, vint)#Argument size cannot be negative."); #if defined VCZH_MSVC fpos_t position=0; if(fgetpos(file, &position)==0) { size_t count=fread(_buffer, 1, _size, file); if(fsetpos(file, &position)==0) { return count; } } return -1; #elif defined VCZH_GCC long position=ftell(file); size_t count=fread(_buffer, 1, _size, file); fseek(file, position, SEEK_SET); return count; #endif } } } /*********************************************************************** .\STREAM\MEMORYSTREAM.CPP ***********************************************************************/ namespace vl { namespace stream { /*********************************************************************** MemoryStream ***********************************************************************/ void MemoryStream::PrepareSpace(vint totalSpace) { if(totalSpace>capacity) { totalSpace=(totalSpace/block+1)*block; char* newBuffer=new char[totalSpace]; if(buffer) { memcpy(newBuffer, buffer, size); delete[] buffer; } buffer=newBuffer; capacity=totalSpace; } } MemoryStream::MemoryStream(vint _block) :block(_block) ,buffer(0) ,size(0) ,position(0) ,capacity(0) { if(block<=0) { block=65536; } } MemoryStream::~MemoryStream() { Close(); } bool MemoryStream::CanRead()const { return block!=0; } bool MemoryStream::CanWrite()const { return block!=0; } bool MemoryStream::CanSeek()const { return block!=0; } bool MemoryStream::CanPeek()const { return block!=0; } bool MemoryStream::IsLimited()const { return false; } bool MemoryStream::IsAvailable()const { return block!=0; } void MemoryStream::Close() { if(buffer) { delete[] buffer; } block=0; buffer=0; size=-1; position=-1; capacity=0; } pos_t MemoryStream::Position()const { return position; } pos_t MemoryStream::Size()const { return size; } void MemoryStream::Seek(pos_t _size) { SeekFromBegin(position+_size); } void MemoryStream::SeekFromBegin(pos_t _size) { CHECK_ERROR(block!=0, L"MemoryStream::SeekFromBegin(pos_t)#Stream is closed, cannot perform this operation."); vint expected=(vint)_size; if(expected<0) { position=0; } else if(expected>=size) { position=size; } else { position=expected; } } void MemoryStream::SeekFromEnd(pos_t _size) { SeekFromBegin(size-_size); } vint MemoryStream::Read(void* _buffer, vint _size) { CHECK_ERROR(block!=0, L"MemoryStream::Read(pos_t)#Stream is closed, cannot perform this operation."); CHECK_ERROR(_size>=0, L"MemoryStream::Read(void*, vint)#Argument size cannot be negative."); vint max=size-position; if(_size>max) { _size=max; } memmove(_buffer, buffer+position, _size); position+=_size; return _size; } vint MemoryStream::Write(void* _buffer, vint _size) { CHECK_ERROR(block!=0, L"MemoryStream::Write(pos_t)#Stream is closed, cannot perform this operation."); CHECK_ERROR(_size>=0, L"MemoryStream::Write(void*, vint)#Argument size cannot be negative."); PrepareSpace(size+_size); memmove(buffer+position, _buffer, _size); position+=_size; if(size=0, L"MemoryStream::Peek(void*, vint)#Argument size cannot be negative."); vint max=size-position; if(_size>max) { _size=max; } memmove(_buffer, buffer+position, _size); return _size; } void* MemoryStream::GetInternalBuffer() { return buffer; } } } /*********************************************************************** .\STREAM\MEMORYWRAPPERSTREAM.CPP ***********************************************************************/ namespace vl { namespace stream { /*********************************************************************** MemoryWrapperStream ***********************************************************************/ MemoryWrapperStream::MemoryWrapperStream(void* _buffer, vint _size) :buffer((char*)_buffer) ,size(_size) ,position(0) { if(size<=0) { buffer=0; size=0; } } MemoryWrapperStream::~MemoryWrapperStream() { } bool MemoryWrapperStream::CanRead()const { return buffer!=0; } bool MemoryWrapperStream::CanWrite()const { return buffer!=0; } bool MemoryWrapperStream::CanSeek()const { return buffer!=0; } bool MemoryWrapperStream::CanPeek()const { return buffer!=0; } bool MemoryWrapperStream::IsLimited()const { return buffer!=0; } bool MemoryWrapperStream::IsAvailable()const { return buffer!=0; } void MemoryWrapperStream::Close() { buffer=0; size=-1; position=-1; } pos_t MemoryWrapperStream::Position()const { return position; } pos_t MemoryWrapperStream::Size()const { return size; } void MemoryWrapperStream::Seek(pos_t _size) { SeekFromBegin(position+_size); } void MemoryWrapperStream::SeekFromBegin(pos_t _size) { CHECK_ERROR(buffer!=0, L"MemoryWrapperStream::SeekFromBegin(pos_t)#Stream is closed, cannot perform this operation."); vint expected=(vint)_size; if(expected<0) { position=0; } else if(expected>=size) { position=size; } else { position=expected; } } void MemoryWrapperStream::SeekFromEnd(pos_t _size) { SeekFromBegin(size-_size); } vint MemoryWrapperStream::Read(void* _buffer, vint _size) { CHECK_ERROR(buffer!=0, L"MemoryWrapperStream::Read(pos_t)#Stream is closed, cannot perform this operation."); CHECK_ERROR(_size>=0, L"MemoryWrapperStream::Read(void*, vint)#Argument size cannot be negative."); vint max=size-position; if(_size>max) { _size=max; } memmove(_buffer, buffer+position, _size); position+=_size; return _size; } vint MemoryWrapperStream::Write(void* _buffer, vint _size) { CHECK_ERROR(buffer!=0, L"MemoryWrapperStream::Write(pos_t)#Stream is closed, cannot perform this operation."); CHECK_ERROR(_size>=0, L"MemoryWrapperStream::Write(void*, vint)#Argument size cannot be negative."); vint max=size-position; if(_size>max) { _size=max; } memmove(buffer+position, _buffer, _size); position+=_size; return _size; } vint MemoryWrapperStream::Peek(void* _buffer, vint _size) { CHECK_ERROR(buffer!=0, L"MemoryWrapperStream::Peek(pos_t)#Stream is closed, cannot perform this operation."); CHECK_ERROR(_size>=0, L"MemoryWrapperStream::Peek(void*, vint)#Argument size cannot be negative."); vint max=size-position; if(_size>max) { _size=max; } memmove(_buffer, buffer+position, _size); return _size; } } } /*********************************************************************** .\STREAM\RECORDERSTREAM.CPP ***********************************************************************/ namespace vl { namespace stream { /*********************************************************************** RecorderStream ***********************************************************************/ RecorderStream::RecorderStream(IStream& _in, IStream& _out) :in(&_in) ,out(&_out) { } RecorderStream::~RecorderStream() { } bool RecorderStream::CanRead()const { return IsAvailable() && in->CanRead(); } bool RecorderStream::CanWrite()const { return false; } bool RecorderStream::CanSeek()const { return false; } bool RecorderStream::CanPeek()const { return false; } bool RecorderStream::IsLimited()const { return IsAvailable() && in->IsLimited(); } bool RecorderStream::IsAvailable()const { return in!=0 && out!=0 && in->IsAvailable() && out->IsAvailable(); } void RecorderStream::Close() { in=0; out=0; } pos_t RecorderStream::Position()const { return IsAvailable()?in->Position():-1; } pos_t RecorderStream::Size()const { return IsAvailable()?in->Size():-1; } void RecorderStream::Seek(pos_t _size) { CHECK_FAIL(L"RecorderStream::Seek(pos_t)#Operation not supported."); } void RecorderStream::SeekFromBegin(pos_t _size) { CHECK_FAIL(L"RecorderStream::SeekFromBegin(pos_t)#Operation not supported."); } void RecorderStream::SeekFromEnd(pos_t _size) { CHECK_FAIL(L"RecorderStream::SeekFromEnd(pos_t)#Operation not supported."); } vint RecorderStream::Read(void* _buffer, vint _size) { _size=in->Read(_buffer, _size); out->Write(_buffer, _size); return _size; } vint RecorderStream::Write(void* _buffer, vint _size) { CHECK_FAIL(L"RecorderStream::Write(void*, vint)#Operation not supported."); } vint RecorderStream::Peek(void* _buffer, vint _size) { CHECK_FAIL(L"RecorderStream::Peek(void*, vint)#Operation not supported."); } } } /*********************************************************************** .\UNITTEST\UNITTEST.CPP ***********************************************************************/ #if defined VCZH_MSVC #endif namespace vl { namespace unittest { using namespace vl::console; /*********************************************************************** UnitTest ***********************************************************************/ #if defined VCZH_MSVC SpinLock spinLockUnitTest; #endif void UnitTest::PrintMessage(const WString& string) { #if defined VCZH_MSVC SpinLock::Scope scope(spinLockUnitTest); #endif Console::SetColor(false, true, false, true); Console::WriteLine(string); Console::SetColor(true, true, true, false); } void UnitTest::PrintInfo(const WString& string) { #if defined VCZH_MSVC SpinLock::Scope scope(spinLockUnitTest); #endif Console::SetColor(true, true, true, true); Console::WriteLine(string); Console::SetColor(true, true, true, false); } void UnitTest::PrintError(const WString& string) { #if defined VCZH_MSVC SpinLock::Scope scope(spinLockUnitTest); #endif Console::SetColor(true, false, false, true); Console::WriteLine(string); Console::SetColor(true, true, true, false); } struct UnitTestLink { UnitTest::TestProc testProc = nullptr; UnitTestLink* next = nullptr; }; UnitTestLink* testHead = nullptr; UnitTestLink** testTail = &testHead; void UnitTest::PushTest(TestProc testProc) { auto link = new UnitTestLink; link->testProc = testProc; *testTail = link; testTail = &link->next; } void UnitTest::RunAndDisposeTests() { auto current = testHead; testHead = nullptr; testTail = nullptr; while (current) { current->testProc(); auto temp = current; current = current->next; delete temp; } } } }