/*********************************************************************** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY DEVELOPER: Zihan Chen(vczh) ***********************************************************************/ #include "Vlpp.h" /*********************************************************************** BASIC.CPP ***********************************************************************/ #if defined VCZH_MSVC #include #elif defined VCZH_GCC #include #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 #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.Length() < 2 || fullPath[1] != L':') { wchar_t buffer[MAX_PATH + 1] = { 0 }; GetCurrentDirectory(sizeof(buffer) / sizeof(*buffer), buffer); fullPath = WString(buffer) + L"\\" + fullPath; } { wchar_t buffer[MAX_PATH + 1] = { 0 }; if (fullPath.Length() == 2 && fullPath[1] == L':') { fullPath += L"\\"; } GetFullPathName(fullPath.Buffer(), sizeof(buffer) / sizeof(*buffer), buffer, NULL); fullPath = buffer; } if (fullPath[fullPath.Length() - 1] == Delimiter) { fullPath = fullPath.Left(fullPath.Length() - 1); } #elif defined VCZH_GCC throw 0; #endif } 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 throw 0; #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 throw 0; #endif } bool FilePath::IsRoot()const { #if defined VCZH_MSVC return fullPath == L""; #elif defined VCZH_GCC throw 0; #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 defined VCZH_MSVC if (fullPath.Length()==0 || _filePath.fullPath.Length()==0 || fullPath[0] != _filePath.fullPath[0]) { return _filePath.fullPath; } 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 throw 0; #endif } /*********************************************************************** File ***********************************************************************/ File::File() { } File::File(const FilePath& _filePath) :filePath(_filePath) { } File::~File() { } const FilePath& File::GetFilePath()const { return filePath; } WString File::ReadAllText()const { WString text; ReadAllText(text); return text; } bool File::ReadAllText(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::ReadAllLines(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 throw 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 throw 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 (!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 throw 0; #endif } bool Folder::GetFiles(collections::List& files)const { #if defined VCZH_MSVC 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 throw 0; #endif } bool Folder::Exists()const { return filePath.IsFolder(); } bool Folder::Create(bool recursively)const { #if defined VCZH_MSVC 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 { return CreateDirectory(filePath.GetFullPath().Buffer(), NULL) != 0; } #elif defined VCZH_GCC throw 0; #endif } bool Folder::Delete(bool recursively)const { #if defined VCZH_MSVC 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); } return RemoveDirectory(filePath.GetFullPath().Buffer()) != 0; #elif defined VCZH_GCC throw 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 throw 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; } /*********************************************************************** 辅助函数 ***********************************************************************/ 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 } #ifdef VCZH_MSVC WString Locale::FormatNumber(const WString& number)const { #if defined 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 throw 0; #endif } WString Locale::FormatCurrency(const WString& currency)const { #if defined 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 throw 0; #endif } #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 { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_FULLWIDTH); #elif defined VCZH_GCC throw 0; #endif } WString Locale::ToHalfWidth(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_HALFWIDTH); #elif defined VCZH_GCC throw 0; #endif } WString Locale::ToHiragana(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_HIRAGANA); #elif defined VCZH_GCC throw 0; #endif } WString Locale::ToKatagana(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_KATAKANA); #elif defined VCZH_GCC throw 0; #endif } #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 { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_SIMPLIFIED_CHINESE); #elif defined VCZH_GCC throw 0; #endif } WString Locale::ToTraditionalChinese(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_TRADITIONAL_CHINESE); #elif defined VCZH_GCC throw 0; #endif } WString Locale::ToTileCase(const WString& str)const { #if defined VCZH_MSVC return Transform(localeName, str, LCMAP_TITLECASE); #elif defined VCZH_GCC throw 0; #endif } #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()); default: throw 0; } #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; default: throw 0; } 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; default: throw 0; } 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; default: throw 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; default: throw 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++; } } #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; } } /*********************************************************************** 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, (1<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 #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 /*********************************************************************** 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() { } 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(++ruleInfos[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(++ruleInfos[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->ruleInfos.Add(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 lai 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, false)==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; Dictionary>> childTypes; // 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=childTypes.Keys().IndexOf(parent); if(index==-1) { children=new List; childTypes.Add(parent, children); } else { children=childTypes.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 for(vint i=0;i& children=*childTypes.Values().Get(i).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.Values()) { if(!scanningStates.Contains(ruleInfo->rootRuleStartState)) { scanningStates.Add(ruleInfo->rootRuleStartState); } while(currentStatetransitions) { 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->ruleInfos.Keys()) { Ptr pdaRuleInfo=jointPDA->ruleInfos[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(ParsingTable::TransitionItem::Compare)); // 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->ruleInfos.Keys()) { // build new rule info Ptr ruleInfo=nondeterministicPDA->ruleInfos[rule]; Ptr newRuleInfo=new RuleInfo; automaton->ruleInfos.Add(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->ruleInfos.Keys()) { Ptr ruleInfo=nondeterministicPDA->ruleInfos[rule]; Ptr newRuleInfo=automaton->ruleInfos[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->ruleInfos[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 ***********************************************************************/ vint CompareTransitionForRearranging(Transition* t1, Transition* t2) { if(t1->transitionTypetransitionType) return -1; if(t1->transitionType>t2->transitionType) return 1; if(t1->transitionSymboltransitionSymbol) return -1; if(t1->transitionSymbol>t2->transitionSymbol) return 1; return 0; } vint CompareActionForRearranging(Ptr a1, Ptr a2) { if(a1->actionTypeactionType) return -1; if(a1->actionType>a2->actionType) return 1; if(a1->actionSourceactionSource) return -1; if(a1->actionSource>a2->actionSource) return 1; if(a1->actionTargetactionTarget) return -1; if(a1->actionTarget>a2->actionTarget) return 1; return 0; } 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->ruleInfos.Keys()) { // build new rule info Ptr ruleInfo=epsilonPDA->ruleInfos[rule]; Ptr newRuleInfo=new RuleInfo; automaton->ruleInfos.Add(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); List newStates; CopyFrom(newStates, oldNewStateMap.Values()); 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; /*********************************************************************** 自举 ***********************************************************************/ 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+") //------------------------------------- .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) { MemoryStream stream(64); { StreamWriter writer(stream); Log(type, writer); } stream.SeekFromBegin(0); { StreamReader reader(stream); return reader.ReadToEnd(); } } WString GrammarToString(ParsingDefinitionGrammar* grammar) { return GrammarStateToString(grammar, 0, true); } WString GrammarStateToString(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode) { MemoryStream stream(64); { StreamWriter writer(stream); Log(grammar, stateNode, beforeNode, writer); } stream.SeekFromBegin(0); { StreamReader reader(stream); return reader.ReadToEnd(); } } 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.Values()) { 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.Values()) { 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 ***********************************************************************/ 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]; } } } } /*********************************************************************** 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, bool forceGivingOrder) { if(t1->token!=t2->token) return UnknownOrder; if(forceGivingOrder) { TransitionLevel level1=GetTransitionLevel(t1); TransitionLevel level2=GetTransitionLevel(t2); if(level1>level2) return CorrectOrder; if(level1stackPattern.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(ic1t2?CorrectOrder:SameOrder; } else { return UnknownOrder; } } vint ParsingTable::TransitionItem::Compare(Ptr t1, Ptr t2) { OrderResult order=CheckOrder(t1, t2, true); 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::Reader reader(input); IO(reader); } void ParsingTable::Serialize(stream::IStream& output) { stream::internal::Writer writer(output); IO(writer); } /*********************************************************************** ParsingTable ***********************************************************************/ 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; } } } } /*********************************************************************** PARSING\PARSINGTREE.CPP ***********************************************************************/ 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); } } /*********************************************************************** ParsingEmptyPrintNodeRecorder ***********************************************************************/ 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); } /*********************************************************************** ParsingEmptyPrintNodeRecorder ***********************************************************************/ ParsingGeneratedLocationRecorder::ParsingGeneratedLocationRecorder(RangeMap& _rangeMap) :rangeMap(_rangeMap) { } ParsingGeneratedLocationRecorder::~ParsingGeneratedLocationRecorder() { } void ParsingGeneratedLocationRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range) { rangeMap.Add(node, 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); } } } /*********************************************************************** 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) { MemoryStream stream; { StreamWriter writer(stream); JsonUnescapeString(value.value.Sub(1, value.value.Length()-2), writer); } stream.SeekFromBegin(0); { StreamReader reader(stream); value.value=reader.ReadToEnd(); } } /*********************************************************************** 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) { MemoryStream stream; { StreamWriter writer(stream); JsonPrint(node, writer); } stream.SeekFromBegin(0); { StreamReader reader(stream); return reader.ReadToEnd(); } } } } } /*********************************************************************** PARSING\JSON\PARSINGJSON_PARSER.CPP ***********************************************************************/ namespace vl { namespace parsing { namespace json { /*********************************************************************** ParserText ***********************************************************************/ const wchar_t parserTextBuffer[] = 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"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"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;" ; vl::WString JsonGetParserTextBuffer() { return parserTextBuffer; } /*********************************************************************** SerializedTable ***********************************************************************/ const vint parserBufferLength = 4034; // 15032 bytes before compressing const vint parserBufferBlock = 1024; const vint parserBufferRemain = 962; const vint parserBufferRows = 4; const char* parserBuffer[] = { "\x00\x0B\x00\x02\x9F\x71\x02\x80\x01\x7F\x05\x06\x83\x20\x0F\x30\x00\x36\x86\x00\x72\x00\x05\x82\x86\x02\x83\x29\x00\x74\x11\x80\x09\x30\x02\x36\x00\x67\x07\x94\x87\x89\x82\x83\x85\x86\x0F\x8D\x92\x83\x97\x06\x81\x21\x8C\x30\xCE\x00\x01\x30\x05\x34\x01\x32\x22\x86\x88\x8A\x80\x89\x97\x8C\x96\x06\xCB\x37\x80\x09\x38\x03\x3A\x88\x12\xE4\x39\x83\x85\x90\x03\x92\x87\x48\x93\x86\x8D\x92\x82\xA0\x9D\xA2\x47\xAA\x80\x0A\xA4\x82\x9D\xA7\xA7\x3E\xAB\x93\xA1\xA3\xA0\xAD\xA8\xAE\x23\xBB\xA6\x9D\x91\xAB\x90\x04\x83\x42\x10\xB5\x3E\x8B\xAB\x9B\x8D\xA2\x5D\xCC\xBC\x88\x9D\xB6\x83\xB6\x81\x71\x8D\xB3\xBF\x8A\xA4\x9A\x88\xBC\x69\xDF\xAC\xBA\xAE\xB0\xBA\xB8\xBA\x85\xF7\x8B\xA4\x9B\xB8\xA8\xC6\xBF\x8E\x82\xD0\xD6\xB7\xC3\xCA\xB4\xA7\x8B\xBF\x86\x96\x82\x82\x9B\xB8\x9B\x62\x43\x92\x99\xB7\x84\x05\xCB\x8F\x1A\xB8\xB8\x30\x90\xB1\xAA\x82\x00\x54\x80\x0D\xAF\x92\x8A\x88\x9A\xBC\xFF\x41\xF9\xCC\x2C\x88\x98\x9C\xDF\x50\xC1\xC1\xE4\x06\x82\x99\x86\xA5\x38\xCA\xFF\x64\xD0\x06\xD1\x9A\x00\xA9\xC7\xC7\x8A\xE4\xEF\x24\xEC\x00\x6A\x43\xA3\x30\x92\xE9\x82\x80\xEF\xA9\xE1\xF8\x83\xFA\x8E\x21\xE2\x9C\x0F\xDC\x9C\xF7\x80\x9A\x89\x8F\x8F\x21\xD2\xF9\xDB\xDB\x88\xE5\xA3\xA6\x1D\x71\x67\x77\x1C\xDB\x42\x76\x40\x71\x01\xAA\x66\x5F\x43\x4D\x76\x1B\x80\x00\x73\x51\x73\x7D\x69\x10\x97\x79\x77\x46\xB9\x63\x7D\x40\x6C\x43\x5C\x82\x75\x77\xDF\x6A\x70\x00\x7B\x00\x14\x76\x1B\x7B\x50\x4A\x54\x81\x79\x06\x68\x70\x7A\x78\x30\x6E\x7D\x44\x7C\x75\x4C\x72\x43\x47\x34\x76\x48\x4F\x48\xE6\x40\x0E\x8A\x88\x24\xB2\x83\x51\x7C\xBA\x46\x4E\x80\x4D\x0F\x51\x85\x83\x74\xF4\x5A\x46\x7C\x5D\x21\x59\x80\x44\x87\x38\x5C\x87\x6F\x03\x06\x64\x06\x40\x96\xB7\x5D\x9B\x92\x74\x5E\x83\x42\x76\x72\x61\x9F\x94\x99\x98\x63\x8A\x79\x02\x41\x54\x00\x02\x14\x00\x55\x00\x05\x10\x00\x56\x00\x0F\x48\x71\x71\xB3\x96\x8D\x7D\x15\xB8\x47\x6E\x00\x06\x4A\x06\x42\x7B\x77\x80\x08\x47\x9C\x75\x85\xA9\x9D\x91\x02\x67\x88\x90\x00\x04\xBB\x86\x43\x00\x06\x6B\x94\x85\x9C\xC4\x44\x79\xA0\x00\x78\xB2\x90\x03\x9E\x1F\x73\x5F\x43\x43\x80\x82\x4B\x9D\x6E\xDE\x71\x5A\x12\x8F\x00\x10\x1E\xA6\x4C\xA5\x80\x0C\x14\x00\x7B\x00\x04\xA6\x40\x4D\x7F\x5C\xAA\xAA\xA0\x44\x7E\x77\xA1\x00\x31\xA3\xAD\x1F\x9F\xA3\x63\x5A\x40\x2F\x6F\x9F\x9A\x77\xAE\xB3\x90\xAE\x41\xB3\x9B\x1C\xA0\x6E\x98\x48\xBE\x9B\xB5\x0B\x7E\xA6\xA2\xA7\xC2\x80\x0D\x15\x89\xD5\x93\xBB\x42\x77\x4D\x00\x05\xBB\x4B\x23\x6C\x04\xB6\x98\xC1\x4A\x6E\x76\xB6\x32\x63\x4A\x0C\x00\xBA\x9F\x8D\x70\x9C\xE6\x80\x01\x5F\x9C\x6F\x9F\x06\x42\xB4\xB3\xAD\x0E\xB4\x00\x3F\x32\xA5\x5F\x0A\x00\x28\x00\x02\x0B\x06\xCA\x58\xC1\x0A\x04\xC9\xC0\x02\xB4\x38\x73\x9F\xB6\xB4\x08\xC1\xC3\xC1\xC1\xB3\x8E\xC0\x00\xC4\x05\xD6\xA0\x02\xC8\xD4\x58\x4D\x9B\x9B\x49\x15\x70\x03\x11\x00\x1B\x06\x42\x08\x12\xD2\xBE\x16\xC1\xB3\xB0\xCF\xB4\x1F\x34\xD3\xC0\x03\xCC\x73\x77\xC9\xCF\x5C\x1D\xF4\xA0\x00\x0D\x00\x04\xB0\xC6\x0A\x00\x30\xC2\xA2\x40\x4B\xD2\x58\xAC\x7D\xAE\xAF\x4B\x43\x9C\xB7\x86\xC4\x80\xC2\x3D\x92\x7A\x96\x40\xBA\xAB\xA8\x82\x71\x1B\x4F\xA2\x06\x41\x5E\xC5\x72\x80\x72\x0F\x4C\xCF\x99\x43\x0D\x5A\x48\x46\x46\x86\x70\x4D\x02\x41\x40\x00\x00\x08\x00\x5A\xBC\x00\x01\xD9\x09\x9A\x7F\xA2\x0F\xF4\xA4\xDC\xA6\xD9\x0A\x8F\xAE\x02\xE0\x5F\xE7\xDF\x80\xC3\x6F\xDC\x60\x4E\x6B\x02\x75\xD7\xDE\xDE\x7C\xE0\xD8\xD8\x00\x80\xDD\xD3\xE1\xDF\x61\xD0\x5D\xD1\xE5\x8A\xCF\xAC\xC1\x0C\x00\x3A\x36\x40\xE5\x9B\xD6\xEF\x80\xE0\xF3\xB7\xD0\xCD\xA8\x50\x4F\x40\xCF\xDD\x34\x44\x87\xDD\xE2\x85\xD0\x52\xE6\x51\x84\xE8\x16\xDE\xD0\x77\xC7\x90\x56\x92\x77\xFD\x0F\xEC\xCC\xD6\x63\xA9\xD3\xEF\xC4\xB3\xD2\xA0\xEA\xB8\xFE\xD0\x54\xEB\xC7\xC0\x0E\xA0\x54\x91\x8B\xF4\xEC\xA4\xBF\xD1\xFD\xE7\x43\xBB\xC7\x59\x82\xEF\x77\xF5\xA1\xF3\x83\xC4\xC0\x06\xF2\xEB\x00\x2E\x7F\xA1\xF6\xB3\xC5\xD0\x02\xF3\x00\x10\xF4\xE2\xF4\x0F\x54\xF7\xDE\x4C\x71\xA5\xBB\xBF\xB5\x77\x6D\x77\x88\x53\x40\x6C\x0E\x5B\x7E\x76\x2A\x67\x37\x77\x5A\x35\x6E\xFA\x76\x7C\x73\x97\x7A\x7F\xF2\x4E\x4D\x4E\xED\x76\x28\x81\xDE\x77\x71\xF8\x3D\x7F\x76\xF3\x40\x02\x78\x49\x43\x29\xF1\x55\x7D\x4C\x89\x0A\x49\x7E\xCD\x60\x03\xF3\x7B\x69\x75\xD0\x53\x78\x00\x02\x86\x67\xB5\x29\x62\x26\x96\x41\x87\x77\x1A\x54\x2E\x80\x06\x87\x83\xDF\x4D\x77\x49\xF8\x20\x01\xDD\x1A\x79\x83", "\x07\x50\x00\x71\xF7\x7F\x7B\xC2\x57\x5C\x6C\x98\x33\x4C\x30\xF3\x79\x49\xFD\x2C\x85\x89\xBF\x7F\x75\x6E\xD4\x2B\x55\x9D\x0F\x5A\x48\xCD\x5B\x8B\x78\x43\x23\x76\xFA\x27\x7C\x85\x2F\xA1\x80\x27\x12\x81\x04\x15\xC9\x8A\x83\x28\xAB\x82\x8B\xE8\x63\x29\x1A\xAC\x8F\x46\x18\x5A\x25\x81\x2A\x93\x88\x1C\xDC\x82\x8E\x18\xBF\x72\x8D\xAB\x5C\x35\xE7\x45\x28\x8A\xC1\x42\x96\x3F\x81\x62\x21\x20\xFD\x36\x2F\xA2\x0C\x65\x06\x00\x0C\x10\x19\x8B\x9D\x37\x46\x98\x76\x8F\xEC\x72\x59\xFC\x52\x57\x6F\x3D\xA0\x88\x27\x37\x97\x6C\xE7\x36\x28\x81\xBA\x5E\x80\x66\xEA\x51\x7E\x27\xE7\x8F\x76\x01\xA3\x94\x7B\x77\x64\x5B\xDD\x5F\x5C\x7D\x6F\x71\x7D\x76\xBF\x67\x92\x25\x8E\x8C\x84\x5D\xBF\x37\x92\x02\x90\x66\x26\xBF\x7C\x93\x32\xB1\x88\x94\x98\x89\x88\x29\xC2\x8D\x83\xEA\x69\x97\x77\xAB\x95\x81\x28\xCA\x90\x96\xF9\x73\x95\x7A\xB6\x9F\x74\x2E\xF7\x6E\x96\xA2\x20\x5A\x91\xED\x68\x44\x91\x1A\x72\x48\x1A\x4A\x2C\x61\x33\x1E\x8E\x40\x28\x75\x9D\x14\x40\x9E\x87\x00\x07\x64\x00\x34\x8B\x65\x56\xBF\x70\x47\xD7\x28\x98\xCC\x73\x5A\x94\x3A\x47\x9E\x9E\xE7\x7C\x8C\x32\xDB\x9C\x55\xF4\x36\x89\x9C\x33\x4E\x9D\x21\xE0\x96\x8D\x0A\x87\x74\xA1\xFF\x8A\x6C\x44\x6D\x6E\x52\x28\xBD\x41\x6F\xC6\x82\xA3\x25\xF7\x6B\xA1\x5E\x8C\x97\x97\x9A\x7D\x9A\x23\x80\x02\x06\x4F\x6B\x9E\xA3\x95\x9F\x96\x04\xC2\x96\x83\x62\x91\x99\x7D\xAE\x80\x6F\x32\xE5\x7E\x98\x0B\xAF\xA2\x84\xC9\x8F\x94\x02\xB2\x93\x61\x5A\x96\x84\xA0\x22\xAC\x99\x16\xF6\x4F\xA2\x6F\xA1\xA5\xA8\x23\xA9\x9F\x9C\x27\xA4\x93\x41\xAF\x99\x93\x2D\xB0\x9A\x3F\x9A\xA3\x9A\x9D\x8D\x9C\x7D\xCF\x9B\x77\x4D\xC8\x91\xA6\x01\x73\xA6\x9A\x3D\xAB\x79\x36\x87\x89\x96\xA4\xAB\x5C\x8E\x21\x47\xA2\xC8\x2B\x55\x8F\xF5\x30\x27\x91\x00\x14\x13\x24\x85\xAF\x44\xB7\x9A\x23\xA5\x42\x7B\x92\x54\xED\x94\x49\x69\xA7\x41\xA1\x44\x45\x94\xF0\x4B\x7F\x99\x4E\x88\xA3\x48\x75\x3E\xAE\x38\xF5\x2B\xA7\xDF\x74\x93\x79\xC4\x57\x95\x35\xED\xA3\x80\x8D\x3C\x94\xAD\x69\xB6\xAF\x53\xCB\x75\x56\xBD\x86\xB4\xAF\x89\xA9\x9B\x5F\x88\xBA\x44\x66\xB4\xA0\xAB\x36\xA7\xB2\x39\x80\xA6\x7B\xC5\xA5\xB1\x96\x8E\xB5\x79\x64\xDA\x93\xB3\xCC\x95\xB7\x9B\x2C\x80\xB6\x52\x0F\xA9\xB6\xD7\x8B\x8B\x6D\x10\x3A\x23\x13\xF5\x27\xA2\x3D\xAA\xB6\x9D\x80\x7C\xA0\x6E\xCD\xA8\x90\xDE\x8C\xBE\x92\x12\xAD\x8A\x70\x9B\x35\xB8\xD4\x41\xA9\xB9\xCC\x8D\x2B\xAA\x40\xB4\xA3\xDC\x1B\xBB\xA2\x6F\xA0\x00\xE9\x25\x03\xAE\xEE\xB0\x23\x8E\xCF\xBF\x94\x1E\xEF\x8C\x89\xE0\x9B\xB0\x90\x74\xA0\x48\x4C\x75\x6E\xBB\xF8\xAA\xAA\x70\x94\xA4\x46\x18\xA9\x6C\xA8\xFB\x9A\xB0\xAF\x9D\xA6\xB6\xCE\x1F\xBE\xB6\xC5\x80\xB4\xB1\x57\xA4\xB1\x6A\xBA\xBC\xB5\xD1\xAB\xB5\xB1\xD7\x8C\x7F\x6C\xE4\xA7\x6F\xFC\xB0\x23\xA8\x41\xA7\xA9\x4A\xDE\x92\x8D\xA5\x86\xBF\xBA\xC9\x8C\xA4\xCC\x3B\x7E\xA5\xA9\x9F\x94\xB5\x56\xA7\xB6\x82\xFD\x9D\xA0\x98\xBF\x71\xC5\x60\xAF\xB2\xCD\x3F\xA5\x9B\xA0\xB5\xBE\xC2\x1A\x2B\xAE\x7F\xB7\xBC\x61\x92\xBC\xBE\xB8\x38\xDB\xB0\xCC\x01\xC7\x6F\x12\xCC\xC6\xC0\xA4\xB5\x9B\x29\x80\x05\xB1\xDE\x87\xC2\x29\x48\xCF\xC0\xF3\x31\xB2\xC2\x1A\xC8\x81\xC8\xF4\xB8\xBE\x6D\xA4\x4A\xC7\x20\xE8\x9B\x9E\x73\xA1\xC8\x80\xD1\xA4\xC1\x27\xCD\xC6\xB7\x08\x8B\xC9\x56\xFB\xA5\xC0\xD1\xA8\xCB\xCA\x11\xD0\xB2\x95\xBF\x71\xC8\xED\xAD\xBC\xA2\x73\x60\x9E\x79\x9A\x21\xBA\xF7\x83\xBA\x29\x4D\x78\xA3\x77\xD2\xBB\xA2\xA1\x82\x74\xC1\xE4\x9E\xB6\x18\xF3\x5D\xBE\x06\xD2\x82\x86\x28\x6A\x66\x0D\xC9\x98\x9E\x1D\x42\xC3\x9F\xA9\xAD\xC4\x4E\x82\x80\x84\x69\xBD\x85\xC2\x5B\xD1\x46\x6F\xB7\xC1\xD4\x8D\x1C\x48\xAD\x06\xBA\xB1\x9F\x94\xAF\xCE\x00\x10\x70\x6F\x40\xC5\xD5\xA1\x9D\xAB\x54\x44\xC7\xD2\xD1\x24\xAA\x9E\x71\x8E\xD9\x98\x48\xE0\xCD\x86\xAC\xB5\xD0\x4E\x98\xD3\xC4\xA9\x9A\xD4\xAB\xBF\x7D\xD1\xFA\x04\xA1\xC8\x06\xE4\xD1\xD5\xB7\xB1\x02\x96\xD0\xDA\xBF\x3B\xF0\x25\x71\x71\x7A\x23\xAB\xBB\x72\xD1\x1D\xE4\x40\x70\xCF\xD5\xAF\x6D\xF9\xC8\xD4\x71\xD5\xD8\xDB\x1B\x3A\x21\x8F\x3B\x78\x74\x31\xCB\xBC\xA8\x1B\xC5\x2B\x11\xE0\x91\xA9\x55\xD7\xD8\x26\xD9\xC0\x20\xDD\x3F\x7D\xDA\x10\xD8\xC6\xAC\xAF\xC9\xBC\x87\xDB\x50\x6F\x74\xF9\x89\x72\xBF\x76\xBA\x59\x80\x73\xA8\x06\xF3\xDE\xC9\x49\xD6\xDE\xDB\x78\xD6\xE1\x75\xFC\xDB\xD7\xBE\xAC\xE3\xAD\xE6\xC1\xE1\xE3\x84\x4C\x71\x14\xF2\x22\x46\x4D\x6C\xDC\x88\xEB\xB2\xE3\x10\xBA\xA3\xC3\xDB\xAF\xB6\xF0", "\x93\xE5\xE0\x22\xFA\xDC\xC2\xF7\x6D\xDB\x63\xD7\x93\xA8\x36\xFD\xE2\xCD\xA0\xE0\xE6\x98\x24\xE1\xE1\x19\xA7\xC4\xE0\x76\xCB\xCE\x00\x27\xD3\xD0\xEE\xB2\xE0\xC1\x8E\x73\xE5\x7D\xF4\xE6\xB8\x45\xE3\xEA\xE0\x45\xED\x46\xA4\xD4\xA4\xE7\x4C\xE3\x66\xD3\xD0\xEE\xE5\x4B\x84\x8C\x8D\x0F\x5F\x71\x0B\xB9\x79\x6D\x5C\xE6\x75\xBF\x55\x8F\x85\x30\xF4\x22\x54\xA8\x12\xB0\x83\x60\xEF\x53\xDD\x62\x70\x26\xF2\x43\xB2\xD9\x38\xAB\x7F\xF2\x49\x7E\xED\x29\xEB\xBE\xB8\x69\xF9\x7D\x88\xAD\xBF\x7D\xA1\x2F\xED\x7B\x71\xF0\x2B\xDC\x9C\x8A\xC4\xBC\xC8\x9A\xEF\x30\x6E\x7C\xF6\x06\xFE\xEE\x37\x80\xF1\xF1\x82\xE2\x80\xFF\x79\x5F\x7F\x37\x53\x99\x87\x54\x5A\x84\x6D\x88\x86\x3A\xD4\x0A\x47\xEF\x0F\x8A\x76\x15\xEB\xE4\x83\x13\xA3\xF0\xF1\x10\x8F\x43\xE2\xE3\x79\xC0\xC7\xFF\x70\xF2\xF1\x9B\x22\xEB\xB0\xB8\xF5\x35\xB1\xF3\xF5\xF0\x92\x9C\x3D\x93\xD2\x80\xD0\xC5\x80\x26\x14\xCB\xE8\x10\xA0\x2C\x99\x70\xF2\xB9\xC7\xD3\xC6\xDD\x78\xC4\x6F\xC7\x76\xF2\xD3\xCC\x9E\xA6\xE6\x3B\xD1\xCE\x9D\x34\xF5\xA5\x9F\x47\xCE\xCE\x99\x90\xC1\xAC\x98\x53\xC7\xD3\xDE\xD3\xBF\xBB\x99\xC6\x90\xB3\x8C\x64\x68\x1E\xCA\xE1\xBC\xC2\xCA\x67\xEC\xEC\xE5\xAA\x32\xAA\xCB\xF7\xC6\xDF\x9E\xFC\xDE\xAD\x9A\x3C\x52\x63\x03\x37\x78\xDC\x46\x56\xB4\x6E\x71\x75\x19\x68\x66\x6F\x7E\xBA\x6C\x4E\x19\x7D\x6B\xB9\x71\x69\xC0\x63\x4D\xC2\x6A\x4F\x7E\x4C\x62\xFD\x79\x4C\xB6\x79\x7C\xCD\x6E\x5B\x1D\x5F\x75\xBF\x70\x15\x7B\x2E\x1C\x75\x1E\x27\x68\x2A\x1C\xCE\x77\x50\x20\x24\x6D\x30\x17\x1B\x16\x0A\x13\x13\x28\x52\x4E\x5C\x1F\xF3\x77\x1B\x18\x00\x83\xC1\x1D\x70\xBE\x5D\x23\x1D\x86\x66\xB7\x1A\x01\x38\x8C\x24\x29\x77\x62\x23\x80\x11\xD0\x1D\x25\x1C\x01\x84\x44\x7D\x75\x45\x8F\x1C\x43\x17\x1B\x1E\x01\x84\x1C\x05\x2A\xAC\x1F\x0F\xB7\x13\x12\x65\x29\x85\x5A\x8A\x13\x69\x1B\x27\xB1\x25\x26\xB1\x2B\x27\xB7\x1D\x20\xFF\x4B\x27\x25\x45\x41\x20\x8A\x7A\x50\x15\x26\xC3\x18\x79\x5D\x29\x86\x2E\x4F\x10\x55\x8D\x14\x5F\x81\x26\x61\x81\x26\x64\x8A\x51\x4D\x12\x79\x0F\x19\x3D\x70\x84\x76\x59\x8D\x86\x21\x8F\x10\xB7\x1F\x87\xF8\x3E\x19\xD4\x15\x87\x5E\x27\x87\x5E\x29\x87\x44\x87\x2F\x6D\x7F\x10\x86\x8A\x44\x6C\x87\x20\x6E\x85\x88\x48\x43\x88\x68\x29\x16\xE4\x6A\x88\x5D\x21\x2B\x58\x87\x2C\x03\x4B\x21\xC7\x7A\x11\x98\x80\x4E\x81\x79\x85\xD4\x15\x7A\x0B\x4B\x11\xA7\x8E\x7B\x6A\x82\x87\x69\x1C\x5B\x9E\x8F\x27\x06\x11\x8A\x02\x12\x25\xA4\x8B\x43\x2D\x81\x2E\xA0\x30\x88\x65\x25\x32\x7C\x27\x1F\xCC\x7F\x8A\xBF\x87\x88\x9E\x13\x12\x55\x3B\x85\x9E\x1C\x88\x5D\x23\x12\x1D\x06\x10\xB1\x24\x1D\xD1\x8A\x85\x93\x87\x39\xCB\x8B\x85\x38\x7F\x4F\xCC\x8D\x8D\x5C\x8F\x8D\xB9\x8E\x8D\x07\x15\x35\xFF\x03\x8D\x61\x23\x12\x15\x02\x8D\xC6\x22\x10\xE9\x8A\x85\xDB\x8A\x51\xB8\x83\x2D\xB6\x77\x1B\x3A\x86\x66\xE5\x86\x10\x4D\x17\x85\x5B\x2A\x8E\x15\x1B\x8F\xEE\x82\x38\x36\x7E\x89\x00\x29\x7F\x04\x24\x8F\xED\x73\x7F\xF7\x8F\x34\x5E\x23\x12\x22\x36\x8E\x02\x12\x32\xC1\x80\x90\xFF\x42\x90\x06\x16\x55\x06\x94\x6F\x66\x52\x8E\x9B\x8A\x13\x4D\x3A\x2B\xCC\x85\x85\x3D\x20\x91\xE2\x85\x85\x3C\x2B\x85\xF1\x87\x1B\x3C\x82\x6B\x0C\x67\x91\xDA\x74\x24\x09\x97\x10\xB1\x2D\x34\xFA\x82\x10\xD2\x62\x10\xD9\x8E\x25\x29\x9C\x82\xED\x1E\x5B\x2C\x95\x6B\xBE\x54\x1D\x35\x9A\x8A\x1B\x79\x64\x9E\x86\x22\x6F\x67\x1B\x29\x8A\x59\x2F\x92\x93\xB7\x86\x10\xBC\x57\x93\x5D\x29\x93\xD2\x7B\x93\x3E\x8B\x8E\x2D\x95\x17\xD4\x1C\x5B\x11\x90\x4E\x0C\x65\x94\x06\x1E\x60\xDD\x7D\x25\x49\x97\x5B\x1A\x9F\x91\x69\x13\x12\xAF\x65\x26\x27\x98\x8F\x2E\x19\x91\x56\x92\x70\x78\x11\x2B\x2F\x94\x6E\x33\x90\x00\xFE\x26\x93\x5B\x84\x83\x4E\x5D\x93\xF0\x6E\x54\xD4\x17\x97\x42\x98\x91\xF3\x70\x95\x65\x2B\x84\x84\x6F\x92\x62\x8D\x94\x02\x15\x8D\xB6\x29\x97\x6D\x95\x83\x6F\x9D\x97\x88\x44\x8D\xDA\x87\x90\x4E\x54\x98\x61\x2F\x8E\x27\x6A\x91\x55\x8E\x85\x5B\x8B\x27\x4D\x12\x92\x5E\x2F\x6F\xF3\x7D\x14\x8C\x9B\x95\x41\x7C\x4A\x89\x9A\x90\x1F\x45\x86\x6C\x2A\x7B\x43\x17\x8D\x0F\x25\x89\x02\x19\x8A\xC6\x83\x76\x87\x83\x87\xFC\x89\x85\xA0\x95\x29\x95\x92\x98\x33\x86\x10\xA7\x99\x99\x12\x9A\x51\xAB\x92\x8F\xFF\x4B\x87\x0F\x2E\x87\x99\x81\x8B\x81\x86\x89\x9A\x87\x9B\xA9\x85\x85\x89\x8F\x99\x6C\x9F\x90\xBF\x92\x83\x88\x46\x9A\xD9\x9C\x72\xC7\x9E\x88\xAA\x90\x89\xB1\x39\x48\xB0\x81\x87\xCF\x95\x9B\x97\x8E\x8B", "\xB8\x9A\x44\x55\x89\x1B\x5A\x96\x87\xD7\x9A\x75\xFF\x80\x9C\xDB\x92\x9C\xDD\x96\x62\xAC\x4E\x19\x22\x37\x6A\x60\x81\x9F\xA2\x9D\x25\xA4\x91\x9C\x8B\x97\x9F\x36\x70\x8E\x07\x1D\x89\xD6\x9C\x9A\xFF\x9C\x97\x41\x5C\x9D\xF3\x99\x9A\x15\x41\x8F\xBA\x82\x7A\x55\x2D\x8B\x5C\x3D\x9C\xE6\x98\x9A\xAC\x87\x21\x12\x12\x9D\x6E\x85\x85\xB4\x89\xA0\xD3\x2B\xA0\x91\x9D\xA0\xF6\x9F\xA0\x2C\x72\xA1\x06\x16\x7C\xBC\x86\x8A\xEA\x96\x9B\xC4\x92\x10\x3F\x45\x1C\x41\x4E\xA1\xD1\x9B\x91\x03\x1A\x2B\x0F\x7E\x8D\x20\x96\x10\x41\x95\x96\x40\xAB\x85\x24\x96\x10\x63\x31\xA4\x9C\x99\x16\x3A\xA6\xA4\x20\xA6\x10\x13\x0B\x85\xB1\x2D\x14\xEF\x9E\x25\x63\x94\x22\xF1\x80\x2A\x76\x16\x69\x7C\x9B\x92\x06\xAF\x0F\x9E\x9A\x85\xBD\x92\x10\xFC\x91\xA3\xDA\x96\x49\x0E\xA1\x98\x10\xAA\x24\xDF\x96\x24\xAE\x92\x10\x67\x8D\x45\x18\xA0\x8C\x61\x22\x88\xCE\x96\xA3\xCE\x9A\x9B\x02\x15\x8B\x06\x1F\xA5\x46\x77\x9F\x26\xA3\xA0\x28\xA8\x9F\x15\x49\xA6\x02\x16\x7B\xCA\x95\x78\x38\x12\x9B\x8F\x24\x9B\xEB\x97\x39\x74\xA6\x9E\xD4\x9B\x9B\x65\x2A\xA7\x61\xA3\x9A\x96\x95\x9F\x7E\xA6\xA6\xDE\x98\x87\x6A\xA6\x9C\xE2\x9A\x3C\x88\xAB\x86\x71\xA0\x9D\x73\xAF\xA2\x1F\xA9\x16\xEE\x9E\xA4\xF1\x93\xA9\x00\xA5\xA9\x64\xA7\xA2\x98\xA0\xA8\x4A\x2A\x9F\xFE\x89\x85\x4F\xA3\xAB\xA8\x90\x97\xD3\x23\x9C\x94\xA3\x84\xAC\x45\x85\x1D\x95\x96\x55\x88\xA0\x5E\xA9\xAA\x7C\xA6\x56\x65\xA7\xAB\xB0\xA3\x14\x2A\xA2\x10\x2C\xAD\x21\x16\xA4\x9E\xC7\x84\x89\x62\xAB\xA1\x0A\x2D\xA8\x80\x8B\xA4\x77\xA2\xA2\x4D\x1A\xAA\x0C\xA6\xAC\xAE\xA8\xAC\x36\x7B\xAC\xA3\x84\xA1\xA2\x76\xAD\xC8\x82\xA6\x33\xA4\x8C\x21\x16\xAE\x94\x83\xA4\x02\x14\x01\x26\x99\x9D\x41\x68\x94\xD1\x7F\x7C\x30\x9A\x13\xB1\x24\x97\x8A\x96\x97\x93\x22\xAF\xB2\x64\xAF\xE0\x41\x64\x7F\x9B\x85\x53\xA0\x13\x98\x9D\x88\x53\x7D\x75\x88\x97\x8E\xAE\xA7\xB0\xB8\x53\xAF\xA2\x88\x59\x3A\x98\x5B\xBA\xA2\x96\xF5\xA7\x50\x0E\xBC\x97\x05\xA6\xA4\x5D\x28\xAD\x00\x0D\xA4\x5A\x85\xAB\x34\x94\xB0\x17\xBA\x59\x55\xA6\x10\x15\x8B\xAA\x5C\x9C\x93\x1C\xBD\xB1\x69\x1F\x6A\xED\x8D\xB2\x66\x9A\x13\x5D\xAC\x9B\xF1\x91\xB3\xC8\xAC\x60\xC7\xA2\xA6\x99\xA8\xB0\x83\xAB\xA6\xB9\x76\x42\xB1\x9F\xA6\xE7\xA2\xA5\xA2\xA9\xA1\xA4\xAA\x89\x76\xA1\x2C\xDA\xA6\x10\x38\xBC\xB3\x08\x8A\x14\x3B\xBB\xAB\x67\xA3\x14\x82\xAD\x9A\x7A\x83\x28\xCB\x93\xB4\xA8\x89\x9E\x46\xB8\x9E\x37\xA7\xA1\x5D\xBA\xB4\x69\x15\x9D\xC3\xAC\x9A\x4F\xB4\xB5\x3E\x96\x66\x53\xBA\xB2\x55\xB8\x13\x57\xB6\x7B\x45\x81\x89\xD0\xAB\xA8\xB3\x91\xAA\x60\xB3\xAA\x62\xB5\x9E\xD7\xA6\xAA\x4E\x98\xAA\x68\xB7\x9F\x3A\xBF\xAD\x50\xB5\xA0\x55\x8B\x9F\x80\xB3\x2D\x69\xBE\xB6\x6B\xB9\x64\x6D\xBA\xB1\xDC\x83\x10\x9C\x80\xA9\x61\x2A\xA7\x8B\xB9\xA5\xBE\x5F\xB8\x91\x91\xAE\x78\xB3\xAE\xA1\x76\x25\x49\xBA\xB7\x6E\xB4\xAD\xDA\x1C\xAE\x97\x3E\xB1\x78\xA6\x2A\x37\xB2\xB8\x99\xB4\xB8\x6A\xB9\xAC\x92\x2F\xB5\x9E\xB5\x8A\x6F\x84\xB4\xD2\xA4\xB5\xE9\xA0\x25\xB5\xB3\xB6\x75\xA9\x16\xB7\x17\x01\x32\xBD\x8D\xED\x9F\xB7\x1C\xB5\x85\xB7\x19\x01\xC1\xBC\xA3\x69\x18\xB8\x41\xA6\xBC\x06\x1E\x32\xC9\xB0\xAC\xB3\x8C\xA4\xF1\xA2\x10\x27\xB7\x23\x57\xAF\x84\x91\x9C\x60\xCE\xB7\xA9\xD1\xB7\x1B\x9D\x94\xB9\x5E\x25\x35\x9A\xBD\x8F\xBC\xA1\xA8\x9A\xAF\xB3\x9C\xAC\xA6\xB0\x97\xA8\xB6\xBC\xA8\x9D\xB0\xA3\x7B\xB1\xAD\xA7\xB9\x18\xE2\xBD\x25\xE4\xBE\xBA\x8C\xB0\xBB\xC5\x2E\xB3\x58\xB7\x62\x85\xA3\x79\xEE\xBC\xBB\x48\xB2\xBB\xF2\xB5\xB7\xD3\x95\xB6\xF7\xB7\x1B\xF9\xBE\xBD\x85\xB0\xB4\x63\x8B\xA9\x8F\x84\x21\x74\xBF\xA9\x84\x81\xBF\x5E\xB8\xC0\xA5\xAA\x13\xA7\xAA\x85\x23\x15\xBE\xEF\x66\xB8\xCB\xB6\xAB\x0C\xBC\x9A\x15\xB0\xB9\x1A\x5B\xA5\xC2\xA9\x85\x0D\xC0\x00\x27\xCB\xB9\xFF\x42\xAE\xCD\xA5\xA1\x2E\xA3\xBF\x76\xB9\xA8\xD3\xA5\x21\xA6\x75\xBA\xA1\xBE\xA8\xD3\xB9\xAD\x5A\x8D\xC2\x2F\xC6\xBE\x6F\xBE\x34\x16\xBC\xAC\x04\x4D\xA2\xBB\xBC\xB7\x45\xBE\xB6\xB9\xB5\xA3\x3D\xCD\xB7\x3A\x17\x1B\x80\x9F\xBD\x5E\x23\xBC\x02\x11\xA5\xCF\x81\x9F\x55\xC9\xBE\x2C\x45\x74\xB2\xA0\xA6\xD5\xB3\x2D\x5D\xCE\xBF\x56\x7F\xAC\x56\xC9\xC6\xB7\x10", }; 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(); } /*********************************************************************** 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); } /*********************************************************************** 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; } } } } namespace vl { namespace reflection { namespace description { #ifndef VCZH_DEBUG_NO_REFLECTION using namespace vl::parsing::json; 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(Accept, {L"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) CLASS_MEMBER_EXTERNALMETHOD(get_content, NO_PARAMETER, vl::WString(JsonString::*)(), [](JsonString* node){ return node->content.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_content, {L"value"}, void(JsonString::*)(const vl::WString&), [](JsonString* node, const vl::WString& value){ node->content.value = value; }) CLASS_MEMBER_PROPERTY(content, get_content, set_content) END_CLASS_MEMBER(JsonString) BEGIN_CLASS_MEMBER(JsonNumber) CLASS_MEMBER_BASE(JsonNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_EXTERNALMETHOD(get_content, NO_PARAMETER, vl::WString(JsonNumber::*)(), [](JsonNumber* node){ return node->content.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_content, {L"value"}, void(JsonNumber::*)(const vl::WString&), [](JsonNumber* node, const vl::WString& value){ node->content.value = value; }) CLASS_MEMBER_PROPERTY(content, get_content, set_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) CLASS_MEMBER_EXTERNALMETHOD(get_name, NO_PARAMETER, vl::WString(JsonObjectField::*)(), [](JsonObjectField* node){ return node->name.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_name, {L"value"}, void(JsonObjectField::*)(const vl::WString&), [](JsonObjectField* node, const vl::WString& value){ node->name.value = value; }) CLASS_MEMBER_PROPERTY(name, get_name, set_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_CLASS_MEMBER(JsonNode::IVisitor) CLASS_MEMBER_BASE(vl::reflection::IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::JsonNode_IVisitor::Create) 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_CLASS_MEMBER(JsonNode) 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\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) { MemoryStream stream; { StreamWriter writer(stream); XmlPrint(node, writer); } stream.SeekFromBegin(0); { StreamReader reader(stream); return reader.ReadToEnd(); } } /*********************************************************************** 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_PARSER.CPP ***********************************************************************/ namespace vl { namespace parsing { namespace xml { /*********************************************************************** ParserText ***********************************************************************/ const wchar_t parserTextBuffer[] = 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"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"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;" ; vl::WString XmlGetParserTextBuffer() { return parserTextBuffer; } /*********************************************************************** SerializedTable ***********************************************************************/ const vint parserBufferLength = 4917; // 18057 bytes before compressing const vint parserBufferBlock = 1024; const vint parserBufferRemain = 821; const vint parserBufferRows = 5; const char* parserBuffer[] = { "\x00\x0E\x00\x02\x9F\x71\x02\x80\x01\x7F\x05\x06\x83\x20\x0F\x30\x00\x36\x86\x00\x72\x00\x05\x82\x87\x02\x83\x20\x00\x74\x19\x80\x0E\x20\x01\x30\x00\x6D\x00\x25\x27\x84\x8F\x81\x84\x81\x0B\x8D\x8F\x8D\x82\x8D\x90\x05\x8B\x1B\x9A\x96\x3E\x8E\x80\x01\x3A\x91\x24\x86\x88\x8A\x80\x8B\x95\x89\x89\x06\x96\x82\x94\x24\x9F\x30\x8E\x9A\x21\xA3\x84\x9A\x97\x90\x01\x95\x9A\x2C\xC0\x95\x86\x84\xA7\x8E\xA3\x8E\x1F\xC9\xB9\x83\x8D\xA7\xA6\x9F\x96\x41\xD4\x85\xA7\xA9\xA8\x9F\xA4\xAE\x3C\xAA\x90\x80\xB2\x87\x96\x80\x21\x10\xB7\xAE\x20\x04\x34\x9A\x89\x3C\x5B\xA6\xA9\xB0\xAF\x9E\x96\x82\xB8\x0D\xF2\xB4\xB6\xB0\x00\xBF\xB2\xBD\x28\xBD\xAB\xB2\xA0\x06\xB4\x00\xC0\x36\x80\x33\xB5\xBF\x8F\xB9\xBD\x9D\x89\xEA\x91\xBE\xBF\xB1\xBA\xC9\xC1\x95\x85\xD7\xDD\xAA\xC3\xCE\x82\xC7\x90\x82\xD4\xDF\x96\xC5\x90\xCC\xA7\xA5\xFD\xA7\xDF\xBE\xCB\xC8\xC3\xD6\x3A\x8C\x3B\xB3\xBA\x8B\x90\x3D\x8D\x5E\x8B\xC6\x97\xCA\xD9\xCF\xCF\xDE\x00\x3F\xDA\x81\xE1\xAB\xE3\xC3\xD7\xCC\xB2\xD3\xA6\xE1\x92\xAC\xDF\xC6\x06\x89\x30\x9A\x8A\x8A\x89\x34\x00\x62\x11\xC8\xFF\x74\xF0\xE8\x00\x22\x34\x9A\x9F\x85\xFF\x7A\xA0\xD9\x86\xD5\xB8\x97\xEC\xFE\xC0\xF5\x87\x31\x91\xD6\xDB\x8C\xFE\xF5\x21\x9B\x91\xFA\x5A\x4C\x7B\x02\x06\x49\x1F\x67\x1C\x1B\x52\x47\x4C\x7E\x1A\x5F\x7D\x43\x5C\xEC\x44\x06\x41\x47\x0D\x75\x5A\x51\x79\x12\x83\x58\x4E\x72\x07\x65\x7D\x01\x76\xDB\x49\x80\x03\x77\xE1\x77\x48\x71\x86\x9F\x65\x53\x4B\x70\xDA\x42\x48\x44\x77\x3F\x64\x82\x78\x4E\x4D\x76\x14\x4F\x43\x37\x63\x45\x48\x69\xE8\x5F\x4A\x78\x00\xEE\x78\x7F\x83\x46\x23\x73\x75\x7A\x7B\x4F\x71\x75\x93\x46\x41\x90\x47\x77\x92\x02\xA5\x75\x7C\x44\xF8\x77\x41\x80\x90\x06\x70\x1F\x4E\x66\x00\x06\x58\x80\x7D\x06\x76\x70\x01\x95\x20\x72\x7B\x44\x81\x02\x52\x4D\x41\x43\x1A\x7E\x7F\x40\x80\x66\x91\x94\x79\x7F\xFF\x65\x90\x94\x00\x0A\x06\x4E\x8E\x88\x32\xA6\x88\x4F\x97\x47\x86\x4E\x98\x4E\x57\xA8\x93\x98\x5F\x08\x9F\x73\x5F\x55\x48\x78\x43\x01\x58\x02\x43\xA0\x9F\x9D\x28\xB3\x5A\x88\x00\x02\x10\xA0\x02\xA4\x76\x87\x78\x76\x40\x08\xB7\x41\x78\x85\x83\x63\x40\xA0\x79\x86\x86\x83\x5C\x82\xDD\x51\x6C\x83\x88\x4E\xB8\x9A\x9D\x4C\x31\xA0\x73\x8E\xA9\x1D\xA8\xA5\x83\x81\x22\x8B\x8B\x46\x83\x9F\x55\xAD\xA3\x48\x28\xA8\x84\x52\x6F\x4C\x86\x42\x92\xA7\x77\xAC\x70\x06\x41\x31\x06\x4F\xB3\x70\xD4\xB9\xAC\x7B\x3F\xD5\x83\x47\xB4\x79\xD9\x96\xBC\x79\xB7\xDB\xA4\x73\xB4\x00\x06\x9D\x43\x14\x00\x44\x52\x10\x01\x15\xB0\x44\x56\x83\x13\x47\x5F\x10\x00\xBC\x50\x1B\xA7\x50\x8A\x2F\x00\x0C\x0C\x00\xF9\xBF\x04\xB5\x53\x11\x3B\xA6\xB8\xBA\x00\x2A\xBC\xBB\x42\xEE\xB3\xB1\xBC\x6C\x4C\x0A\xC7\xBA\x7F\xF8\x80\x0E\xBD\xBE\x3E\x0C\x66\x02\x41\x14\x3C\x40\xBD\x13\x00\x35\xBD\xC2\x7F\x58\x00\x02\xBE\x7F\x1F\xC0\x0C\xC6\x7F\x1D\x44\x52\xBC\xBD\xF6\x9D\x41\xC7\xBE\xF9\xB9\xB9\xA7\x74\x00\x19\xC2\x43\xB9\xE5\x80\x07\x10\x00\x25\xE3\xCC\xCE\xBD\x27\xC7\x5A\xC8\xC3\x0E\xF6\xB1\xC5\xCC\x00\x15\xCF\xA1\x5B\x06\x45\x76\xBD\xC9\x41\xE9\xC2\xCA\xC2\xF5\xA8\xC8\xA6\x41\xF9\xBB\xB8\x89\x8B\x00\x1F\x81\xA7\xCF\xFE\x51\xD4\xC2\xBC\x0B\x4D\xC0\xBF\xC3\x57\xC2\x44\xC4\x00\x4D\x79\x92\x41\x53\xFE\x51\x1B\xB8\x00\x18\x4D\xC3\xCC\xBF\x00\x3D\x00\x03\xC5\xDA\xA4\x78\x89\x47\x18\x41\xD1\xC2\x40\x5B\x34\x4D\x08\x00\x7A\x34\xD0\x03\xE1\x5A\x00\x00\x0F\xE2\x00\x39\x00\x02\x0E\x00\x2E\x03\xD5\xBE\x87\xDD\x10\x03\x0A\x58\x82\x46\xA2\x63\x18\x44\x54\x53\x4C\x75\xF3\xDE\x7F\x04\x06\x62\x00\x01\xE1\x5E\x3A\xB9\xD0\x00\xAA\xDA\xEA\x08\xEC\x00\x3C\x10\x03\x09\xAB\xC0\x0D\xEB\xBE\x15\xF8\xE2\xEF\xED\x9F\x80\x0E\xD0\x92\x0A\xDC\xC2\xD8\x51\xAA\xEA\xDE\xE9\xBE\x21\x10\xE7\xE0\x0A\xB9\xED\xE8\xE7\xEB\x9A\xF6\xE7\xE0\xEB\x78\xC7\xE5\xC5\xF5\xCE\xD1\xF4\xF4\x00\x29\x00\x03\xEF\xE1\x87\xEB\xDC\xD6\xD7\x6C\xFC\x48\x79\xE8\x8A\xEC\x08\xD7\xF2\x00\x0D\xF9\xBD\xE1\x0B\x6B\xF4\xC0\x46\xF3\xC0\x00\xF4\xF6\xF9\x9A\xEC\xF5\xFF\xDE\x60\x83\xFF\x00\x0A\x72\x00\x98\x7B\x7B\xE0\x62\x7C\xDE\x05\x84\x80\xBC\x55\x66\x6D\xD6\x46\x5A\xBD\x21\x64\x28\x12\x06\x23\x7F\xBA\x6E\x75\xC5\x7A\x6A\x74\xDC\x60\x00\x6F\x12\x39\x5F\x5C\x79\x5F\x47\xC3\x49\x70\x23\x8C\x6E\x70\xE4\x12\x74\x72\xCB\x72\x5B\x7A\x9A\x61\x7C\xE7\x36\x7A\x74\xDB\x78\x76\x50\xEC\x3B\x46\x41\x67\x55\x5E\x8C\x0B\x26\x3F\x4B\x78\x6C\x82\x1C\x7E\x68", "\xF6\x11\x5C\x69\x02\x21\x65\x92\x1D\x57\x3A\x09\x06\x22\x89\x10\x2A\x4A\xA7\x16\x7A\x5D\x35\x5B\x27\x5C\x3F\x52\x22\x46\x68\x70\x08\x00\x1F\x86\x82\xFB\x50\x88\x7C\x4C\x8B\x23\x8A\x4E\x32\x8C\x65\x57\x49\x40\x49\x8F\x3D\x34\xB1\x4D\x72\x00\x18\x88\x61\x1A\x2E\x69\x2E\x9F\x81\x8C\x6D\x92\x8B\x75\x66\x8F\x89\x3C\xA4\x8A\x23\x10\x88\x8E\x1E\x9B\x26\x73\x68\x61\x7A\x20\x78\x8B\x8B\x95\x15\x64\x73\x0F\x8B\x23\x63\x26\x6D\x64\xC1\x1F\x8D\x91\x43\x43\x48\x39\xD7\x3F\x83\x47\x08\x4E\x91\x28\xBF\x88\x00\x5D\x87\x8E\x1F\xD7\x43\x5C\x41\x9F\x94\x8A\x10\x2C\x4E\xBD\x36\x38\x7C\x30\x80\x06\x94\x8B\x9E\x88\x28\x80\x0C\x6B\x90\x62\x4C\x4C\x85\x5D\x8F\x2D\xF9\x3F\x8C\xCB\x72\x00\x00\x60\x06\x20\x1E\xBB\x96\x4B\x37\x8C\x92\x96\x5D\x9B\x0E\x2C\xA1\x6A\x54\x00\x2C\x57\x27\xBE\x4D\x41\xAC\x14\x92\x96\x2D\x6A\x4C\x2F\x5E\x52\x96\xED\x1F\x80\x97\x37\x94\x9F\x83\xD6\x91\x35\x36\x9F\x8D\x0F\x65\xB6\x5F\x4D\x9F\x9F\x9B\x96\x10\x2D\x4D\x3A\x57\x4A\x93\xCE\x92\x94\x31\x9F\x92\x95\x73\x62\x57\x28\x15\x58\x25\x20\xF1\x81\x33\x51\x50\x26\x42\x70\x91\x59\x0D\x42\x9F\x94\x7E\xB7\x9C\x54\x00\xA7\x9B\x07\xCD\x74\x83\x0D\x5B\x27\x83\xDB\x91\x7D\x41\xF5\x79\x3C\x9A\x10\xA2\x96\x0C\xA3\x96\x37\xB5\x78\xA3\x82\x9C\x57\x4A\xA1\x9D\x8F\x47\xEF\x8B\x9F\x91\xB7\x4D\x90\x00\x06\x10\x41\xA1\x66\xA4\x4F\x4A\xA4\x76\xFB\x4A\x76\x1D\xC7\x21\x70\x7B\x6A\x9E\x52\x9D\x5F\x82\x32\xDC\x9A\x70\x18\x5E\x3E\x56\x7E\x43\x26\x3A\xFB\x4D\x55\x3E\x44\x49\x9E\xE4\x92\x94\xF4\x1F\x8A\x75\xB5\x6A\x77\xA2\x4C\xAF\x77\x53\x80\x0B\xA7\x82\xB6\x9E\x56\x08\xB8\x26\x3A\xA1\x58\xAB\x7F\xBF\x4A\x96\xE5\x91\xA8\xCC\x34\x7F\x82\xC0\x51\x96\x3F\xEA\x98\x3E\x4F\x09\x5F\x32\x46\x57\x51\xAA\x15\x73\xA9\xF8\x70\x9C\x93\x73\x84\x57\x8D\x4E\x6C\x98\xAF\x2D\x51\x9A\x58\x43\x4B\x8D\x05\xAD\x9B\x33\x8A\x47\x50\x69\x83\x48\xA5\x72\x68\x91\x60\xFB\xA0\x9B\xC2\xBE\xAF\x33\x2F\xAA\x77\xBE\x7E\x52\xA6\x59\xA6\xA9\x68\x37\xA3\x5A\x2C\xD5\xA1\x65\x17\x7C\x48\xA8\x47\xA3\xA8\xAD\x3F\xA5\x45\xA3\xB5\xA9\xAC\xB4\x7E\x5D\x5C\xB2\x9B\x92\x59\x82\xB5\x57\x8E\xA0\x5B\x5C\x22\x9D\xA5\xEB\x25\xA6\x9D\xBD\x80\x02\x0D\x00\x24\x22\x3C\xB5\xB5\x8C\x93\x72\x96\x64\xE4\xA4\xA7\xB3\xB2\x95\x92\x38\xBA\x2A\x4E\xE6\x9E\xB3\xA2\xA0\xB0\x39\xA2\xBE\xA4\xAC\x25\xB8\x39\xD3\x8A\xAA\xB8\x0E\x84\xB9\x44\xAA\x7B\xB5\x0F\x89\x9E\x9C\x57\xBE\x9D\x3E\xC2\xA1\xB9\x0F\x9C\xAA\xBC\xA5\x48\xA8\x00\x28\xB3\xB9\x7C\x53\xAF\xB2\x36\xA5\xBF\xA1\x6B\xA0\x57\x45\x64\x29\xA7\xB4\x7D\xB9\x02\xF4\xA2\x97\xDF\x9B\x8A\x56\xBE\xB8\xB7\x9D\x11\xBE\x75\xF7\x8A\x70\xB3\xF2\xA9\xBA\x56\xD4\xAC\xB9\xD1\x93\xBF\x56\xC7\xAC\xB6\x83\xC6\xA5\xBA\xB0\x97\xB9\xAA\x4E\xBA\x98\x76\xAB\xB3\xA6\xCE\x86\xA5\xAB\xE3\xB1\xC2\x79\xFD\x98\x9F\xF4\x96\xBA\xAC\x78\x66\xC1\x4D\xE8\xA2\xBE\xB5\x90\x24\xAD\xF6\xB8\x28\x7E\xDC\xB4\xB9\xB9\xB4\x25\xAE\xFE\xA1\x79\xC8\x61\xB5\xC4\x80\xA5\x97\xC3\xE8\xA0\xA0\x2A\xD6\x8D\x9C\x56\x86\x26\x95\x3B\xC4\xC5\x56\xA3\x25\x62\xEF\xBA\xC6\xAE\x93\x5E\x53\x6D\xE8\x97\x4A\x5F\xBC\xB2\xB1\x2C\xA2\xC2\x4B\xF2\xB3\xB8\x15\xC6\xB9\xB3\x97\x5D\xC1\x83\xD2\xB4\xC3\x05\xD5\x94\xA8\xB5\x54\xBB\x57\xC9\xAF\x83\xA5\xB4\x71\xC3\x50\xB9\xBC\x71\x9E\xCC\xC7\x25\xE2\xC1\x9E\x07\xBE\xA8\xAE\x6C\xC0\xA7\x14\xD6\xB7\xC0\xF1\xB5\x92\x8B\x8D\x20\xC7\x2E\x77\xBA\xB9\x72\xD2\xAE\x84\xB8\xCA\xCB\xEB\x1F\x41\x4F\x01\xD4\xCA\x31\xDC\xC5\xC1\x3F\xEB\xC7\xCE\x0A\xC4\xBF\x77\xBC\xAD\xB9\x34\xD0\xC1\xBA\x9F\xAA\xCF\x9E\xEB\xB7\xC3\x37\xD2\xAA\xC3\x70\xB3\xCC\x78\xCA\xCA\xCF\x3B\xE7\xBD\xC7\x6B\xC4\xD4\x8A\xEE\xB6\xD3\x2F\xED\xC0\x51\xF5\xA6\xD2\x8C\x88\xD4\xC6\x45\xFC\xBF\x83\x39\xD9\xAC\xB9\x0C\xB4\xB1\x57\x72\xB0\x20\x7D\x8F\xB4\x5F\xB1\xB1\x56\x2B\xE4\x13\xA5\xC3\xCB\x54\x6C\xC6\xD1\x56\x02\xD3\xB4\xB8\xF0\xAC\xC4\x72\x9A\xB2\xCC\x4E\xD3\xC7\xB9\x66\xD2\xC0\x99\xE0\xD3\xD4\xF6\x92\x67\xD4\xBF\xD1\xD9\x3C\xCB\xD4\xDB\x21\x4F\xD6\x75\x7A\xB2\xD8\xBB\xBF\x55\xDA\x4A\xD7\xDE\xCB\x08\xDB\xDB\x5B\xB3\x9E\xC3\x4E\xE4\xB7\xD3\xF2\xA8\xCF\xBF\xC1\xAA\xBC\x73\xEA\xB4\xB8\xAD\xBF\x82\xB2\x8D\xBD\xDD\xCF\x34\xB5\xD1\x1B\x33\xCB\x5D\xA7\xA0\x01\x81\xAA\xA0\xCB\x50\xDF\x92\xB5\xD8\xD0\xD0\x6D\xF2\x91\xD3\x9B\xA3\xCD\xA8\x80\xE7\xCD\x6F\xE2\xD5\xE0\xA5\xCD\xA8\xBA\x9C\xA9\xD5\xA9", "\xB4\xCC\xD5\x21\xDB\xA8\xCC\xA6\xC6\xC3\x59\xF4\x73\xA6\xD9\xD7\xCF\xA0\xF1\x9A\x50\x5D\xDA\xB5\xE5\xB2\x96\xC5\xC2\x99\xE7\x4B\xA6\x0D\xA0\x59\x1A\x2E\x3F\xD1\xC9\x34\x90\x00\x11\x59\x64\x18\xE7\x58\xD3\x9A\x2F\xA5\x9C\xE9\xA9\x56\x98\x8F\xA0\xCB\xF6\x52\x6E\x76\x65\x77\xEA\x97\x9B\xA1\x44\xEC\x73\x74\xC5\x4D\x64\x5D\x1E\xFF\x83\xB2\x4F\x4E\x53\x38\xC4\x28\x64\x93\x97\xD5\xD8\xF7\x49\xDC\xA9\xDC\x45\x8B\x7C\x73\xA3\x79\x15\xAF\x22\x51\x94\xA3\x4F\x1F\x28\xA7\x08\x50\xDF\xEF\x8D\x1F\x27\xA5\x14\xAC\x7C\x46\x60\xEC\x59\xB6\xF7\xC2\x96\x85\xFF\x45\x48\xEC\x89\xC6\x89\xD1\xCF\x3A\x96\x73\x05\x4A\xD0\xD9\xC7\x8D\xF8\xD9\xD0\x1F\xFF\xE4\x83\xDE\xD3\xDD\x93\xE0\xD6\xB9\x27\xE7\xC6\xFE\x58\xB0\xCF\xAD\xFD\xD1\xE4\x3C\xB5\xCD\xAB\xB2\xE9\xCF\x10\xEA\xF5\xBD\x1C\xF7\xD3\xD5\xF4\xBD\xE6\xB7\xB3\xC3\xE5\x42\xEA\xBD\x8E\xDD\x8B\x9E\x7F\xCF\xC4\xE0\xC2\xC6\xF9\x99\xA3\x28\xA5\x7D\x58\xE2\xF9\xE4\xCF\x75\x25\xD6\xE9\xC0\x6E\xD8\xBC\x83\xB2\x84\xEC\x00\x24\x7F\x66\xB4\xF7\xCE\x46\x1F\x38\x47\x82\xC3\xE0\xFB\x93\xC2\xDB\xE1\xC5\xD4\xDF\x5F\xC9\xD4\xD8\x57\x6A\xFF\x33\x99\xE0\x01\x62\xF0\xDA\xDD\xC1\xAE\xFE\xB0\x90\xB6\xDF\xB9\x9F\xF9\xED\x14\x78\xBD\xDF\x26\x74\x72\xE2\x63\x72\x04\x77\x7B\xE7\x6A\x5F\x43\x78\x7E\xF7\x7F\x58\x73\x13\x79\x1E\x50\x71\x80\x42\x52\x10\x80\x47\x37\x0B\x79\x18\x7D\x79\xFA\x7C\x7F\x98\x62\x7A\x00\x85\x7A\x02\x80\x4F\x1E\x85\x80\x35\x7B\x7A\x18\x6B\x72\xDB\x5B\x72\x2F\x75\x7B\xE9\x54\x7B\x20\x64\x73\x7C\x68\x7B\x1A\x8B\x7B\x2F\x69\x6B\xBE\x7A\x15\x33\x5F\x7A\x1F\x41\x7C\x8C\x62\x69\x77\x26\x74\x04\x38\x74\x5D\x3D\x47\x76\x7D\x74\x55\x4C\x4E\xAB\x43\x18\x10\x48\x64\x3F\x83\x75\xAF\x3E\x64\x79\x70\x45\x3D\x26\x78\xC8\x6C\x46\x91\x74\x13\x43\x66\x84\xFE\x16\x1B\x86\x2A\x84\x55\x87\x78\xC8\x4F\x64\x39\x6F\x63\x39\x67\x85\xAA\x49\x85\x83\x1D\x4A\xF4\x78\x81\x4E\x65\x4B\x7B\x77\x1F\xBC\x47\x27\x86\x26\x4B\x54\x2F\x86\x53\x4E\x74\xC0\x40\x6D\xF3\x41\x4B\x95\x4E\x61\x0A\x8D\x57\xC7\x6A\x4E\xE1\x4C\x25\xE3\x4B\x75\xDD\x44\x77\xF2\x51\x88\xD8\x48\x72\x3C\x59\x63\xEA\x47\x4D\x65\x83\x81\xE9\x69\x87\x6F\x44\x7C\x7D\x45\x7E\x10\x69\x7C\x01\x84\x70\x56\x6E\x7C\xF4\x76\x89\x04\x75\x75\x1D\x7B\x81\xFB\x6A\x3A\xD8\x73\x53\xDA\x7C\x7D\x67\x70\x7A\x1F\x40\x7E\x35\x19\x23\x8B\x69\x7D\x99\x87\x54\xE7\x7D\x7E\x7E\x81\x2B\x36\x3B\x58\xF2\x6C\x70\xEF\x73\x17\x64\x8B\x11\x66\x85\x17\x83\x30\x00\x4A\x8D\x87\xCC\x63\x24\x4D\x63\x4B\x6C\x82\x89\x77\x21\x8C\x72\x8E\x86\xC5\x44\x71\x45\x8F\x88\xB6\x10\x58\x4A\x8A\x8C\x5B\x6E\x64\xC5\x71\x8B\xC8\x18\x89\x21\x87\x54\xF1\x7C\x89\x78\x4E\x89\x47\x50\x8A\xBA\x75\x7D\xA3\x89\x37\xC4\x57\x8A\x66\x76\x3A\xDF\x77\x23\x91\x14\x5E\xE4\x7A\x8D\x38\x14\x89\x6C\x42\x8E\xC8\x1E\x44\xF5\x82\x8F\xCC\x75\x30\xA9\x4E\x8B\x9F\x15\x17\x0F\x07\x64\x9D\x8A\x8F\x4D\x83\x4B\xB3\x89\x8B\xE9\x78\x7F\x73\x16\x01\xEC\x78\x90\x0B\x87\x6C\xBD\x8A\x11\x72\x41\x1A\x1A\x11\x8C\x33\x53\x8C\xB4\x85\x8C\xF9\x77\x90\xEB\x6A\x8B\x0A\x90\x00\xF8\x88\x8B\x1D\x99\x90\x0C\x80\x47\x13\x9F\x13\x1A\x13\x2E\x33\x58\x47\xC4\x8D\x70\x73\x1C\x47\x94\x73\x81\x21\x99\x65\x3C\x85\x87\xD1\x87\x45\x52\x8A\x45\x41\x82\x10\x17\x99\x86\x13\x80\x93\x0F\x85\x93\xD7\x10\x58\x34\x93\x71\x75\x87\x92\x3A\x95\x47\xB2\x41\x69\x46\x9B\x47\xE9\x3C\x46\x43\x8A\x11\x01\x90\x95\x0E\x5A\x11\x11\x9C\x4F\x59\x41\x71\x06\x1D\x93\x78\x41\x95\xAF\x3E\x83\x5E\x91\x87\x4B\x8C\x21\x96\x38\x94\x1B\x1C\x35\x2B\x95\x50\x5E\x95\x31\xC9\x83\x87\xCF\x8E\x29\xA8\x3C\x46\xD6\x88\x79\xFC\x84\x64\x58\x93\x47\x53\x83\x4B\x5F\x44\x7F\x73\x90\x5C\x6D\x9E\x8C\x9F\x43\x95\x05\x5D\x97\x56\x97\x97\x14\x9B\x93\x7A\x9C\x97\x6E\x9A\x71\x4F\x62\x7B\x21\x63\x93\x40\x60\x6B\xFB\x87\x93\x12\x99\x93\x1B\x1C\x45\xB2\x4A\x84\x8E\x99\x5E\x40\x99\x64\x2A\x80\x50\x44\x91\x99\x76\x65\x96\x96\x94\x47\x5B\x9B\x94\x56\x53\x73\x09\x52\x2B\xF9\x8D\x8D\xC8\x17\x8B\x9D\x54\x90\x57\x96\x96\x52\x97\x9A\x7B\x91\x8E\x04\x9F\x40\x95\x84\x90\x3F\x66\x8F\x38\x14\x9A\x59\x9A\x11\x80\x59\x96\xB1\x9E\x9A\x38\x15\x31\x4F\x80\x1B\x51\x8F\x23\x3F\x6D\x85\x70\x44\x99\x86\x98\x92\x00\x06\x28\x5C\x9A\x77\xCB\x94\x13\xC8\x9D\x47\xCE\x92\x6C\xCE\x90\x9C\x78\x90\x41\xC4\x9A\x9C\x7C\x7F\x3A\x7E\x7E\x49\x57\x2B\x4F\x8A\x49\x5B", "\xBF\x47\x48\xF4\x79\x9E\x03\x62\x5F\x8F\x41\x49\xC7\x3A\x73\x58\x7B\x51\x43\x7E\x9E\x9E\x2D\x45\x1C\x96\x7F\xB5\x8B\x7E\x6C\x4D\x92\xBB\x80\x47\x34\x02\x7F\xD0\x60\xA0\x1F\x9B\x71\x94\x55\x6B\xF9\x61\x7A\xFB\x6D\x81\x04\x81\x5A\x01\x74\x90\x06\x87\x70\x53\x59\x80\x19\x9E\x92\xB3\x4F\x70\x42\x9A\x95\x31\x9B\xA1\x85\x93\xA0\x17\x7E\x93\x1E\xA2\x7D\xD8\x51\x53\x0A\xAA\x8A\xFE\x78\x68\x0E\xA8\x7A\x1F\x85\x51\x2C\xA2\x82\x7C\x6E\x66\x2A\x7A\x5F\x27\x8A\x5F\x29\x8D\x82\x00\x5C\x82\x41\x61\x6B\xE6\x63\x56\x31\x87\x6B\xBC\x7D\x56\x87\x6B\x60\x38\x8B\x5F\x8F\x70\x6C\x13\x8D\x45\x60\x95\x95\x9D\x3A\x96\x4C\xA6\x65\x50\x74\x7F\x6B\x92\x5F\xD4\x72\x68\xF5\x96\x88\x11\x51\x37\x73\x3F\x75\x72\x7D\x78\x99\x4B\x75\xEA\x85\x3A\xDE\x7C\x78\x6C\x7F\xA5\x11\x5F\x76\x4E\xA4\xA6\x47\x5F\xA5\x43\x7E\x95\x5D\x4F\x97\x87\x2F\x96\xD7\x12\x96\x84\x90\x47\x9A\x71\x4C\x18\x75\xA7\x2F\x5C\x87\x17\xA1\xA0\x80\x8B\x4E\x3E\x13\x88\x11\x55\x88\x8E\x75\x49\x88\x81\xA8\x8A\x81\x94\x4D\x9A\x75\x95\x4E\x88\xFE\x83\xA2\x91\x8B\x98\x20\x5C\x9A\x05\x5E\x9B\x23\x1C\x8D\x0F\xA8\x1C\x96\x33\xA0\xE0\x85\xA9\xB9\x94\xA5\xA1\x80\x66\xBF\x78\x7D\x1F\x41\xA6\xDD\x78\xA2\xAC\x82\x7E\xF0\x8A\x5E\x96\xA3\x4B\xC9\x9E\x9C\xE5\x97\x9D\x81\x70\x00\xBF\x43\x78\x18\x7E\x9C\x88\x7B\x77\x8A\x74\x9F\x73\x7E\x78\xF7\x9B\x77\x80\x79\xA1\xB3\x14\x85\xE6\x9F\x46\xC4\x33\x46\x57\x20\x2E\xE5\x1B\x9F\xD3\x61\xA0\xA9\x2D\xA7\x1F\x93\x1C\x1C\x0A\x13\x52\x22\x81\x23\xA4\x27\x23\xA3\x1C\x1E\x04\xAD\xE4\x1B\xA4\x40\x82\x41\x40\x83\x1C\x1F\x4D\x37\xFF\x00\xA7\xB8\x4F\x46\x53\x20\x98\xC9\xA9\x3A\xDC\xAF\x0F\xF5\x4A\x9A\x38\x1F\x37\xAD\x63\x1C\x16\x44\xAE\xD9\x86\x9C\x23\x1C\x35\xAD\xA3\x1C\x26\x0D\xAE\xAF\xA0\xAC\x52\x8C\x23\xE3\x93\x1C\xD0\x34\xAE\x10\x0B\x34\xCF\x13\x1C\x25\x1D\x2D\x0C\xBD\xB0\x0E\xB3\x10\xAE\x18\x3E\x77\x3D\x2D\x25\x1B\xB0\x9A\x2B\x76\x6B\xAB\x11\xC3\x15\x9E\xC8\xAF\x46\x3A\x1E\x1A\x25\x11\x44\x14\xBE\xB0\xC7\xAE\x46\x77\x2B\xB1\xDA\x95\xAC\xCD\x21\x44\xFF\x07\x37\x4D\x1A\xB0\x06\x15\x02\x06\x12\xB2\xD9\x25\xB2\x83\x4A\x11\x28\xB4\xAC\x1D\xB7\x27\x79\x72\xB3\x0D\xBC\xB1\x26\xBE\x29\x34\xBF\xB3\x7D\x4B\x99\x00\x5D\xB2\x06\x18\x22\x30\xB2\x10\xB6\xA0\x00\x43\xB4\x2D\x36\xBF\x49\x39\xBA\x77\x3B\xBE\x29\x79\x7D\xB4\xDD\x20\xB4\x37\xB9\x36\x50\xB9\x25\x80\xA0\x11\xD9\x4C\x22\xBA\x42\xA9\x6F\x48\xB4\x02\x1A\xB4\x06\x15\x12\x28\x2F\xB4\xC3\x11\xB5\xEB\xA8\x44\x54\xB1\xB4\xD7\x19\x77\x68\xB5\x2D\x5A\xBF\x49\x13\xBA\x29\x87\xA0\xB6\xF1\x42\xB6\x72\x94\xB6\x27\xBF\xB0\x82\xB9\x2D\xCF\x18\x22\xEE\x13\xB2\x6F\x39\xB4\x0E\xB6\xAE\x74\x87\x1D\x1F\xBA\x13\x8E\x19\x77\x88\xBF\x94\x00\x05\xB7\xD4\x2C\xB8\x72\xAA\xB1\x8F\xB3\x10\x12\xBE\xB0\x2E\xBA\xB8\x0D\xB8\xB9\x9F\x46\xB1\x34\x38\xB1\x59\x78\xB3\xC3\xA1\xB7\x5B\xBB\xB9\x79\x1C\x35\x0F\xBF\x1C\x77\x3E\x18\x4B\xB1\x3C\x77\x39\x77\xB2\xB9\x2D\xEF\xAF\x99\x38\x19\xB7\x70\xBF\x6A\x76\x68\x20\x53\xB5\x94\x97\x7A\xB9\x83\xB0\x2E\xAE\x16\x28\x10\x43\xB9\xA4\xB5\xB9\x06\x10\x72\xC1\xB4\x74\x1E\xB3\xB8\xCF\x16\x28\x86\x2A\xBC\xD9\x22\x2C\x97\x23\x1C\xCC\xA3\x6F\xD1\xAC\xB0\xCF\x19\x77\x4E\x32\xB8\xCF\x11\xB9\x9E\xB6\x10\x4D\x17\xBB\x76\xB6\xAD\x8B\xAA\x11\x4D\x1E\xB3\x0C\xB9\xBB\x38\xA8\x13\x97\x10\x41\xE8\x3D\x2D\x41\x47\xBE\x0E\xBA\xA1\xEB\xB4\xB9\xEE\xB9\xB5\x45\xB0\xAF\x3A\x25\xB3\xCA\x27\xA5\x9E\x23\x1C\xDE\xAC\x84\xD3\xB6\x10\xF5\xB9\x2D\xF7\xB9\xBA\xFE\xBD\xA1\xFB\xBD\xBE\xF9\xBF\xBF\xBA\xB1\xC0\xD5\x2D\x24\xBD\xAE\xB8\xE6\xB2\x84\x4C\xAF\x1C\x4E\x3B\xC0\xD5\x2D\xC0\x70\xBF\xC0\x8A\xA3\xBC\xEC\xB1\xB3\x13\xCC\x46\x46\xB8\x13\xCB\xB8\xC1\x5E\xA4\xBC\x94\xBB\x74\x1C\x2F\x1C\x9D\xBD\xB0\x22\xC1\x3C\x24\xC2\xBC\x9F\x42\xC1\x44\xBA\xC2\x00\xCC\x18\x6D\xB3\xC0\x19\xC0\xC3\x77\xB7\x25\xCF\x10\x58\x80\x56\xBF\x1B\xC3\xC2\xB8\xBA\xBE\x26\xCC\xBF\x29\xC9\x9A\x15\xC0\xC4\x17\xB4\xC0\x1A\xC2\x10\xFF\xA2\xAB\x97\x12\x98\x20\xC4\x2D\x37\xC8\xBE\xD4\x2A\xBF\x4F\xCC\xC3\xEF\xB4\xC1\xF1\xB6\xC1\x5D\xB2\x10\xA6\xB1\xBD\x89\xB4\x95\xE1\xA5\xBC\x84\xBE\x1A\xEE\x12\x98\xE2\xBE\x1A\x5C\x30\xC6\xDE\xB7\xBC\xD2\x25\xBE\x6D\xC4\xA9\x39\xC0\xBD\x77\x2B\xBC\xD8\xBD\x29\xC3\x17\xAF\x99\xA2\xBF\xC6\xBC\x14\x06\x11\x8C\x70\xC7\x19\x86\x23\x2E\xDD\x2F\xB9\x9E\x3E\xB0\xDB", "\xBE\x91\x25\x92\xC8\xCD\xBA\x59\x85\xCB\x9B\xF8\xA0\xC7\x09\xC2\x10\x21\x96\xBD\xD5\x26\x28\x3B\x75\x68\x35\x88\xC8\x70\xBA\xC3\x6F\xB0\xB1\xAC\xB1\x97\x0C\xBB\xBC\xC3\x10\xAE\x4C\x86\xC0\x1C\xC0\x84\xB0\xBB\xC4\xD4\x25\x12\xEE\xBC\xB6\xA0\xB3\x96\x30\xC7\xC0\x1C\x2D\xB3\x0E\xB0\xCC\x1B\x1C\xCB\xE9\xBE\xC3\x53\xC2\xBD\x20\xB8\x31\x0E\xB0\xCB\xB8\xCE\x9C\xC3\x19\xC5\xE3\x97\xCB\x7D\xC3\xBB\xBB\xC3\xCC\xEA\x33\xB0\x06\x12\xCD\xC1\xA2\xCC\x0D\xBC\xCD\x52\x86\xCC\x61\xC6\xC6\x3B\xAB\x22\x75\xCC\xBA\x15\x0D\xCC\x24\xB2\x28\x13\x8F\xBC\x39\x6F\x0F\x2C\xB2\xC9\xB9\xC8\xC2\x02\x12\xCE\xD8\xAB\xBF\xEE\xC3\x81\xDE\xC5\xC6\x10\xCF\xC4\xE2\xCF\xBC\x2B\xCA\x14\x77\x3C\x90\xD5\x25\x12\x4D\xB6\xCF\xEC\xC9\xAD\xA9\xBA\xCA\x6F\x47\xB5\x51\xCC\xD0\x81\xC9\x2D\x86\x2E\xA8\xED\x4A\xD0\x02\x12\xBA\x46\xC3\xD0\xD9\x2A\xB6\x33\xBB\xCE\x5F\x36\xD1\x60\x8A\xCF\xBD\xCF\xC7\x39\x6B\xBC\x13\xDD\x8F\x15\xD8\xCF\x20\x2F\xB7\xEA\xAC\xC6\x8D\xCC\xBA\xFF\x00\x41\x17\x0F\xD2\x30\xD5\x12\x18\x0A\xCE\x0D\xBF\xAC\x0E\x9D\x9F\x9F\x1A\xBD\x0D\x93\x92\x0F\x91\x2B\x66\xB7\x10\x77\x36\xB9\x06\xDD\xD1\x39\xDB\x2B\x3B\xDA\x91\x73\x1E\xD3\xFF\x90\xAD\x25\x9E\xD0\x0D\xB5\xC9\x24\x97\x6C\xBC\xBD\xA4\x7B\xBD\x10\x61\xBB\xD2\x83\x90\xB8\x9E\x23\xD4\x46\xDD\xCB\xE2\xCA\xD3\x40\xDC\xD3\x4D\xDD\x34\x3F\xDC\x9F\x4C\xDB\x37\x23\xD9\x2D\x54\xD1\xD4\x43\x27\xD5\xEE\x19\xD5\x86\x60\xBC\x5C\xDD\x8C\x71\xA2\xB5\x34\xDC\xCA\x03\x1C\x35\x74\xCB\xD7\x80\xD1\xD8\x35\xD6\x10\x19\x08\xD3\xFC\xCD\x86\x79\xDB\xCA\x18\xDE\xD2\x81\xDE\xC1\x06\x1A\x01\x86\xDB\xBC\x35\x2E\x8E\xAE\x8B\xC9\xAD\x97\xC8\xE6\xC2\xD8\x0E\xBF\x1C\x25\x1B\x01\x86\xDD\x2D\xFA\xA4\x90\x96\xDE\xA9\x9D\xC3\xD4\x43\xD5\xBD\x69\xB6\x10\x86\x22\xCE\xA1\xDD\xC9\xA3\xD5\x9C\x98\xDC\xD6\x93\xCD\xB0\x86\xCF\xA2\x47\x57\xD5\x10\x42\x70\xC7\x76\x5A\xD4\x2F\xD6\x66\xD4\xD4\x06\x19\xBC\xA9\xD2\x10\x10\x4C\xDA\x21\x26\xDB\xC8\x1F\xDA\x3D\x51\xDB\x79\x72\xDC\xD5\x25\xDB\x9E\x64\x70\xB8\xD3\x2B\x9D\xC6\xD7\xA9\xC0\xC8\x05\xCA\xD9\xCE\x1E\x1A\xC3\x1D\x01\xDA\xD9\xC7\x3A\x16\xB8\xDF\xD9\xB0\x06\x1F\x01\xDF\xDF\xBA\xAE\x14\xBE\x80\xD4\xDE\x02\x1D\x3C\xE7\xD8\xDE\x3A\x14\xBF\x91\xD2\xC0\x6A\xC6\xC5\xBF\xC5\xCB\x08\xCA\xC7\x02\x1D\xC5\xB3\xBD\xC2\x42\xCF\xC2\xA8\xBD\xC7\x32\xCB\x1F\xAE\x1F\xC1\xF3\xD7\xC1\xFF\xD5\xA6\xF7\xDE\xC6\xB3\xCB\xC5\x0A\xC7\xE0\x69\xC6\x49\x00\xEF\x2F\xF8\xD3\xC3\xDC\xD6\x10\x58\xBF\xDE\x7C\xD7\x10\xE2\xDD\xB0\x3A\x4C\xB4\x8B\xB3\xB6\x2D\xD1\xB8\x97\x1A\xDE\xAF\xC8\xCB\x19\xE5\x2D\x8B\xD4\xE2\x97\x15\xC3\x0C\xB2\xCF\x29\xE7\xB9\x22\xE9\xD8\x6F\x4E\xDF\xF5\xD3\xC4\x01\xEF\x64\xF8\x9A\xC1\xEC\xD0\x00\xFD\xBA\xE1\xD4\x23\xBE\xDB\xC6\xD8\x64\xCF\xC7\x01\xDB\xE1\x31\xDF\xE0\x0D\xB2\xCF\x3F\xE7\xCC\x52\xC7\xC6\x54\xC5\xBA\xF6\xD9\xE3\xC4\xC2\x20\xFA\xD8\x98\x91\xC8\xCB\x4D\xE3\xCE\xC8\xC0\xE5\x36\xE2\xE1\x0A\xE4\xE5\x15\xE4\xE0\xB9\x1A\xE4\x2F\xEA\xE5\x0F\xD2\x9A\xAD\x6F\xE5\x6B\xCC\xE2\x55\xED\xE2\x06\x17\xD5\xC3\x1C\xE4\x69\xE7\xE4\x6C\xE3\xE5\x5C\xEA\xBA\x9F\x47\xC4\x06\x19\xC4\xD9\x24\xE7\x3D\xCF\xE4\xE5\xC1\xE5\x4D\xAD\xE6\xD9\xD8\xC5\x29\xBA\xC5\xCF\x1C\xC5\x7C\xC0\xC5\x81\xEE\x99\x5E\xE4\xDF\x60\xE9\xB1\x62\xEC\xE0\x16\xEA\x13\xC3\x18\x3B\x40\xED\xB0\x9F\xC0\x00\x90\xCB\xD1\xC3\xD4\x2D\x83\xCA\x15\xCA\xDB\xAF\x30\xD3\x1C\xEC\x9B\xE9\x9C\xEE\x1A\x48\xC0\xE1\x41\xC7\xE3\x13\xE1\xCD\x89\xEA\xCD\xAA\xE5\xEB\xB6\xEF\xB0", }; 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(); } /*********************************************************************** 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); } /*********************************************************************** 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; } } } } namespace vl { namespace reflection { namespace description { #ifndef VCZH_DEBUG_NO_REFLECTION using namespace vl::parsing::xml; 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(Accept, {L"visitor"}) END_CLASS_MEMBER(XmlNode) BEGIN_CLASS_MEMBER(XmlText) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_EXTERNALMETHOD(get_content, NO_PARAMETER, vl::WString(XmlText::*)(), [](XmlText* node){ return node->content.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_content, {L"value"}, void(XmlText::*)(const vl::WString&), [](XmlText* node, const vl::WString& value){ node->content.value = value; }) CLASS_MEMBER_PROPERTY(content, get_content, set_content) END_CLASS_MEMBER(XmlText) BEGIN_CLASS_MEMBER(XmlCData) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_EXTERNALMETHOD(get_content, NO_PARAMETER, vl::WString(XmlCData::*)(), [](XmlCData* node){ return node->content.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_content, {L"value"}, void(XmlCData::*)(const vl::WString&), [](XmlCData* node, const vl::WString& value){ node->content.value = value; }) CLASS_MEMBER_PROPERTY(content, get_content, set_content) END_CLASS_MEMBER(XmlCData) BEGIN_CLASS_MEMBER(XmlAttribute) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_EXTERNALMETHOD(get_name, NO_PARAMETER, vl::WString(XmlAttribute::*)(), [](XmlAttribute* node){ return node->name.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_name, {L"value"}, void(XmlAttribute::*)(const vl::WString&), [](XmlAttribute* node, const vl::WString& value){ node->name.value = value; }) CLASS_MEMBER_EXTERNALMETHOD(get_value, NO_PARAMETER, vl::WString(XmlAttribute::*)(), [](XmlAttribute* node){ return node->value.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_value, {L"value"}, void(XmlAttribute::*)(const vl::WString&), [](XmlAttribute* node, const vl::WString& value){ node->value.value = value; }) CLASS_MEMBER_PROPERTY(name, get_name, set_name) CLASS_MEMBER_PROPERTY(value, get_value, set_value) END_CLASS_MEMBER(XmlAttribute) BEGIN_CLASS_MEMBER(XmlComment) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_EXTERNALMETHOD(get_content, NO_PARAMETER, vl::WString(XmlComment::*)(), [](XmlComment* node){ return node->content.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_content, {L"value"}, void(XmlComment::*)(const vl::WString&), [](XmlComment* node, const vl::WString& value){ node->content.value = value; }) CLASS_MEMBER_PROPERTY(content, get_content, set_content) END_CLASS_MEMBER(XmlComment) BEGIN_CLASS_MEMBER(XmlElement) CLASS_MEMBER_BASE(XmlNode) CLASS_MEMBER_CONSTRUCTOR(vl::Ptr(), NO_PARAMETER) CLASS_MEMBER_EXTERNALMETHOD(get_name, NO_PARAMETER, vl::WString(XmlElement::*)(), [](XmlElement* node){ return node->name.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_name, {L"value"}, void(XmlElement::*)(const vl::WString&), [](XmlElement* node, const vl::WString& value){ node->name.value = value; }) CLASS_MEMBER_EXTERNALMETHOD(get_closingName, NO_PARAMETER, vl::WString(XmlElement::*)(), [](XmlElement* node){ return node->closingName.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_closingName, {L"value"}, void(XmlElement::*)(const vl::WString&), [](XmlElement* node, const vl::WString& value){ node->closingName.value = value; }) CLASS_MEMBER_PROPERTY(name, get_name, set_name) CLASS_MEMBER_PROPERTY(closingName, get_closingName, set_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) CLASS_MEMBER_EXTERNALMETHOD(get_name, NO_PARAMETER, vl::WString(XmlInstruction::*)(), [](XmlInstruction* node){ return node->name.value; }) CLASS_MEMBER_EXTERNALMETHOD(set_name, {L"value"}, void(XmlInstruction::*)(const vl::WString&), [](XmlInstruction* node, const vl::WString& value){ node->name.value = value; }) CLASS_MEMBER_PROPERTY(name, get_name, set_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_CLASS_MEMBER(XmlNode::IVisitor) CLASS_MEMBER_BASE(vl::reflection::IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::XmlNode_IVisitor::Create) 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_CLASS_MEMBER(XmlNode) 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; } } } } /*********************************************************************** REFLECTION\GUITYPEDESCRIPTOR.CPP ***********************************************************************/ namespace vl { using namespace collections; namespace reflection { /*********************************************************************** DescriptableObject ***********************************************************************/ DescriptableObject::DescriptableObject() :referenceCounter(0) ,sharedPtrDestructorProc(0) ,objectSize(0) ,typeDescriptor(0) { } DescriptableObject::~DescriptableObject() { } description::ITypeDescriptor* DescriptableObject::GetTypeDescriptor() { return typeDescriptor?*typeDescriptor:0; } 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) { if (referenceCounter > 0 && forceDisposing) { throw description::ValueNotDisposableException(); } if (sharedPtrDestructorProc) { return sharedPtrDestructorProc(this, forceDisposing); } else { delete this; return true; } } /*********************************************************************** description::Value ***********************************************************************/ namespace description { Value::Value(DescriptableObject* value) :valueType(value ? RawPtr :Null) ,rawPtr(value) ,typeDescriptor(0) { } Value::Value(Ptr value) :valueType(value ? SharedPtr : Null) ,rawPtr(value.Obj()) ,sharedPtr(value) ,typeDescriptor(0) { } Value::Value(const WString& value, ITypeDescriptor* associatedTypeDescriptor) :valueType(Text) ,rawPtr(0) ,text(value) ,typeDescriptor(associatedTypeDescriptor) { } vint Value::Compare(const Value& a, const Value& b)const { ValueType va=a.valueType; ValueType vb=b.valueType; if(va==vb) { switch(va) { case Text: return WString::Compare(a.text, b.text); case RawPtr: case SharedPtr: return (vint)a.rawPtr-(vint)b.rawPtr; default: return 0; } } else { return (vint)va-(vint)vb; } } Value::Value() :valueType(Null) ,rawPtr(0) ,typeDescriptor(0) { } Value::Value(const Value& value) :valueType(value.valueType) ,rawPtr(value.rawPtr) ,sharedPtr(value.sharedPtr) ,text(value.text) ,typeDescriptor(value.typeDescriptor) { } Value& Value::operator=(const Value& value) { valueType=value.valueType; rawPtr=value.rawPtr; sharedPtr=value.sharedPtr; text=value.text; typeDescriptor=value.typeDescriptor; return *this; } Value::ValueType Value::GetValueType()const { return valueType; } DescriptableObject* Value::GetRawPtr()const { return rawPtr; } Ptr Value::GetSharedPtr()const { return sharedPtr; } const WString& Value::GetText()const { return text; } ITypeDescriptor* Value::GetTypeDescriptor()const { switch(valueType) { case RawPtr: case SharedPtr: return rawPtr?rawPtr->GetTypeDescriptor():0; case Text: 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 Text: return GetTypeDescriptor()->GetTypeName(); default: return L"null"; } } bool Value::IsNull()const { return valueType==Null; } bool Value::CanConvertTo(ITypeDescriptor* targetType, ValueType targetValueType)const { if(targetType==GetGlobalTypeManager()->GetRootType()) { return true; } switch(valueType) { case Null: return targetValueType!=Text; case RawPtr: case SharedPtr: if(targetValueType!=RawPtr && targetValueType!=SharedPtr) return false; break; case Text: return targetValueType==Text; } 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=Text; currentType=0; break; default: currentType=currentType->GetElementType(); } } } return CanConvertTo(targetType->GetTypeDescriptor(), targetValueType); } Value Value::From(DescriptableObject* value) { return Value(value); } Value Value::From(Ptr value) { return Value(value); } Value Value::From(const WString& value, ITypeDescriptor* type) { return Value(value, type); } 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::DeleteRawPtr() { if(valueType!=RawPtr) return false; if(!rawPtr) return false; rawPtr->Dispose(true); *this=Value(); return true; } /*********************************************************************** 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); } rootType=description::GetTypeDescriptor(); 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 { 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; } IValueSerializer* GetValueSerializer(const WString& name) { ITypeDescriptor* descriptor=GetTypeDescriptor(name); return descriptor?descriptor->GetValueSerializer():0; } ITypeDescriptor* GetTypeDescriptor(const WString& name) { if(globalTypeManager) { if(!globalTypeManager->IsLoaded()) { globalTypeManager->Load(); } return globalTypeManager->GetTypeDescriptor(name); } return 0; } /*********************************************************************** LogTypeManager (enum) ***********************************************************************/ void LogTypeManager_Enum(stream::TextWriter& writer, ITypeDescriptor* type, IValueSerializer* serializer) { writer.WriteLine((serializer->CanMergeCandidate()?L"flags ":L"enum ")+type->GetTypeName()); writer.WriteLine(L"{"); for(vint j=0;jGetCandidateCount();j++) { writer.WriteLine(L" "+serializer->GetCandidate(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"data "+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=IsInterfaceType(type, acceptProxy); 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::TypeName) { acceptProxy = true; return true; } } } } if(!containsConstructor) { if(typeDescriptor->GetTypeName()==TypeInfo::TypeName) { return true; } else { for(vint i=0;iGetBaseTypeDescriptorCount();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;iGetTypeDescriptorCount();i++) { ITypeDescriptor* type=globalTypeManager->GetTypeDescriptor(i); IValueSerializer* serializer=type->GetValueSerializer(); if(serializer) { if(serializer->HasCandidate()) { LogTypeManager_Enum(writer, type, serializer); } else if(type->GetPropertyCount()>0) { LogTypeManager_Struct(writer, type); } else { LogTypeManager_Data(writer, type); } } else { LogTypeManager_Class(writer, type); } writer.WriteLine(L""); } } /*********************************************************************** IValueEnumerable ***********************************************************************/ Ptr IValueEnumerable::Create(collections::LazyList values) { Ptr> enumerable=new LazyList(values); return new ValueEnumerableWrapper>>(enumerable); } /*********************************************************************** IValueList ***********************************************************************/ Ptr IValueList::Create() { Ptr> list=new List; return new ValueListWrapper>>(list); } Ptr IValueList::Create(Ptr values) { Ptr> list=new List; CopyFrom(*list.Obj(), GetLazyList(values)); return new ValueListWrapper>>(list); } Ptr IValueList::Create(collections::LazyList values) { Ptr> list=new List; CopyFrom(*list.Obj(), values); return new ValueListWrapper>>(list); } /*********************************************************************** 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); } } } } /*********************************************************************** REFLECTION\GUITYPEDESCRIPTORBUILDER.CPP ***********************************************************************/ namespace vl { using namespace collections; namespace reflection { namespace description { /*********************************************************************** TypeInfoImpl ***********************************************************************/ TypeInfoImpl::TypeInfoImpl(Decorator _decorator) :decorator(_decorator) ,typeDescriptor(0) { } TypeInfoImpl::~TypeInfoImpl() { } TypeInfoImpl::Decorator TypeInfoImpl::GetDecorator() { return decorator; } ITypeInfo* TypeInfoImpl::GetElementType() { return elementType.Obj(); } ITypeDescriptor* TypeInfoImpl::GetTypeDescriptor() { return typeDescriptor?typeDescriptor: elementType?elementType->GetTypeDescriptor(): 0; } vint TypeInfoImpl::GetGenericArgumentCount() { return genericArguments.Count(); } ITypeInfo* TypeInfoImpl::GetGenericArgument(vint index) { return genericArguments[index].Obj(); } WString TypeInfoImpl::GetTypeFriendlyName() { switch(decorator) { case RawPtr: return elementType->GetTypeFriendlyName()+L"*"; case SharedPtr: return elementType->GetTypeFriendlyName()+L"^"; case Nullable: return elementType->GetTypeFriendlyName()+L"?"; case TypeDescriptor: return typeDescriptor->GetTypeName(); case Generic: { WString result=elementType->GetTypeFriendlyName()+L"<"; FOREACH_INDEXER(Ptr, type, i, genericArguments) { if(i>0) result+=L", "; result+=type->GetTypeFriendlyName(); } result+=L">"; return result; } default: return L""; } } void TypeInfoImpl::SetTypeDescriptor(ITypeDescriptor* value) { typeDescriptor=value; } void TypeInfoImpl::AddGenericArgument(Ptr value) { genericArguments.Add(value); } void TypeInfoImpl::SetElementType(Ptr value) { elementType=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::EventHandlerImpl ***********************************************************************/ EventInfoImpl::EventHandlerImpl::EventHandlerImpl(EventInfoImpl* _ownerEvent, DescriptableObject* _ownerObject, Ptr _handler) :ownerEvent(_ownerEvent) , ownerObject(_ownerObject) , handler(_handler) , attached(true) { } EventInfoImpl::EventHandlerImpl::~EventHandlerImpl() { } IEventInfo* EventInfoImpl::EventHandlerImpl::GetOwnerEvent() { return ownerEvent; } Value EventInfoImpl::EventHandlerImpl::GetOwnerObject() { return Value::From(ownerObject); } bool EventInfoImpl::EventHandlerImpl::IsAttached() { return attached; } bool EventInfoImpl::EventHandlerImpl::Detach() { if(attached) { attached=false; ownerEvent->DetachInternal(ownerObject, this); ownerEvent->RemoveEventHandler(ownerObject, this); return true; } else { return false; } } void EventInfoImpl::EventHandlerImpl::Invoke(const Value& thisObject, collections::Array& arguments) { if(thisObject.IsNull()) { throw ArgumentNullException(L"thisObject", this); } Ptr eventArgs = IValueList::Create(); FOREACH(Value, argument, arguments) { eventArgs->Add(argument); } handler->Invoke(eventArgs); arguments.Resize(eventArgs->GetCount()); for (vint i = 0; i < arguments.Count(); i++) { arguments[i] = eventArgs->Get(i); } } Ptr EventInfoImpl::EventHandlerImpl::GetDescriptableTag() { return descriptableTag; } void EventInfoImpl::EventHandlerImpl::SetDescriptableTag(Ptr _tag) { descriptableTag = _tag; } Ptr EventInfoImpl::EventHandlerImpl::GetObjectTag() { return objectTag; } void EventInfoImpl::EventHandlerImpl::SetObjectTag(Ptr _tag) { objectTag = _tag; } /*********************************************************************** EventInfoImpl ***********************************************************************/ const wchar_t* EventInfoImpl::EventHandlerListInternalPropertyName = L"List"; void EventInfoImpl::AddEventHandler(DescriptableObject* thisObject, Ptr eventHandler) { WString key=EventHandlerListInternalPropertyName; Ptr value=thisObject->GetInternalProperty(key).Cast(); if(!value) { value=new EventHandlerList; thisObject->SetInternalProperty(key, value); } value->Add(eventHandler); } void EventInfoImpl::RemoveEventHandler(DescriptableObject* thisObject, IEventHandler* eventHandler) { WString key=EventHandlerListInternalPropertyName; Ptr value=thisObject->GetInternalProperty(key).Cast(); if(value) { value->Remove(eventHandler); if(value->Count()==0) { thisObject->SetInternalProperty(key, 0); } } } 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) { Ptr eventHandler=new EventHandlerImpl(this, rawThisObject, handler); AddEventHandler(rawThisObject, eventHandler); AttachInternal(rawThisObject, eventHandler.Obj()); return eventHandler; } else { return 0; } } void EventInfoImpl::Invoke(const Value& thisObject, collections::Array& 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; } 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); } } /*********************************************************************** 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->GetValueSerializer() ? Value::Text : 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->GetValueSerializer() ? Value::Text : 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(const WString& _typeName, const WString& _cppFullTypeName) :typeName(_typeName) ,cppFullTypeName(_cppFullTypeName) ,loaded(false) { } TypeDescriptorImpl::~TypeDescriptorImpl() { } const WString& TypeDescriptorImpl::GetTypeName() { return typeName; } const WString& TypeDescriptorImpl::GetCppFullTypeName() { return cppFullTypeName; } IValueSerializer* TypeDescriptorImpl::GetValueSerializer() { Load(); return valueSerializer.Obj(); } 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(); } /*********************************************************************** Function Related ***********************************************************************/ namespace internal_helper { void UnboxSpecifiedParameter(Ptr arguments, vint index) { } void UnboxSpecifiedParameter(MethodInfoImpl* methodInfo, collections::Array& arguments, vint index) { } void UnboxSpecifiedParameter(collections::Array& arguments, vint index) { } void AddValueToList(Ptr arguments) { } void AddValueToArray(collections::Array& arguments, vint index) { } } } } } /*********************************************************************** REFLECTION\GUITYPEDESCRIPTORPREDEFINED.CPP ***********************************************************************/ #include #include namespace vl { using namespace collections; using namespace regex; namespace reflection { namespace description { /*********************************************************************** SerializableTypeDescriptorBase ***********************************************************************/ SerializableTypeDescriptorBase::SerializableTypeDescriptorBase(const WString& _typeName, const WString& _cppFullTypeName, Ptr _serializer) :typeName(_typeName) ,cppFullTypeName(_cppFullTypeName) ,serializer(_serializer) { } SerializableTypeDescriptorBase::~SerializableTypeDescriptorBase() { } const WString& SerializableTypeDescriptorBase::GetTypeName() { return typeName; } const WString& SerializableTypeDescriptorBase::GetCppFullTypeName() { return cppFullTypeName; } IValueSerializer* SerializableTypeDescriptorBase::GetValueSerializer() { return serializer.Obj(); } vint SerializableTypeDescriptorBase::GetBaseTypeDescriptorCount() { return 0; } ITypeDescriptor* SerializableTypeDescriptorBase::GetBaseTypeDescriptor(vint index) { return 0; } bool SerializableTypeDescriptorBase::CanConvertTo(ITypeDescriptor* targetType) { return this==targetType; } vint SerializableTypeDescriptorBase::GetPropertyCount() { return 0; } IPropertyInfo* SerializableTypeDescriptorBase::GetProperty(vint index) { return 0; } bool SerializableTypeDescriptorBase::IsPropertyExists(const WString& name, bool inheritable) { return false; } IPropertyInfo* SerializableTypeDescriptorBase::GetPropertyByName(const WString& name, bool inheritable) { return 0; } vint SerializableTypeDescriptorBase::GetEventCount() { return 0; } IEventInfo* SerializableTypeDescriptorBase::GetEvent(vint index) { return 0; } bool SerializableTypeDescriptorBase::IsEventExists(const WString& name, bool inheritable) { return false; } IEventInfo* SerializableTypeDescriptorBase::GetEventByName(const WString& name, bool inheritable) { return 0; } vint SerializableTypeDescriptorBase::GetMethodGroupCount() { return 0; } IMethodGroupInfo* SerializableTypeDescriptorBase::GetMethodGroup(vint index) { return 0; } bool SerializableTypeDescriptorBase::IsMethodGroupExists(const WString& name, bool inheritable) { return false; } IMethodGroupInfo* SerializableTypeDescriptorBase::GetMethodGroupByName(const WString& name, bool inheritable) { return 0; } IMethodGroupInfo* SerializableTypeDescriptorBase::GetConstructorGroup() { return 0; } /*********************************************************************** TypeName ***********************************************************************/ IMPL_TYPE_INFO_RENAME(Sys, system::Sys) IMPL_TYPE_INFO_RENAME(Math, system::Math) 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::IValueListener, system::Listener) 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::IValueSerializer, system::reflection::ValueSerializer) 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::ITypeDescriptor, system::reflection::TypeDescriptor) /*********************************************************************** TypedValueSerializerProvider ***********************************************************************/ 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); 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); 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; } //--------------------------------------- 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; } /*********************************************************************** ObjectTypeDescriptor ***********************************************************************/ class ObjectTypeDescriptor : public SerializableTypeDescriptorBase { public: ObjectTypeDescriptor() :SerializableTypeDescriptorBase(TypeInfo::TypeName, TypeInfo::CppFullTypeName, 0) { } }; /*********************************************************************** BoolValueSerializer ***********************************************************************/ class BoolValueSerializer : public EnumValueSerializer { public: BoolValueSerializer(ITypeDescriptor* _ownerTypeDescriptor) :EnumValueSerializer(_ownerTypeDescriptor, false) { candidates.Add(L"true", true); candidates.Add(L"false", false); } }; /*********************************************************************** DateTimeValueSerializer ***********************************************************************/ class DateTimeValueSerializer : public GeneralValueSerializer { protected: Regex regexDateTime; DateTime GetDefaultValue()override { return DateTime(); } WString Format(vint number, vint length) { WString result = itow(number); while (result.Length() < length) { result = L"0" + result; } return result; } bool Serialize(const DateTime& input, WString& output)override { output = Format(input.year, 4) + L"-" + Format(input.month, 2) + L"-" + Format(input.day, 2) + L" " + Format(input.hour, 2) + L":" + Format(input.minute, 2) + L":" + Format(input.second, 2) + L"." + Format(input.milliseconds, 3); return true; } bool Deserialize(const WString& input, DateTime& output)override { Ptr match=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; } public: DateTimeValueSerializer(ITypeDescriptor* _ownerTypeDescriptor) :GeneralValueSerializer(_ownerTypeDescriptor) ,regexDateTime(L"(/d/d/d/d)-(/d/d)-(/d/d) (/d/d):(/d/d):(/d/d).(/d/d/d)") { } }; /*********************************************************************** Helper Functions ***********************************************************************/ 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(); } Value IValueSerializer_Parse(IValueSerializer* serializer, const WString& input) { Value value; if(serializer->Parse(input, value)) { return value; } else { return Value(); } } /*********************************************************************** Interface Implementation Proxy (Implement) ***********************************************************************/ namespace interface_proxy { #pragma warning(push) #pragma warning(disable:4250) class description_IValueEnumerator : public ValueInterfaceRoot, public virtual IValueEnumerator { public: description_IValueEnumerator(Ptr proxy) :ValueInterfaceRoot(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueEnumerator(proxy); } Value GetCurrent()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetCurrent); } vint GetIndex()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetIndex); } bool Next()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(Next); } }; class description_IValueEnumerable : public ValueInterfaceRoot, public virtual IValueEnumerable { public: description_IValueEnumerable(Ptr proxy) :ValueInterfaceRoot(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueEnumerable(proxy); } Ptr CreateEnumerator()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(CreateEnumerator); } }; class description_IValueReadonlyList : public description_IValueEnumerable, public virtual IValueReadonlyList { public: description_IValueReadonlyList(Ptr proxy) :description_IValueEnumerable(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueReadonlyList(proxy); } vint GetCount()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetCount); } Value Get(vint index)override { return INVOKEGET_INTERFACE_PROXY(Get, index); } bool Contains(const Value& value)override { return INVOKEGET_INTERFACE_PROXY(Contains, value); } vint IndexOf(const Value& value)override { return INVOKEGET_INTERFACE_PROXY(IndexOf, value); } }; class description_IValueList : public description_IValueReadonlyList, public virtual IValueList { public: description_IValueList(Ptr proxy) :description_IValueReadonlyList(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueList(proxy); } void Set(vint index, const Value& value)override { INVOKE_INTERFACE_PROXY(Set, index, value); } vint Add(const Value& value)override { return INVOKEGET_INTERFACE_PROXY(Add, value); } vint Insert(vint index, const Value& value)override { return INVOKEGET_INTERFACE_PROXY(Insert, index, value); } bool Remove(const Value& value)override { return INVOKEGET_INTERFACE_PROXY(Remove, value); } bool RemoveAt(vint index)override { return INVOKEGET_INTERFACE_PROXY(RemoveAt, index); } void Clear()override { INVOKE_INTERFACE_PROXY_NOPARAMS(Clear); } }; class description_IValueObservableList :public description_IValueReadonlyList, public virtual IValueObservableList { public: description_IValueObservableList(Ptr proxy) :description_IValueReadonlyList(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueObservableList(proxy); } }; class description_IValueReadonlyDictionary : public ValueInterfaceRoot, public virtual IValueReadonlyDictionary { public: description_IValueReadonlyDictionary(Ptr proxy) :ValueInterfaceRoot(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueReadonlyDictionary(proxy); } IValueReadonlyList* GetKeys()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetKeys); } IValueReadonlyList* GetValues()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetValues); } vint GetCount()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetCount); } Value Get(const Value& key)override { return INVOKEGET_INTERFACE_PROXY(Get, key); } }; class description_IValueDictionary : public description_IValueReadonlyDictionary, public virtual IValueDictionary { public: description_IValueDictionary(Ptr proxy) :description_IValueReadonlyDictionary(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueDictionary(proxy); } void Set(const Value& key, const Value& value)override { INVOKE_INTERFACE_PROXY(Set, key, value); } bool Remove(const Value& key)override { return INVOKEGET_INTERFACE_PROXY(Remove, key); } void Clear()override { INVOKE_INTERFACE_PROXY_NOPARAMS(Clear); } }; class description_IValueInterfaceProxy : public ValueInterfaceRoot, public virtual IValueInterfaceProxy { public: description_IValueInterfaceProxy(Ptr proxy) :ValueInterfaceRoot(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueInterfaceProxy(proxy); } Value Invoke(const WString& methodName, Ptr arguments)override { return INVOKEGET_INTERFACE_PROXY(Invoke, methodName, arguments); } }; class description_IValueFunctionProxy : public ValueInterfaceRoot, public virtual IValueFunctionProxy { public: description_IValueFunctionProxy(Ptr proxy) :ValueInterfaceRoot(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueFunctionProxy(proxy); } Value Invoke(Ptr arguments)override { return INVOKEGET_INTERFACE_PROXY(Invoke, arguments); } }; class description_IValueListener : public ValueInterfaceRoot, public virtual IValueListener { public: description_IValueListener(Ptr proxy) :ValueInterfaceRoot(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueListener(proxy); } IValueSubscription* GetSubscription()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetSubscription); } bool GetStopped()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(GetStopped); } bool StopListening()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(StopListening); } }; class description_IValueSubscription: public ValueInterfaceRoot, public virtual IValueSubscription { public: description_IValueSubscription(Ptr proxy) :ValueInterfaceRoot(proxy) { } static Ptr Create(Ptr proxy) { return new description_IValueSubscription(proxy); } Ptr Subscribe(const Func& callback)override { return INVOKEGET_INTERFACE_PROXY(Subscribe, callback); } bool Update()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(Update); } bool Close()override { return INVOKEGET_INTERFACE_PROXY_NOPARAMS(Close); } }; #pragma warning(pop) } /*********************************************************************** Collections ***********************************************************************/ #define _ , template<> struct CustomTypeDescriptorSelector { public: class CustomTypeDescriptorImpl : public TypeDescriptorImpl { public: CustomTypeDescriptorImpl() :TypeDescriptorImpl(TypeInfo::TypeName, TypeInfo::CppFullTypeName) { Description::SetAssociatedTypeDescroptor(this); } ~CustomTypeDescriptorImpl() { Description::SetAssociatedTypeDescroptor(0); } protected: void LoadInternal()override { } }; }; BEGIN_CLASS_MEMBER(Sys) CLASS_MEMBER_STATIC_METHOD(Len, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Left, { L"value" _ L"length" }) CLASS_MEMBER_STATIC_METHOD(Right, { L"value" _ L"length" }) CLASS_MEMBER_STATIC_METHOD(Mid, { L"value" _ L"start" _ L"length" }) CLASS_MEMBER_STATIC_METHOD(Find, { L"value" _ L"substr" }) END_CLASS_MEMBER(Sys) BEGIN_CLASS_MEMBER(Math) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint8_t(*)(vint8_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint16_t(*)(vint16_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint32_t(*)(vint32_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint64_t(*)(vint64_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, float(*)(float)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, double(*)(double)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Max, { L"a" _ L"b" }, vint8_t(*)(vint8_t, vint8_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Max, { L"a" _ L"b" }, vint16_t(*)(vint16_t, vint16_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Max, { L"a" _ L"b" }, vint32_t(*)(vint32_t, vint32_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Max, { L"a" _ L"b" }, vint64_t(*)(vint64_t, vint64_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Max, { L"a" _ L"b" }, float(*)(float, float)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Max, { L"a" _ L"b" }, double(*)(double, double)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Min, { L"a" _ L"b" }, vint8_t(*)(vint8_t, vint8_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Min, { L"a" _ L"b" }, vint16_t(*)(vint16_t, vint16_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Min, { L"a" _ L"b" }, vint32_t(*)(vint32_t, vint32_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Min, { L"a" _ L"b" }, vint64_t(*)(vint64_t, vint64_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Min, { L"a" _ L"b" }, float(*)(float, float)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Min, { L"a" _ L"b" }, double(*)(double, double)) CLASS_MEMBER_STATIC_METHOD(Sin, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Cos, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Tan, { L"value" }) CLASS_MEMBER_STATIC_METHOD(ASin, { L"value" }) CLASS_MEMBER_STATIC_METHOD(ACos, { L"value" }) CLASS_MEMBER_STATIC_METHOD(ATan, { L"value" }) CLASS_MEMBER_STATIC_METHOD(ATan2, { L"x" _ L"y" }) CLASS_MEMBER_STATIC_METHOD(Exp, { L"value" }) CLASS_MEMBER_STATIC_METHOD(LogN, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Log10, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Log, { L"value" _ L"base" }) CLASS_MEMBER_STATIC_METHOD(Pow, { L"value" _ L"power" }) CLASS_MEMBER_STATIC_METHOD(Ceil, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Floor, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Round, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Trunc, { L"value" }) CLASS_MEMBER_STATIC_METHOD(CeilI, { L"value" }) CLASS_MEMBER_STATIC_METHOD(FloorI, { L"value" }) CLASS_MEMBER_STATIC_METHOD(RoundI, { L"value" }) CLASS_MEMBER_STATIC_METHOD(TruncI, { L"value" }) END_CLASS_MEMBER(Math) BEGIN_STRUCT_MEMBER(VoidValue) END_STRUCT_MEMBER(VoidValue) BEGIN_CLASS_MEMBER(IDescriptable) END_CLASS_MEMBER(IDescriptable) BEGIN_CLASS_MEMBER(IValueEnumerator) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueEnumerator::Create) CLASS_MEMBER_PROPERTY_READONLY_FAST(Current) CLASS_MEMBER_PROPERTY_READONLY_FAST(Index) CLASS_MEMBER_METHOD(Next, NO_PARAMETER) END_CLASS_MEMBER(IValueEnumerator) BEGIN_CLASS_MEMBER(IValueEnumerable) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueEnumerable::Create) CLASS_MEMBER_METHOD(CreateEnumerator, NO_PARAMETER) END_CLASS_MEMBER(IValueEnumerable) BEGIN_CLASS_MEMBER(IValueReadonlyList) CLASS_MEMBER_BASE(IValueEnumerable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueReadonlyList::Create) 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_CLASS_MEMBER(IValueReadonlyList) BEGIN_CLASS_MEMBER(IValueList) CLASS_MEMBER_BASE(IValueReadonlyList) CLASS_MEMBER_EXTERNALCTOR(Ptr(), NO_PARAMETER, (Ptr(*)())&IValueList::Create) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"values"}, (Ptr(*)(Ptr))&IValueList::Create) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::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_CLASS_MEMBER(IValueList) BEGIN_CLASS_MEMBER(IValueObservableList) CLASS_MEMBER_BASE(IValueReadonlyList) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueObservableList::Create) CLASS_MEMBER_EVENT(ItemChanged) END_CLASS_MEMBER(IValueObservableList) BEGIN_CLASS_MEMBER(IValueReadonlyDictionary) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueReadonlyDictionary::Create) 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_CLASS_MEMBER(IValueReadonlyDictionary) BEGIN_CLASS_MEMBER(IValueDictionary) CLASS_MEMBER_BASE(IValueReadonlyDictionary) CLASS_MEMBER_EXTERNALCTOR(Ptr(), NO_PARAMETER, (Ptr(*)())&IValueDictionary::Create) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"values"}, (Ptr(*)(Ptr))&IValueDictionary::Create) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueDictionary::Create) CLASS_MEMBER_METHOD(Set, {L"key" _ L"value"}) CLASS_MEMBER_METHOD(Remove, {L"key"}) CLASS_MEMBER_METHOD(Clear, NO_PARAMETER) END_CLASS_MEMBER(IValueDictionary) BEGIN_CLASS_MEMBER(IValueInterfaceProxy) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueInterfaceProxy::Create) CLASS_MEMBER_METHOD(Invoke, {L"name" _ L"arguments"}) END_CLASS_MEMBER(IValueInterfaceProxy) BEGIN_CLASS_MEMBER(IValueFunctionProxy) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueFunctionProxy::Create) CLASS_MEMBER_METHOD(Invoke, {L"arguments"}) END_CLASS_MEMBER(IValueFunctionProxy) BEGIN_CLASS_MEMBER(IValueListener) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueListener::Create) CLASS_MEMBER_PROPERTY_READONLY_FAST(Subscription) CLASS_MEMBER_PROPERTY_READONLY_FAST(Stopped) CLASS_MEMBER_METHOD(StopListening, NO_PARAMETER) END_CLASS_MEMBER(IValueListener) BEGIN_CLASS_MEMBER(IValueSubscription) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_EXTERNALCTOR(Ptr(Ptr), {L"proxy"}, &interface_proxy::description_IValueSubscription::Create) CLASS_MEMBER_METHOD(Subscribe, { L"callback" }) CLASS_MEMBER_METHOD(Update, NO_PARAMETER) CLASS_MEMBER_METHOD(Close, NO_PARAMETER) END_CLASS_MEMBER(IValueSubscription) BEGIN_CLASS_MEMBER(IValueCallStack) CLASS_MEMBER_BASE(IDescriptable) 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_CLASS_MEMBER(IValueCallStack) BEGIN_CLASS_MEMBER(IValueException) CLASS_MEMBER_BASE(IDescriptable) #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_CLASS_MEMBER(IValueException) BEGIN_CLASS_MEMBER(IValueSerializer) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerTypeDescriptor) CLASS_MEMBER_PROPERTY_READONLY_FAST(CandidateCount) CLASS_MEMBER_METHOD(Validate, {L"text"}) CLASS_MEMBER_EXTERNALMETHOD(Parse, {L"input"}, Value(IValueSerializer::*)(const WString&), &IValueSerializer_Parse) CLASS_MEMBER_METHOD(HasCandidate, NO_PARAMETER) CLASS_MEMBER_METHOD(GetCandidate, {L"index"}) CLASS_MEMBER_METHOD(CanMergeCandidate, NO_PARAMETER) END_CLASS_MEMBER(IValueSerializer) BEGIN_CLASS_MEMBER(ITypeInfo) CLASS_MEMBER_BASE(IDescriptable) 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_CLASS_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_CLASS_MEMBER(IMemberInfo) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerTypeDescriptor) CLASS_MEMBER_PROPERTY_READONLY_FAST(Name) END_CLASS_MEMBER(IMemberInfo) BEGIN_CLASS_MEMBER(IEventHandler) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerEvent) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerObject) CLASS_MEMBER_METHOD(IsAttached, NO_PARAMETER) CLASS_MEMBER_METHOD(Detach, NO_PARAMETER) CLASS_MEMBER_METHOD(Invoke, {L"thisObject" _ L"arguments"}) END_CLASS_MEMBER(IEventHandler) BEGIN_CLASS_MEMBER(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_CLASS_MEMBER(IEventInfo) BEGIN_CLASS_MEMBER(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_CLASS_MEMBER(IPropertyInfo) BEGIN_CLASS_MEMBER(IParameterInfo) CLASS_MEMBER_BASE(IMemberInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(Type) CLASS_MEMBER_PROPERTY_READONLY_FAST(OwnerMethod) END_CLASS_MEMBER(IParameterInfo) BEGIN_CLASS_MEMBER(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_CLASS_MEMBER(IMethodInfo) BEGIN_CLASS_MEMBER(IMethodGroupInfo) CLASS_MEMBER_BASE(IMemberInfo) CLASS_MEMBER_PROPERTY_READONLY_FAST(MethodCount) CLASS_MEMBER_METHOD(GetMethod, {L"index"}) END_CLASS_MEMBER(IMethodGroupInfo) BEGIN_CLASS_MEMBER(ITypeDescriptor) CLASS_MEMBER_BASE(IDescriptable) CLASS_MEMBER_PROPERTY_READONLY_FAST(TypeName) CLASS_MEMBER_PROPERTY_READONLY_FAST(ValueSerializer) 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(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(*)(), &ITypeDescriptor_GetTypeDescriptorCount) CLASS_MEMBER_STATIC_EXTERNALMETHOD(GetTypeDescriptor, {L"index"}, ITypeDescriptor*(*)(vint), &ITypeDescriptor_GetTypeDescriptor) CLASS_MEMBER_STATIC_EXTERNALMETHOD(GetTypeDescriptor, {L"name"}, ITypeDescriptor*(*)(const WString&), &ITypeDescriptor_GetTypeDescriptor) CLASS_MEMBER_STATIC_EXTERNALMETHOD(GetTypeDescriptor, {L"value"}, ITypeDescriptor*(*)(const Value&), &ITypeDescriptor_GetTypeDescriptor) END_CLASS_MEMBER(ITypeDescriptor) #undef _ /*********************************************************************** LoadPredefinedTypes ***********************************************************************/ class PredefinedTypeLoader : public Object, public ITypeLoader { public: template void AddSerializableType(ITypeManager* manager) { manager->SetTypeDescriptor(TypeInfo::TypeName, new SerializableTypeDescriptor); } void Load(ITypeManager* manager)override { manager->SetTypeDescriptor(TypeInfo::TypeName, new ObjectTypeDescriptor); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType>(manager); AddSerializableType(manager); AddSerializableType(manager); ADD_TYPE_INFO(Sys) ADD_TYPE_INFO(Math) ADD_TYPE_INFO(VoidValue) ADD_TYPE_INFO(IDescriptable) ADD_TYPE_INFO(DescriptableObject) ADD_TYPE_INFO(IValueEnumerator) ADD_TYPE_INFO(IValueEnumerable) ADD_TYPE_INFO(IValueReadonlyList) ADD_TYPE_INFO(IValueList) ADD_TYPE_INFO(IValueObservableList) ADD_TYPE_INFO(IValueReadonlyDictionary) ADD_TYPE_INFO(IValueDictionary) ADD_TYPE_INFO(IValueInterfaceProxy) ADD_TYPE_INFO(IValueFunctionProxy) ADD_TYPE_INFO(IValueListener) ADD_TYPE_INFO(IValueSubscription) ADD_TYPE_INFO(IValueCallStack) ADD_TYPE_INFO(IValueException) ADD_TYPE_INFO(IValueSerializer) ADD_TYPE_INFO(ITypeInfo) ADD_TYPE_INFO(ITypeInfo::Decorator) ADD_TYPE_INFO(IMemberInfo) ADD_TYPE_INFO(IEventHandler) ADD_TYPE_INFO(IEventInfo) ADD_TYPE_INFO(IPropertyInfo) ADD_TYPE_INFO(IParameterInfo) ADD_TYPE_INFO(IMethodInfo) ADD_TYPE_INFO(IMethodGroupInfo) ADD_TYPE_INFO(ITypeDescriptor) } void Unload(ITypeManager* manager)override { } }; bool LoadPredefinedTypes() { ITypeManager* manager=GetGlobalTypeManager(); if(manager) { Ptr loader=new PredefinedTypeLoader; return manager->AddTypeLoader(loader); } return false; } } } } /*********************************************************************** 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) { //构造所有DFA 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); } //为每一个DFA设置标记 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(); } } } //将DFA组合成大的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); } //转换成DFA 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; } //构造状态机 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; } /*********************************************************************** 辅助函数 ***********************************************************************/ 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; } } //递归保证转换先后顺序 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; //每次迭代当前状态的epsilon闭包 List transitions; //每次迭代当前状态的epsilon闭包的转换集合 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++) { //清空epsilonStates并包含自己 State* targetState=target->states[i].Obj(); State* sourceState=nfaStateMap[targetState]; if(sourceState->finalState) { targetState->finalState=true; } epsilonStates.Clear(); transitions.Clear(); //对所有产生的epsilonStates进行遍历,计算出该状态的一次epsilon直接目标加进去,并继续迭代 CollectEpsilon(targetState, sourceState, epsilonChecker, epsilonStates, transitions); //遍历所有epsilon闭包转换 for(vint j=0;jtarget)) { stateMap.Add(transition->target, target->NewState()); nfaStateMap.Add(stateMap[transition->target], transition->target); } //将该转换复制到新状态机里 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;//保证转换先后顺序不被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(); //对该DFA状态的所有等价NFA状态进行遍历 const List& nfaStates=dfaStateMap[currentState]; for(vint j=0;jtransitions.Count();k++) { Transition* nfaTransition=nfaState->transitions[k]; //检查该NFA转换类型是否已经具有已经被记录 Transition* transitionClass=0; for(vint l=0;l& transitionSet=nfaTransitions[transitionClasses[j]]; //对所有转换的NFA目标状态集合进行排序 transitionTargets.Clear(); for(vint l=0;ltarget; if(!transitionTargets.Contains(nfaState)) { transitionTargets.Add(nfaState); } } //判断转换类的所有转换的NFA目标状态组成的集合是否已经有一个对应的DFA状态 State* dfaState=0; for(vint k=0;kNewState(); for(vint k=0;kfinalState) { dfaState->finalState=true; } } } //将该转换复制到新状态机里 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 { /*********************************************************************** 辅助函数 ***********************************************************************/ 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); //填充字符映射表 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."); } } } //填充终结状态表 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 void Push(List& elements, vint& available, vint& count, const T& element) { if(elements.Count()==count) { elements.Add(element); } else { elements[count]=element; } T& current=elements[count]; current.previous=available; available=count++; } template T Pop(List& elements, vint& available, vint& count) { T& 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]; } } template<> struct POD { static const bool Result=true; }; template<> struct POD { static const bool Result=true; }; 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; StateSaver oldState=currentState; //开始遍历转换 for(vint i=currentState.minTransition;itransitions.Count();i++) { Transition* transition=currentState.currentState->transitions[i]; switch(transition->type) { case Transition::Chars: { CharRange range=transition->range; found= range.begin<=*currentState.reading && range.end>=*currentState.reading; if(found) { currentState.reading++; } } break; case Transition::BeginString: { found=currentState.reading==start; } break; case Transition::EndString: { found=*currentState.reading==L'\0'; } break; case Transition::Nop: { found=true; } break; case Transition::Capture: { ExtensionSaver saver; saver.captureListIndex=currentState.captureCount; saver.reading=currentState.reading; saver.transition=transition; Push(extensionSavers, currentState.extensionSaverAvailable, currentState.extensionSaverCount, saver); 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;jcapture) { if(capture.length!=-1 && (transition->index==-1 || transition->index==index)) { if(wcsncmp(start+capture.start, currentState.reading, capture.length)==0) { currentState.reading+=capture.length; found=true; break; } } if(transition->index!=-1 && index==transition->index) { break; } else { index++; } } } } break; case Transition::Positive: { ExtensionSaver saver; saver.captureListIndex=-1; saver.reading=currentState.reading; saver.transition=transition; Push(extensionSavers, currentState.extensionSaverAvailable, currentState.extensionSaverCount, saver); //Positive的oldState一定会被push oldState.storeType=StateSaver::Positive; found=true; } break; case Transition::Negative: { ExtensionSaver saver; saver.captureListIndex=-1; saver.reading=currentState.reading; saver.transition=transition; Push(extensionSavers, currentState.extensionSaverAvailable, currentState.extensionSaverCount, saver); //Negative的oldState一定会被push oldState.storeType=StateSaver::Negative; found=true; } break; case Transition::NegativeFail: { //只有在回溯的时候NegativeFail才会被考虑 } break; case Transition::End: { ExtensionSaver extensionSaver=Pop(extensionSavers, currentState.extensionSaverAvailable, currentState.extensionSaverCount); switch(extensionSaver.transition->type) { case Transition::Capture: { CaptureRecord& capture=result.captures[extensionSaver.captureListIndex]; capture.length=(currentState.reading-start)-capture.start; found=true; } break; case Transition::Positive: for(vint j=currentState.stateSaverCount-1;j>=0;j--) { StateSaver& stateSaver=stateSavers[j]; if(stateSaver.storeType==StateSaver::Positive) { oldState.reading=stateSaver.reading; oldState.stateSaverCount=j; currentState.reading=stateSaver.reading; currentState.stateSaverCount=j; break; } } found=true; break; case Transition::Negative: for(vint j=currentState.stateSaverCount-1;j>=0;j--) { StateSaver& stateSaver=stateSavers[j]; if(stateSaver.storeType==StateSaver::Negative) { oldState=stateSaver; oldState.storeType=StateSaver::Other; currentState=stateSaver; currentState.storeType=StateSaver::Other; i=currentState.minTransition-1; break; } } break; default:; } } break; default:; } //寻找成功,在必要的时候保存当前的回溯状态 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(!found) { //存在回溯记录则回溯 if(currentState.stateSaverCount) { //恢复Negative失败状态的时候要移动到NegativeFail后面 currentState=PopNonSaver(stateSavers, currentState.stateSaverCount); //minTransition总是被+1后保存,因此直接-1总是有效值 if(currentState.currentState->transitions[currentState.minTransition-1]->type==Transition::Negative) { //寻找NegativeFail for(vint i=0;itransitions.Count();i++) { Transition* transition=currentState.currentState->transitions[i]; if(transition->type==Transition::NegativeFail) { //将当前状态移动到NegativeFail后面 currentState.currentState=transition->target; currentState.minTransition=0; currentState.storeType=StateSaver::Other; break; } } } } else { break; } } } //判断是否成功并且处理返回结果 if(currentState.currentState->finalState) { 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 { 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); } /*********************************************************************** 外部函数 ***********************************************************************/ 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; wchar_t buffer[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; 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 #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) { bool needTrail=false; for(vint i=0;i=128) { needTrail=true; } } return !needTrail; } bool CanBeUtf8(unsigned char* buffer, vint size) { for(vint i=0;i=128 && buffer[i+1]==0) return false; vuint16_t c=buffer[i]+(buffer[i+1]<<8); if(c==0xFFFF) return false; vint type=0; if(0xD800<=c && c<=0xDBFF) type=1; else if(0xDC00<=c && c<=0xDFFF) type=2; if(needTrail) { if(type==2) { needTrail=false; } else { return false; } } else { if(type==1) { needTrail=true; } else if(type!=0) { return false; } } } return !needTrail; } bool CanBeUtf16BE(unsigned char* buffer, vint size) { if(size%2!=0) return false; bool needTrail=false; for(vint i=0;i=128 && buffer[i]==0) return false; vuint16_t c=buffer[i+1]+(buffer[i]<<8); if(c==0xFFFF) return false; vint type=0; if(0xD800<=c && c<=0xDBFF) type=1; else if(0xDC00<=c && c<=0xDFFF) type=2; if(needTrail) { if(type==2) { needTrail=false; } else { return false; } } else { if(type==1) { needTrail=true; } else if(type!=0) { return false; } } } return !needTrail; } #if defined VCZH_MSVC template bool GetEncodingResult(int (&tests)[Count], bool(&results)[Count], int test) { for(vint i=0;i=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=true; bool roughMbcs=CanBeMbcs(buffer, size); bool roughUtf8=CanBeUtf8(buffer, size); bool roughUtf16=CanBeUtf16(buffer, size); bool roughUtf16BE=CanBeUtf16BE(buffer, size); #if defined VCZH_MSVC vint roughCount=(roughMbcs?1:0)+(roughUtf8?1:0)+(roughUtf16?1:0)+(roughUtf16BE?1:0); if(roughCount==1) { #endif if(roughUtf8) encoding=BomEncoder::Utf8; if(roughUtf16) encoding=BomEncoder::Utf16; if(roughUtf16BE) encoding=BomEncoder::Utf16BE; #if defined VCZH_MSVC } else if(roughCount>1) { 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=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; } } } /*********************************************************************** 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; } } } }