Files
GacUI/Import/Vlpp.cpp
T
2016-01-10 18:13:01 -08:00

25913 lines
715 KiB
C++

/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "Vlpp.h"
/***********************************************************************
BASIC.CPP
***********************************************************************/
#if defined VCZH_MSVC
#include <Windows.h>
#elif defined VCZH_GCC
#include <time.h>
#include <sys/time.h>
#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 <iostream>
#include <string>
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<<s<<ends;
#endif
}
void Console::Write(const wchar_t* string)
{
Write(string, wcslen(string));
}
void Console::Write(const WString& string)
{
Write(string.Buffer(), string.Length());
}
void Console::WriteLine(const WString& string)
{
Write(string);
Write(L"\r\n");
}
WString Console::Read()
{
#if defined VCZH_MSVC
WString result;
DWORD count;
for(;;)
{
wchar_t buffer;
ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&buffer,1,&count,0);
if(buffer==L'\r')
{
ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&buffer,1,&count,0);
break;
}
else if(buffer==L'\n')
{
break;
}
else
{
result=result+buffer;
}
}
return result;
#elif defined VCZH_GCC
wstring s;
getline(wcin, s, L'\n');
return s.c_str();
#endif
}
void Console::SetColor(bool red, bool green, bool blue, bool light)
{
#if defined VCZH_MSVC
WORD attribute=0;
if(red)attribute |=FOREGROUND_RED;
if(green)attribute |=FOREGROUND_GREEN;
if(blue)attribute |=FOREGROUND_BLUE;
if(light)attribute |=FOREGROUND_INTENSITY;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),attribute);
SetConsoleTextAttribute(GetStdHandle(STD_INPUT_HANDLE),attribute);
#elif defined VCZH_GCC
//vint color = (blue?1:0)*4 + (green?1:0)*2 + (red?1:0);
//if(light)
// wprintf(L"\e[3%dm;", (int)color);
//else
// wprintf(L"\e[9%dm;", (int)color);
#endif
}
void Console::SetTitle(const WString& string)
{
#if defined VCZH_MSVC
SetConsoleTitle(string.Buffer());
#endif
}
}
}
/***********************************************************************
EXCEPTION.CPP
***********************************************************************/
namespace vl
{
/***********************************************************************
Exception
***********************************************************************/
Exception::Exception(const WString& _message)
:message(_message)
{
}
const WString& Exception::Message()const
{
return message;
}
/***********************************************************************
ArgumentException
***********************************************************************/
ArgumentException::ArgumentException(const WString& _message, const WString& _function, const WString& _name)
:Exception(_message)
,function(_function)
,name(_name)
{
}
const WString& ArgumentException::GetFunction()const
{
return function;
}
const WString& ArgumentException::GetName()const
{
return name;
}
/***********************************************************************
ParsingException
***********************************************************************/
ParsingException::ParsingException(const WString& _message, const WString& _expression, vint _position)
:Exception(_message)
,expression(_expression)
,position(_position)
{
}
const WString& ParsingException::GetExpression()const
{
return expression;
}
vint ParsingException::GetPosition()const
{
return position;
}
}
/***********************************************************************
FILESYSTEM.CPP
***********************************************************************/
#if defined VCZH_MSVC
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#elif defined VCZH_GCC
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#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<wchar_t> 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 };
auto result = GetCurrentDirectory(sizeof(buffer) / sizeof(*buffer), buffer);
if (result > MAX_PATH + 1 || result == 0)
{
throw ArgumentException(L"Failed to call GetCurrentDirectory.", L"vl::filesystem::FilePath::Initialize", L"");
}
fullPath = WString(buffer) + L"\\" + fullPath;
}
{
wchar_t buffer[MAX_PATH + 1] = { 0 };
if (fullPath.Length() == 2 && fullPath[1] == L':')
{
fullPath += L"\\";
}
auto result = GetFullPathName(fullPath.Buffer(), sizeof(buffer) / sizeof(*buffer), buffer, NULL);
if (result > MAX_PATH + 1 || result == 0)
{
throw ArgumentException(L"The path is illegal.", L"vl::filesystem::FilePath::FilePath", L"_filePath");
}
fullPath = buffer;
}
#elif defined VCZH_GCC
if (fullPath.Length() == 0)
fullPath = L"/";
if (fullPath[0] != Delimiter)
{
char buffer[PATH_MAX] = { 0 };
getcwd(buffer, PATH_MAX);
fullPath = atow(AString(buffer)) + Delimiter + fullPath;
}
{
collections::List<WString> components;
GetPathComponents(fullPath, components);
for(int i = 0; i < components.Count(); i++)
{
if(components[i] == L".")
{
components.RemoveAt(i);
i--;
}
else if(components[i] == L"..")
{
if(i > 0)
{
components.RemoveAt(i);
components.RemoveAt(i - 1);
i -= 2;
}
else
{
throw ArgumentException(L"Illegal path.");
}
}
}
fullPath = ComponentsToPath(components);
}
#endif
if (fullPath != L"/" && fullPath[fullPath.Length() - 1] == Delimiter)
{
fullPath = fullPath.Left(fullPath.Length() - 1);
}
}
FilePath::FilePath()
{
}
FilePath::FilePath(const WString& _filePath)
:fullPath(_filePath)
{
Initialize();
}
FilePath::FilePath(const wchar_t* _filePath)
:fullPath(_filePath)
{
Initialize();
}
FilePath::FilePath(const FilePath& _filePath)
:fullPath(_filePath.fullPath)
{
Initialize();
}
FilePath::~FilePath()
{
}
vint FilePath::Compare(const FilePath& a, const FilePath& b)
{
return WString::Compare(a.fullPath, b.fullPath);
}
FilePath FilePath::operator/(const WString& relativePath)const
{
if (IsRoot())
{
return relativePath;
}
else
{
return fullPath + L"/" + relativePath;
}
}
bool FilePath::IsFile()const
{
#if defined VCZH_MSVC
WIN32_FILE_ATTRIBUTE_DATA info;
BOOL result = GetFileAttributesEx(fullPath.Buffer(), GetFileExInfoStandard, &info);
if (!result) return false;
return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
#elif defined VCZH_GCC
struct stat info;
AString path = wtoa(fullPath);
int result = stat(path.Buffer(), &info);
if(result != 0) return false;
else return S_ISREG(info.st_mode);
#endif
}
bool FilePath::IsFolder()const
{
#if defined VCZH_MSVC
WIN32_FILE_ATTRIBUTE_DATA info;
BOOL result = GetFileAttributesEx(fullPath.Buffer(), GetFileExInfoStandard, &info);
if (!result) return false;
return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
#elif defined VCZH_GCC
struct stat info;
AString path = wtoa(fullPath);
int result = stat(path.Buffer(), &info);
if(result != 0) return false;
else return S_ISDIR(info.st_mode);
#endif
}
bool FilePath::IsRoot()const
{
#if defined VCZH_MSVC
return fullPath == L"";
#elif defined VCZH_GCC
return fullPath == L"/";
#endif
}
WString FilePath::GetName()const
{
WString delimiter = Delimiter;
auto index = INVLOC.FindLast(fullPath, delimiter, Locale::None);
if (index.key == -1) return fullPath;
return fullPath.Right(fullPath.Length() - index.key - 1);
}
FilePath FilePath::GetFolder()const
{
WString delimiter = Delimiter;
auto index = INVLOC.FindLast(fullPath, delimiter, Locale::None);
if (index.key == -1) return FilePath();
return fullPath.Left(index.key);
}
WString FilePath::GetFullPath()const
{
return fullPath;
}
WString FilePath::GetRelativePathFor(const FilePath& _filePath)
{
if (fullPath.Length()==0 || _filePath.fullPath.Length()==0 || fullPath[0] != _filePath.fullPath[0])
{
return _filePath.fullPath;
}
#if defined VCZH_MSVC
wchar_t buffer[MAX_PATH + 1] = { 0 };
PathRelativePathTo(
buffer,
fullPath.Buffer(),
(IsFolder() ? FILE_ATTRIBUTE_DIRECTORY : 0),
_filePath.fullPath.Buffer(),
(_filePath.IsFolder() ? FILE_ATTRIBUTE_DIRECTORY : 0)
);
return buffer;
#elif defined VCZH_GCC
collections::List<WString> srcComponents, tgtComponents, resultComponents;
GetPathComponents(IsFolder() ? fullPath : GetFolder().GetFullPath(), srcComponents);
GetPathComponents(_filePath.fullPath, tgtComponents);
int minLength = srcComponents.Count() <= tgtComponents.Count() ? srcComponents.Count() : tgtComponents.Count();
int lastCommonComponent = 0;
for(int i = 0; i < minLength; i++)
{
if(srcComponents[i] == tgtComponents[i])
{
lastCommonComponent = i;
}
else
break;
}
for(int i = lastCommonComponent + 1; i < srcComponents.Count(); i++)
{
resultComponents.Add(L"..");
}
for(int i = lastCommonComponent + 1; i < tgtComponents.Count(); i++)
{
resultComponents.Add(tgtComponents[i]);
}
return ComponentsToPath(resultComponents);
#endif
}
void FilePath::GetPathComponents(WString path, collections::List<WString>& components)
{
WString pathRemaining = path;
WString delimiter = Delimiter;
components.Clear();
while(true)
{
auto index = INVLOC.FindFirst(pathRemaining, delimiter, Locale::None);
if (index.key == -1)
break;
if(index.key != 0)
components.Add(pathRemaining.Left(index.key));
else
{
#if defined VCZH_GCC
// Unix absolute path starting with "/"
// components[0] will be L"/"
components.Add(delimiter);
#elif defined VCZH_MSVC
if(pathRemaining.Length() >= 2 && pathRemaining[1] == Delimiter)
{
// Windows UNC Path starting with "\\"
// components[0] will be L"\\"
components.Add(L"\\");
index.value++;
}
#endif
}
pathRemaining = pathRemaining.Right(pathRemaining.Length() - (index.key + index.value));
}
if(pathRemaining.Length() != 0)
{
components.Add(pathRemaining);
}
}
WString FilePath::ComponentsToPath(const collections::List<WString>& components)
{
WString result;
WString delimiter = Delimiter;
int i = 0;
#if defined VCZH_GCC
// For Unix-like OSes, if first component is "/" then take it as absolute path
if(components.Count() > 0 && components[0] == delimiter)
{
result += delimiter;
i++;
}
#elif defined VCZH_MSVC
// For Windows, if first component is "\\" then it is an UNC path
if(components.Count() > 0 && components[0] == L"\\")
{
result += delimiter;
i++;
}
#endif
for(; i < components.Count(); i++)
{
result += components[i];
if(i + 1 < components.Count())
result += delimiter;
}
return result;
}
/***********************************************************************
File
***********************************************************************/
File::File()
{
}
File::File(const FilePath& _filePath)
:filePath(_filePath)
{
}
File::~File()
{
}
const FilePath& File::GetFilePath()const
{
return filePath;
}
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<WString>& 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<WString>& lines, bool bom, stream::BomEncoder::Encoding encoding)
{
FileStream fileStream(filePath.GetFullPath(), FileStream::WriteOnly);
if (!fileStream.IsAvailable()) return false;
IEncoder* encoder = nullptr;
if (bom)
{
encoder = new BomEncoder(encoding);
}
else switch (encoding)
{
case BomEncoder::Utf8:
encoder = new Utf8Encoder;
break;
case BomEncoder::Utf16:
encoder = new Utf16Encoder;
break;
case BomEncoder::Utf16BE:
encoder = new Utf16BEEncoder;
break;
default:
encoder = new MbcsEncoder;
break;
}
{
EncoderStream encoderStream(fileStream, *encoder);
StreamWriter writer(encoderStream);
FOREACH(WString, line, lines)
{
writer.WriteLine(line);
}
}
delete encoder;
return true;
}
bool File::Exists()const
{
return filePath.IsFile();
}
bool File::Delete()const
{
#if defined VCZH_MSVC
return DeleteFile(filePath.GetFullPath().Buffer()) != 0;
#elif defined VCZH_GCC
AString path = wtoa(filePath.GetFullPath());
return unlink(path.Buffer()) == 0;
#endif
}
bool File::Rename(const WString& newName)const
{
#if defined VCZH_MSVC
WString oldFileName = filePath.GetFullPath();
WString newFileName = (filePath.GetFolder() / newName).GetFullPath();
return MoveFile(oldFileName.Buffer(), newFileName.Buffer()) != 0;
#elif defined VCZH_GCC
AString oldFileName = wtoa(filePath.GetFullPath());
AString newFileName = wtoa((filePath.GetFolder() / newName).GetFullPath());
return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0;
#endif
}
/***********************************************************************
Folder
***********************************************************************/
Folder::Folder()
{
}
Folder::Folder(const FilePath& _filePath)
:filePath(_filePath)
{
}
Folder::~Folder()
{
}
const FilePath& Folder::GetFilePath()const
{
return filePath;
}
bool Folder::GetFolders(collections::List<Folder>& 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
if (!Exists()) return false;
DIR *dir;
AString searchPath = wtoa(filePath.GetFullPath());
if ((dir = opendir(searchPath.Buffer())) == NULL)
{
return false;
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL)
{
WString childName = atow(AString(entry->d_name));
FilePath childFullPath = filePath / childName;
if (childName != L"." && childName != L".." && childFullPath.IsFolder())
{
folders.Add(Folder(childFullPath));
}
}
if (closedir(dir) != 0)
{
return false;
}
return true;
#endif
}
bool Folder::GetFiles(collections::List<File>& 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
if (!Exists()) return false;
DIR *dir;
AString searchPath = wtoa(filePath.GetFullPath());
if ((dir = opendir(searchPath.Buffer())) == NULL)
{
return false;
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL)
{
FilePath childFullPath = filePath / (atow(AString(entry->d_name)));
if (childFullPath.IsFile())
{
files.Add(File(childFullPath));
}
}
if (closedir(dir) != 0)
{
return false;
}
return true;
#endif
}
bool Folder::Exists()const
{
return filePath.IsFolder();
}
bool Folder::Create(bool recursively)const
{
if (recursively)
{
auto folder = filePath.GetFolder();
if (folder.IsFile()) return false;
if (folder.IsFolder()) return Create(false);
return Folder(folder).Create(true) && Create(false);
}
else
{
#if defined VCZH_MSVC
return CreateDirectory(filePath.GetFullPath().Buffer(), NULL) != 0;
#elif defined VCZH_GCC
AString path = wtoa(filePath.GetFullPath());
return mkdir(path.Buffer(), 0777) == 0;
#endif
}
}
bool Folder::Delete(bool recursively)const
{
if (!Exists()) return false;
if (recursively)
{
List<Folder> folders;
GetFolders(folders);
FOREACH(Folder, folder, folders)
{
if (!folder.Delete(true)) return false;
}
List<File> files;
GetFiles(files);
FOREACH(File, file, files)
{
if (!file.Delete()) return false;
}
return Delete(false);
}
#if defined VCZH_MSVC
return RemoveDirectory(filePath.GetFullPath().Buffer()) != 0;
#elif defined VCZH_GCC
AString path = wtoa(filePath.GetFullPath());
return rmdir(path.Buffer()) == 0;
#endif
}
bool Folder::Rename(const WString& newName)const
{
#if defined VCZH_MSVC
WString oldFileName = filePath.GetFullPath();
WString newFileName = (filePath.GetFolder() / newName).GetFullPath();
return MoveFile(oldFileName.Buffer(), newFileName.Buffer()) != 0;
#elif defined VCZH_GCC
AString oldFileName = wtoa(filePath.GetFullPath());
AString newFileName = wtoa((filePath.GetFolder() / newName).GetFullPath());
return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0;
#endif
}
}
}
/***********************************************************************
GLOBALSTORAGE.CPP
***********************************************************************/
namespace vl
{
using namespace collections;
class GlobalStorageManager
{
public:
Ptr<Dictionary<WString, GlobalStorage*>> 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<WString, GlobalStorage*>;
}
}
void FinalizeGlobalStorage()
{
if(GetGlobalStorageManager().storages)
{
for(vint i=0;i<GetGlobalStorageManager().storages->Count();i++)
{
GetGlobalStorageManager().storages->Values().Get(i)->ClearResource();
}
GetGlobalStorageManager().storages=0;
}
}
}
/***********************************************************************
HTTPUTILITY.CPP
***********************************************************************/
#ifdef VCZH_MSVC
#include <winhttp.h>
#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<LPCWSTR> acceptTypes;
List<BufferPair> 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;i<request.acceptTypes.Count();i++)
{
acceptTypes.Add(request.acceptTypes.Get(i).Buffer());
}
acceptTypes.Add(0);
requestInternet=WinHttpOpenRequest(connectedInternet, request.method.Buffer(), request.query.Buffer(), NULL, WINHTTP_NO_REFERER, &acceptTypes[0], (request.secure?WINHTTP_FLAG_SECURE:0));
error=GetLastError();
if(!requestInternet) goto CLEANUP;
// authentication, cookie and request
if(request.username!=L"" && request.password!=L"")
{
WinHttpSetCredentials(requestInternet, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_BASIC, request.username.Buffer(), request.password.Buffer(), NULL);
}
if(request.contentType!=L"")
{
httpResult=WinHttpAddRequestHeaders(requestInternet, (L"Content-type:"+request.contentType).Buffer(), -1, WINHTTP_ADDREQ_FLAG_REPLACE|WINHTTP_ADDREQ_FLAG_ADD);
}
if(request.cookie!=L"")
{
WinHttpAddRequestHeaders(requestInternet, (L"Cookie:"+request.cookie).Buffer(), -1, WINHTTP_ADDREQ_FLAG_REPLACE|WINHTTP_ADDREQ_FLAG_ADD);
}
// extra headers
for(int i=0;i<request.extraHeaders.Count();i++)
{
WString key=request.extraHeaders.Keys()[i];
WString value=request.extraHeaders.Values().Get(i);
WinHttpAddRequestHeaders(requestInternet, (key+L":"+value).Buffer(), -1, WINHTTP_ADDREQ_FLAG_REPLACE|WINHTTP_ADDREQ_FLAG_ADD);
}
if(request.body.Count()>0)
{
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<utf8Size;i++)
{
unsigned char x=(unsigned char)utf8[i];
if(L'a'<=x && x<='z' || L'A'<=x && x<=L'Z' || L'0'<=x && x<=L'9')
{
writing[0]=x;
writing+=1;
}
else
{
writing[0]=L'%';
writing[1]=L"0123456789ABCDEF"[x/16];
writing[2]=L"0123456789ABCDEF"[x%16];
writing+=3;
}
}
WString result=encoded;
delete[] encoded;
delete[] utf8;
return result;
}
}
#endif
/***********************************************************************
LOCALE.CPP
***********************************************************************/
#if defined VCZH_MSVC
#elif defined VCZH_GCC
#include <ctype.h>
#include <wctype.h>
#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<Locale>*)lParam)->Add(Locale(lpLocaleString));
return TRUE;
}
BOOL CALLBACK Locale_EnumDateFormatsProcExEx(
_In_ LPWSTR lpDateFormatString,
_In_ CALID CalendarID,
_In_ LPARAM lParam
)
{
((List<WString>*)lParam)->Add(lpDateFormatString);
return TRUE;
}
BOOL CALLBACK EnumTimeFormatsProcEx(
_In_ LPWSTR lpTimeFormatString,
_In_ LPARAM lParam
)
{
((List<WString>*)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<wchar_t> 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<Locale>& 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<WString>& 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<WString>& 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<WString>& 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<WString>& 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<WString>& 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<wchar_t> 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<wchar_t> 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<wchar_t> 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<wchar_t> 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<vint, vint> 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<vint, vint>(-1, 0):Pair<vint, vint>(result, length);
#elif defined VCZH_GCC
if(text.Length() < find.Length() || find.Length() == 0)
{
return Pair<vint, vint>(-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<vint, vint>(-1, 0) : Pair<vint, vint>(result - text.Buffer(), find.Length());
#endif
}
collections::Pair<vint, vint> 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<vint, vint>(-1, 0):Pair<vint, vint>(result, length);
#elif defined VCZH_GCC
if(text.Length() < find.Length() || find.Length() == 0)
{
return Pair<vint, vint>(-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<vint, vint>(-1, 0) : Pair<vint, vint>(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<HANDLE> handles(count);
for(vint i=0;i<count;i++)
{
handles[i]=objects[i]->waitableData->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<HANDLE> handles(count);
for(vint i=0;i<count;i++)
{
handles[i]=objects[i]->waitableData->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<HANDLE> handles(count);
for(vint i=0;i<count;i++)
{
handles[i]=objects[i]->waitableData->handle;
}
DWORD result=WaitForMultipleObjects((DWORD)count, &handles[0], FALSE, INFINITE);
if(WAIT_OBJECT_0 <= result && result<WAIT_OBJECT_0+count)
{
*abandoned=false;
return result-WAIT_OBJECT_0;
}
else if(WAIT_ABANDONED_0 <= result && result<WAIT_ABANDONED_0+count)
{
*abandoned=true;
return result-WAIT_ABANDONED_0;
}
else
{
return -1;
}
}
vint WaitableObject::WaitAnyForTime(WaitableObject** objects, vint count, vint ms, bool* abandoned)
{
Array<HANDLE> handles(count);
for(vint i=0;i<count;i++)
{
handles[i]=objects[i]->waitableData->handle;
}
DWORD result=WaitForMultipleObjects((DWORD)count, &handles[0], FALSE, (DWORD)ms);
if(WAIT_OBJECT_0 <= result && result<WAIT_OBJECT_0+count)
{
*abandoned=false;
return result-WAIT_OBJECT_0;
}
else if(WAIT_ABANDONED_0 <= result && result<WAIT_ABANDONED_0+count)
{
*abandoned=true;
return result-WAIT_ABANDONED_0;
}
else
{
return -1;
}
}
/***********************************************************************
Thread
***********************************************************************/
namespace threading_internal
{
struct ThreadData : public WaitableData
{
DWORD id;
ThreadData()
:WaitableData(NULL)
{
id=-1;
}
};
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;
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<void()> 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<void()>& _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<void()>& 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<<index));
}
/***********************************************************************
Mutex
***********************************************************************/
namespace threading_internal
{
struct MutexData : public WaitableData
{
MutexData(HANDLE _handle)
:WaitableData(_handle)
{
}
};
}
Mutex::Mutex()
:internalData(0)
{
}
Mutex::~Mutex()
{
if(internalData)
{
CloseHandle(internalData->handle);
delete internalData;
}
}
bool Mutex::Create(bool owned, const WString& name)
{
if(IsCreated())return false;
BOOL aOwned=owned?TRUE:FALSE;
LPCTSTR aName=name==L""?NULL:name.Buffer();
HANDLE handle=CreateMutex(NULL, aOwned, aName);
if(handle)
{
internalData=new MutexData(handle);
SetData(internalData);
}
return IsCreated();
}
bool Mutex::Open(bool inheritable, const WString& name)
{
if(IsCreated())return false;
BOOL aInteritable=inheritable?TRUE:FALSE;
HANDLE handle=OpenMutex(SYNCHRONIZE, aInteritable, name.Buffer());
if(handle)
{
internalData=new MutexData(handle);
SetData(internalData);
}
return IsCreated();
}
bool Mutex::Release()
{
if(IsCreated())
{
return ReleaseMutex(internalData->handle)!=0;
}
return false;
}
/***********************************************************************
Semaphore
***********************************************************************/
namespace threading_internal
{
struct SemaphoreData : public WaitableData
{
SemaphoreData(HANDLE _handle)
:WaitableData(_handle)
{
}
};
}
Semaphore::Semaphore()
:internalData(0)
{
}
Semaphore::~Semaphore()
{
if(internalData)
{
CloseHandle(internalData->handle);
delete internalData;
}
}
bool Semaphore::Create(vint initialCount, vint maxCount, const WString& name)
{
if(IsCreated())return false;
LONG aInitial=(LONG)initialCount;
LONG aMax=(LONG)maxCount;
LPCTSTR aName=name==L""?NULL:name.Buffer();
HANDLE handle=CreateSemaphore(NULL, aInitial, aMax, aName);
if(handle)
{
internalData=new SemaphoreData(handle);
SetData(internalData);
}
return IsCreated();
}
bool Semaphore::Open(bool inheritable, const WString& name)
{
if(IsCreated())return false;
BOOL aInteritable=inheritable?TRUE:FALSE;
HANDLE handle=OpenSemaphore(SYNCHRONIZE, aInteritable, name.Buffer());
if(handle)
{
internalData=new SemaphoreData(handle);
SetData(internalData);
}
return IsCreated();
}
bool Semaphore::Release()
{
if(IsCreated())
{
return Release(1)!=-1;
}
return false;
}
vint Semaphore::Release(vint count)
{
if(IsCreated())
{
LONG previous=-1;
if(ReleaseSemaphore(internalData->handle, (LONG)count, &previous)!=0)
{
return (vint)previous;
}
}
return -1;
}
/***********************************************************************
EventObject
***********************************************************************/
namespace threading_internal
{
struct EventData : public WaitableData
{
EventData(HANDLE _handle)
:WaitableData(_handle)
{
}
};
}
EventObject::EventObject()
:internalData(0)
{
}
EventObject::~EventObject()
{
if(internalData)
{
CloseHandle(internalData->handle);
delete internalData;
}
}
bool EventObject::CreateAutoUnsignal(bool signaled, const WString& name)
{
if(IsCreated())return false;
BOOL aSignaled=signaled?TRUE:FALSE;
LPCTSTR aName=name==L""?NULL:name.Buffer();
HANDLE handle=CreateEvent(NULL, FALSE, aSignaled, aName);
if(handle)
{
internalData=new EventData(handle);
SetData(internalData);
}
return IsCreated();
}
bool EventObject::CreateManualUnsignal(bool signaled, const WString& name)
{
if(IsCreated())return false;
BOOL aSignaled=signaled?TRUE:FALSE;
LPCTSTR aName=name==L""?NULL:name.Buffer();
HANDLE handle=CreateEvent(NULL, TRUE, aSignaled, aName);
if(handle)
{
internalData=new EventData(handle);
SetData(internalData);
}
return IsCreated();
}
bool EventObject::Open(bool inheritable, const WString& name)
{
if(IsCreated())return false;
BOOL aInteritable=inheritable?TRUE:FALSE;
HANDLE handle=OpenEvent(SYNCHRONIZE, aInteritable, name.Buffer());
if(handle)
{
internalData=new EventData(handle);
SetData(internalData);
}
return IsCreated();
}
bool EventObject::Signal()
{
if(IsCreated())
{
return SetEvent(internalData->handle)!=0;
}
return false;
}
bool EventObject::Unsignal()
{
if(IsCreated())
{
return ResetEvent(internalData->handle)!=0;
}
return false;
}
/***********************************************************************
ThreadPoolLite
***********************************************************************/
struct ThreadPoolQueueProcArgument
{
void(*proc)(void*);
void* argument;
};
DWORD WINAPI ThreadPoolQueueProc(void* argument)
{
Ptr<ThreadPoolQueueProcArgument> proc=(ThreadPoolQueueProcArgument*)argument;
ThreadLocalStorage::FixStorages();
try
{
proc->proc(proc->argument);
ThreadLocalStorage::ClearStorages();
}
catch (...)
{
ThreadLocalStorage::ClearStorages();
}
return 0;
}
DWORD WINAPI ThreadPoolQueueFunc(void* argument)
{
Ptr<Func<void()>> proc=(Func<void()>*)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<void()>& proc)
{
Func<void()>* p=new Func<void()>(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 <pthread.h>
#include <fcntl.h>
#include <semaphore.h>
#include <errno.h>
#if defined(__APPLE__) || defined(__APPLE_CC__)
#include <CoreFoundation/CoreFoundation.h>
#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<void()> 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<void()>& _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<void()>& 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<void()> task;
Ptr<ThreadPoolTask> next;
};
struct ThreadPoolData
{
Semaphore semaphore;
EventObject taskFinishEvent;
Ptr<ThreadPoolTask> taskBegin;
Ptr<ThreadPoolTask>* taskEnd = nullptr;
volatile bool stopping = false;
List<Thread*> taskThreads;
};
SpinLock threadPoolLock;
ThreadPoolData* threadPoolData = nullptr;
void ThreadPoolProc(Thread* thread, void* argument)
{
while (true)
{
Ptr<ThreadPoolTask> 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<void()>& 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<ThreadPoolTask>();
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<void()>& 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<ParsingTable> _table)
:table(_table)
{
}
ParsingGeneralParser::~ParsingGeneralParser()
{
}
Ptr<ParsingTable> ParsingGeneralParser::GetTable()
{
return table;
}
void ParsingGeneralParser::BeginParse()
{
}
bool ParsingGeneralParser::Parse(ParsingState& state, ParsingTransitionProcessor& processor, collections::List<Ptr<ParsingError>>& errors)
{
BeginParse();
processor.Reset();
for(vint i=0;i<state.GetTokens().Count();i++)
{
const RegexToken* token=&state.GetTokens().Get(i);
if(token->token==-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<ParsingTreeNode> ParsingGeneralParser::Parse(ParsingState& state, collections::List<Ptr<ParsingError>>& errors)
{
ParsingTreeBuilder builder;
Parse(state, builder, errors);
Ptr<ParsingTreeNode> 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<ParsingTreeNode> ParsingGeneralParser::Parse(const WString& input, const WString& rule, collections::List<Ptr<ParsingError>>& 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<Ptr<ParsingError>>& 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<ParsingTable> _table)
:ParsingGeneralParser(_table)
{
}
ParsingStrictParser::~ParsingStrictParser()
{
}
ParsingState::TransitionResult ParsingStrictParser::ParseStep(ParsingState& state, collections::List<Ptr<ParsingError>>& 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<Ptr<ParsingError>>& errors)
{
if(recoveringFutureIndex==-1)
{
List<vint> prioritizedTokens;
prioritizedTokens.Add(ParsingTable::TokenFinish);
CopyFrom(
prioritizedTokens,
Range<vint>(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(processingFutureIndex<usedFutureCount)
{
RecoverFuture previous;
if(processingFutureIndex!=-1)
{
previous = GetRecoverFuture(processingFutureIndex);
}
processingFutureIndex++;
if(previous.future && previous.future->currentState==-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<ParsingTable> _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<ParsingTable> _table)
:ParsingGeneralParser(_table)
,consumedDecisionCount(0)
{
}
ParsingAmbiguousParser::~ParsingAmbiguousParser()
{
}
void ParsingAmbiguousParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& errors)
{
begin=end;
}
vint ParsingAmbiguousParser::GetResolvableFutureLevels(collections::List<ParsingState::Future*>& futures, vint begin, vint end)
{
if(end-begin<2)
{
return 1;
}
List<ParsingState::Future*> resolvingFutures;
for(vint i=begin;i<end;i++)
{
resolvingFutures.Add(futures[i]);
}
vint level=0;
while(true)
{
for(vint i=0;i<resolvingFutures.Count()-1;i++)
{
ParsingState::Future* first=resolvingFutures[i];
ParsingState::Future* second=resolvingFutures[i+1];
if(first->currentState!=second->currentState
|| first->reduceStateCount!=second->reduceStateCount
|| first->shiftStates.Count()!=second->shiftStates.Count()
)
{
return level;
}
else
{
for(vint j=0;j<first->shiftStates.Count();j++)
{
if(first->shiftStates[j]!=second->shiftStates[j])
{
return level;
}
}
}
}
level++;
for(vint i=0;i<resolvingFutures.Count();i++)
{
if(!(resolvingFutures[i]=resolvingFutures[i]->previous))
{
return level;
}
}
}
}
vint ParsingAmbiguousParser::SearchPathForOneStep(ParsingState& state, collections::List<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& 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<ParsingState::Future*> 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<ParsingState::Future*>& futures)
{
vint conflictReduceCount=-1;
for(vint i=0;i<futures.Count()-1;i++)
{
vint count=0;
ParsingState::Future* first=futures[i];
ParsingState::Future* second=futures[i+1];
vint firstIndex=first->selectedItem->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<ParsingState::Future*>& futures, vint conflictReduceCount, collections::Array<vint>& conflictReduceIndices)
{
conflictReduceIndices.Resize(futures.Count());
for(vint i=0;i<futures.Count();i++)
{
ParsingState::Future* future=futures[i];
vint index=future->selectedItem->instructions.Count();
vint count=0;
while(count<conflictReduceCount && index>0)
{
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<ParsingState::Future*>& futures, collections::Array<vint>& conflictReduceIndices)
{
vint affectedStackNodeCount=-1;
for(vint i=0;i<futures.Count();i++)
{
ParsingState::Future* future=futures[i];
vint count=1;
while(future && future->selectedItem)
{
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<Pair<ParsingTable::TransitionItem*, regex::RegexToken*>> path;
while(future && future->selectedToken!=-1)
{
path.Add(Pair<ParsingTable::TransitionItem*, regex::RegexToken*>(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<ParsingState::Future*>& futures, vint begin, vint end, vint resolvableFutureLevels, collections::List<Ptr<ParsingError>>& errors)
{
List<ParsingState::Future*> resolvingFutures;
CopyFrom(
resolvingFutures,
From(futures)
.Skip(begin)
.Take(end - begin)
);
for (vint i = 1; i < resolvableFutureLevels; i++)
{
for(vint j=0;j<resolvingFutures.Count();j++)
{
resolvingFutures[j] = resolvingFutures[j]->previous;
}
}
Array<vint> 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<ParsingState::StateGroup> stateGroup;
for(vint i=0;i<resolvingFutures.Count();i++)
{
if(stateGroup)
{
state.RestoreSnapshot(stateGroup);
}
else
{
stateGroup=state.TakeSnapshot();
}
{
ParsingState::TransitionResult result(
i==0
?ParsingState::TransitionResult::AmbiguityBegin
:ParsingState::TransitionResult::AmbiguityBranch
);
if(i==0)
{
result.ambiguityAffectedStackNodeCount=affectedStackNodeCount;
}
decisions.Add(result);
}
{
BuildSingleDecisionPath(state, resolvingFutures[i], conflictReduceIndices[i]);
if(i==resolvingFutures.Count()-1)
{
ParsingState::TransitionResult result(ParsingState::TransitionResult::AmbiguityEnd);
result.ambiguityNodeType=ambiguityNodeType;
decisions.Add(result);
vint start=conflictReduceIndices[i];
ParsingState::TransitionResult lastDecision=decisions[decisions.Count()-2];
decisions.Add(state.RunTransition(lastDecision.transition, lastDecision.token, start, lastDecision.transition->instructions.Count()-start, true));
}
}
}
ParsingState::Future* lastFuture=futures[end-1];
ParsingState::Future** futureCleaner=&lastFuture;
for(int i=1;i<resolvableFutureLevels;i++)
{
futureCleaner=&(*futureCleaner)->previous;
}
*futureCleaner=0;
if(lastFuture)
{
BuildSingleDecisionPath(state, lastFuture, -1);
}
}
void ParsingAmbiguousParser::BuildDecisions(ParsingState& state, collections::List<ParsingState::Future*>& futures, vint begin, vint end, vint resolvableFutureLevels, collections::List<Ptr<ParsingError>>& 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<Ptr<ParsingError>>& errors)
{
if(decisions.Count()==consumedDecisionCount)
{
List<ParsingState::Future*> 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<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& errors)
{
vint insertedTokenCount = 0;
while (insertedTokenCount++ < maxInsertedTokenCount)
{
// keep all futures that consumed a token in a list
List<ParsingState::Future*> 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<ParsingState::Future*> 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<ParsingTable> _table, vint _maxInsertedTokenCount)
:ParsingAmbiguousParser(_table)
, maxInsertedTokenCount(_maxInsertedTokenCount == -1 ? 4 : _maxInsertedTokenCount)
{
}
ParsingAutoRecoverAmbiguousParser::~ParsingAutoRecoverAmbiguousParser()
{
}
/***********************************************************************
Helper Functions
***********************************************************************/
Ptr<ParsingGeneralParser> CreateStrictParser(Ptr<ParsingTable> table)
{
if(table)
{
if(table->GetAmbiguity())
{
return new ParsingAmbiguousParser(table);
}
else
{
return new ParsingStrictParser(table);
}
}
else
{
return 0;
}
}
Ptr<ParsingGeneralParser> CreateAutoRecoverParser(Ptr<ParsingTable> table)
{
if(table)
{
if(table->GetAmbiguity())
{
return new ParsingAutoRecoverAmbiguousParser(table);
}
else
{
return new ParsingAutoRecoverParser(table);
}
}
else
{
return 0;
}
}
Ptr<ParsingGeneralParser> CreateBootstrapStrictParser()
{
List<Ptr<ParsingError>> errors;
Ptr<ParsingDefinition> definition=CreateParserDefinition();
Ptr<ParsingTable> table=GenerateTable(definition, false, errors);
return CreateStrictParser(table);
}
Ptr<ParsingGeneralParser> CreateBootstrapAutoRecoverParser()
{
List<Ptr<ParsingError>> errors;
Ptr<ParsingDefinition> definition=CreateParserDefinition();
Ptr<ParsingTable> 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<ParsingTreeToken>(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<ParsingTreeObject>(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<ParsingTreeObject>(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<ParsingError>(), NO_PARAMETER)
CLASS_MEMBER_CONSTRUCTOR(Ptr<ParsingError>(const WString&), {L"errorMessage"})
CLASS_MEMBER_CONSTRUCTOR(Ptr<ParsingError>(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<ITypeLoader> 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 && index<subSymbolList.Count())
{
return subSymbolList[index];
}
else
{
return 0;
}
}
ParsingSymbol* ParsingSymbol::GetSubSymbolByName(const WString& name)
{
vint index=subSymbolMap.Keys().IndexOf(name);
if(index==-1)
{
return 0;
}
else
{
return subSymbolMap.Values().Get(index);
}
}
ParsingSymbol* ParsingSymbol::GetDescriptorSymbol()
{
return descriptorSymbol;
}
WString ParsingSymbol::GetDescriptorString()
{
return descriptorString;
}
ParsingSymbol* ParsingSymbol::GetParentSymbol()
{
return parentSymbol;
}
bool ParsingSymbol::IsType()
{
switch(type)
{
case ParsingSymbol::ClassType:
case ParsingSymbol::EnumType:
case ParsingSymbol::ArrayType:
case ParsingSymbol::TokenType:
return true;
default:
return false;
}
}
ParsingSymbol* ParsingSymbol::SearchClassSubSymbol(const WString& name)
{
if(type==ParsingSymbol::ClassType)
{
ParsingSymbol* scope=this;
while(scope)
{
ParsingSymbol* subSymbol=scope->GetSubSymbolByName(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=aCount<bCount?aCount:bCount;
for(vint i=aCount;i>min;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<ParsingSymbol> 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<Ptr<ParsingError>>& errors;
ParsingSymbol* result;
FindTypeVisitor(ParsingSymbolManager* _manager, ParsingSymbol* _scope, List<Ptr<ParsingError>>& _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<Ptr<ParsingError>>& 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<Ptr<ParsingError>>& errors;
PrepareSymbolsTypeDefinitionVisitor(ParsingSymbolManager* _manager, ParsingSymbol* _scope, List<Ptr<ParsingError>>& _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<ParsingDefinitionTypeDefinition>, subType, node->subTypes)
{
subType->Accept(&visitor);
}
FOREACH(Ptr<ParsingDefinitionClassMemberDefinition>, 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<ParsingDefinitionEnumMemberDefinition>, member, node->members)
{
member->Accept(&visitor);
}
}
else
{
errors.Add(new ParsingError(node, L"An enum type cannot be defined here."));
}
}
}
};
void PrepareSymbols(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
{
{
PrepareSymbolsTypeDefinitionVisitor visitor(manager, manager->GetGlobal(), errors);
FOREACH(Ptr<ParsingDefinitionTypeDefinition>, typeDefinition, definition->types)
{
typeDefinition->Accept(&visitor);
}
}
FOREACH(Ptr<ParsingDefinitionTokenDefinition>, 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<ParsingDefinitionRuleDefinition>, 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<ParsingDefinition> definition;
ParsingSymbolManager* manager;
ParsingDefinitionRuleDefinition* rule;
List<Ptr<ParsingError>>& errors;
vint loopCount;
ValidateRuleStructureVisitor(Ptr<ParsingDefinition> _definition, ParsingSymbolManager* _manager, ParsingDefinitionRuleDefinition* _rule, List<Ptr<ParsingError>>& _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<ParsingDefinitionTokenDefinition>, 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;i<manager->GetGlobal()->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<ParsingDefinitionPrimitiveGrammar>() && !node->grammar.Cast<ParsingDefinitionTextGrammar>())
{
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<ParsingDefinitionPrimitiveGrammar>())
{
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<definitions::ParsingDefinition> definition, Ptr<definitions::ParsingDefinitionRuleDefinition> rule, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
{
FOREACH(Ptr<ParsingDefinitionGrammar>, 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<Ptr<GrammarPathFragment>> fragments;
ParsingSymbol* pathType;
GrammarPath()
:pathType(0)
{
}
WString ToString()
{
WString result;
FOREACH(Ptr<GrammarPathFragment>, fragment, fragments)
{
if(!fragment->epsilon)
{
if(result!=L"") result+=L" ";
result+=GrammarToString(fragment->grammar);
}
}
return result;
}
};
struct GrammarPathContainer
{
List<Ptr<GrammarPath>> paths;
};
class EnumerateGrammarPathVisitor : public Object, public ParsingDefinitionGrammar::IVisitor
{
public:
ParsingSymbolManager* manager;
ParsingDefinitionRuleDefinition* rule;
List<Ptr<GrammarPathFragment>> createdFragments;
List<GrammarPathFragment*> 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;i<currentFragmentEnds.Count();i++)
{
GrammarPathFragment* fragment=new GrammarPathFragment;
fragment->grammar=node;
fragment->epsilon=epsilon;
fragment->createdType=createdType;
createdFragments.Add(fragment);
fragment->previousFragment=currentFragmentEnds[i];
currentFragmentEnds[i]=fragment;
}
}
void BuildPath(List<Ptr<GrammarPath>>& paths)
{
FOREACH(GrammarPathFragment*, fragment, currentFragmentEnds)
{
Ptr<GrammarPath> 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<ParsingDefinitionGrammar*, Ptr<GrammarPathContainer>> GrammarPathMap;
ParsingSymbolManager* manager;
List<Ptr<ParsingError>>& errors;
GrammarPathMap& grammarPaths;
ResolveAssignerGrammarVisitor(ParsingSymbolManager* _manager, List<Ptr<ParsingError>>& _errors, GrammarPathMap& _grammarPaths)
:manager(_manager)
,errors(_errors)
,grammarPaths(_grammarPaths)
{
}
ParsingSymbol* GetFieldFromCombined(ParsingDefinitionGrammar* node, const WString& fieldName)
{
Ptr<GrammarPathContainer> paths=grammarPaths[node];
ParsingSymbol* pathType=paths->paths[0]->pathType;
for(vint i=1;i<paths->paths.Count();i++)
{
pathType=pathType->SearchCommonBaseClass(paths->paths[i]->pathType);
if(!pathType) break;
}
WString pathNames;
WString typeNames;
for(int i=0;i<paths->paths.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<definitions::ParsingDefinitionRuleDefinition> rule, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
{
ParsingSymbol* ruleType=manager->GetGlobal()->GetSubSymbolByName(rule->name)->GetDescriptorSymbol();
FOREACH(Ptr<ParsingDefinitionGrammar>, grammar, rule->grammars)
{
List<Ptr<GrammarPath>> paths;
{
EnumerateGrammarPathVisitor visitor(manager, rule.Obj());
grammar->Accept(&visitor);
visitor.BuildPath(paths);
}
FOREACH(Ptr<GrammarPath>, path, paths)
{
path->pathType=ruleType;
vint createdTypeCount=0;
vint transitionCount=0;
FOREACH(Ptr<GrammarPathFragment>, 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<GrammarPath>, path, paths)
{
FOREACH(Ptr<GrammarPathFragment>, fragment, path->fragments)
{
ParsingDefinitionGrammar* grammar=fragment->grammar;
Ptr<GrammarPathContainer> 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<ParsingDefinitionTypeDefinition> type, ParsingSymbolManager* manager, ParsingSymbol* scope, collections::List<Ptr<ParsingError>>& errors)
{
if(Ptr<ParsingDefinitionClassDefinition> node=type.Cast<ParsingDefinitionClassDefinition>())
{
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<ParsingDefinitionTypeDefinition>, subType, node->subTypes)
{
ResolveTypeSymbols(subType, manager, classType, errors);
}
}
}
}
void ResolveSymbols(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
{
FOREACH(Ptr<ParsingDefinitionTypeDefinition>, type, definition->types)
{
ResolveTypeSymbols(type, manager, manager->GetGlobal(), errors);
}
FOREACH(Ptr<ParsingDefinitionRuleDefinition>, rule, definition->rules)
{
vint errorCount=errors.Count();
ValidateRuleStructure(definition, rule, manager, errors);
if(errors.Count()==errorCount)
{
ResolveRuleSymbols(rule, manager, errors);
}
}
}
/***********************************************************************
ValidateDefinition
***********************************************************************/
void ValidateDefinition(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& 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;j<t1->actions.Count();j++)
{
Ptr<Action> a1=t1->actions[j];
Ptr<Action> 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 <epsilon* symbol> 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<Transition*>& transitionPath, Transition* transition, State* state, List<ClosureItem>& closure)
{
FOREACH(Transition*, singleTransitionPath, transitionPath)
{
if(singleTransitionPath->source==state && closurePredicate(singleTransitionPath)!=ClosureItem::Blocked)
{
Ptr<List<Transition*>> path=new List<Transition*>;
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<List<Transition*>> path=new List<Transition*>;
CopyFrom(*path.Obj(), transitionPath);
closure.Add(ClosureItem(state, path, false));
}
break;
default:;
}
}
void SearchClosure(ClosureItem::SearchResult(*closurePredicate)(Transition*), State* startState, List<ClosureItem>& closure)
{
List<Transition*> 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<Automaton> newAutomaton, State* oldState, List<State*>& scanningStates, Dictionary<State*, State*>& 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<State*, State*>& oldNewStateMap, collections::List<State*>& scanningStates, Ptr<Automaton> automaton)
{
vint currentStateIndex=0;
while(currentStateIndex<scanningStates.Count())
{
// map visiting state to new state
State* currentOldState=scanningStates[currentStateIndex++];
State* currentNewState=GetMappedState(automaton, currentOldState, scanningStates, oldNewStateMap);
// search for epsilon closure
List<ClosureItem> 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> automaton;
ParsingDefinitionRuleDefinition* rule;
ParsingDefinitionGrammar* ruleGrammar;
State* startState;
State* endState;
Transition* result;
CreateEpsilonPDAVisitor(Ptr<Automaton> _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> 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> 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> 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> 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> 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> automaton, Ptr<definitions::ParsingDefinitionRuleDefinition> rule, ParsingSymbolManager* manager)
{
Ptr<RuleInfo> 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<ParsingDefinitionGrammar>, 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<Automaton> CreateEpsilonPDA(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager)
{
Ptr<Automaton> automaton=new Automaton(manager);
FOREACH(Ptr<ParsingDefinitionRuleDefinition>, 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<Ptr<ParsingTable::LookAheadInfo>>& la, List<Ptr<ParsingTable::LookAheadInfo>>& sla, const List<Ptr<ParsingTable::LookAheadInfo>>& la2)
{
CopyFrom(sla, From(la)
.Where([&](Ptr<ParsingTable::LookAheadInfo> lai)
{
return From(la2).All([&](Ptr<ParsingTable::LookAheadInfo> lai2)
{
return ParsingTable::LookAheadInfo::TestPrefix(lai, lai2)==ParsingTable::LookAheadInfo::NotPrefix;
});
}),
true);
}
void RemoveStableLookAheads(List<Ptr<ParsingTable::LookAheadInfo>>& la, const List<Ptr<ParsingTable::LookAheadInfo>>& sla)
{
for(vint i=la.Count()-1;i>=0;i--)
{
if(sla.Contains(la[i].Obj()))
{
la.RemoveAt(i);
}
}
}
bool WalkLookAheads(Ptr<ParsingTable> table, List<Ptr<ParsingTable::LookAheadInfo>>& la, vint maxTokenCount)
{
vint count=la.Count();
for(vint i=0;i<count;i++)
{
Ptr<ParsingTable::LookAheadInfo> lai=la[i];
if(lai->tokens.Count()==maxTokenCount)
{
return false;
}
ParsingTable::LookAheadInfo::Walk(table, lai, lai->state, la);
}
return true;
}
void CompactLookAheads(Ptr<ParsingTable::TransitionItem> t, List<Ptr<ParsingTable::LookAheadInfo>>& sla)
{
CopyFrom(sla, t->lookAheads, true);
CopyFrom(t->lookAheads, From(sla)
.Where([&](Ptr<ParsingTable::LookAheadInfo> lai)
{
return From(sla).All([&](Ptr<ParsingTable::LookAheadInfo> 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<lai2;
default:
return true;
}
});
}));
}
bool CreateLookAhead(Ptr<ParsingTable> table, Ptr<ParsingTable::TransitionItem> t1, Ptr<ParsingTable::TransitionItem> t2, vint maxTokenCount)
{
List<Ptr<ParsingTable::LookAheadInfo>> 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<ParsingTable::LookAheadInfo>, lai1, la1)
{
FOREACH(Ptr<ParsingTable::LookAheadInfo>, 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<ParsingSymbol*>& types)
{
if(symbol->GetType()==ParsingSymbol::ClassType)
{
types.Add(symbol);
}
vint count=symbol->GetSubSymbolCount();
for(vint i=0;i<count;i++)
{
CollectType(symbol->GetSubSymbol(i), types);
}
}
void CollectAttributeInfo(Ptr<ParsingTable::AttributeInfoList> att, List<Ptr<definitions::ParsingDefinitionAttribute>>& atts)
{
FOREACH(Ptr<definitions::ParsingDefinitionAttribute>, datt, atts)
{
Ptr<ParsingTable::AttributeInfo> tatt=new ParsingTable::AttributeInfo(datt->name);
CopyFrom(tatt->arguments, datt->arguments);
att->attributes.Add(tatt);
}
}
Ptr<ParsingTable::AttributeInfoList> CreateAttributeInfo(List<Ptr<definitions::ParsingDefinitionAttribute>>& atts)
{
Ptr<ParsingTable::AttributeInfoList> 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<ParsingTable> table, List<State*>& stateIds, vint state, vint token, Ptr<ParsingTable::TransitionItem> t1, Ptr<ParsingTable::TransitionItem> t2, bool enableAmbiguity, collections::List<Ptr<ParsingError>>& 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<tabling::ParsingTable> GenerateTableFromPDA(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, Ptr<Automaton> jointPDA, bool enableAmbiguity, collections::List<Ptr<ParsingError>>& errors)
{
List<Ptr<ParsingTable::AttributeInfoList>> atts;
/***********************************************************************
find all class types
***********************************************************************/
List<ParsingSymbol*> types;
Dictionary<WString, vint> typeAtts;
Dictionary<Pair<WString, WString>, vint> treeFieldAtts;
Dictionary<ParsingSymbol*, Ptr<List<ParsingSymbol*>>> childTypes;
// find all class types
CollectType(manager->GetGlobal(), types);
FOREACH(ParsingSymbol*, type, types)
{
Ptr<ParsingTable::AttributeInfoList> typeAtt=new ParsingTable::AttributeInfoList;
ParsingSymbol* parent=type;
while(parent)
{
ParsingDefinitionClassDefinition* classDef=manager->CacheGetClassDefinition(parent);
CollectAttributeInfo(typeAtt, classDef->attributes);
Ptr<List<ParsingSymbol*>> children;
vint index=childTypes.Keys().IndexOf(parent);
if(index==-1)
{
children=new List<ParsingSymbol*>;
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<childTypes.Count();i++)
{
ParsingSymbol* type=childTypes.Keys().Get(i);
List<ParsingSymbol*>& children=*childTypes.Values().Get(i).Obj();
ParsingDefinitionClassDefinition* classDef=manager->CacheGetClassDefinition(type);
List<vint> fieldAtts;
FOREACH_INDEXER(Ptr<ParsingDefinitionClassMemberDefinition>, 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<ParsingDefinitionClassMemberDefinition>, field, index, classDef->members)
{
treeFieldAtts.Add(Pair<WString, WString>(type, field->name), fieldAtts[index]);
}
}
}
/***********************************************************************
find all tokens
***********************************************************************/
vint tokenCount=0;
vint discardTokenCount=0;
Dictionary<ParsingSymbol*, vint> tokenIds;
List<WString> discardTokens;
Dictionary<WString, vint> tokenAtts;
Dictionary<WString, vint> ruleAtts;
FOREACH(Ptr<ParsingDefinitionTokenDefinition>, 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<ParsingDefinitionRuleDefinition>, 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<State*> stateIds;
vint availableStateCount=0;
{
vint currentState=0;
List<State*> scanningStates;
FOREACH(Ptr<RuleInfo>, ruleInfo, jointPDA->ruleInfos.Values())
{
if(!scanningStates.Contains(ruleInfo->rootRuleStartState))
{
scanningStates.Add(ruleInfo->rootRuleStartState);
}
while(currentState<scanningStates.Count())
{
State* state=scanningStates[currentState++];
stateIds.Add(state);
FOREACH(Transition*, transition, state->transitions)
{
if(!scanningStates.Contains(transition->target))
{
scanningStates.Add(transition->target);
}
}
}
}
availableStateCount=scanningStates.Count();
}
// there will be some states that is used in shift and reduce but it is not a reachable state
// so the state table will record all state
FOREACH(Ptr<State>, state, jointPDA->states)
{
if(!stateIds.Contains(state.Obj()))
{
stateIds.Add(state.Obj());
}
}
vint stateCount=stateIds.Count();
Ptr<ParsingTable> table=new ParsingTable(atts.Count(), typeAtts.Count(), treeFieldAtts.Count(), tokenCount, discardTokenCount, stateCount, definition->rules.Count());
/***********************************************************************
fill attribute infos
***********************************************************************/
FOREACH_INDEXER(Ptr<ParsingTable::AttributeInfoList>, att, index, atts)
{
table->SetAttributeInfo(index, att);
}
/***********************************************************************
fill tree type infos
***********************************************************************/
typedef Pair<WString, vint> TreeTypeAttsPair;
FOREACH_INDEXER(TreeTypeAttsPair, type, index, typeAtts)
{
table->SetTreeTypeInfo(index, ParsingTable::TreeTypeInfo(type.key, type.value));
}
/***********************************************************************
fill tree field infos
***********************************************************************/
typedef Pair<Pair<WString, WString>, 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<RuleInfo> 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<ParsingDefinitionPrimitiveType> classType=rule->type.Cast<ParsingDefinitionPrimitiveType>())
{
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<ParsingTable::TransitionBag> bag=table->GetTransitionBag(stateIndex, tokenIndex);
if(!bag)
{
bag=new ParsingTable::TransitionBag;
table->SetTransitionBag(stateIndex, tokenIndex, bag);
}
Ptr<ParsingTable::TransitionItem> item=new ParsingTable::TransitionItem;
item->token=tokenIndex;
item->targetState=stateIds.IndexOf(transition->target);
bag->transitionItems.Add(item);
FOREACH(Ptr<Action>, 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<ParsingTable::TransitionBag> 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<ParsingTable::TransitionItem> t1=bag->transitionItems[k1];
Ptr<ParsingTable::TransitionItem> 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<ParsingTable::TransitionBag> reduceBag = table->GetTransitionBag(i, t))
{
for (vint k1 = 0; k1 < reduceBag->transitionItems.Count(); k1++)
{
for (vint k2 = 0; k2 < bag->transitionItems.Count(); k2++)
{
Ptr<ParsingTable::TransitionItem> t1=reduceBag->transitionItems[k1];
Ptr<ParsingTable::TransitionItem> 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<tabling::ParsingTable> GenerateTable(Ptr<definitions::ParsingDefinition> definition, bool enableAmbiguity, collections::List<Ptr<ParsingError>>& errors)
{
errors.Clear();
ParsingSymbolManager symbolManager;
ValidateDefinition(definition, &symbolManager, errors);
if(errors.Count()==0)
{
Ptr<Automaton> epsilonPDA=CreateEpsilonPDA(definition, &symbolManager);
Ptr<Automaton> nondeterministicPDA=CreateNondeterministicPDAFromEpsilonPDA(epsilonPDA);
Ptr<Automaton> jointPDA=CreateJointPDAFromNondeterministicPDA(nondeterministicPDA);
CompactJointPDA(jointPDA);
MarkLeftRecursiveInJointPDA(jointPDA, errors);
if(errors.Count()==0)
{
Ptr<ParsingTable> 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<Automaton> CreateJointPDAFromNondeterministicPDA(Ptr<Automaton> nondeterministicPDA)
{
Ptr<Automaton> automaton=new Automaton(nondeterministicPDA->symbolManager);
// build rule info data
Dictionary<WString, ParsingDefinitionRuleDefinition*> ruleMap;
Dictionary<State*, State*> oldNewStateMap;
FOREACH(ParsingDefinitionRuleDefinition*, rule, nondeterministicPDA->ruleInfos.Keys())
{
// build new rule info
Ptr<RuleInfo> ruleInfo=nondeterministicPDA->ruleInfos[rule];
Ptr<RuleInfo> 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<State>, 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> ruleInfo=nondeterministicPDA->ruleInfos[rule];
Ptr<RuleInfo> 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<State*> scanningStates;
vint currentStateIndex=0;
scanningStates.Add(ruleInfo->rootRuleStartState);
while(currentStateIndex<scanningStates.Count())
{
State* currentOldState=scanningStates[currentStateIndex++];
State* currentNewState=oldNewStateMap[currentOldState];
FOREACH(Transition*, oldTransition, currentOldState->transitions)
{
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<RuleInfo> oldRuleInfo=nondeterministicPDA->ruleInfos[rule];
{
Transition* shiftTransition=automaton->Epsilon(newSource, oldNewStateMap[oldRuleInfo->startState]);
Ptr<Action> 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> 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<Automaton> jointPDA)
{
FOREACH(Ptr<State>, state, jointPDA->states)
{
State* currentState=state.Obj();
// search for epsilon closure
List<ClosureItem> 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>, 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 <shift* token>, <reduce* token> or <reduce* shift* token>
// but there will not be something like <reduce* shift* reduce* token>
// 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<Automaton> jointPDA, collections::List<Ptr<ParsingError>>& errors)
{
vint errorCount=errors.Count();
// record all left recursive shifts and delete all left recursive epsilon transition
SortedList<Pair<State*, State*>> leftRecursiveShifts;
FOREACH(Ptr<State>, state, jointPDA->states)
{
for(vint i=state->transitions.Count()-1;i>=0;i--)
{
Transition* transition=state->transitions[i];
if(transition->stackOperationType==Transition::LeftRecursive)
{
Ptr<Action> shiftAction;
FOREACH(Ptr<Action>, 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<State*, State*>(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>, state, jointPDA->states)
{
FOREACH(Transition*, transition, state->transitions)
{
for(vint i=transition->actions.Count()-1;i>=0;i--)
{
Ptr<Action> action=transition->actions[i];
if(action->actionType==Action::Reduce)
{
Pair<State*, State*> 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<Action> 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>, 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> automaton, Ptr<RuleInfo> ruleInfo, List<State*>& 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> ruleInfo)
{
if(state==ruleInfo->rootRuleStartState || state==ruleInfo->rootRuleEndState || state==ruleInfo->startState)
{
return false;
}
return true;
}
/***********************************************************************
RearrangeState
***********************************************************************/
vint CompareTransitionForRearranging(Transition* t1, Transition* t2)
{
if(t1->transitionType<t2->transitionType) return -1;
if(t1->transitionType>t2->transitionType) return 1;
if(t1->transitionSymbol<t2->transitionSymbol) return -1;
if(t1->transitionSymbol>t2->transitionSymbol) return 1;
return 0;
}
vint CompareActionForRearranging(Ptr<Action> a1, Ptr<Action> a2)
{
if(a1->actionType<a2->actionType) return -1;
if(a1->actionType>a2->actionType) return 1;
if(a1->actionSource<a2->actionSource) return -1;
if(a1->actionSource>a2->actionSource) return 1;
if(a1->actionTarget<a2->actionTarget) return -1;
if(a1->actionTarget>a2->actionTarget) return 1;
return 0;
}
void RearrangeState(State* state, SortedList<State*>& 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<Ptr<Action>> 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;i<state1->transitions.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;i<state1->inputs.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> 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> 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> automaton, Ptr<RuleInfo> ruleInfo, List<State*>& newStates)
{
SortedList<State*> stateContentSorted;
while(true)
{
for(vint i=0;i<newStates.Count();i++)
{
State* state1=newStates[i];
if(IsMergableCandidate(state1, ruleInfo))
{
for(vint j=i+1;j<newStates.Count();j++)
{
State* state2=newStates[j];
if(state1!=state2 && IsMergableCandidate(state2, ruleInfo))
{
RearrangeState(state1, stateContentSorted);
RearrangeState(state2, stateContentSorted);
if(IsMergableBecauseTransitions(state1, state2))
{
MergeState2ToState1BecauseTransitions(automaton, state1, state2);
newStates.RemoveAt(j);
goto MERGED_STATES_PAIR;
}
else if(IsMergableBecauseInputs(state1, state2))
{
MergeState2ToState1BecauseInputs(automaton, state1, state2);
newStates.RemoveAt(j);
goto MERGED_STATES_PAIR;
}
}
}
}
}
break;
MERGED_STATES_PAIR:
continue;
}
}
}
}
}
/***********************************************************************
PARSING\PARSINGAUTOMATON_NPDA.CPP
***********************************************************************/
namespace vl
{
namespace parsing
{
using namespace collections;
using namespace definitions;
namespace analyzing
{
/***********************************************************************
CreateNondeterministicPDAFromEpsilonPDA
***********************************************************************/
Ptr<Automaton> CreateNondeterministicPDAFromEpsilonPDA(Ptr<Automaton> epsilonPDA)
{
Ptr<Automaton> automaton=new Automaton(epsilonPDA->symbolManager);
FOREACH(ParsingDefinitionRuleDefinition*, rule, epsilonPDA->ruleInfos.Keys())
{
// build new rule info
Ptr<RuleInfo> ruleInfo=epsilonPDA->ruleInfos[rule];
Ptr<RuleInfo> 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<State*, State*> oldNewStateMap;
List<State*> 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<State*> 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<ParsingDefinitionAttribute> ParsingDefinitionAttributeWriter::Attribute()const
{
return attribute;
}
ParsingDefinitionAttributeWriter Attribute(const WString& name)
{
return ParsingDefinitionAttributeWriter(name);
}
/***********************************************************************
ParsingDefinitionTypeWriter
***********************************************************************/
ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(Ptr<ParsingDefinitionType> internalType)
{
type=internalType;
}
ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(const ParsingDefinitionTypeWriter& typeWriter)
{
type=typeWriter.type;
}
ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(const WString& name)
{
Ptr<ParsingDefinitionPrimitiveType> primitiveType=new ParsingDefinitionPrimitiveType;
primitiveType->name=name;
type=primitiveType;
}
ParsingDefinitionTypeWriter ParsingDefinitionTypeWriter::Sub(const WString& subTypeName)const
{
Ptr<ParsingDefinitionSubType> subType=new ParsingDefinitionSubType;
subType->parentType=type;
subType->subTypeName=subTypeName;
return ParsingDefinitionTypeWriter(subType);
}
ParsingDefinitionTypeWriter ParsingDefinitionTypeWriter::Array()const
{
Ptr<ParsingDefinitionArrayType> arrayType=new ParsingDefinitionArrayType;
arrayType->elementType=type;
return ParsingDefinitionTypeWriter(arrayType);
}
Ptr<ParsingDefinitionType> ParsingDefinitionTypeWriter::Type()const
{
return type;
}
ParsingDefinitionTypeWriter Type(const WString& name)
{
return ParsingDefinitionTypeWriter(name);
}
ParsingDefinitionTypeWriter TokenType()
{
Ptr<ParsingDefinitionTokenType> 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<ParsingDefinitionClassMemberDefinition> 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<ParsingDefinitionTypeDefinition> 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<ParsingDefinitionEnumMemberDefinition> 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<ParsingDefinitionTypeDefinition> ParsingDefinitionEnumDefinitionWriter::Definition()const
{
return definition;
}
ParsingDefinitionEnumDefinitionWriter Enum(const WString& name)
{
return ParsingDefinitionEnumDefinitionWriter(name);
}
/***********************************************************************
ParsingDefinitionGrammarWriter
***********************************************************************/
ParsingDefinitionGrammarWriter::ParsingDefinitionGrammarWriter(Ptr<ParsingDefinitionGrammar> internalGrammar)
{
grammar=internalGrammar;
}
ParsingDefinitionGrammarWriter::ParsingDefinitionGrammarWriter(const ParsingDefinitionGrammarWriter& grammarWriter)
{
grammar=grammarWriter.grammar;
}
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator+(const ParsingDefinitionGrammarWriter& next)const
{
Ptr<ParsingDefinitionSequenceGrammar> sequence=new ParsingDefinitionSequenceGrammar;
sequence->first=grammar;
sequence->second=next.Grammar();
return ParsingDefinitionGrammarWriter(sequence);
}
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator|(const ParsingDefinitionGrammarWriter& next)const
{
Ptr<ParsingDefinitionAlternativeGrammar> alternative=new ParsingDefinitionAlternativeGrammar;
alternative->first=grammar;
alternative->second=next.Grammar();
return ParsingDefinitionGrammarWriter(alternative);
}
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator*()const
{
Ptr<ParsingDefinitionLoopGrammar> loop=new ParsingDefinitionLoopGrammar;
loop->grammar=grammar;
return ParsingDefinitionGrammarWriter(loop);
}
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::As(const ParsingDefinitionTypeWriter& type)const
{
Ptr<ParsingDefinitionCreateGrammar> create=new ParsingDefinitionCreateGrammar;
create->grammar=grammar;
create->type=type.Type();
return ParsingDefinitionGrammarWriter(create);
}
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator[](const WString& memberName)const
{
Ptr<ParsingDefinitionAssignGrammar> assign=new ParsingDefinitionAssignGrammar;
assign->grammar=grammar;
assign->memberName=memberName;
return ParsingDefinitionGrammarWriter(assign);
}
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator!()const
{
Ptr<ParsingDefinitionUseGrammar> use=new ParsingDefinitionUseGrammar;
use->grammar=grammar;
return ParsingDefinitionGrammarWriter(use);
}
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::Set(const WString& memberName, const WString& value)const
{
Ptr<ParsingDefinitionSetterGrammar> setter=new ParsingDefinitionSetterGrammar;
setter->grammar=grammar;
setter->memberName=memberName;
setter->value=value;
return ParsingDefinitionGrammarWriter(setter);
}
Ptr<ParsingDefinitionGrammar> ParsingDefinitionGrammarWriter::Grammar()const
{
return grammar;
}
ParsingDefinitionGrammarWriter Rule(const WString& name)
{
Ptr<ParsingDefinitionPrimitiveGrammar> grammar=new ParsingDefinitionPrimitiveGrammar;
grammar->name=name;
return ParsingDefinitionGrammarWriter(grammar);
}
ParsingDefinitionGrammarWriter Text(const WString& text)
{
Ptr<ParsingDefinitionTextGrammar> grammar=new ParsingDefinitionTextGrammar;
grammar->text=text;
return ParsingDefinitionGrammarWriter(grammar);
}
ParsingDefinitionGrammarWriter Opt(const ParsingDefinitionGrammarWriter& writer)
{
Ptr<ParsingDefinitionOptionalGrammar> grammar=new ParsingDefinitionOptionalGrammar;
grammar->grammar=writer.Grammar();
return ParsingDefinitionGrammarWriter(grammar);
}
/***********************************************************************
ParsingDefinitionTokenDefinitionWriter
***********************************************************************/
ParsingDefinitionTokenDefinitionWriter::ParsingDefinitionTokenDefinitionWriter(ParsingDefinitionWriter& _owner, Ptr<ParsingDefinitionTokenDefinition> _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<ParsingDefinitionRuleDefinition> _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<ParsingDefinitionTokenDefinition> 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<ParsingDefinitionTokenDefinition> 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<ParsingDefinitionRuleDefinition> rule=new ParsingDefinitionRuleDefinition;
rule->name=name;
rule->type=type.Type();
definition->rules.Add(rule);
return ParsingDefinitionRuleDefinitionWriter(*this, rule);
}
Ptr<ParsingDefinition> ParsingDefinitionWriter::Definition()const
{
return definition;
}
}
}
}
/***********************************************************************
PARSING\PARSINGDEFINITIONS_CREATEPARSERDEFINITION.CPP
***********************************************************************/
namespace vl
{
namespace parsing
{
namespace definitions
{
using namespace collections;
/***********************************************************************
自举
***********************************************************************/
Ptr<ParsingDefinition> 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<wchar_t> 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<ParsingTreeToken> token)
{
const WString& value=token->GetValue();
return DeserializeString(value);
}
void SetName(WString& target, Ptr<ParsingTreeNode> node)
{
Ptr<ParsingTreeToken> token=node.Cast<ParsingTreeToken>();
if(token)
{
target=token->GetValue();
}
}
void SetText(WString& target, Ptr<ParsingTreeNode> node)
{
Ptr<ParsingTreeToken> token=node.Cast<ParsingTreeToken>();
if(token)
{
target=DeserializeString(token);
}
}
extern Ptr<ParsingTreeCustomBase> Deserialize(Ptr<ParsingTreeObject> node);
template<typename T>
void SetArray(List<Ptr<T>>& target, Ptr<ParsingTreeNode> node)
{
Ptr<ParsingTreeArray> source=node.Cast<ParsingTreeArray>();
if(source)
{
for(vint i=0;i<source->Count();i++)
{
target.Add(Deserialize(source->GetItem(i).Cast<ParsingTreeObject>()).Cast<T>());
}
}
}
void SetArray(List<WString>& target, Ptr<ParsingTreeNode> node)
{
Ptr<ParsingTreeArray> source=node.Cast<ParsingTreeArray>();
if(source)
{
for(vint i=0;i<source->Count();i++)
{
WString name;
SetName(name, source->GetItem(i));
target.Add(name);
}
}
}
template<typename T>
void SetMember(Ptr<T>& target, Ptr<ParsingTreeNode> node)
{
Ptr<ParsingTreeObject> source=node.Cast<ParsingTreeObject>();
if(source)
{
target=Deserialize(source).Cast<T>();
}
}
Ptr<ParsingTreeCustomBase> Deserialize(Ptr<ParsingTreeObject> node)
{
if(!node)
{
return 0;
}
else if(node->GetType()==L"AttributeDef")
{
Ptr<ParsingDefinitionAttribute> target=new ParsingDefinitionAttribute;
SetName(target->name, node->GetMember(L"name"));
SetArray(target->arguments, node->GetMember(L"arguments"));
for(vint i=0;i<target->arguments.Count();i++)
{
target->arguments[i]=DeserializeString(target->arguments[i]);
}
return target;
}
else if(node->GetType()==L"PrimitiveTypeObj")
{
Ptr<ParsingDefinitionPrimitiveType> target=new ParsingDefinitionPrimitiveType;
SetName(target->name, node->GetMember(L"name"));
return target;
}
else if(node->GetType()==L"TokenTypeObj")
{
Ptr<ParsingDefinitionTokenType> target=new ParsingDefinitionTokenType;
return target;
}
else if(node->GetType()==L"SubTypeObj")
{
Ptr<ParsingDefinitionSubType> 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<ParsingDefinitionArrayType> target=new ParsingDefinitionArrayType;
SetMember(target->elementType, node->GetMember(L"elementType"));
return target;
}
else if(node->GetType()==L"ClassMemberDef")
{
Ptr<ParsingDefinitionClassMemberDefinition> 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<ParsingDefinitionClassDefinition> 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<ParsingDefinitionEnumMemberDefinition> 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<ParsingDefinitionEnumDefinition> 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<ParsingDefinitionPrimitiveGrammar> target=new ParsingDefinitionPrimitiveGrammar;
SetName(target->name, node->GetMember(L"name"));
return target;
}
else if(node->GetType()==L"TextGrammarDef")
{
Ptr<ParsingDefinitionTextGrammar> target=new ParsingDefinitionTextGrammar;
SetText(target->text, node->GetMember(L"text"));
return target;
}
else if(node->GetType()==L"SequenceGrammarDef")
{
Ptr<ParsingDefinitionSequenceGrammar> 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<ParsingDefinitionAlternativeGrammar> 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<ParsingDefinitionLoopGrammar> target=new ParsingDefinitionLoopGrammar;
SetMember(target->grammar, node->GetMember(L"grammar"));
return target;
}
else if(node->GetType()==L"OptionalGrammarDef")
{
Ptr<ParsingDefinitionOptionalGrammar> target=new ParsingDefinitionOptionalGrammar;
SetMember(target->grammar, node->GetMember(L"grammar"));
return target;
}
else if(node->GetType()==L"CreateGrammarDef")
{
Ptr<ParsingDefinitionCreateGrammar> 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<ParsingDefinitionAssignGrammar> 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<ParsingDefinitionUseGrammar> target=new ParsingDefinitionUseGrammar;
SetMember(target->grammar, node->GetMember(L"grammar"));
return target;
}
else if(node->GetType()==L"SetterGrammarDef")
{
Ptr<ParsingDefinitionSetterGrammar> 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<ParsingDefinitionTokenDefinition> 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<ParsingTreeToken> token=node->GetMember(L"discard").Cast<ParsingTreeToken>();
target->discard=(token && token->GetValue()==L"DiscardToken");
return target;
}
else if(node->GetType()==L"RuleDef")
{
Ptr<ParsingDefinitionRuleDefinition> 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<ParsingDefinition> target=new ParsingDefinition;
Ptr<ParsingTreeArray> defs=node->GetMember(L"definitions").Cast<ParsingTreeArray>();
if(defs)
{
vint count=defs->Count();
for(vint i=0;i<count;i++)
{
Ptr<ParsingTreeObject> def=defs->GetItem(i).Cast<ParsingTreeObject>();
Ptr<ParsingTreeCustomBase> defObject=Deserialize(def);
if(Ptr<ParsingDefinitionTypeDefinition> defType=defObject.Cast<ParsingDefinitionTypeDefinition>())
{
target->types.Add(defType);
}
else if(Ptr<ParsingDefinitionTokenDefinition> defToken=defObject.Cast<ParsingDefinitionTokenDefinition>())
{
target->tokens.Add(defToken);
}
else if(Ptr<ParsingDefinitionRuleDefinition> defRule=defObject.Cast<ParsingDefinitionRuleDefinition>())
{
target->rules.Add(defRule);
}
}
}
return target;
}
else
{
return 0;
}
}
Ptr<ParsingDefinition> DeserializeDefinition(Ptr<ParsingTreeNode> node)
{
return Deserialize(node.Cast<ParsingTreeObject>()).Cast<ParsingDefinition>();
}
}
}
}
/***********************************************************************
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;i<input.Length();i++)
{
if(input[i]==L'\"')
{
writer.WriteString(L"\"\"");
}
else
{
writer.WriteChar(input[i]);
}
}
writer.WriteChar(L'\"');
}
WString SerializeString(const WString& value)
{
MemoryStream stream;
{
StreamWriter writer(stream);
LogString(value, writer);
}
stream.SeekFromBegin(0);
StreamReader reader(stream);
return reader.ReadToEnd();
}
void LogAttributeList(ParsingDefinitionBase* definition, TextWriter& writer)
{
for(vint i=0;i<definition->attributes.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;j<att->arguments.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;i<node->subTypes.Count();i++)
{
LogInternal(node->subTypes[i].Obj(), prefix+L" ", writer);
writer.WriteLine(L"");
}
for(int i=0;i<node->members.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;i<node->members.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<ParsingDefinition> definition, TextWriter& writer)
{
FOREACH(Ptr<ParsingDefinitionTypeDefinition>, type, definition->types)
{
Log(type.Obj(), L"", writer);
writer.WriteLine(L"");
}
FOREACH(Ptr<ParsingDefinitionTokenDefinition>, 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<ParsingDefinitionRuleDefinition>, 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<ParsingDefinitionGrammar>, 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> automaton, stream::TextWriter& writer)
{
FOREACH(Ptr<RuleInfo>, 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<State*> states;
FOREACH(Ptr<RuleInfo>, ruleInfo, automaton->ruleInfos.Values())
{
vint currentState=states.Count();
states.Add(ruleInfo->rootRuleStartState);
while(currentState<states.Count())
{
State* state=states[currentState++];
writer.WriteLine(state->stateExpression);
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>, 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<ParsingTable> table, vint attributeIndex, const WString& prefix, stream::TextWriter& writer)
{
if(attributeIndex!=-1)
{
Ptr<ParsingTable::AttributeInfoList> atts=table->GetAttributeInfo(attributeIndex);
FOREACH(Ptr<ParsingTable::AttributeInfo>, att, atts->attributes)
{
writer.WriteString(prefix);
writer.WriteString(L"@");
writer.WriteString(att->name);
writer.WriteString(L"(");
for(vint i=0;i<att->arguments.Count();i++)
{
if(i>0) writer.WriteString(L", ");
definitions::LogString(att->arguments[i], writer);
}
writer.WriteLine(L")");
}
}
}
void Log(Ptr<ParsingTable> table, stream::TextWriter& writer)
{
vint rows=table->GetStateCount()+1;
vint columns=table->GetTokenCount()+1;
Array<WString> stringTable(rows*columns);
stringTable[0]=L"<Parsing Table>";
for(vint row=0; row<table->GetStateCount();row++)
{
stringTable[(row+1)*columns]=itow(row)+L": "+table->GetStateInfo(row).stateName;
}
for(vint column=0;column<table->GetTokenCount();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; row<table->GetStateCount();row++)
{
for(vint column=0;column<table->GetTokenCount();column++)
{
Ptr<ParsingTable::TransitionBag> bag=table->GetTransitionBag(row, column);
if(bag)
{
WString content;
FOREACH(Ptr<ParsingTable::TransitionItem>, 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<ParsingTable::LookAheadInfo>, 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;i<table->GetRuleCount();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;i<table->GetTokenCount();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;i<table->GetRuleCount();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;i<table->GetTreeTypeInfoCount();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;i<table->GetTreeFieldInfoCount();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;i<node->GetCreatorRules().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;i<node->GetMembers().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;i<node->Count();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<vint>* 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<vint>* ParsingTokenWalker::TokenLookAhead::CreateEnumerator()const
{
return new LookAheadEnumerator(walker, walker->currentToken);
}
/***********************************************************************
ParsingTokenWalker::ReduceLookAhead
***********************************************************************/
ParsingTokenWalker::ReduceLookAhead::ReduceLookAhead(const ParsingTokenWalker* _walker)
:walker(_walker)
{
}
collections::IEnumerator<vint>* 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 && index<tokens.Count())
{
index++;
while(0<=index && index<tokens.Count())
{
if(table->IsInputToken(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 && index<tokens.Count())
{
return table->GetTableTokenIndex(tokens[index].token);
}
else
{
return -1;
}
}
ParsingTokenWalker::ParsingTokenWalker(collections::List<regex::RegexToken>& _tokens, Ptr<ParsingTable> _table)
:tokens(_tokens)
,table(_table)
,currentToken(-2)
, tokenLookAhead(this)
, reduceLookAhead(this)
{
}
ParsingTokenWalker::~ParsingTokenWalker()
{
}
const collections::IEnumerable<vint>& ParsingTokenWalker::GetTokenLookahead()const
{
return tokenLookAhead;
}
const collections::IEnumerable<vint>& 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<tokens.Count())
{
return currentToken;
}
else
{
return -1;
}
}
/***********************************************************************
ParsingState::StateGroup
***********************************************************************/
ParsingState::StateGroup::StateGroup()
:currentState(-1)
,tokenSequenceIndex(0)
,shiftToken(0)
,reduceToken(0)
{
}
ParsingState::StateGroup::StateGroup(const ParsingTable::RuleInfo& info)
:currentState(info.rootStartState)
,tokenSequenceIndex(0)
,shiftToken(0)
,reduceToken(0)
{
}
ParsingState::StateGroup::StateGroup(const StateGroup& group)
:currentState(group.currentState)
,tokenSequenceIndex(group.tokenSequenceIndex)
,shiftToken(group.shiftToken)
,reduceToken(group.reduceToken)
{
CopyFrom(stateStack, group.stateStack);
CopyFrom(shiftTokenStack, group.shiftTokenStack);
}
/***********************************************************************
ParsingState
***********************************************************************/
ParsingState::ParsingState(const WString& _input, Ptr<ParsingTable> _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<ParsingTable> ParsingState::GetTable()
{
return table;
}
const collections::List<regex::RegexToken>& 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<vint>& 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<vint>* lookAheadTokens)
{
bool passLookAheadTest=true;
if(item->lookAheads.Count()>0 && lookAheadTokens)
{
passLookAheadTest=false;
FOREACH(Ptr<ParsingTable::LookAheadInfo>, 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;j<item->stackPattern.Count();j++)
{
vint state=
j<future->shiftStates.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<vint>* lookAheadTokens)
{
ParsingTable::TransitionBag* bag=table->GetTransitionBag(future->currentState, tableTokenIndex).Obj();
if(bag)
{
for(vint i=0;i<bag->transitionItems.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<vint>* 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;j<transition->instructions.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;j<instructionBegin+instructionCount;j++)
{
ParsingTable::Instruction& ins=transition->instructions[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<vint>* 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<vint>* 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;i<bag->transitionItems.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<Future*>& 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;i<bag->transitionItems.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<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities)
{
if(walker->GetTableTokenIndex()==-1)
{
return false;
}
vint token = walker->GetTableTokenIndex();
RegexToken* regexToken = walker->GetRegexToken();
vint oldPossibilitiesCount = possibilities.Count();
for (vint i = 0; i<count; i++)
{
Future* previous = previousFutures[start + i];
Explore(token, previous, possibilities);
}
if (possibilities.Count() == oldPossibilitiesCount)
{
return false;
}
for (vint i = oldPossibilitiesCount; i < possibilities.Count(); i++)
{
possibilities[i]->selectedRegexToken = regexToken;
}
return true;
}
bool ParsingState::ExploreNormalReduce(collections::List<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities)
{
if(walker->GetTableTokenIndex()==-1)
{
return false;
}
vint oldPossibilitiesCount = possibilities.Count();
for(vint i=0;i<count;i++)
{
Future* previous=previousFutures[start+i];
Explore(ParsingTable::NormalReduce, previous, possibilities);
}
return possibilities.Count() > oldPossibilitiesCount;
}
bool ParsingState::ExploreLeftRecursiveReduce(collections::List<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities)
{
if(walker->GetTableTokenIndex()==-1)
{
return false;
}
vint oldPossibilitiesCount = possibilities.Count();
for(vint i=0;i<count;i++)
{
Future* previous=previousFutures[start+i];
Explore(ParsingTable::LeftRecursiveReduce, previous, possibilities);
}
return possibilities.Count() > oldPossibilitiesCount;
}
ParsingState::Future* ParsingState::ExploreCreateRootFuture()
{
Future* future=new Future;
future->currentState=stateGroup->currentState;
return future;
}
Ptr<ParsingState::StateGroup> ParsingState::TakeSnapshot()
{
return new StateGroup(*stateGroup.Obj());
}
void ParsingState::RestoreSnapshot(Ptr<StateGroup> 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<ParsingTreeObject>();
ambiguityBranchNodeStack.Clear();
ambiguityBranchSharedNodeCount=nodeStack.Count()-result.ambiguityAffectedStackNodeCount+1;
for(vint i=ambiguityBranchSharedNodeCount;i<nodeStack.Count();i++)
{
ambiguityBranchNodeStack.Add(nodeStack[i]->Clone().Cast<ParsingTreeObject>());
}
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<ParsingTreeObject>();
for(vint i=0;i<ambiguityBranchNodeStack.Count();i++)
{
nodeStack.Add(ambiguityBranchNodeStack[i]->Clone().Cast<ParsingTreeObject>());
}
}
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<ParsingTreeObject> ambiguousNode=new ParsingTreeObject(result.ambiguityNodeType, operationTarget->GetCodeRange());
Ptr<ParsingTreeArray> items=new ParsingTreeArray(L"", operationTarget->GetCodeRange());
FOREACH(Ptr<ParsingTreeObject>, 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;j<result.instructionBegin+result.instructionCount;j++)
{
ParsingTable::Instruction& ins=result.transition->instructions[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<ParsingTreeObject> obj=createdObject.Cast<ParsingTreeObject>();
if(!obj)
{
return false;
}
for(vint i=0;i<operationTarget->GetMembers().Count();i++)
{
WString name=operationTarget->GetMembers().Keys().Get(i);
Ptr<ParsingTreeNode> 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<ParsingTreeToken> 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<ParsingTreeArray> arr=operationTarget->GetMember(ins.nameParameter).Cast<ParsingTreeArray>();;
if(!arr)
{
arr=new ParsingTreeArray();
operationTarget->SetMember(ins.nameParameter, arr);
}
ParsingTextRange arrRange=arr->GetCodeRange();
ParsingTextRange itemRange;
if(!createdObject)
{
Ptr<ParsingTreeToken> 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.start<arrRange.start)
{
arrRange.start=itemRange.start;
}
if(arrRange.end.index==ParsingTextPos::UnknownValue || itemRange.end>arrRange.end)
{
arrRange.end=itemRange.end;
}
arr->SetCodeRange(arrRange);
}
break;
case ParsingTable::Instruction::Setter:
{
Ptr<ParsingTreeToken> 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<ParsingTreeObject> 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<vint>& ParsingTransitionCollector::GetAmbiguityBranchesFromBegin(vint transitionIndex)const
{
vint index=ambiguityBeginToBranches.Keys().IndexOf(transitionIndex);
return index==-1?*(collections::List<vint>*)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::AttributeInfo> ParsingTable::AttributeInfoList::FindFirst(const WString& name)
{
for(vint i=0;i<attributes.Count();i++)
{
if(attributes[i]->name==name)
{
return attributes[i];
}
}
return 0;
}
/***********************************************************************
ParsingTable::LookAheadInfo
***********************************************************************/
ParsingTable::LookAheadInfo::PrefixResult ParsingTable::LookAheadInfo::TestPrefix(Ptr<LookAheadInfo> a, Ptr<LookAheadInfo> b)
{
if(a->tokens.Count()>b->tokens.Count())
{
return ParsingTable::LookAheadInfo::NotPrefix;
}
for(vint i=0;i<a->tokens.Count();i++)
{
if(a->tokens[i]!=b->tokens[i])
{
return ParsingTable::LookAheadInfo::NotPrefix;
}
}
return a->tokens.Count()<b->tokens.Count()?ParsingTable::LookAheadInfo::Prefix:ParsingTable::LookAheadInfo::Equal;
}
void ParsingTable::LookAheadInfo::WalkInternal(Ptr<ParsingTable> table, Ptr<LookAheadInfo> previous, vint state, collections::SortedList<vint>& walkedStates, collections::List<Ptr<LookAheadInfo>>& newInfos)
{
if (walkedStates.Contains(state)) return;
walkedStates.Add(state);
for (vint i = 0; i < table->GetTokenCount(); i++)
{
if(Ptr<TransitionBag> bag=table->GetTransitionBag(state, i))
{
FOREACH(Ptr<TransitionItem>, item, bag->transitionItems)
{
if (i == ParsingTable::NormalReduce || i == ParsingTable::LeftRecursiveReduce)
{
WalkInternal(table, previous, item->targetState, walkedStates, newInfos);
}
else
{
Ptr<LookAheadInfo> 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<ParsingTable> table, Ptr<LookAheadInfo> previous, vint state, collections::List<Ptr<LookAheadInfo>>& newInfos)
{
SortedList<vint> walkedStates;
WalkInternal(table, previous, state, walkedStates, newInfos);
}
/***********************************************************************
ParsingTable::TransitionItem
***********************************************************************/
enum TransitionLevel
{
ReduceTransition,
LeftRecursiveReduceTransition,
NormalTransition,
};
TransitionLevel GetTransitionLevel(Ptr<ParsingTable::TransitionItem> 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<TransitionItem> t1, Ptr<TransitionItem> 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(level1<level2) return WrongOrder;
}
vint ic1=t1->stackPattern.Count();
vint ic2=t2->stackPattern.Count();
vint ic=ic1<ic2?ic1:ic2;
for(vint i=0;i<ic;i++)
{
vint s1=t1->stackPattern[i];
vint s2=t2->stackPattern[i];
if(s1>s2)
{
return CorrectOrder;
}
else if(s1<s2)
{
return WrongOrder;
}
}
if(t1->token==TokenFinish)
{
if(ic1>ic2)
{
return CorrectOrder;
}
else if(ic1<ic2)
{
return WrongOrder;
}
}
if(forceGivingOrder)
{
return t1>t2?CorrectOrder:SameOrder;
}
else
{
return UnknownOrder;
}
}
vint ParsingTable::TransitionItem::Compare(Ptr<TransitionItem> t1, Ptr<TransitionItem> t2)
{
OrderResult order=CheckOrder(t1, t2, true);
switch(order)
{
case CorrectOrder: return -1;
case WrongOrder: return 1;
default: return 0;
}
}
template<typename TIO>
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::AttributeInfoList> ParsingTable::GetAttributeInfo(vint index)
{
return attributeInfos[index];
}
void ParsingTable::SetAttributeInfo(vint index, Ptr<AttributeInfoList> 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<WString, WString> 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::TransitionBag> ParsingTable::GetTransitionBag(vint state, vint token)
{
return transitionBags[state*tokenCount+token];
}
void ParsingTable::SetTransitionBag(vint state, vint token, Ptr<TransitionBag> bag)
{
transitionBags[state*tokenCount+token]=bag;
}
void ParsingTable::Initialize()
{
List<WString> 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<tokenInfos.Count();i++)
{
tokenInfos[i].regexTokenIndex=regexTokenIndex++;
}
for(vint i=0;i<discardTokenInfos.Count();i++)
{
discardTokenInfos[i].regexTokenIndex=regexTokenIndex++;
}
lexer=new RegexLexer(tokens);
ruleMap.Clear();
FOREACH_INDEXER(RuleInfo, rule, index, ruleInfos)
{
ruleMap.Add(rule.name, index);
}
for(vint i=0;i<stateInfos.Count();i++)
{
StateInfo& info=stateInfos[i];
info.ruleAmbiguousType=ruleInfos[ruleMap[info.ruleName]].ambiguousType;
}
treeTypeInfoMap.Clear();
FOREACH_INDEXER(TreeTypeInfo, info, index, treeTypeInfos)
{
treeTypeInfoMap.Add(info.type, index);
}
treeFieldInfoMap.Clear();
FOREACH_INDEXER(TreeFieldInfo, info, index, treeFieldInfos)
{
Pair<WString, WString> key(info.type, info.field);
treeFieldInfoMap.Add(key, index);
}
}
bool ParsingTable::IsInputToken(vint regexTokenIndex)
{
return regexTokenIndex>=0 && regexTokenIndex<tokenCount-UserTokenStart;
}
vint ParsingTable::GetTableTokenIndex(vint regexTokenIndex)
{
return IsInputToken(regexTokenIndex)?regexTokenIndex+UserTokenStart:-1;
}
vint ParsingTable::GetTableDiscardTokenIndex(vint regexTokenIndex)
{
return regexTokenIndex>=tokenCount-UserTokenStart?regexTokenIndex-(tokenCount-UserTokenStart):-1;
}
}
}
}
/***********************************************************************
PARSING\PARSINGTREE.CPP
***********************************************************************/
namespace vl
{
using namespace collections;
namespace parsing
{
vint CompareTextRange(Ptr<ParsingTreeNode> r1, Ptr<ParsingTreeNode> 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<ParsingTreeNode>, node, node->GetSubNodes())
{
node->Accept(this);
}
}
break;
case TraverseDirection::ByStorePosition:
{
FOREACH(Ptr<ParsingTreeNode>, 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<ParsingTreeNode>, node, node->GetSubNodes())
{
node->Accept(this);
}
}
break;
case TraverseDirection::ByStorePosition:
{
FOREACH(Ptr<ParsingTreeNode>, node, node->GetItems())
{
node->Accept(this);
}
}
break;
}
AfterVisit(node);
}
/***********************************************************************
ParsingTreeNode
***********************************************************************/
bool ParsingTreeNode::BeforeAddChild(Ptr<ParsingTreeNode> node)
{
return node->parent==0;
}
void ParsingTreeNode::AfterAddChild(Ptr<ParsingTreeNode> node)
{
node->parent=this;
ClearQueryCache();
}
bool ParsingTreeNode::BeforeRemoveChild(Ptr<ParsingTreeNode> node)
{
return node->parent!=0;
}
void ParsingTreeNode::AfterRemoveChild(Ptr<ParsingTreeNode> 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<ParsingTreeNode>, node, subNodes)
{
node->InitializeQueryCache();
}
//if (codeRange.start.IsInvalid() || codeRange.start.IsInvalid())
{
FOREACH(Ptr<ParsingTreeNode>, 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<ParsingTreeNode> 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.end<selectedRange.start)
{
end = selected - 1;
}
else if (range.start>selectedRange.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<ParsingTreeNode> ParsingTreeToken::Clone()
{
Ptr<ParsingTreeToken> 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<ParsingTreeNode> ParsingTreeObject::Clone()
{
Ptr<ParsingTreeObject> clone=new ParsingTreeObject(type, codeRange);
CopyFrom(clone->rules, rules);
for(vint i=0;i<members.Count();i++)
{
WString name=members.Keys().Get(i);
Ptr<ParsingTreeNode> 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<ParsingTreeNode> 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<ParsingTreeNode> node)
{
vint index=members.Keys().IndexOf(name);
if(index!=-1)
{
Ptr<ParsingTreeNode> 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<ParsingTreeNode> 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<ParsingTreeNode> ParsingTreeArray::Clone()
{
Ptr<ParsingTreeArray> clone=new ParsingTreeArray(elementType, codeRange);
for(vint i=0;i<items.Count();i++)
{
Ptr<ParsingTreeNode> 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<ParsingTreeNode> ParsingTreeArray::GetItem(vint index)
{
if(0<=index && index<items.Count())
{
return items[index];
}
else
{
return 0;
}
}
bool ParsingTreeArray::SetItem(vint index, Ptr<ParsingTreeNode> node)
{
if(0<=index && index<items.Count())
{
items[index]=node;
return true;
}
else
{
return false;
}
}
bool ParsingTreeArray::AddItem(Ptr<ParsingTreeNode> node)
{
return InsertItem(items.Count(), node);
}
bool ParsingTreeArray::InsertItem(vint index, Ptr<ParsingTreeNode> 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<items.Count())
{
Ptr<ParsingTreeNode> 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<ParsingTreeNode>, node, items)
{
if(!BeforeRemoveChild(node)) return false;
}
FOREACH(Ptr<ParsingTreeNode>, 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<IParsingPrintNodeRecorder> recorder)
{
recorders.Add(recorder);
}
void ParsingMultiplePrintNodeRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)
{
FOREACH(Ptr<IParsingPrintNodeRecorder>, recorder, recorders)
{
recorder->Record(node, range);
}
}
/***********************************************************************
ParsingEmptyPrintNodeRecorder
***********************************************************************/
ParsingOriginalLocationRecorder::ParsingOriginalLocationRecorder(Ptr<IParsingPrintNodeRecorder> _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<IParsingPrintNodeRecorder> _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<vl::regex::RegexToken>& 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<JsonNode>, 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<JsonObjectField>, 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<JsonNode> node, stream::TextWriter& writer)
{
JsonPrintVisitor visitor(writer);
node->Accept(&visitor);
}
WString JsonToString(Ptr<JsonNode> 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 = 4313; // 20568 bytes before compressing
const vint parserBufferBlock = 1024;
const vint parserBufferRemain = 217;
const vint parserBufferRows = 5;
const char* parserBuffer[] = {
"\x00\x0B\x00\x02\x83\x80\x07\x7D\x00\x82\x03\xFF\x45\x08\x82\x83\x20\x01\x37\x00\x6C\x0F\x80\x02\x38\x03\x82\x86\x06\x0C\x80\x13\x20\x04\x38\x8A\x00\x69\x00\x2E\x20\x07\x35\x83\x8A\x84\x0A\x9A\x8E\x90\x82\x88\x89\x8B\x93\x04\x87\x1A\x81\x2D\x8D\x9A\x26\x00\x61\x00\x2D\x20\x05\x36\x92\x8D\x94\x0C\xAB\x91\x93\x8F\x92\x8E\x98\x86\x4B\x3C\x80\x19\x30\x07\x38\xA2\x00\x64\x3E\x8C\x80\xA8\x82\xA1\x97\x8F\x30\x83\x87\xA8\x89\xA5\x9C\xA6\xA7\x2E\xD0\x92\xA8\x9B\x81\xA3\x89\xAB\x45\x8C\x9B\xA4\x8D\xAB\xA5\xA7\xA7\x51\x86\xBF\x85\xB5\xAF\xB3\xA7\xAC\x02\x88\x1A\x82\x23\x8D\x3A\x90\xB1\x39\x95\x8C\xB2\xB3\xAC\xB8\x82\xAB\x77\x9A\xBA\xAC\x8C\xB8\x8A\xBF\x91\x51\x81\xEE\xA4\xC4\xB2\x96\xBB\xB0\x78\x80\x0B\xC8\x8D\xC0\x03\xC6\xC0\x1F\x83\xD9\xD4\xA7\xC7\xC8\xAC\xC5\x7B\xFD\xBF\xB1\xC1\xD3\xB0\x82\xD2\x03\x88\xD8\xDA\x89\x8C\x87\x9A\xBF\x3B\xE2\x0A\xB5\x84\xCF\xD4\x06\xCB\x10\xA3\x9E\x9D\x98\x3D\x9A\xD9\x8F\x1A\x80\x2B\xA3\x86\xC3\x80\x9B\x8A\x15\xB9\x83\xDF\x74\xED\xEB\x7F\xE5\x02\xCC\x20\x95\x9D\x99\xEB\xA0\xEB\xD6\x84\x1A\x97\x90\x89\xA9\x9E\xF0\xD5\xB5\xC8\x97\xDA\x98\x02\xDD\xEE\x05\xE8\xFF\x6A\xF4\x87\x26\xF6\x00\x6A\x4A\xA3\x35\x92\xFF\x7D\x80\x86\xF6\x7A\x69\x7D\x4F\xFB\x5E\x46\x13\x76\x3D\x52\x41\x5E\x7C\xF4\x43\x4C\x46\x47\x15\x61\x43\x49\x49\xFD\x58\x70\x01\x73\x02\x4F\x7F\x46\x74\x17\x9A\x41\x4B\x70\xED\x73\x11\x7C\x7A\x16\x9A\x7F\x87\x6E\x38\x43\x58\x84\x00\x76\x29\x82\x46\x5F\xE7\x4C\x83\x7A\x67\xED\x6F\x7F\x46\x85\xFB\x41\x7C\x77\x5F\x1E\x7D\x7D\x82\x40\x01\xB8\x7A\x7D\x4D\x3F\x80\x06\x18\x82\x43\x51\x52\x89\x7F\xFF\x48\x41\x93\x80\x00\x05\x80\x03\x81\x21\x49\x82\x5A\x78\x0C\x63\x49\x4F\x4E\x3D\x59\x6D\x91\x7D\xF7\x50\x92\x94\x95\x4A\x4A\x8D\x84\x43\x2D\xB9\x4F\x8A\x52\x3E\x9A\x4F\x83\x47\x12\xA4\x4A\x72\x46\x39\xBC\x8A\x52\x70\xC9\x40\x0F\x02\x46\x24\x1A\x4B\x9D\x9E\x80\x89\x4D\x7E\x7C\x81\xA8\x43\xA0\x7A\x85\xAF\x67\xA0\x78\x89\x82\xAB\xA1\x75\x09\x1A\x44\x14\x00\x52\x00\x05\x14\x00\x45\x00\x06\x14\x00\x34\x5A\x77\xA5\xA6\x58\x88\x40\x84\x8D\x3D\x49\x72\x02\x46\x0A\x1A\x47\x81\xA7\x1B\x58\xAA\xA4\xA7\x00\x1E\xAE\xAB\x8A\x47\xAA\x90\x02\x88\x5D\x9A\x43\x02\x46\x91\xB6\x66\xA5\xAC\xC0\x9B\xAC\xAB\xA7\x00\x21\xA4\x43\x48\x7E\x52\x42\x47\xA9\x0C\x46\xBA\x56\x46\xF6\x7C\x5A\x10\x00\xF6\x50\x1E\xAB\x4D\xCC\x88\x4C\x14\x00\x7B\x00\x0B\xAC\x43\x2B\x9B\x60\x9A\xB4\x00\x0E\x4A\x76\x7D\x1C\x59\xA9\xB4\x41\xDB\xBD\x15\xB0\x6D\x46\x73\x44\xA7\xBC\xD5\x97\xB0\x03\xBA\x03\x5B\xBB\x17\x99\x08\x56\x82\xBA\x73\xF3\x95\xA6\xB8\xB5\xAD\xAA\xBA\x47\xB6\x5D\x00\x05\x93\xBF\x02\x6B\x8E\x42\x7D\x4D\x00\x01\xC4\x4D\x99\x6C\x03\x9F\x54\xF2\x4E\xC4\xC3\xB9\x00\x37\x49\x66\x0E\x9A\x7F\x42\x8E\xAF\x97\x91\xCC\x5D\xA6\x95\x9F\x0A\x47\xBE\xDB\xAD\x00\x01\xC2\x3F\x00\x0B\xB5\x54\x2B\x00\x08\x08\x00\x2E\x32\xC2\x59\xCD\x29\x00\x01\xCF\xCD\xFB\xBD\x49\xA5\xC2\xFB\xB5\xCD\xCB\xCB\x3E\xFA\xC4\xCC\x00\x3D\xF1\xCD\xAC\x42\x4F\xC4\x45\x90\x47\x93\x95\xA9\x11\xC7\x00\x07\x10\x03\x06\x1A\x62\x06\xCC\x00\xFB\x9E\x1A\xCF\xB6\x5E\xC9\xCC\x1F\xD8\x60\xC0\x02\xDA\x5F\x66\xE8\xDE\x5F\xCC\xDC\x80\x04\x0C\x00\xEE\xBD\xCA\x08\x00\x5E\xE9\xAC\x42\xDE\x08\x59\x6B\x88\x47\xD6\xB4\x4E\x41\xA6\xDF\x9A\xB7\xAC\x00\x35\xDF\x9E\xA0\x78\x7D\x8C\x4C\xC0\x00\xD3\xA6\x8B\x8E\x77\x12\x52\x0A\x45\xE4\xDB\x60\x84\xE4\xCE\xF3\x90\x40\x46\x47\x6F\x92\x6E\x45\x03\x1A\x40\x10\x00\x08\x00\x3D\x9C\x0C\xE4\xC0\xA7\x80\x7E\xAD\x3E\x21\xCC\x40\xE6\xAE\xDB\x83\x52\x03\x97\xED\xE3\xE6\x8B\x9C\xE1\xEF\x46\x47\xBF\x4C\x46\xE8\xEA\xAB\xF4\xEB\xEC\xEC\xB2\xC8\x46\xF2\xE6\xBC\xFC\xD4\x43\xF2\x28\xB6\xA9\xCD\x0C\x00\x3A\x3A\x45\xF1\xBA\xCC\xF8\xF0\xC8\xA8\xF7\x45\xC8\x00\x27\xF3\xB8\xE8\xF7\x51\x93\x48\x9D\x4F\x78\xA8\xE9\x4E\x88\xDD\xF4\x89\x6C\x8A\xA6\xE4\xE9\xA8\xF6\x92\xDA\xF3\x51\xEC\xE4\xDE\xD3\xA8\x8C\x78\xE7\xE9\x88\xFB\xD9\x71\x7B\x50\x43\x7F\x2D\x13\x68\x0E\x7F\xDD\x48\x75\x9A\x43\x2C\x7E\xD4\x7D\x06\x7F\x5E\x73\x51\x45\x7C\x7E\x6A\xD4\x6E\x5A\x7E\x00\x14\x7D\xE6\x02\x82\x22\xFC\x50\x87\x2F\xC9\x43\x29\x05\xFF\x7E\x7F\xFA\x5C\x80\x00\x04\x8E\x2A\x01\x88\x8E\x7F\x05\xAB\x4D\x27\x0E\x9F\x80\x7B\x4A\x5D\x7E\x0B\x80\x00\x83\x1A\x95\x77\xE6\x1E\x88\x74\xAF\x75\x53\x28\xB8\x55\x84\x09\xA8\x76\x85",
"\xD7\x43\x86\x7F\x2A\x95\x27\x01\xA8\x79\x80\x16\x7C\x75\x81\x00\x0F\x81\x0F\xD3\x4C\x77\x20\xA3\x87\x82\x00\x13\x7C\xEB\x45\x86\x77\x0E\x80\x04\x7C\x54\x73\x5F\xD5\x37\x2A\x6B\xF1\x7E\x7D\x4E\xE7\x76\x4E\xFA\x07\x78\x75\x37\x51\x47\x2F\x25\x26\x77\xE3\x50\x76\x88\x89\x10\x01\x77\x5C\x9B\x71\xCE\x15\x5E\x73\x9A\x19\x50\x32\x37\x9C\x4D\x06\xDB\x8B\x83\x3A\x80\x01\x76\xA8\x66\x75\x91\x53\x5B\x52\x5B\x7C\x7B\x8E\xAF\x4E\x92\x52\x53\x71\x8B\xEB\x6C\x75\x91\x0C\x8A\x28\x0F\x80\x01\x04\xD6\x4F\x4B\x48\x1E\x31\x7D\x16\x83\x9C\x91\x27\x9A\x97\x8B\xFE\x7D\x93\xB4\x1A\x4E\x3A\xA6\x22\x92\x8B\xA5\x92\x91\x4F\x1B\x9A\x95\x00\x86\x92\x91\xB9\x64\x4E\x95\x51\x20\x92\x5D\x89\x4C\x73\x33\x08\x94\x43\x58\x7E\x96\x33\x5B\x91\x8C\x56\x78\x69\x19\xA8\x98\x74\x2D\x6D\x38\x86\xFD\x60\x67\x08\xB1\x99\x92\x68\xA4\x7E\x85\xA4\x5E\x7F\xFA\x7E\x7F\x92\x02\x75\x25\x98\x62\x38\x97\xEC\x30\x50\x3B\x14\x4C\x28\x92\xAC\x86\x9C\xE7\x32\x00\x00\x46\x16\x93\x95\x1F\x2D\x97\x21\xCC\x9D\x7F\x7D\x63\x83\x5F\xA8\x74\x9B\x0B\xFE\x74\x7D\xDA\x7B\x22\x44\x04\x8D\x8A\xD7\x16\x63\x9B\x48\x95\x9C\x9F\xFE\x7E\x9C\x1B\xF4\x6E\x7F\x84\x53\x89\x61\x23\x9B\x98\xEA\x69\x9C\x42\x1C\xAC\x74\xA2\x6E\x3B\x92\xD7\x76\x9E\x7E\x7C\x97\x96\x94\xD6\x89\xA3\x8E\x7F\x9E\x7E\xD3\x42\xA0\x00\x04\xBE\x7E\x3E\xD9\x96\x8C\xD4\x4A\xA0\x80\xEE\x48\x76\x43\xFD\x70\xA2\x6D\x8B\xA0\xA3\x4C\x2B\x92\x41\xFB\x98\x77\x71\x98\x93\x9F\x7B\x93\x23\xE7\x2E\x50\x90\xC5\x42\x22\x75\x1F\xB2\x97\x3C\x89\x9A\x61\x5C\x88\x4E\x4C\x3D\xAA\x78\x15\xD5\x4F\x97\xA0\xBD\x8E\x23\x7F\x82\x2E\x51\xA9\x74\x95\xA9\xA5\x4A\x2C\x88\x88\x87\xC5\x52\xAD\x9B\xF2\x5E\x21\x6A\x03\x33\x59\x59\xD2\x49\x67\x1A\x00\x04\x12\xEF\x84\x62\x80\x20\x93\x9F\xFC\x71\x6F\x9E\x2A\xBE\xAB\x2E\x88\xA8\x75\x23\x54\xAE\x4C\x00\x86\xA7\x07\xA9\xA9\x9E\xBD\xBF\x95\xA5\x46\x4F\xAA\x58\x30\xAD\xA1\x0F\xAE\x59\xA2\x0B\xAB\xAD\x4D\x16\xAA\xAD\x30\x74\xAA\xA3\x77\xBD\xA1\x5E\xE0\x91\x2A\xC4\xBE\xAF\xAB\x4A\x42\xAC\x13\x83\xB2\x89\x69\x5C\xB4\xAF\x89\xBF\xAF\x62\xFE\x71\xA6\xA4\x53\x8F\xB1\x36\xA0\x82\x64\x9E\x2A\xA6\x9C\x89\x7F\x79\xE4\x96\x74\x53\x39\x61\x99\x4C\x43\x9F\xA2\xF1\x8A\x9C\x66\x9C\xA8\x74\x8F\xAB\xA0\x8A\xFD\x83\xA7\x42\xA7\xA4\xB1\xA4\x87\xA0\xB1\x2F\xAC\xB5\x63\x8F\xA2\x88\x89\xB9\xB2\x9E\xE2\x92\xAA\x6D\xE8\x91\xB8\x0E\x79\x63\x6E\xBE\xA8\x20\xF6\x36\xB3\xB8\x21\x86\xBB\xA7\x2C\xB4\x9D\x74\xA3\xB3\x8B\x94\x84\x87\xB8\x4A\x30\xBA\x72\x8C\xB2\xA7\x0F\xB5\xA3\x8D\x00\x96\xB6\x85\x15\xB3\xAE\x6F\xA7\xA9\x77\xB3\xAB\x9C\x00\x57\x6F\xB6\xFE\x82\x4E\xBF\x75\xBF\x81\xB7\x78\xA5\xB1\xD3\x9E\xB2\xB1\xA1\xAC\xBD\xFF\x4D\xB6\xB4\x08\xE8\xB7\xB3\x7B\xB4\xBE\x6B\xFD\x70\xB6\xFC\x9C\x9E\xB2\x08\xC6\x77\x7E\xF2\xA7\xC0\xB3\x80\x00\xAD\x02\x26\xC2\x98\x35\x2C\xB7\x01\xF1\xA9\xC0\x98\xAB\xC2\x66\x8D\xC6\xC3\x07\xEA\xB1\xC2\x71\x6D\xBD\xFF\x6F\xB6\xB0\x33\x76\xC0\xB4\x0B\xAD\xB7\x4C\xDE\x6D\xC3\x21\xA4\xC3\xC5\xB4\xB9\x76\x6D\xD1\xA8\xB6\xDB\x96\xAB\x22\x58\xAB\x34\x40\x02\x93\xBD\xEE\x99\xA5\xA4\xFC\x58\xB4\x1F\xD0\xC3\xAC\x2D\xC2\xAC\xC5\x00\x14\x79\x09\x71\xAB\xCB\xA1\xB4\x96\x93\x20\xC6\xC7\x2B\xDD\xA5\xCD\x9A\x27\xC8\x9E\xE5\x9C\x42\x88\x80\xC9\xCC\x29\x68\xC0\xCD\xFD\xA6\xC4\x25\x84\xC2\xBC\x3C\xE5\xC2\x4A\x31\xDB\xC7\x8C\xAC\x7E\xC0\x7A\x98\xC7\x97\x00\x8C\xB9\x69\xBD\xC2\x2D\x1F\xD9\xC2\xBA\xF5\xAF\xB5\x75\x91\xB5\xCE\x22\x4A\xCE\xCA\xE7\x97\xD1\x9C\xEE\x24\x93\xF0\x84\x25\xCA\x9B\xCC\x29\x79\xDE\x64\x81\xF3\xBF\xA1\xBD\xC9\xA0\x44\x49\x92\xC3\xA1\x45\xE7\xD0\xB9\x22\xAA\xD5\x90\xD3\xB4\xA7\x49\xF9\xB8\xD3\x5D\xC9\xAF\x91\xF4\xAF\x4E\xB2\x95\xD6\x23\x4F\xC3\xA9\x56\xD1\x21\x78\x84\x08\xAA\xC5\x97\xB8\xCA\x4E\xA7\xBD\x96\x0B\xD4\x90\x64\x05\xCC\xD1\x54\x47\x90\x01\xAA\x6E\xC4\x8C\xA8\xAE\x98\x97\x22\xB1\x9A\x57\xE0\xA0\xB5\xD8\x90\x8A\x75\x81\xC7\xB5\x15\x53\x5D\xCD\xA3\x79\x74\xBA\x9C\x7B\xDD\x61\xE3\x94\x21\xC7\xDD\x70\x97\xE1\xA9\xBA\xDC\x8C\xDE\xA9\x37\xC2\xC0\xB4\xFD\xC5\xC3\x7C\xD4\xDE\xDA\x63\x99\x69\xB6\xA9\x4B\xDB\x29\x92\x9C\xDB\xF0\xA1\xA6\x02\xDF\xDE\xC2\xD4\x64\xDE\xC2\xCB\xD6\xC3\x1D\xE3\x97\xB5\x60\xF5\x26\x77\x15\x3E\x23\x56\x84\x81\xDF\xD3\xB1\x71\xE2\xF9\xC5\xDA\xBD\xCE\xDD\x54\x8F\x22\x77\xDD\x08\x24\x80\x31\x96\xCF\xE2\x4D",
"\xFA\xB0\x00\x13\xFA\xB8\xAE\x96\xE0\x75\x9A\x27\xE3\xE3\xFE\x71\xDC\x79\xCD\xA3\x9C\xDB\xA2\xE2\xD7\x4E\xC5\xE5\x8A\x19\xE8\xE4\x82\x2A\xE0\xB8\xA1\xD3\x9E\x4E\xAF\xDA\x29\x98\xF8\xB4\xE9\x3D\x34\xE6\xD0\xB7\xE5\x75\x9C\xDD\xA8\xEA\x4A\xF9\x74\xD6\xBF\xE9\xC4\xF4\xBC\x79\x67\x18\xF5\x26\xF3\x03\x27\xE9\x84\xF3\x9E\xDC\xF2\xC3\xA9\xAF\xDE\xC7\xAA\x76\xDF\xCD\xE6\x26\xFF\x75\xD1\xE4\xE6\xEA\xEC\x6B\xD9\x76\x68\xEB\xDF\x56\xE7\xDF\xED\xDE\x76\xE2\xEE\x77\xC5\xED\xDA\xEE\xC9\xD7\xAE\xC1\xC1\x02\x74\xD9\xCC\x5B\x83\xF0\xEF\xA1\xF5\x24\xEB\xDC\xD1\xDC\x8C\x85\xFE\xCE\x24\xC1\x93\x9C\x01\xC0\xEF\xDF\xC4\xE8\xE6\xE2\x55\xF1\xD9\x90\x99\x8D\xF3\x78\x85\x91\x2E\x82\xC6\x7A\xD1\xC2\xF7\xF6\x1F\x88\x59\xA1\x12\x20\xB2\x00\x8A\xF7\x50\x28\x79\x88\x8F\x0B\x89\xC7\x4E\x8A\xA9\x0C\xD3\x83\x86\x11\x92\xBB\xCD\x39\x87\x7B\xFD\x74\x9A\x7F\x8F\x14\x81\xB6\x25\x85\xF7\xE6\x34\xFB\x83\xDB\xCD\x89\xDC\xF1\xB5\x93\x14\x92\x89\x9B\x2B\xA2\xAC\xB2\xB6\x86\xF4\x66\xBF\x82\x22\x2B\x88\xFC\x88\xCA\xFC\x74\xF3\xAB\x82\xC2\xE8\xD0\x9A\x8A\xFD\x67\x42\xAD\x5E\xF6\x86\xE0\xC4\x92\x87\xBC\x7B\x92\xF7\x12\x60\x7C\x57\x55\x50\xB1\x68\x9B\x45\xFA\x46\xCC\x3D\xF7\x70\x3E\xFD\x74\x4A\x7D\xF4\x48\x4C\xD7\x62\x70\xF8\x76\x3E\xFA\x75\x13\x0D\x72\x74\x6F\x43\x21\x62\x50\x72\x40\x6D\x6C\xF9\x6F\x5D\xC2\x4C\x6F\xD2\x69\x60\x6D\x45\x6D\x62\x4A\x4C\x03\x7B\x25\xD1\x7E\x35\x07\x75\x58\x58\x78\x58\xE6\x7F\x7D\xBB\x68\x60\xA7\x55\x6F\x40\x78\x6B\xDC\x59\x74\x6D\x5E\x2A\xD1\x6B\x73\x76\x54\x5C\x69\x32\x82\x0C\x7A\x5E\xF3\x5C\x42\x3A\x65\x50\x23\x88\x83\xB2\x6A\x61\x43\x68\x34\xB0\x7E\x3F\xB6\x53\x67\x98\x7F\x6B\x27\x69\x78\x7F\x60\x66\x73\x3C\x67\x9F\x6F\x79\x08\x61\x68\x0C\x64\x68\x35\x66\x68\x16\x69\x68\xA4\x55\x50\x85\x64\x3E\x87\x60\x58\x90\x6B\x61\x44\x66\x6B\x1F\x6A\x78\x35\x1A\x82\x79\x14\x7A\xF0\x76\x2B\xCE\x22\x10\xE4\x12\x16\xA5\x2D\x28\x23\x20\x1E\x10\x8B\x57\x5B\x5F\x70\xF9\x69\x1C\x16\x02\x32\xE8\x15\x5B\xB8\x6B\x22\xB6\x59\x1C\x18\x0A\x87\x72\x8A\x75\xDF\x6B\x86\x58\x35\x1E\x4A\x19\x1C\x1A\x02\x88\xD6\x19\x77\x7D\x76\x88\x6D\x86\x1E\x79\x2C\x01\x8C\x85\x1D\x23\x61\x60\x45\x21\x60\xC9\x1E\x01\x95\x84\x1D\x1C\x08\x2F\xAE\x19\x10\xC9\x19\x19\x70\x85\x8A\x81\x2D\x1B\x09\x16\x88\xA0\x86\x8A\xAB\x86\x88\xC9\x1B\x22\x25\x86\x88\xD4\x7F\x48\x68\x82\x7C\x12\x15\x8A\x25\x21\x7E\xB6\x29\x1C\xA1\x7A\x8B\xDF\x13\x1A\x2B\x2B\x8A\xA5\x8D\x8A\x70\x80\x8B\xDF\x6B\x22\xEA\x70\x44\x4A\x1D\x8B\x69\x83\x14\xB8\x8A\x11\xB2\x77\x8B\xA8\x13\x4E\xD1\x81\x8A\x02\x13\x1F\x1A\x12\x8C\x70\x84\x8C\x8D\x26\x8C\x4A\x50\x89\x34\x24\x43\xCC\x86\x8B\xA6\x89\x8B\xCD\x82\x8D\x8E\x35\x8B\xF6\x38\x8E\x09\x13\x1A\xA4\x3C\x10\xDA\x8D\x28\xAB\x84\x8A\xF1\x2C\x10\xF9\x70\x22\x78\x2C\x8B\xEA\x87\x42\xA5\x85\x24\xFD\x77\x1F\xF0\x1A\x8F\xD4\x8E\x8B\x12\x18\x8A\xD7\x8C\x64\x03\x11\x8F\x89\x23\x8F\x70\x88\x23\x08\x88\x8F\x35\x12\x90\x52\x55\x8D\xFD\x8E\x26\x35\x1D\x80\x72\x22\x91\xB8\x54\x91\x06\x96\x8D\xDE\x26\x8A\x8D\x2D\x91\xFF\x0C\x8D\x89\x29\x19\x5C\x30\x8F\xF0\x2C\x10\x27\x90\x92\x03\x13\x8E\xEB\x8F\x91\x2C\x91\x28\x4B\x7F\x6D\x31\x99\x1C\x22\x99\x19\x16\x25\x93\x09\x15\x38\xAF\x1B\x8A\x2B\x23\x8A\x1A\x15\x01\xD9\x89\x92\x08\x12\x94\x3A\x93\x93\x4A\x54\x8F\xE0\x2A\x11\x25\x89\x1C\x73\x8F\x4B\x23\x94\x94\x85\x29\x19\x88\x78\x92\x18\x1A\x11\x55\x95\x93\x48\x97\x50\x0A\x94\x10\x2B\x21\x5D\x4E\x9E\x72\xF2\x41\x95\x57\x9D\x28\x5E\x23\x94\x65\x98\x10\x5B\x55\x91\x3E\x5F\x6D\x5D\x9C\x1C\x1E\x29\x83\x61\x9D\x73\xB8\x69\x28\x37\x93\x8D\x35\x9A\x94\x89\x25\x87\x48\x87\x5A\x73\x92\x55\xA7\x54\x96\x28\x1B\x8A\x77\x60\x94\x0C\x1E\x74\x03\x1C\x93\x2C\x9C\x97\x64\x86\x20\x16\x6F\x97\x23\x79\x6F\x45\x28\x98\x20\x9F\x94\x66\x2F\x96\x02\x15\x24\x5D\x8B\x5A\xC9\x17\x89\x48\x82\x98\x04\x15\x98\x1A\x19\x19\xEF\x88\x10\x8A\x90\x92\x8C\x9B\x84\x8E\x97\x87\x52\x9A\x6B\xA7\x55\x24\xA5\x91\x93\x96\x92\x16\x98\x9C\x73\x08\x1B\x99\xA1\x5D\x99\x4A\x86\x79\x3A\x92\x92\x63\x72\x10\xBF\x9A\x93\xED\x8F\x13\x5B\x5B\x96\xC2\x97\x9C\xA6\x82\x92\x8F\x30\x79\xC8\x9E\x91\xFE\x1A\x11\xB1\x9D\x9C\x28\x13\x1A\x99\x18\x90\x20\x9A\x97\x85\x2E\x87\x75\x9D\x9A\x5D\x76\x5B\xA0\x99\x10\xAB\x8B\x76\x81\x29\x19\x1D\x0A\x2B\xC2\x9A\x9D\x49\x70\x99",
"\x2B\x89\x74\x45\x25\x9E\x47\x92\x96\xEA\x47\x9A\xC8\x9E\x88\x6D\x7F\x9D\x02\x1E\x8A\xA3\x9A\x11\x2B\x94\x10\xF2\x95\x8A\xE8\x9F\x72\xEA\x9D\x9D\xB8\x65\x24\xFB\x9C\x92\x7C\x89\x74\xFD\x92\x9C\x5B\x9B\x4F\xA5\x82\x92\xAA\x82\x9C\x86\x8B\x22\xC6\x9D\x28\x07\xAF\x72\x2B\x25\xA0\x95\x94\x88\xDF\x85\x8C\x4C\x95\x88\x92\x26\x7C\xCB\x8B\x8F\x86\x4F\x8C\x0C\x14\x91\x78\x9B\x91\x04\x9E\x9C\xC1\x80\xA1\x1A\x12\xA1\x0A\xA0\x9F\x1C\x27\xA1\x2F\xAD\x96\x1B\xAD\x8D\x1D\xAA\x54\xC8\x85\x45\x21\xA3\x90\xE7\x85\x8E\xD0\x89\xA2\x1A\x9A\x6B\xD5\x82\x92\x45\x25\x9B\xC9\x11\xA1\x1A\x13\xA1\x89\x25\xA1\xF2\x42\xA3\xEF\x94\xA3\x07\x58\x9F\x4B\x98\x26\x1E\xAE\x2B\x21\x42\x11\x2E\x9C\x8F\x0D\x9F\xA3\x3D\xA1\xA4\x5D\x73\xA4\xA3\x16\x21\x94\x9C\x8A\x2D\xA9\xA4\x33\xA2\x73\x49\x7E\xA4\x5A\x9A\xA1\x07\x5E\x9C\x77\x69\x95\x31\x9E\x93\x66\xAF\xA4\x68\xA6\xA1\xFA\x97\xA6\x4F\x74\x93\xD7\x8E\x8E\x68\x95\x93\x48\xAC\x10\x4A\xA5\x28\x4C\xAA\x4E\x6A\xA2\x9B\x6C\xAB\x4F\xD8\x9F\x2C\xF6\x8F\x90\x77\x21\x91\x27\xA2\xA4\x40\xA0\x87\xFE\x8E\x3E\x00\x98\x1C\x8F\xAF\xA5\x29\xA2\x92\xD6\x97\x2F\x2C\xA3\xA5\x6A\x98\xA7\xEB\x96\xA7\x2A\x90\xAA\x5D\x78\x75\x89\xA2\x10\x0E\x9A\x23\x10\x9E\x11\x5E\xAF\x7E\xE4\x8C\x96\x08\x1E\x46\xDB\x1E\x80\xAD\xA1\x80\x9B\x3E\x9C\x99\x16\x39\x3A\x97\xAA\x79\x29\x89\x48\x8A\x9B\x47\x8D\x98\x05\x1B\x8A\xF6\x9A\x27\x70\x84\x9E\xE6\x94\xA7\x60\x22\xAC\xC0\xAE\x6B\xC2\xAD\x9E\xC2\x9E\x99\xC2\xA9\xA0\x3A\x94\x9F\x5C\x65\xAC\x52\xAD\x37\x77\xAC\x10\xD4\xAB\xA4\xD0\x2F\xAB\xF5\x8E\xAC\xAA\x96\x9B\x04\x18\xA1\x3E\xA1\xAC\xE3\xAD\xAD\x86\xA0\xA5\x0C\xA8\x9C\x9A\xAA\x11\x13\x02\x9C\x72\xAC\x10\xD1\x90\x92\xD2\xA3\xAE\xBC\xA6\x88\xDA\x69\x88\xDC\x94\x85\xAC\x91\x92\xD4\x9A\x11\x14\x02\x9D\xEE\xA3\x1A\xCB\x94\xB0\x36\x93\x1A\x9B\xA1\xAF\x3A\x93\xAF\x08\x13\xA6\x24\xA2\xAE\x96\x79\xAF\x1A\x1B\xAF\x6F\x89\x96\x91\x90\x64\xAF\x13\x1A\x0F\xAA\x93\x7F\xA8\x10\x70\xA6\xA0\x30\xAE\x16\x85\xA2\xB2\xEC\xA9\x4D\xD9\xAE\x95\x37\xA1\xA5\x1F\xA3\x41\x3B\xA3\x91\x91\xAD\x28\xE6\x8F\xAA\x97\xAE\xAA\x2F\x92\x92\x2B\xAE\xB1\x65\xAC\x10\x21\xB9\xA1\x74\x99\xA6\xDB\xAB\xA6\x27\xBC\x3F\x29\xB0\x97\x54\xA8\xA3\xAA\x2A\xA3\x3D\x19\xA5\x23\xAB\xA5\x25\xA1\xB3\x08\x1C\xB4\xA6\x74\xA4\x7D\xA1\x93\x1F\xB4\x10\x3D\xB6\x8A\x83\xA1\xA3\x41\xBB\xAE\x52\x58\x75\x45\xBD\x30\x2B\xBB\x4F\xE0\x87\xA5\xB7\x50\xA9\x5D\xAE\xB4\x08\x16\xA2\xE9\x8C\xA3\xE4\x82\x92\x62\xA2\xAF\x3B\xB0\xB2\xA4\xA8\x74\xA2\xA8\x10\xE6\xA0\xAB\x79\xAA\x54\x6E\xA8\x95\x72\xBE\xA9\x58\xB5\xB7\x70\x67\xB7\xE5\xA2\xB8\x5E\x7C\x26\xA3\x11\x9C\xC1\x9D\x9C\x22\x95\xAF\x9C\xAA\xB3\x80\xB3\x10\x59\xBA\xB7\xA1\xAD\xA4\x5D\xB6\xB2\x5F\xBF\x6D\xBC\xA9\xAA\x76\x28\x3E\x8E\xAD\xB6\x30\xB9\xB6\x14\xA3\x23\xB8\x15\xA9\x15\x15\xAB\xD9\x7B\x39\xEF\xA6\x95\x7E\xA3\xB7\x81\xBA\xAC\x95\xB4\xA8\x97\xBE\xB3\x99\xB9\x94\x6A\xB4\x10\xF7\x8D\xA8\xAC\xA5\xB3\xB6\xAC\x3B\x94\xB2\x10\xB2\xA1\x27\x25\x18\xBA\x6C\xB7\x9C\x22\x90\x79\x46\x98\xB0\x35\x9E\xA0\x55\xBC\x92\x57\xB3\x10\xC9\xBE\xB5\x19\xBB\x57\x25\xB4\xBB\x7B\xBC\xB2\x36\xA7\xB4\xD8\xB8\x10\xB3\x8F\xB2\x28\xA2\xBA\x89\x23\xB3\x2F\x94\xBC\x99\xA0\x8C\xCD\xB0\x92\xCF\xB2\x10\xD1\xB8\xB9\xD3\xBF\x4B\xD5\xBA\xB5\x87\xA8\xB2\x1C\xAA\xBD\xFB\x49\xA3\xEB\x7E\xBD\x68\xB4\xB3\x32\xBC\xA5\xFA\xB1\xB5\x22\xA3\xB5\xA3\x15\xA4\x9D\xA8\x10\x2B\x2B\xBE\xD6\xBE\x9A\x16\x6F\xBE\xBF\xBE\x5C\x64\xB3\xBF\x08\x11\x8B\xA4\xBE\x7A\x67\xB8\xA9\xE0\xB5\x28\xE2\xBA\xA5\xA0\xBF\xBD\x6F\xB1\xA6\x1A\x10\xB1\xDB\x8E\xBA\xD0\xB6\xB8\xE5\x63\xBB\xF0\xB3\xB4\x89\x82\x92\x6F\xAF\xB7\x04\xC1\x94\x22\xC9\xC0\x24\xCB\xC0\x66\x73\x9C\x53\x1E\xB8\x46\xAA\x11\xE9\xB0\x00\x06\xC5\xC2\x80\x9E\xC2\xA3\xA0\xBB\xA5\xAA\xB9\xB7\xB3\x10\xB9\xBE\xB9\xBB\xB9\xC1\xF9\xB3\xBE\x92\xA1\xC1\xFE\x76\xA9\x46\xC4\xC1\x1B\xCF\x13\x9B\xA5\xC3\xCD\x20\xC2\xEA\xBD\xC2\xF9\x6A\xC0\x49\xC6\xC2\xB9\x2B\xBF\x8B\xAA\xAA\xBA\xB9\x27\x52\xB7\xAB\x59\xC1\xAB\x17\x93\xAB\x19\x9C\xBB\xA9\xBC\x3B\x22\x99\x1C\x17\x0A\xBC\x08\xBB\xBA\x08\x1C\xB0\x79\x99\x9F\x8D\x2A\xAF\x04\x7C\xAF\x18\xB8\xC0\xF9\x6B\xC6\x1A\x19\x01\x6E\xC2\x9C\x28\xCE\xB7\x7F\xC2\xC3\x28\x19\x1C\x79\xB3\xC8\x09\xBF\x13\x1D\xB5\x93\xF2\x98\xC5\xA3\xBA\xC5\xEF\x29\xBD\x0F\xC5\xA5\xDC",
"\xB0\xA2\x4B\xBF\xBF\x62\xCC\xC5\x6B\xB0\xB5\x04\x11\xC6\x6A\xC6\xBE\xAC\xB1\x93\x8D\xCF\xC2\x63\xC7\xBD\x0D\xC2\xC9\x04\x15\x82\xF6\xBA\x8C\x97\xCE\xB6\x48\xCA\xC9\x04\x15\xBC\x9D\xC8\xC9\x9F\xCF\x13\x02\xCA\x93\xA3\xCD\xC3\x42\xB5\xBB\xDB\xB9\x9D\x63\xB2\xBF\x56\xA2\xC1\x9E\xCB\x8B\x41\xC9\x1D\x9C\xCD\x92\xB4\xC6\x2B\x70\xBD\xC1\xC2\x9E\x37\xA4\xCF\xC8\xBC\xCC\xA0\x81\xCC\xB3\xCD\xC4\xC5\x5B\x36\xB8\x58\x74\xC8\xAF\x14\xC3\xC2\x99\xCB\x78\xB8\xCD\x40\xC0\xCB\x42\xCC\xA8\x44\xC0\xC6\xC9\xCE\x8C\xA5\xC3\x10\xFF\x86\x23\xA7\xB8\xC6\x60\xA0\xC5\xE7\xB6\x8A\xDE\xC5\xB8\x3E\xCC\xC0\xD9\x4B\xB9\x74\x24\xCE\x76\x24\xBE\x15\xC2\x93\x16\x93\x2A\xC2\xB6\xCE\xAE\xC7\x42\x7C\xCC\x10\xEE\x98\xC8\x0D\xAC\xC1\x87\x95\xCD\x91\xB2\x10\x07\xD1\x93\xD6\xA3\x54\x7D\xB4\xCD\xBB\xA6\xCD\x0F\xDC\x92\x11\xDF\xB9\x7B\xAF\x13\xC9\x1A\x32\x08\xD9\xD0\x3F\x11\xB7\x1F\xD3\xD2\xC7\x90",
};
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<vl::vuint8_t> 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<vl::regex::RegexToken>& 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<vl::parsing::ParsingTreeNode> node, const TokenList& tokens)
{
vl::Ptr<vl::parsing::ParsingTreeToken> token=node.Cast<vl::parsing::ParsingTreeToken>();
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<JsonNode> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
}
void Fill(vl::Ptr<JsonLiteral> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
SetMember(tree->value, obj->GetMember(L"value"), tokens);
}
void Fill(vl::Ptr<JsonString> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
if(SetMember(tree->content, obj->GetMember(L"content"), tokens))
{
JsonUnescapingString(tree->content, tokens);
}
}
void Fill(vl::Ptr<JsonNumber> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
SetMember(tree->content, obj->GetMember(L"content"), tokens);
}
void Fill(vl::Ptr<JsonArray> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
SetMember(tree->items, obj->GetMember(L"items"), tokens);
}
void Fill(vl::Ptr<JsonObjectField> tree, vl::Ptr<vl::parsing::ParsingTreeObject> 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<JsonObject> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
SetMember(tree->fields, obj->GetMember(L"fields"), tokens);
}
vl::Ptr<vl::parsing::ParsingTreeCustomBase> ConvertClass(vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)override
{
if(obj->GetType()==L"Literal")
{
vl::Ptr<JsonLiteral> tree = new JsonLiteral;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<JsonNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"String")
{
vl::Ptr<JsonString> tree = new JsonString;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<JsonNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"Number")
{
vl::Ptr<JsonNumber> tree = new JsonNumber;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<JsonNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"Array")
{
vl::Ptr<JsonArray> tree = new JsonArray;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<JsonNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"ObjectField")
{
vl::Ptr<JsonObjectField> tree = new JsonObjectField;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<JsonNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"Object")
{
vl::Ptr<JsonObject> tree = new JsonObject;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<JsonNode>(), obj, tokens);
return tree;
}
else
return 0;
}
};
vl::Ptr<vl::parsing::ParsingTreeCustomBase> JsonConvertParsingTreeNode(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
JsonTreeConverter converter;
vl::Ptr<vl::parsing::ParsingTreeCustomBase> tree;
converter.SetMember(tree, node, tokens);
return tree;
}
/***********************************************************************
Parsing Tree Conversion Implementation
***********************************************************************/
vl::Ptr<JsonLiteral> JsonLiteral::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonLiteral>();
}
vl::Ptr<JsonString> JsonString::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonString>();
}
vl::Ptr<JsonNumber> JsonNumber::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonNumber>();
}
vl::Ptr<JsonArray> JsonArray::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonArray>();
}
vl::Ptr<JsonObjectField> JsonObjectField::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonObjectField>();
}
vl::Ptr<JsonObject> JsonObject::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonObject>();
}
/***********************************************************************
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<vl::parsing::ParsingTreeNode> JsonParseAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex)
{
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
state.Reset(L"JRoot");
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
return node;
}
vl::Ptr<vl::parsing::ParsingTreeNode> JsonParseAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
{
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
return JsonParseAsParsingTreeNode(input, table, errors, codeIndex);
}
vl::Ptr<JsonNode> JsonParse(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex)
{
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
state.Reset(L"JRoot");
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
if(node && errors.Count()==0)
{
return JsonConvertParsingTreeNode(node, state.GetTokens()).Cast<JsonNode>();
}
return 0;
}
vl::Ptr<JsonNode> JsonParse(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
{
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
return JsonParse(input, table, errors, codeIndex);
}
/***********************************************************************
Table Generation
***********************************************************************/
vl::Ptr<vl::parsing::tabling::ParsingTable> JsonLoadTable()
{
vl::stream::MemoryStream stream;
JsonGetParserBuffer(stream);
vl::Ptr<vl::parsing::tabling::ParsingTable> 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<JsonLiteral>(), 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<JsonString>(), 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<JsonNumber>(), 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<JsonArray>(), NO_PARAMETER)
CLASS_MEMBER_FIELD(items)
END_CLASS_MEMBER(JsonArray)
BEGIN_CLASS_MEMBER(JsonObjectField)
CLASS_MEMBER_BASE(JsonNode)
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<JsonObjectField>(), 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<JsonObject>(), 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<JsonNode::IVisitor>(Ptr<IValueInterfaceProxy>), {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<ITypeLoader> 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<vl::Ptr<XmlNode>>& value, const vl::collections::List<vl::regex::RegexToken>& 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<XmlText>())
{
if(end==-1) end=i;
}
else
{
if(end!=-1) begin=i+1;
}
if(begin!=-1 && end!=-1)
{
vint tokenBegin=value[begin].Cast<XmlText>()->content.tokenIndex;
vint tokenEnd=value[end].Cast<XmlText>()->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<tokens.Count()-1)
{
if(tokens.Get(tokenEnd+1).token==(vint)XmlParserTokenIndex::SPACE || tokens.Get(tokenEnd+1).token==-1)
{
tokenEnd++;
}
else
{
break;
}
}
const RegexToken& beginToken=tokens.Get(tokenBegin);
const RegexToken& endToken=tokens.Get(tokenEnd);
const wchar_t* textBegin=beginToken.reading;
const wchar_t* textEnd=endToken.reading+endToken.length;
WString text(textBegin, vint(textEnd-textBegin));
ParsingTextRange range(&beginToken, &endToken);
Ptr<XmlText> 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<vl::regex::RegexToken>& tokens)
{
value.value=XmlUnescapeValue(value.value.Sub(1, value.value.Length()-2));
}
void XmlUnescapeCData(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
value.value=XmlUnescapeCData(value.value);
}
void XmlUnescapeComment(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& 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<XmlAttribute>, att, node->attributes)
{
writer.WriteChar(L' ');
att->Accept(this);
}
if(node->subNodes.Count()==0)
{
writer.WriteString(L"/>");
}
else
{
writer.WriteChar(L'>');
FOREACH(Ptr<XmlNode>, subNode, node->subNodes)
{
subNode->Accept(this);
}
writer.WriteString(L"</");
writer.WriteString(node->name.value);
writer.WriteChar(L'>');
}
}
void Visit(XmlInstruction* node)
{
writer.WriteString(L"<?");
writer.WriteString(node->name.value);
FOREACH(Ptr<XmlAttribute>, att, node->attributes)
{
writer.WriteChar(L' ');
att->Accept(this);
}
writer.WriteString(L"?>");
}
void Visit(XmlDocument* node)
{
FOREACH(Ptr<XmlNode>, 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"&lt;";
break;
case L'>':
result+=L"&gt;";
break;
case L'&':
result+=L"&amp;";
break;
case L'\'':
result+=L"&apos;";
break;
case L'\"':
result+=L"&quot;";
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"&lt;", 4)==0)
{
result+=L'<';
reading+=4;
}
else if(wcsncmp(reading, L"&gt;", 4)==0)
{
result+=L'>';
reading+=4;
}
else if(wcsncmp(reading, L"&amp;", 5)==0)
{
result+=L'&';
reading+=5;
}
else if(wcsncmp(reading, L"&apos;", 6)==0)
{
result+=L'\'';
reading+=6;
}
else if(wcsncmp(reading, L"&quot;", 6)==0)
{
result+=L'\"';
reading+=6;
}
else
{
result+=*reading++;
}
}
return result;
}
WString XmlEscapeCData(const WString& value)
{
return L"<![CDATA["+value+L"]]>";
}
WString XmlUnescapeCData(const WString& value)
{
return value.Sub(9, value.Length()-12);
}
WString XmlEscapeComment(const WString& value)
{
return L"<!--"+value+L"-->";
}
WString XmlUnescapeComment(const WString& value)
{
return value.Sub(4, value.Length()-7);
}
void XmlPrint(Ptr<XmlNode> node, stream::TextWriter& writer)
{
XmlPrintVisitor visitor(writer);
node->Accept(&visitor);
}
void XmlPrintContent(Ptr<XmlElement> element, stream::TextWriter& writer)
{
XmlPrintVisitor visitor(writer);
FOREACH(Ptr<XmlNode>, node, element->subNodes)
{
node->Accept(&visitor);
}
}
WString XmlToString(Ptr<XmlNode> node)
{
MemoryStream stream;
{
StreamWriter writer(stream);
XmlPrint(node, writer);
}
stream.SeekFromBegin(0);
{
StreamReader reader(stream);
return reader.ReadToEnd();
}
}
/***********************************************************************
Linq To Xml
***********************************************************************/
Ptr<XmlAttribute> XmlGetAttribute(Ptr<XmlElement> element, const WString& name)
{
return XmlGetAttribute(element.Obj(), name);
}
Ptr<XmlElement> XmlGetElement(Ptr<XmlElement> element, const WString& name)
{
return XmlGetElement(element.Obj(), name);
}
collections::LazyList<Ptr<XmlElement>> XmlGetElements(Ptr<XmlElement> element)
{
return XmlGetElements(element.Obj());
}
collections::LazyList<Ptr<XmlElement>> XmlGetElements(Ptr<XmlElement> element, const WString& name)
{
return XmlGetElements(element.Obj(), name);
}
WString XmlGetValue(Ptr<XmlElement> element)
{
return XmlGetValue(element.Obj());
}
Ptr<XmlAttribute> XmlGetAttribute(XmlElement* element, const WString& name)
{
FOREACH(Ptr<XmlAttribute>, att, element->attributes)
{
if(att->name.value==name)
{
return att;
}
}
return 0;
}
Ptr<XmlElement> XmlGetElement(XmlElement* element, const WString& name)
{
FOREACH(Ptr<XmlNode>, node, element->subNodes)
{
Ptr<XmlElement> subElement=node.Cast<XmlElement>();
if(subElement && subElement->name.value==name)
{
return subElement;
}
}
return 0;
}
collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element)
{
return From(element->subNodes)
.FindType<XmlElement>();
}
collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element, const WString& name)
{
return From(element->subNodes)
.FindType<XmlElement>()
.Where([name](Ptr<XmlElement> e){return e->name.value==name;});
}
WString XmlGetValue(XmlElement* element)
{
WString result;
FOREACH(Ptr<XmlNode>, node, element->subNodes)
{
if(Ptr<XmlText> text=node.Cast<XmlText>())
{
result+=text->content.value;
}
else if(Ptr<XmlCData> text=node.Cast<XmlCData>())
{
result+=text->content.value;
}
}
return result;
}
/***********************************************************************
XmlElementWriter
***********************************************************************/
XmlElementWriter::XmlElementWriter(Ptr<XmlElement> _element, const XmlElementWriter* _previousWriter)
:element(_element)
,previousWriter(_previousWriter)
{
}
XmlElementWriter::~XmlElementWriter()
{
}
const XmlElementWriter& XmlElementWriter::Attribute(const WString& name, const WString& value)const
{
Ptr<XmlAttribute> 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<XmlElement> 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<XmlText> node=new XmlText;
node->content.value=value;
element->subNodes.Add(node);
return *this;
}
const XmlElementWriter& XmlElementWriter::CData(const WString& value)const
{
Ptr<XmlCData> node=new XmlCData;
node->content.value=value;
element->subNodes.Add(node);
return *this;
}
const XmlElementWriter& XmlElementWriter::Comment(const WString& value)const
{
Ptr<XmlComment> 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\t@Color(\"Boundary\");"
L"\r\n" L"token INSTRUCTION_CLOSE = \"/?/>\"\t\t@Color(\"Boundary\");"
L"\r\n" L"token COMPLEX_ELEMENT_OPEN = \"/<//\"\t\t@Color(\"Boundary\");"
L"\r\n" L"token SINGLE_ELEMENT_CLOSE = \"///>\"\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 = \"/</!/[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} \"</\" NAME:closingName \">\") as Element;"
L"\r\n" L"rule Node XSubNode = !XText | !XCData | !XComment | !XElement;"
L"\r\n" L"rule Instruction XInstruction = \"<?\" NAME:name {XAttribute:attributes} \"?>\" 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 = 5216; // 23281 bytes before compressing
const vint parserBufferBlock = 1024;
const vint parserBufferRemain = 96;
const vint parserBufferRows = 6;
const char* parserBuffer[] = {
"\x00\x0E\x00\x02\x83\x80\x07\x7D\x00\x82\x03\xFF\x45\x08\x82\x83\x20\x01\x37\x00\x6C\x0F\x80\x02\x38\x03\x82\x86\x07\x0C\x80\x14\x20\x01\x30\x01\x33\x00\x4E\x1D\x80\x0D\x30\x01\x33\x82\x17\x88\x8A\x9A\x8E\x80\x8A\x88\x88\x15\xA9\x84\x99\x8C\x81\x20\x00\x3A\x37\xA1\xA3\x85\x97\x96\x82\x8D\x95\x0C\xAD\x91\x93\x81\x9A\x8C\x04\x8D\x36\xB8\xB8\x96\x23\x92\x89\x3A\x93\x28\xBF\x8B\x81\xA3\x8F\x94\x8A\x8B\x1A\xB4\x88\x9C\x8E\x88\x92\x90\x8F\x3C\xD1\x8C\x80\xA8\x82\xA2\xAB\xA2\x18\x9A\x9C\xBF\x8A\x98\xB0\xA8\x9F\x63\xD3\xA5\xB5\xA4\xA0\xAC\x87\xA3\x0C\xC2\x13\x8F\xAE\x30\x00\x33\x91\x15\xF9\x22\xAA\x92\xBC\x82\xB3\xBA\x32\x83\xB8\xA8\x8A\xB8\x88\xBE\xBF\x80\x80\x02\xD0\xB4\xC4\x94\xBA\x98\x76\x88\x8B\xC4\x8D\xC0\x03\xC7\xBF\x1E\x81\xC3\xC4\x84\xB6\xC3\xCB\xAB\x89\x82\x9B\xC3\x8D\xCF\xCD\xC9\xC9\xA9\x85\x85\xC3\x87\xC0\xCD\xD9\xD5\x02\xAD\xC0\x1D\xB0\xD7\xA8\xD8\xA9\x96\xAE\x88\xC6\xAA\x8A\xDC\xDF\xD7\xA3\x89\x8C\x01\xEB\xD9\x9F\x92\x3C\x39\xB5\xD7\xBA\x89\xE2\x83\x7F\xE5\x54\x90\xBD\xB8\x9F\xE1\xEB\xD3\x8A\xD4\x94\xE4\xD3\xDD\x87\xED\xCD\x99\xCC\xA5\xA1\xBB\xE0\x00\xDC\x01\x04\x48\xB9\xB8\x95\x89\x30\x02\x30\xCF\xCE\x85\xBF\x7B\xFC\xFD\xD0\xDA\x00\x44\x23\x48\x4E\x47\xFD\x7D\x7A\x56\x69\x10\x6A\x70\x54\x7B\x05\xBC\x7E\x79\x80\x10\x63\x18\x7F\x7A\x39\x4D\x8B\x7F\x81\x03\x45\x13\x53\x49\x14\xB8\x46\x87\x3F\x0B\x1A\x49\x11\x73\x73\x39\x45\x47\x53\x12\xB8\x45\x7E\x76\xFA\x4D\x84\x02\x46\x22\x50\x4F\x5D\x4F\x16\xAF\x8C\x40\x47\xDD\x5E\x86\x85\x03\x1A\x70\x75\x4E\x7C\x57\x75\x77\x7F\x53\xDC\x40\x06\x8C\x42\x7D\x6E\x57\x49\x6C\x3E\x88\x49\x52\x89\x00\x02\x98\x7D\x91\xE4\x40\x06\x1D\x53\xF8\x67\x42\x02\x46\x55\x8E\x41\x82\x47\x03\x80\x08\x86\x40\x12\xAC\x85\x90\x83\x16\xA3\x90\x02\x50\x0A\xA7\x4C\x7A\x9A\x65\x8D\x77\x99\x85\x16\x8F\x83\x46\x84\x4F\x5D\x82\x9A\x46\x70\x17\x52\x70\x44\x20\x65\x8F\x86\x9D\x11\x93\x8B\x81\x4E\x21\x8C\x45\x44\x44\x10\x78\x4A\x86\x44\x1C\x87\xAA\x8D\x83\x6A\x8F\xA0\x56\x9E\x0A\x1A\x40\x98\x94\x52\x84\x90\x56\xA0\x69\x9A\x46\xA5\xA4\x6E\x88\xAA\x46\x84\x56\x65\x85\x7D\x5F\x5E\x7B\x40\x57\x91\xE8\x4C\x43\xA8\x49\x92\x86\x9A\x45\x92\xB4\xA7\x43\x01\x56\xA2\x9B\x89\xAE\x9C\xED\x5A\x45\x8B\x53\xF7\x71\x80\x67\x49\xA0\x8D\x89\xA0\x42\x23\xBD\x55\x8B\x7C\xF8\x69\x81\x97\x44\x7D\x59\xAC\x43\xA6\xD0\x9D\xA9\x7D\xB2\x05\x8B\xB4\x41\xB3\x00\x0F\xB7\x54\x8A\x39\x6B\x8D\x70\xAC\x03\x78\xA1\x58\x75\xE8\x82\x48\x8C\x00\xD0\x78\x40\x9C\xB5\xF9\x68\x9D\x80\x04\x1A\x71\x0A\x44\xBE\xD4\x7D\xBA\x4B\x87\x16\xBE\xB3\x58\xC0\x0D\x82\xCF\xBC\xC1\xFD\x46\xC4\x68\xC2\xFD\x7C\xBC\xB2\x4E\x53\x1B\x40\x02\x14\x00\x15\x1B\x9A\xC4\x23\x8F\x1A\x4F\x17\x00\x1A\xC0\x14\x00\x1A\xA2\x4D\xB8\x00\x2F\x00\x0C\x0C\xC9\x00\x3F\x0D\xBD\x95\x11\x22\x80\xC6\xC4\x14\xD6\xCE\x40\x47\x19\xDB\xC7\xC4\x13\x1D\xC0\x01\xC6\x86\x23\xE5\xCA\xC9\xC9\x3E\x27\x73\x42\x01\x1A\x54\x06\x66\xC6\x4D\x00\x0F\xC4\xCE\x1A\x98\x10\x00\xC7\x1A\x8C\xD0\x01\xD2\x21\xD2\xCC\xC6\xC7\x20\xFA\x4D\xCE\xC9\x28\xE5\xCB\x95\x5A\x0C\x46\xDC\x41\xC4\x23\xA2\x47\x10\x00\x52\xD0\xD8\xD9\xD6\x54\xFA\x4C\x44\xC7\x0E\x78\xCA\xC7\xCE\xB6\x8C\x45\xCB\xDD\x00\x01\xDB\xAF\x5D\x1A\x58\x78\x41\xD4\x6C\xD9\xD2\x4B\xDB\x39\xDF\xC5\xD7\xD7\x08\x65\xC7\xCB\xC8\x4D\x84\x4C\x8E\xAC\x6B\xDA\x8D\xDB\xE0\x4F\xF7\xC9\xCC\xDD\x88\xC4\x40\xD0\x00\x55\x96\xB8\x41\x95\x1A\x91\x15\xC4\x00\x36\x78\xC9\xE7\x40\x25\xFD\x00\x00\xD1\x03\xEE\x80\x8C\xE9\x53\xD9\xDD\xC8\x43\x5B\x23\x4D\x08\x00\x7A\x30\xE7\xEE\x16\x00\x30\x00\x03\xED\x39\x00\x0A\x0C\x00\x2E\x15\xE5\xCB\xED\x5D\x00\x0B\x0B\x9E\x0C\x5E\xBA\x61\x7C\x1C\x5C\x4C\x51\xE9\xA3\xDA\x83\x06\x46\x22\x00\x05\xEE\x17\x5C\xC1\xD9\xF5\xF2\x2A\x00\x09\xF4\x1F\x00\x27\x0A\xF4\x00\xDC\xE7\xC1\xD2\xF9\xE0\xE5\xF1\xB0\x43\x7E\xF1\xA3\x5C\xD2\xB1\xD5\xDC\x45\xF6\x76\xDC\xD5\xC9\x08\xBF\xFD\xF8\x0B\xF9\xDC\x67\x79\xDE\x00\x09\x78\xF2\x77\x73\x7B\x28\x77\x75\xD0\x05\x8D\x7F\x03\xA8\x7B\x80\xC9\x69\x04\x00\x61\x77\x77\xDB\x5B\x75\x71\x03\x2F\x73\xE7\x16\x31\x40\x9B\x1C\x26\x26\x2C\x1A\x22\xE2\x28\x6C\x7F\x92\x75\x76\x4B\xB0\x7F\x80\xCA\x35\x7F\x7E\x04\xA5\x61\x79\x0C\x8F\x84\x00\xA8\x60\x86\x00\x24\x7A\x86\x32\x88\x83\x02\x80\x02\x83\xF0\x78\x84\x80\x28\x61\x6A\xE7\x0B\x6E\x75",
"\x1B\x59\x6E\x69\x1C\x24\x06\x46\x2D\x8F\x80\xF5\x40\x02\x75\xD9\x66\x7C\x08\x28\x65\x23\x92\x7D\x2D\x64\x61\x57\x75\xEE\x36\x2B\x77\xDE\x7D\x79\x78\xC3\x65\x78\xC7\x02\x81\x82\xE5\x76\x82\x7C\x67\x86\x7E\xF3\x56\x36\x43\xD8\x15\x49\x62\x1F\x76\x26\x43\x1A\x4B\x6F\xC4\x61\x5E\x8C\xF1\x69\x22\x85\x7A\x5C\x20\x0C\x82\x26\x69\x10\x40\x00\x9E\x3F\x5C\x3D\xEB\x4C\x20\x90\x77\x46\x51\xA9\x38\x25\x78\x8A\x4C\x51\x27\x11\x61\x4D\x45\x38\x21\x20\x86\x00\x08\x00\x53\x8A\x8B\xC9\x08\x95\x51\x3C\x75\x51\x68\x7E\x80\x00\x27\x82\x9A\x90\x60\x4F\x02\x23\xA3\x83\x92\x9E\x45\x71\x93\xC8\x38\x22\x83\x04\x37\x93\x14\x9B\x90\x41\x44\x9E\x93\x91\x03\x8E\x3E\xD3\x33\x58\x52\x54\x99\x68\x52\x84\x99\x25\xF1\x7A\x56\x10\x8D\x34\x94\x97\x9F\x82\x78\x26\xE8\x87\x65\xEC\x72\x92\x27\x36\x2D\x6F\x14\xC3\x73\x8A\x75\x50\x2B\x8A\x7B\x0B\x9A\xD3\x4F\x49\x5A\xFB\x13\x4F\x9A\xCA\x93\x88\xB6\x41\x4E\x9A\x4F\x48\x5B\x99\x7D\x0B\x9B\xFF\x53\x89\x7B\xCD\x59\x7B\x8A\xE4\x6C\x9F\x00\xEF\x90\x01\x6C\x93\x8E\x69\x11\x64\x5A\x4E\x32\x40\x9C\x6A\xB7\x8A\x9F\xC6\x53\x47\x1D\xD3\x89\x9C\x79\xA7\x65\x64\xF4\x82\x25\x34\xD9\x63\x9B\x65\xA8\x53\x22\xAA\x4D\x39\xAB\x4A\x4B\x99\xEC\x5E\x7B\x99\x12\x82\x9F\x40\xBF\x97\x53\x5A\x79\x8F\x8F\x00\x00\x5E\xB8\x27\x44\x94\x15\x74\x5D\x92\x08\x2E\x6A\x48\xD0\x44\x5C\x93\xAC\x43\x98\x00\x02\x74\x43\x34\x9B\xA4\x68\x6D\xA3\x5A\x2C\x41\x6A\x3F\xD9\x77\x64\x95\x4E\x9B\x99\x0A\xB5\x7F\x32\xFE\x96\x9B\x93\x18\x9A\x9B\xB0\x6A\x28\x39\xC3\x49\x3F\x86\x9A\xA2\xA9\xF4\x25\x9F\xB6\x68\x95\xA3\x94\x73\x9B\x99\x1E\x25\x47\x14\xB5\xA3\x5D\x92\xB8\xA5\x39\xBA\x97\x61\x82\x41\x98\x27\x21\x83\x26\x69\x6C\x44\xAC\xF1\x00\x0A\x5E\x09\xB3\xA2\x94\x62\xB4\x56\x9E\x3A\xAB\x98\x87\x34\x7B\x72\x12\x6E\xA8\x29\xE6\x45\x56\x8D\x9A\xA9\xAE\x6D\x40\x5B\x25\xE1\xA8\x98\x5C\xA6\xA8\xA4\x85\xA0\x59\xF1\x32\x00\x21\xD4\x07\x9E\x57\x73\xA1\x9C\x33\xE8\x83\x8B\xA0\x92\x9A\xB2\x45\xA0\x03\x33\xF6\x90\xAE\x6E\x8B\xAF\x9B\x46\xB2\xB3\x38\xD1\xAC\xA9\x22\x7F\xAD\xA0\x00\x0B\x9C\x1A\xEE\x9B\x99\x78\xA8\x8F\xA2\x47\xB7\x9E\xCE\x78\x35\x59\x89\x02\xA2\xAF\xC3\x5E\x99\x40\x9F\x54\xAA\x83\xA8\x61\xA1\xB0\x77\xB2\x3F\x8F\xA0\x23\x88\xAC\x55\x2D\xBF\x52\x9C\x6C\xBC\x88\xAB\x8D\x89\xB4\x3D\x3C\x59\x53\x63\xC0\x91\xB3\x9D\x9C\x68\xB8\x0B\xBA\x42\x5E\x99\xB3\x8B\x4B\x9C\xB3\x9B\x40\x44\xB4\x68\xC3\xAD\xB8\xA8\x93\x5D\xB4\xBC\xA4\xA2\x3A\xD5\xAC\xB4\x78\x95\xAB\xB9\xDF\xB3\xB4\x40\xB6\xBD\x9F\x65\xB9\xB5\xB6\xFC\x87\x9E\x7A\xBE\xB8\xA0\xA0\x81\xBC\xA1\x92\xA4\xBB\x1D\xAB\x5C\x2D\xAF\x09\xBF\xB5\x94\xAC\xBA\x5F\xCB\x9F\xB9\x9C\x1F\xA0\xAE\x5C\xA4\xA6\xB4\x66\x5D\x2E\x94\x84\x22\xA5\x24\x4C\xA6\x57\x94\xCB\xAC\xC6\xA4\x16\x98\x10\xD9\xC2\x4D\x9B\xC4\x5E\xBA\xBE\xB6\xA7\xFE\xB9\xB8\x79\xD5\x9E\x55\x93\x1B\xB0\xA9\x9E\xA2\xBE\x39\xAB\xC2\x40\x4E\x52\xAE\xB4\xBD\xA8\x8E\xCA\x4B\xB9\xAB\x65\x91\xC1\x5A\xE5\x54\x5D\x74\xDC\x68\xC2\x67\x5A\xC3\xC2\x25\xD2\xB0\x4F\xD6\xA8\xBA\xA1\x9B\xBD\xC5\xCB\x9E\xB8\x8C\xE1\xB7\xBD\xF1\xBA\xAB\xB4\x55\xD3\xC7\x69\xD5\xAB\xC7\x04\xFD\xC3\xAB\x22\xDD\xA8\x92\xAC\x41\x95\x54\xA5\x94\x3D\x6B\x90\xAD\x20\xAA\x95\x57\xC5\x80\x00\x0C\x20\xC6\xCF\x2D\xC0\x56\xC4\xCD\xB5\x98\xA9\x3F\xD7\xA4\x87\xFA\xAD\x4F\x45\x43\x28\x50\x1B\xAE\xB4\x5A\x93\x21\xB0\xF6\x3C\xCE\x4F\x7F\xCC\x2F\x96\xB2\xBD\xC0\x9C\x3A\xAE\xCF\x8D\x5C\xA0\xA9\x40\x5B\xC1\x29\xAB\xCF\xCC\x39\x21\xAD\x3E\xBA\xB4\xBF\x93\x07\xB0\xAE\x9B\xD8\xBF\xB1\x6B\xAA\x5F\x1A\x31\xCA\xBE\x9C\xD9\xBF\x00\xFE\x9C\x7E\x24\x90\x29\x5E\xAD\xAB\x99\xAB\x97\x6F\x4B\x9C\x1E\x26\xBD\x53\x93\xD5\x5A\xFA\x48\xD6\x00\x33\xD5\xD1\x76\xC1\xAF\xAE\xB5\x5E\x61\x0B\xC0\xB2\xAD\x8D\x93\x21\xA4\x9A\x47\x38\x58\x83\x22\x93\x70\xA3\xD8\x2E\xC1\x6D\xBB\xF7\x69\xA2\xD2\x6A\xBF\xD3\x2E\x90\xBD\xCC\x00\x33\x00\x00\xC5\x8F\xAF\xB6\xD4\xB9\x98\xEB\x8D\x99\xC5\x4E\xD8\xB0\x94\xB1\xBD\xB2\x2A\xDA\x5D\x48\x57\xCE\xDF\x8D\xE9\xB0\x00\xD4\xAA\xB5\x9D\x57\xBD\xD6\x45\x89\xC1\xBF\x50\xFB\x9B\xD4\xB8\xB4\xB7\xBF\x82\xAB\xD1\xC9\xBD\xBD\xB2\xFF\xBA\xB9\x80\x89\xD6\xB9\x02\xEB\xD8\xC1\xF4\x99\xA3\x48\x7F\xA0\xD9\xC1\xBE\x90\xD8\xDA\xD8\xDB\x2A\x80\x06\x07\xC6\xA2\xDA\xE3\xE5\xD5\xAB\xB9\x88\xEA\xC5\x27\xD4\xA4\xDD\xE0\xA6\xBF\xBB\xF5\xBF\xA8\x1B",
"\xE8\xBA\xBF\xF5\xCB\xBE\x3C\xED\xB7\x8C\xE5\x89\xC2\xCA\xB2\xBE\xDF\x6E\xA1\xBE\x9F\xFB\x83\xE4\xDE\xA8\xAB\xCB\xC1\xD0\x99\xDD\xE1\x8C\xE3\x5A\xC7\xA6\xC1\x58\x36\xE1\xE3\xE6\x94\xE4\xDB\xB8\x83\xCB\x74\x9D\xA3\xDA\x25\xD7\xB8\xDD\xC2\xAB\x98\x77\xF7\xC2\xB7\x18\xD9\xCD\xA9\xA2\xB2\xDF\xCB\x9B\xA6\xDE\xF6\xB9\xDD\xE6\x10\xF6\xCC\xCA\xA8\xD2\xD5\xDB\x92\xB6\xE7\x3B\xE4\xEE\xC8\xBF\xB8\xEA\x00\xC6\xE9\x55\x48\xEE\xE3\xC9\xE9\xE3\x8A\x89\xDF\xC8\xE4\x86\xBE\x96\xD7\xAB\xE7\x25\x07\xE9\xE6\xE5\xE3\xB0\xA7\xC9\x1F\xE3\xF1\x79\xE7\x25\xCE\x96\xB6\xEE\xD6\xD0\xCF\x99\xEC\x50\x8B\x99\x1E\x92\x63\xF4\x6B\x66\x62\x85\xFE\x9F\x4A\x1E\x2E\x28\x38\xFF\xED\xF1\xB1\xC6\xF1\xA4\x61\xD2\xC1\x90\xAC\x46\xC3\xB3\xA8\xF6\xC8\x23\xC3\xCD\x73\x45\x7F\xDA\x99\x88\x24\xA6\xA9\xE0\xCA\x4B\xCD\x35\xCF\x25\xE8\xC4\xE4\x45\xF3\xF3\xDE\xF1\xB5\xF4\x2B\xE1\xEA\xE5\x8E\xF2\xEE\x3C\xDD\xC4\x9F\xBF\xF9\xCC\xC4\x2C\x56\xE3\x21\xEC\xEF\xE7\x93\x05\xDE\xF5\x3A\xFD\xD3\x5A\x8E\x93\x22\x47\x4D\x3F\x2F\xCE\xC2\x20\xB4\xF8\x92\xE1\xB8\xD4\xDE\xCE\x65\xD5\x95\x27\xEA\xA9\xCC\x39\xC8\xDC\xAD\x6F\xC7\xD7\xA5\xF3\xCC\x3D\x3A\xF1\xBF\xF9\xB2\xFD\x2F\xA1\xFE\xC6\x2B\x40\x71\xD2\xB6\xD2\x64\x69\x92\x5D\x67\xA7\x1E\x7F\xFB\x50\x57\xC0\x6F\x68\xCA\x69\x13\x09\x83\x71\xCB\x43\x7F\x6A\x52\x7D\xD7\x60\x6C\xD7\x78\x58\x50\x7A\x58\x13\x3B\x80\xDE\x7D\x6C\x1A\x13\x7E\x80\x74\x67\x51\x66\x6D\xC6\x68\x71\x17\x77\x81\xEC\x15\x3C\xA6\x61\x6E\xB7\x78\x80\x26\x89\x13\xBD\x77\x75\xC0\x79\x75\x2C\x63\x7C\x53\x68\x7C\x63\x71\x6F\x36\x83\x5E\x05\x77\x6F\x41\x49\x60\xAE\x5B\x6F\xF4\x4D\x6F\xE5\x7A\x7D\x01\x73\x5F\xAA\x65\x70\x42\x78\x46\xCF\x41\x79\x9E\x7E\x50\x47\x74\x60\x13\x57\x60\x40\x88\x51\x4E\x7C\x60\x2D\x88\x13\x55\x2E\x6A\x39\x2C\x3C\xD7\x6F\x2E\xB0\x60\x53\x4E\x3F\x71\x5E\x8E\x82\x92\x5C\x84\x34\x61\x27\xEC\x18\x4B\xBD\x61\x3A\xA3\x34\x3D\x7A\x58\x86\xF5\x29\x13\xBD\x69\x79\xD2\x30\x3B\x38\x3D\x79\x67\x84\x2F\x73\x2E\x68\x68\x7C\x11\x4D\x39\x57\x0B\x7C\x57\x6A\x8E\x80\x53\x43\x86\x38\x17\x49\xAC\x37\x6D\x28\x4B\x29\x1E\x12\x6C\xB5\x4C\x88\xA4\x60\x00\x23\x07\x6A\x8B\x86\x6B\xAB\x65\x57\xB5\x49\x79\x36\x1F\x86\x7A\x8D\x57\x84\x84\x6B\x35\x6E\x11\x97\x49\x71\xC5\x73\x63\xA7\x75\x8A\xF9\x1E\x66\x8B\x7B\x82\x87\x7D\x4D\x63\x70\x79\x09\x74\x63\x5B\x76\x79\x4A\x88\x79\x12\x35\x87\xD4\x38\x87\x7A\x50\x7A\x43\x1F\x14\xA1\x54\x7A\x62\x73\x5E\xA7\x78\x7F\xAB\x7D\x1C\x62\x37\x6D\xC4\x8B\x7B\x7D\x19\x6C\x8F\x4B\x81\x90\x13\x3B\x08\x1E\x81\xC9\x8F\x55\x7D\x17\x7E\x97\x49\x7E\x10\x8A\x27\xD0\x86\x6C\xD9\x8D\x6D\xDC\x7B\x6C\xDF\x70\x10\x1D\x84\x64\xEA\x74\x4A\xF4\x74\x86\xD5\x64\x58\x57\x80\x00\x19\x70\x6C\xC5\x37\x03\xE0\x67\x6A\xC0\x6F\x82\x23\x74\x74\x32\x8D\x1C\x34\x8D\x75\xC1\x83\x63\x38\x88\x78\x5A\x69\x63\x3C\x84\x73\x3F\x87\x76\x42\x86\x84\x00\x7F\x76\x43\x87\x84\x39\x69\x84\x4D\x67\x8F\x02\x6D\x70\x51\x81\x16\x95\x77\x76\x7E\x7E\x5C\xEB\x89\x85\x12\x3B\x85\xE1\x70\x57\x86\x8B\x7D\x1A\x89\x35\xC7\x1F\x69\x1E\x8D\x91\xD6\x8B\x3A\xBE\x45\x89\x61\x2D\x7A\x20\x58\x92\x23\x1C\x8C\xDD\x70\x92\x90\x19\x66\x1E\x8C\x92\x1E\x15\x92\xA4\x8B\x8F\xF9\x17\x8A\x38\x95\x24\xB4\x7C\x35\x8C\x7B\x93\x50\x10\x8B\x25\x7A\x6E\x7B\x74\x8B\xF4\x44\x87\x00\x0B\x79\x77\x82\x79\x53\x4C\x8B\xA2\x7F\x8B\x1B\x58\x8A\x45\x23\x8A\x82\x70\x94\x27\x12\x01\x55\x99\x83\x33\x6E\x92\xE0\x87\x1C\xA7\x4C\x10\x1E\x82\x95\x41\x91\x82\xC3\x89\x7B\x7A\x64\x2F\x16\x0E\x4B\xD3\x8C\x61\x5C\x90\x49\x96\x83\x49\x00\x0B\x8D\x03\x1F\x4C\xD2\x86\x96\xD0\x7C\x7B\x00\x05\x96\xB0\x72\x66\xC5\x8D\x17\x58\x93\x7D\x6B\x94\x2F\xAC\x4F\x96\x39\x15\x81\x6A\x74\x8E\x81\x99\x53\x22\x8E\x7A\xC0\x6F\x97\x13\x8B\x8E\x6D\x98\x13\xAD\x41\x1A\x39\x1B\x91\x74\x94\x8E\xF3\x8B\x98\x16\x84\x6E\xB8\x4A\x92\x2C\x8C\x99\x18\x83\x99\x57\x18\x13\x0F\x6F\x4C\x53\x73\x69\xF5\x7C\x39\xBE\x4D\x91\x5F\x9D\x85\xAF\x62\x4C\x19\x8D\x8C\xB3\x52\x49\x39\x1F\x69\x97\x94\x4B\x24\x9A\x9A\xD3\x7D\x91\xED\x79\x91\xF0\x20\x9B\xA2\x90\x97\xA1\x46\x9A\x1C\x9F\x9A\x38\x12\x44\x59\x9E\x8F\xF9\x17\x8C\xC6\x62\x96\x27\x11\x99\xB3\x9E\x4A\x00\x0D\x9A\xB1\x4B\x4C\x61\x96\x95\x03\x47\x93\x5A\x99\x1F\x86\x9D\x8A\x9F\x5B\x95\xD1\x94\x99\x94\x4A\x11\xC4\x9E\x9D\x32\x69\x1F\x41\x3A\x69",
"\x09\x93\x6A\x8E\x96\x6C\xD9\x7A\x6A\xD0\x91\x9C\x95\x94\x9E\xD6\x94\x8E\xEF\x93\x6A\xE9\x9E\x4B\xF7\x92\x50\x9E\x94\x7E\x06\x92\x50\x83\x94\x9B\xA4\x94\x9F\xB3\x40\x6A\xEB\x92\x50\xF9\x93\x7D\x01\x8C\x1E\xED\x9E\x7A\x0B\xA0\x9B\xDF\x8E\x96\x02\xA0\x00\x96\x95\x9F\xB4\x4F\xA0\xC7\x9A\x99\xD1\x64\x68\x6A\x5D\x9F\xC7\x6B\x71\xF2\x93\xA0\x96\x4B\x4C\x17\xAC\xA1\x91\x59\x88\xC6\x64\x93\x00\x0D\x9D\xA0\x80\x89\xF1\x94\x98\x38\x19\x66\xB7\x9B\xA1\xB5\x61\x26\x41\x38\xA2\x0E\xAF\x88\x96\x87\x7A\x2A\xA1\xA0\xD2\x96\x9B\x24\xA4\xA3\xA1\x83\x40\xD8\x86\x4B\xEC\x7E\x4B\xDD\x88\x4B\x3D\x90\x67\x1F\x79\xA4\x20\x8E\x4F\xF7\x76\x97\xF9\x74\x63\x04\x8F\x27\x8A\x6F\x7F\x1B\xA3\x56\xBC\x63\x80\x88\x6D\x7F\xCA\x7F\x99\x54\x72\x80\xFE\x40\x69\x0C\x8B\x8E\x95\x65\x8E\x6C\x68\x4B\x97\x4A\x97\x77\x41\x7B\x7D\x92\x8E\x80\x92\xA5\x6F\xA5\x3C\x34\x01\x53\xA7\x69\x98\x78\x96\x6E\x4C\x65\x77\x4D\x83\x83\x07\x64\x7C\xD8\x9D\x8F\xAE\x8A\x83\x0B\x96\x55\x3C\x6B\x51\x78\xAD\x17\x12\x83\x82\xEB\x8D\x8E\x90\x90\x00\x75\xAA\x82\x04\x17\x9A\x6A\x54\x8F\x09\x66\x86\x26\x7F\xA7\x35\x8A\x9C\xF0\x67\x7C\x9C\xA0\x74\x32\x7B\x5A\x67\x73\x90\xF0\x58\x54\xFB\x9C\x72\xFF\x49\x6A\xA3\x68\x84\xFA\x37\xA9\xB1\x8C\x89\x78\x70\x85\xC8\x5B\x74\x7C\x7A\x60\x9F\x85\x71\xBA\x9E\x9A\x5B\x8A\x26\x5A\x8F\x9B\x8C\x40\x00\x8C\x51\x86\xAC\x8E\x9B\xB0\x62\x94\xC1\x73\x45\x70\x8B\x87\x58\xAC\x86\x16\x3E\x86\x81\x80\x2C\x83\x8E\x5A\x48\x9A\x94\xD5\x39\x87\x82\x82\x80\xAE\x5E\x87\xC5\x9C\x89\xD7\xA6\x68\x9F\x8D\x91\x54\x93\x7D\xCE\x99\x97\xC9\x93\xA8\xE0\x95\xA7\xAB\x83\xA9\xED\x6B\x9D\x45\x26\xAC\xF7\x83\x8B\x4F\x49\x60\xD3\xA6\x87\xD5\xAB\x8B\x58\x2E\x8B\x55\x83\x45\xE3\xAB\xA8\x39\xAA\xA5\xB5\x29\x71\x18\xAD\x61\xCC\x5F\x71\x01\xB5\x67\x76\x51\x3B\x78\x5C\x11\xDC\xA0\xAD\x02\x8F\x77\x01\xB8\x88\x27\x9A\xA3\x61\x2E\x88\x35\xAD\x92\xC0\xA2\x89\x94\x82\xB1\x23\x16\xB0\x99\x82\x31\x9B\x8F\xAC\x69\x8D\xB0\x1B\x5A\xA2\xFC\xA2\x10\x45\xAB\x7E\x7A\x24\x28\xE6\x8A\x56\x0A\x3A\x47\x0D\x2C\xA6\x23\x5A\x7B\xD4\x80\x00\x69\x69\xA8\xFD\x2C\x01\x3F\x15\x27\x25\x80\x9A\x6F\x2D\x2B\x3C\xB9\x13\xD4\x1E\x01\x39\xBD\x20\x18\x9D\x91\x23\x3D\x91\xD4\x13\x45\xAD\x35\x20\xDA\x9F\xA9\x27\x11\x4A\xE3\xA4\x1D\xF8\x37\x30\x05\x2A\x9E\xFF\x9F\x2A\xAF\x3A\x6A\xD4\x1A\x44\x4B\xBD\x1F\x8E\x8E\xAF\xB8\x4A\x26\x01\xB4\x1D\x26\x03\xB4\x05\x28\xA3\x2B\x9A\xB1\x1E\x1D\x25\x6A\xBD\x2F\xFF\x3D\xB5\xFC\x10\x01\x75\x49\x10\xB1\x1F\x0F\xD4\x11\x1B\x2D\xB9\xB7\x2D\xB2\x1E\x09\x13\x32\x73\xBA\xB7\x03\x1E\x46\x1A\x18\xB7\x79\xB7\xB2\x2B\xBA\x27\x74\xBF\x13\xEE\x17\x3A\x80\xB2\x34\x02\x15\x25\x84\xBD\xB2\x86\xB9\xA6\xC0\x24\x1A\x75\xBB\x91\x23\x3A\xB7\x8C\xB9\xAB\x04\x11\xB9\x0A\x33\xB9\x98\x68\x13\x9E\xB2\x3F\x04\x19\xAC\xB5\x24\x1D\x5F\xB2\x57\xA7\xB6\x30\x7C\xB6\x1D\x69\x65\x25\x7A\xB1\x1B\xA3\xB3\x10\x23\x39\x59\xA8\xBB\xB3\x61\xAC\x1E\x79\xBD\xBA\x05\x19\x66\x68\xB0\xB8\xB2\xB9\xB7\xB5\xB0\x65\xD4\x10\xB3\x47\x6F\xA6\x2A\x15\xB7\x4C\x2D\xB8\x08\x13\xBB\xFE\x22\xB6\x26\xAB\xBA\x7C\x3A\xA0\xD1\xB8\x4B\xFF\x0F\xB7\xD6\x1B\xB9\xEE\x17\xB7\x1A\x15\x02\x1A\x18\xBD\x80\xB0\xBD\x60\xB5\xB9\xC4\x14\xBD\xE3\xBC\x1E\xBF\xBE\xBD\xCC\xBF\x3C\xE6\xBA\xBA\xB8\x40\xBE\xEB\xB4\x10\x56\xBA\xAA\x02\x5F\x0F\x9B\xBA\x26\xDC\xB0\x36\x08\x10\xBF\x79\xB2\xBE\xEE\xB4\xBE\xD3\xBA\x88\xD5\xB0\x2C\xBF\xB8\xBF\x79\xB9\xBA\x85\x69\x13\x9B\xB4\x1D\x6A\x25\xA5\x89\x6E\x7F\xD4\x10\xBA\xE7\x8E\x21\xF7\xB9\xB7\xC1\xBC\x10\xFC\xBD\xB2\xFE\xB9\xC0\x38\x17\xBB\xED\xBC\xC1\x26\x9C\x10\xCE\xBD\x2F\x08\xCA\x56\x0B\xCC\x2B\x0C\x1E\xC0\x5E\xA5\x22\x11\xC8\xA4\x46\xA8\xB8\xCC\xBC\xBB\xFF\x0A\x26\x9F\x61\xBF\x96\xBF\x13\xA1\x49\x66\x36\xC9\xB8\x63\x19\x66\x0F\x6A\xB9\x5C\x21\xC4\x36\xCA\x8E\x3F\xB2\xBA\xC2\xB7\x2B\xC4\xBA\x11\x4D\xB6\xAE\xF9\x1D\x2F\x32\xC5\x25\x1B\x9B\xC3\x63\x15\xB7\x3E\xCB\xC3\x9B\xB5\x25\xBF\xBA\xB7\xC6\xBE\xA6\xCA\x8E\xB8\xFD\x23\xBC\x14\x54\x1D\x4B\xCF\x9D\x4D\xCF\x13\x75\xBE\xB7\x3B\xC2\xB8\xFA\xBB\xBE\x12\xCC\xB2\xD6\x15\xB7\x8B\xB9\xC6\x42\xC8\x10\x06\xC2\xB9\x2E\xC8\xB2\xD2\xB5\x1D\x05\x18\xB9\x56\xC3\xC7\xA4\xBC\xBC\x6D\xCA\x27\x23\xC3\x2F\xDD\xA0\xB4\xE5\xB2\xC0\xE7\xB6\xC8\x7A\xCC\xBB\x9E\x92\xC5\x32\xCB\xB9\x3A\xC3\xB8\x1A\x19\x66\x9B",
"\xBF\xBB\x91\xCD\xB2\xF3\xBD\x76\x50\x17\xC2\x01\xC4\x10\x70\x7A\x7D\x2C\xC7\xC8\x8C\xA5\xC4\x52\xC6\xC6\xA6\xCC\x10\x86\x91\xBB\x3B\xC5\x29\xEB\x8E\xC1\x8F\x94\xCA\xD7\xBF\x13\xDA\xB6\xC1\xDD\xBF\xBD\xAB\xCE\xB3\xB9\xBA\xC8\x9A\x18\xBB\xA8\x99\x13\xE9\xBB\xC3\x44\xC9\xCB\x38\x19\xC1\xF1\xB9\xC9\xD5\x75\x10\x9B\xB4\x9D\x02\x31\x1B\x6A\x24\xCC\x06\x3C\xCA\xA4\xCE\xCA\xA3\xC2\xCC\x21\xC4\xC7\xC0\xCC\xCB\x6A\x53\xC2\x69\x64\xA6\xDE\x71\xCD\x3D\x27\xC7\x87\xB5\x2B\xF6\xBA\x11\xCA\xCE\x2F\x17\xCB\xBF\xB7\xC0\x39\xDE\xCD\xC9\x8C\x9B\x8E\xBF\xB3\xC2\xD2\xCD\xCE\xA4\xCA\xCD\x1A\x1C\xCD\x1F\x8A\xBB\xDF\xC3\x7D\x4E\xA8\xCF\x80\xB2\xC3\xBF\xB2\x97\xA5\xCF\xC6\x8A\xBA\x11\x9C\xCA\x30\x57\xC3\xC9\xD7\xC3\x7D\xC0\x65\x25\xEA\xB5\xCC\xFA\x97\xA0\x50\x1B\xC8\x9F\x6D\xA0\x8D\xB0\xBE\x55\x27\xC9\x0A\x31\xCC\xBD\xC8\x85\xB5\xC3\xC4\x0F\xD7\xB5\x4B\x2D\xBF\xA7\x2D\x89\xB8\x44\x1D\x45\xB6\x9C\x8B\xC9\x66\x14\xD0\xB8\x16\xD8\xD0\x1E\xDA\xD0\x17\x9D\xD1\x0E\xD3\x7D\xA7\xA1\xD2\x1A\xC3\xD2\x85\xCD\xC1\x7E\xCE\x7A\x1D\x92\xC3\x0F\x6B\xD2\x7A\xBD\xD2\xCD\x39\xD0\xAF\xC4\xCD\x0C\xD4\xD4\xEE\x90\xD1\x36\xDA\x30\x84\xCC\xB0\xFC\xCB\x41\xBB\x98\xD2\x32\xCC\xC7\x36\xC2\xD4\x08\x18\xD1\x06\x3A\xD1\x6A\x57\xD4\x2F\xD7\x6D\x35\xDE\xC5\x0C\xC8\xD3\x4E\xDA\xCB\xF2\xB1\xB1\x89\xCE\x21\x75\xBE\x99\x86\x41\xBF\x56\xD4\x10\x58\xD2\x30\x5A\xDA\x27\x5C\xD3\xD3\x5E\xDA\xD4\x60\xD8\xC2\x08\x16\xBA\x25\xDA\x11\xBF\xB3\x68\x15\xB4\x20\x75\xB5\xCE\x00\x00\xD4\x79\xBD\xD6\x03\x1F\xD6\xFE\x21\xD7\xB5\x23\xD7\xEB\xB6\xCC\x71\x73\xC8\x62\xD1\xB2\x4F\xD4\x10\x27\xDB\x85\xFE\x22\xC3\x9F\x6C\x9C\x01\xD7\xCA\xC9\xBA\x11\x15\x02\xC7\x36\xC5\xB3\x72\xAD\xC5\xC5\xBA\x96\xA3\xD3\xB3\xE3\xC3\x16\x15\xCD\xB2\xCC\xC6\xCB\xA1\xDE\x32\x7B\x9A\x7A\xA4\xDD\x37\xA6\xD1\xDB\x32\xBC\x61\x05\xCB\xC3\x5B\xCC\x97\x5D\xC5\xD0\x7F\xC2\x10\x2A\xC3\x11\x10\xC9\xCF\xD7\x6B\xCF\x15\x2B\xDA\x0A\x37\xCE\x04\x1E\xCC\x02\x32\xDA\xB6\xD7\x96\x2C\x25\xDA\x71\xAF\xDC\x77\x9D\x17\xEF\xCA\xDB\xB5\xDD\xA6\xBC\xD3\xB3\xBE\xD3\x10\x0D\xCD\xA5\xC2\xD7\x47\x2D\xCA\xCF\x2F\xC9\xC7\x01\xD2\xC3\xB1\x19\x96\x36\xC0\xCF\xA2\xC3\x10\xC6\xDA\xD3\x7D\x40\xCE\x94\xB3\xD9\x9B\xDE\xC4\x54\xCA\x11\x17\x00\xDA\xCD\xB9\xB7\x69\x6F\x90\x79\x71\x91\x11\xDD\xDE\x9B\x94\xCD\x9D\xD3\xC5\x1A\x18\x01\xFA\xDB\xBE\x47\xB8\xD2\x26\xDB\x9A\x52\xD5\xB7\xB3\xCC\xDA\x32\xDB\xDC\x3B\xCB\xE0\x96\xDB\xD3\x20\x5D\x91\xBF\xC6\xC3\x95\xDE\xAB\x00\x0C\xDC\x8D\xBE\xD8\xDA\x7B\xB7\xCA\xBA\x11\x19\x09\xE0\xCC\xBC\xB6\x7F\xDD\x2F\x7D\xDD\xA2\x96\x8F\xC8\x02\xED\x2F\xB1\x1D\xD0\x14\xEC\xE1\x1C\x43\xA4\xD4\x1D\xE2\x2A\xAB\xE1\xF1\xBA\xE3\x6D\xB0\xE2\x80\xB2\xE2\x5A\xBE\xC8\x75\xBF\x60\x1A\x08\xE2\x02\x13\xC2\x55\x2E\x94\x59\x2D\x2F\x63\xC7\x9E\x45\x25\xDF\x7A\xB2\xC3\xA1\x45\xC3\x52\xE7\xE5\x3C\xC5\xE0\x08\x1B\x01\x48\xE0\xB8\x50\xB8\x9D\x62\xC5\xAE\x64\xC5\x24\xA9\xDA\x12\x95\xC4\xCB\x0C\x1F\xBB\x40\xE3\xDE\x4E\x20\xE6\x4A\xC2\xE6\x50\xE0\x15\xBF\xB9\xC5\x79\xBF\xE4\x5F\x75\x24\xDD\xD2\x10\x9F\x68\x65\x84\x72\xDE\xB4\xD3\xDD\xDA\xD2\xDB\xA8\xD7\xD0\x12\xEC\x10\x55\x2B\xE6\xC4\xD4\x10\x51\xBF\xE6\xE2\xA8\x9D\xBF\xB0\xBB\x75\xE0\xE7\x77\xEB\xC9\x91\xE7\x2D\xD8\x91\xCA\xEC\xC3\xE0\x1B\xD7\xE5\x32\xC4\x1D\x1D\x08\xE5\x31\xC7\xC6\xAE\xD0\xEA\xE1\x15\xB7\xD4\x1F\x01\xA4\xE1\xBF\x32\xC1\xC7\xA9\xE9\xE5\xA4\x14\x1D\xFC\x3D\xEA\xEB\xB8\xD9\x1A\x14\xD8\x85\xEB\xDF\x37\xDC\x10\x7A\xD0\xC0\x50\xDA\xAB\x1E\xE2\xC3\x2A\xDD\xE5\x90\xDA\xEB\x24\xDC\xEB\x94\xDE\xE0\x5B\x8E\xD3\xB5\xE2\xEC\x22\xD4\xEC\x39\xDB\x32\xC8\xEE\xE1\x02\xD3\x16\x82\xD6\xEB\xC9\xD2\xC9\xB9\xE9\xD7\xC5\xE4\xDF\x8F\xB1\xED\xB0\x6D\xE9\x1A\x13\x89\xB2\xE3\xEB\xF7\xD0\x3F\xCC\xED\xB2\x60\xCF\x2B\x61\xED\xE8\xEC\xA1\xE0\xD3\xEA\x12\xD4\x14\xE3\xE3\xEA\x30\xAB\xE4\xD0\x5D\xEC\xD8\xCC\xB2\xE4\xA3\x62\xD1\xCB\xE6\xC3\x84\xE8\x10\xF2\xE1\xE2\x1F\xD4\xBF\x50\x13\xEC\xDA\xEF\xEC\x0D\xE1\xD5\xC9\xE5\xEE\x08\x16\xED\x06\x3F\xEF\x04\x11\xF0\x41\xE3\xF0\x9A\xCB\xD4\xCF\xC1\xD9\x71\x80\xDF\xBD\xE6\x6C\x3D\xD5\xE4\xFD\xE1\xBF\x10\xF3\x10\x12\xFA\xB7\xFA\xE2\x50\x06\xF5\xBA\xDB\xE4\xD6\x03\x1D\xE1\xDF\xE7\xB9\x1A\x19\xB9\x79\xB1\xF2\x02\x13\xF2\x07\xC4\xF1\xC7\xC7\xF2\x03\x1B\xEB\xDC\xEA\xA1\x83\x67\xD6\x8B\xCA",
"\xD6\x7D\xC6\xE8\x13\xE9\xEF\x36\xFF\xD8\xCD\xE7\xF0\x63\xDA\xF1\x04\x1E\xE3\x2B\xE2\xC3\xD5\xE1\xF4\x1B\xF2\xF2\x48\xD8\x7D\x76\xD8\xF3\x64\x29\xF2\x4A\xFB\xF2\xDE\xE5\x21\xA6\xEA\x11\xE6\x33\xEF\xE4\xEF\x13\x54\xD1\xBF\xCA\xD2\x30\x4D\xD2\xD9\x2A\xFA\x1A\x66\xDF\xBF\xF8\xC0\xEE\x0C\x1E\x56\x60\xF1\xEA\x3F\x10\xF4\xEB\xD8\xED\x4C\xD8\xF1\xCA\xA9\xE3\x11\xBB\xE2\x71\xFD\xF7\xA0\xE0",
};
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<vl::vuint8_t> 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<vl::Ptr<XmlNode>>& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
extern void XmlUnescapeAttributeValue(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
extern void XmlUnescapeCData(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
extern void XmlUnescapeComment(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
/***********************************************************************
Parsing Tree Conversion Driver Implementation
***********************************************************************/
class XmlTreeConverter : public vl::parsing::ParsingTreeConverter
{
public:
using vl::parsing::ParsingTreeConverter::SetMember;
void Fill(vl::Ptr<XmlNode> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
}
void Fill(vl::Ptr<XmlText> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
SetMember(tree->content, obj->GetMember(L"content"), tokens);
}
void Fill(vl::Ptr<XmlCData> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
if(SetMember(tree->content, obj->GetMember(L"content"), tokens))
{
XmlUnescapeCData(tree->content, tokens);
}
}
void Fill(vl::Ptr<XmlAttribute> tree, vl::Ptr<vl::parsing::ParsingTreeObject> 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<XmlComment> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
if(SetMember(tree->content, obj->GetMember(L"content"), tokens))
{
XmlUnescapeComment(tree->content, tokens);
}
}
void Fill(vl::Ptr<XmlElement> tree, vl::Ptr<vl::parsing::ParsingTreeObject> 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<XmlInstruction> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
SetMember(tree->name, obj->GetMember(L"name"), tokens);
SetMember(tree->attributes, obj->GetMember(L"attributes"), tokens);
}
void Fill(vl::Ptr<XmlDocument> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
{
SetMember(tree->prologs, obj->GetMember(L"prologs"), tokens);
SetMember(tree->rootElement, obj->GetMember(L"rootElement"), tokens);
}
vl::Ptr<vl::parsing::ParsingTreeCustomBase> ConvertClass(vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)override
{
if(obj->GetType()==L"Text")
{
vl::Ptr<XmlText> tree = new XmlText;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<XmlNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"CData")
{
vl::Ptr<XmlCData> tree = new XmlCData;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<XmlNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"Attribute")
{
vl::Ptr<XmlAttribute> tree = new XmlAttribute;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<XmlNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"Comment")
{
vl::Ptr<XmlComment> tree = new XmlComment;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<XmlNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"Element")
{
vl::Ptr<XmlElement> tree = new XmlElement;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<XmlNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"Instruction")
{
vl::Ptr<XmlInstruction> tree = new XmlInstruction;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<XmlNode>(), obj, tokens);
return tree;
}
else if(obj->GetType()==L"Document")
{
vl::Ptr<XmlDocument> tree = new XmlDocument;
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
Fill(tree, obj, tokens);
Fill(tree.Cast<XmlNode>(), obj, tokens);
return tree;
}
else
return 0;
}
};
vl::Ptr<vl::parsing::ParsingTreeCustomBase> XmlConvertParsingTreeNode(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
XmlTreeConverter converter;
vl::Ptr<vl::parsing::ParsingTreeCustomBase> tree;
converter.SetMember(tree, node, tokens);
return tree;
}
/***********************************************************************
Parsing Tree Conversion Implementation
***********************************************************************/
vl::Ptr<XmlText> XmlText::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlText>();
}
vl::Ptr<XmlCData> XmlCData::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlCData>();
}
vl::Ptr<XmlAttribute> XmlAttribute::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlAttribute>();
}
vl::Ptr<XmlComment> XmlComment::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlComment>();
}
vl::Ptr<XmlElement> XmlElement::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlElement>();
}
vl::Ptr<XmlInstruction> XmlInstruction::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlInstruction>();
}
vl::Ptr<XmlDocument> XmlDocument::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
{
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlDocument>();
}
/***********************************************************************
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<vl::parsing::ParsingTreeNode> XmlParseDocumentAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex)
{
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
state.Reset(L"XDocument");
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
return node;
}
vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseDocumentAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
{
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
return XmlParseDocumentAsParsingTreeNode(input, table, errors, codeIndex);
}
vl::Ptr<XmlDocument> XmlParseDocument(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex)
{
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
state.Reset(L"XDocument");
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
if(node && errors.Count()==0)
{
return XmlConvertParsingTreeNode(node, state.GetTokens()).Cast<XmlDocument>();
}
return 0;
}
vl::Ptr<XmlDocument> XmlParseDocument(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
{
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
return XmlParseDocument(input, table, errors, codeIndex);
}
vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseElementAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex)
{
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
state.Reset(L"XElement");
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
return node;
}
vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseElementAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
{
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
return XmlParseElementAsParsingTreeNode(input, table, errors, codeIndex);
}
vl::Ptr<XmlElement> XmlParseElement(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex)
{
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
state.Reset(L"XElement");
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
if(node && errors.Count()==0)
{
return XmlConvertParsingTreeNode(node, state.GetTokens()).Cast<XmlElement>();
}
return 0;
}
vl::Ptr<XmlElement> XmlParseElement(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
{
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
return XmlParseElement(input, table, errors, codeIndex);
}
/***********************************************************************
Table Generation
***********************************************************************/
vl::Ptr<vl::parsing::tabling::ParsingTable> XmlLoadTable()
{
vl::stream::MemoryStream stream;
XmlGetParserBuffer(stream);
vl::Ptr<vl::parsing::tabling::ParsingTable> 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<XmlText>(), 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<XmlCData>(), 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<XmlAttribute>(), 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<XmlComment>(), 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<XmlElement>(), 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<XmlInstruction>(), 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<XmlDocument>(), 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<XmlNode::IVisitor>(Ptr<IValueInterfaceProxy>), {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<ITypeLoader> 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<Object> 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<Object> 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<DescriptableObject> 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<DescriptableObject> 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<DescriptableObject> value)
{
return Value(value);
}
Value Value::From(const WString& value, ITypeDescriptor* type)
{
return Value(value, type);
}
IMethodInfo* Value::SelectMethod(IMethodGroupInfo* methodGroup, collections::Array<Value>& arguments)
{
if(methodGroup->GetMethodCount()==1)
{
return methodGroup->GetMethod(0);
}
List<IMethodInfo*> methods;
for(vint i=0;i<methodGroup->GetMethodCount();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;i<methods.Count();i++)
{
IMethodInfo* method=methods[i];
try
{
method->CheckArguments(arguments);
return method;
}
catch(const TypeDescriptorException&)
{
}
}
return methods[0];
}
}
Value Value::Create(ITypeDescriptor* type)
{
Array<Value> arguments;
return Create(type, arguments);
}
Value Value::Create(ITypeDescriptor* type, collections::Array<Value>& 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<Value> arguments;
return Create(typeName, arguments);
}
Value Value::Create(const WString& typeName, collections::Array<Value>& 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<Value> arguments;
return InvokeStatic(typeName, name, arguments);
}
Value Value::InvokeStatic(const WString& typeName, const WString& name, collections::Array<Value>& 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<Value> arguments;
return Invoke(name, arguments);
}
Value Value::Invoke(const WString& name, collections::Array<Value>& 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<IEventHandler> 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<IValueFunctionProxy> proxy=UnboxValue<Ptr<IValueFunctionProxy>>(function, Description<IValueFunctionProxy>::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<WString, Ptr<ITypeDescriptor>> typeDescriptors;
List<Ptr<ITypeLoader>> 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<ITypeDescriptor> 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<ITypeLoader> 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<ITypeLoader> 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;i<typeLoaders.Count();i++)
{
typeLoaders[i]->Load(this);
}
return true;
}
else
{
return false;
}
}
bool Unload()override
{
if(loaded)
{
loaded=false;
rootType=0;
for(vint i=0;i<typeLoaders.Count();i++)
{
typeLoaders[i]->Unload(this);
}
typeDescriptors.Clear();
return true;
}
else
{
return false;
}
}
bool Reload()override
{
Unload();
Load();
return true;
}
bool IsLoaded()override
{
return loaded;
}
ITypeDescriptor* GetRootType()override
{
if (!rootType)
{
rootType=description::GetTypeDescriptor<Value>();
}
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;j<serializer->GetCandidateCount();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;j<type->GetPropertyCount();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;j<type->GetEventCount();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;i<count;i++)
{
if(i>0) 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<IMethodInfo*>& propertyAccessors)
{
bool printed=false;
for(vint j=0;j<type->GetPropertyCount();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<IMethodInfo*>& propertyAccessors, bool isPropertyAccessor)
{
bool printed=false;
for(vint j=0;j<type->GetMethodGroupCount();j++)
{
IMethodGroupInfo* group=type->GetMethodGroup(j);
for(vint k=0;k<group->GetMethodCount();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;l<info->GetParameterCount();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;k<group->GetMethodCount();k++)
{
IMethodInfo* info=group->GetMethod(k);
writer.WriteString(L" constructor "+info->GetReturn()->GetTypeFriendlyName());
writer.WriteString(L" "+info->GetName()+L"(");
for(vint l=0;l<info->GetParameterCount();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;j<type->GetBaseTypeDescriptorCount();j++)
{
writer.WriteString(j==0?L" : ":L", ");
writer.WriteString(type->GetBaseTypeDescriptor(j)->GetTypeName());
}
writer.WriteLine(L"");
writer.WriteLine(L"{");
List<IMethodInfo*> 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<IValueInterfaceProxy>::TypeName)
{
acceptProxy = true;
return true;
}
}
}
}
if(!containsConstructor)
{
if(typeDescriptor->GetTypeName()==TypeInfo<IDescriptable>::TypeName)
{
return true;
}
else
{
for(vint i=0;i<typeDescriptor->GetBaseTypeDescriptorCount();i++)
{
bool _acceptProxy = false;
if(!IsInterfaceType(typeDescriptor->GetBaseTypeDescriptor(i), _acceptProxy))
{
return false;
}
}
const wchar_t* name=typeDescriptor->GetTypeName().Buffer();
while(const wchar_t* next=::wcschr(name, L':'))
{
name=next+1;
}
return name[0]==L'I' && (L'A'<=name[1] && name[1]<=L'Z');
}
}
return false;
}
void LogTypeManager(stream::TextWriter& writer)
{
for(vint i=0;i<globalTypeManager->GetTypeDescriptorCount();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> IValueEnumerable::Create(collections::LazyList<Value> values)
{
Ptr<IEnumerable<Value>> enumerable=new LazyList<Value>(values);
return new ValueEnumerableWrapper<Ptr<IEnumerable<Value>>>(enumerable);
}
/***********************************************************************
IValueList
***********************************************************************/
Ptr<IValueList> IValueList::Create()
{
Ptr<List<Value>> list=new List<Value>;
return new ValueListWrapper<Ptr<List<Value>>>(list);
}
Ptr<IValueList> IValueList::Create(Ptr<IValueReadonlyList> values)
{
Ptr<List<Value>> list=new List<Value>;
CopyFrom(*list.Obj(), GetLazyList<Value>(values));
return new ValueListWrapper<Ptr<List<Value>>>(list);
}
Ptr<IValueList> IValueList::Create(collections::LazyList<Value> values)
{
Ptr<List<Value>> list=new List<Value>;
CopyFrom(*list.Obj(), values);
return new ValueListWrapper<Ptr<List<Value>>>(list);
}
/***********************************************************************
IValueDictionary
***********************************************************************/
Ptr<IValueDictionary> IValueDictionary::Create()
{
Ptr<Dictionary<Value, Value>> dictionary=new Dictionary<Value, Value>;
return new ValueDictionaryWrapper<Ptr<Dictionary<Value, Value>>>(dictionary);
}
Ptr<IValueDictionary> IValueDictionary::Create(Ptr<IValueReadonlyDictionary> values)
{
Ptr<Dictionary<Value, Value>> dictionary=new Dictionary<Value, Value>;
CopyFrom(*dictionary.Obj(), GetLazyList<Value, Value>(values));
return new ValueDictionaryWrapper<Ptr<Dictionary<Value, Value>>>(dictionary);
}
Ptr<IValueDictionary> IValueDictionary::Create(collections::LazyList<collections::Pair<Value, Value>> values)
{
Ptr<Dictionary<Value, Value>> dictionary=new Dictionary<Value, Value>;
CopyFrom(*dictionary.Obj(), values);
return new ValueDictionaryWrapper<Ptr<Dictionary<Value, Value>>>(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<ITypeInfo>, 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<ITypeInfo> value)
{
genericArguments.Add(value);
}
void TypeInfoImpl::SetElementType(Ptr<ITypeInfo> value)
{
elementType=value;
}
/***********************************************************************
ParameterInfoImpl
***********************************************************************/
ParameterInfoImpl::ParameterInfoImpl(IMethodInfo* _ownerMethod, const WString& _name, Ptr<ITypeInfo> _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<ITypeInfo> _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<parameters.Count())
{
return parameters[index].Obj();
}
else
{
return 0;
}
}
ITypeInfo* MethodInfoImpl::GetReturn()
{
return returnInfo.Obj();
}
bool MethodInfoImpl::IsStatic()
{
return isStatic;
}
void MethodInfoImpl::CheckArguments(collections::Array<Value>& arguments)
{
if(arguments.Count()!=parameters.Count())
{
throw ArgumentCountMismtatchException(ownerMethodGroup);
}
for(vint i=0;i<parameters.Count();i++)
{
if(!arguments[i].CanConvertTo(parameters[i]->GetType()))
{
throw ArgumentTypeMismtatchException(parameters[i]->GetName(), parameters[i]->GetType(), arguments[i]);
}
}
}
Value MethodInfoImpl::Invoke(const Value& thisObject, collections::Array<Value>& 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<IParameterInfo> parameter)
{
for(vint i=0;i<parameters.Count();i++)
{
if(parameters[i]->GetName()==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<methods.Count())
{
return methods[index].Obj();
}
else
{
return 0;
}
}
bool MethodGroupInfoImpl::AddMethod(Ptr<IMethodInfo> _method)
{
methods.Add(_method);
return true;
}
/***********************************************************************
EventInfoImpl::EventHandlerImpl
***********************************************************************/
EventInfoImpl::EventHandlerImpl::EventHandlerImpl(EventInfoImpl* _ownerEvent, DescriptableObject* _ownerObject, Ptr<IValueFunctionProxy> _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<Value>& arguments)
{
if(thisObject.IsNull())
{
throw ArgumentNullException(L"thisObject", this);
}
Ptr<IValueList> 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<DescriptableObject> EventInfoImpl::EventHandlerImpl::GetDescriptableTag()
{
return descriptableTag;
}
void EventInfoImpl::EventHandlerImpl::SetDescriptableTag(Ptr<DescriptableObject> _tag)
{
descriptableTag = _tag;
}
Ptr<Object> EventInfoImpl::EventHandlerImpl::GetObjectTag()
{
return objectTag;
}
void EventInfoImpl::EventHandlerImpl::SetObjectTag(Ptr<Object> _tag)
{
objectTag = _tag;
}
/***********************************************************************
EventInfoImpl
***********************************************************************/
const wchar_t* EventInfoImpl::EventHandlerListInternalPropertyName = L"List<EventInfoImpl::EventHandlerImpl>";
void EventInfoImpl::AddEventHandler(DescriptableObject* thisObject, Ptr<IEventHandler> eventHandler)
{
WString key=EventHandlerListInternalPropertyName;
Ptr<EventHandlerList> value=thisObject->GetInternalProperty(key).Cast<EventHandlerList>();
if(!value)
{
value=new EventHandlerList;
thisObject->SetInternalProperty(key, value);
}
value->Add(eventHandler);
}
void EventInfoImpl::RemoveEventHandler(DescriptableObject* thisObject, IEventHandler* eventHandler)
{
WString key=EventHandlerListInternalPropertyName;
Ptr<EventHandlerList> value=thisObject->GetInternalProperty(key).Cast<EventHandlerList>();
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<IEventHandler> EventInfoImpl::Attach(const Value& thisObject, Ptr<IValueFunctionProxy> 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<EventHandlerImpl> 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<Value>& 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<Value> arguments;
return getter->Invoke(thisObject, arguments);
}
else
{
throw PropertyIsNotReadableException(this);
}
}
void PropertyInfoImpl::SetValue(Value& thisObject, const Value& newValue)
{
if(setter)
{
Array<Value> arguments(1);
arguments[0]=newValue;
setter->Invoke(thisObject, arguments);
}
else
{
throw PropertyIsNotWritableException(this);
}
}
/***********************************************************************
FieldInfoImpl
***********************************************************************/
FieldInfoImpl::FieldInfoImpl(ITypeDescriptor* _ownerTypeDescriptor, const WString& _name, Ptr<ITypeInfo> _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<MethodGroupInfoImpl> 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<IPropertyInfo> value)
{
properties.Add(value->GetName(), value);
return value.Obj();
}
IEventInfo* TypeDescriptorImpl::AddEvent(Ptr<IEventInfo> value)
{
events.Add(value->GetName(), value);
return value.Obj();
}
IMethodInfo* TypeDescriptorImpl::AddMethod(const WString& name, Ptr<MethodInfoImpl> value)
{
MethodGroupInfoImpl* methodGroup=PrepareMethodGroup(name);
value->SetOwnerMethodgroup(methodGroup);
methodGroup->AddMethod(value);
return value.Obj();
}
IMethodInfo* TypeDescriptorImpl::AddConstructor(Ptr<MethodInfoImpl> 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 && index<baseTypeDescriptors.Count())
{
return baseTypeDescriptors[index];
}
else
{
return 0;
}
}
bool TypeDescriptorImpl::CanConvertTo(ITypeDescriptor* targetType)
{
Load();
if(this==targetType) return true;
for(vint i=0;i<baseTypeDescriptors.Count();i++)
{
if(baseTypeDescriptors[i]->CanConvertTo(targetType)) return true;
}
return false;
}
vint TypeDescriptorImpl::GetPropertyCount()
{
Load();
return properties.Count();
}
IPropertyInfo* TypeDescriptorImpl::GetProperty(vint index)
{
Load();
if(0<=index && index<properties.Count())
{
return properties.Values().Get(index).Obj();
}
else
{
return 0;
}
}
bool TypeDescriptorImpl::IsPropertyExists(const WString& name, bool inheritable)
{
Load();
if(properties.Keys().Contains(name))
{
return true;
}
if(inheritable)
{
for(vint i=0;i<baseTypeDescriptors.Count();i++)
{
if(baseTypeDescriptors[i]->IsPropertyExists(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;i<baseTypeDescriptors.Count();i++)
{
IPropertyInfo* result=baseTypeDescriptors[i]->GetPropertyByName(name, true);
if(result)
{
return result;
}
}
}
return 0;
}
vint TypeDescriptorImpl::GetEventCount()
{
Load();
return events.Count();
}
IEventInfo* TypeDescriptorImpl::GetEvent(vint index)
{
Load();
if(0<=index && index<events.Count())
{
return events.Values().Get(index).Obj();
}
else
{
return 0;
}
}
bool TypeDescriptorImpl::IsEventExists(const WString& name, bool inheritable)
{
Load();
if(events.Keys().Contains(name))
{
return true;
}
if(inheritable)
{
for(vint i=0;i<baseTypeDescriptors.Count();i++)
{
if(baseTypeDescriptors[i]->IsEventExists(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;i<baseTypeDescriptors.Count();i++)
{
IEventInfo* result=baseTypeDescriptors[i]->GetEventByName(name, true);
if(result)
{
return result;
}
}
}
return 0;
}
vint TypeDescriptorImpl::GetMethodGroupCount()
{
Load();
return methodGroups.Count();
}
IMethodGroupInfo* TypeDescriptorImpl::GetMethodGroup(vint index)
{
Load();
if(0<=index && index<methodGroups.Count())
{
return methodGroups.Values().Get(index).Obj();
}
else
{
return 0;
}
}
bool TypeDescriptorImpl::IsMethodGroupExists(const WString& name, bool inheritable)
{
Load();
if(methodGroups.Keys().Contains(name))
{
return true;
}
if(inheritable)
{
for(vint i=0;i<baseTypeDescriptors.Count();i++)
{
if(baseTypeDescriptors[i]->IsMethodGroupExists(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;i<baseTypeDescriptors.Count();i++)
{
IMethodGroupInfo* result=baseTypeDescriptors[i]->GetMethodGroupByName(name, true);
if(result)
{
return result;
}
}
}
return 0;
}
IMethodGroupInfo* TypeDescriptorImpl::GetConstructorGroup()
{
Load();
return constructorGroup.Obj();
}
/***********************************************************************
Function Related
***********************************************************************/
namespace internal_helper
{
void UnboxSpecifiedParameter(Ptr<IValueList> arguments, vint index)
{
}
void UnboxSpecifiedParameter(MethodInfoImpl* methodInfo, collections::Array<Value>& arguments, vint index)
{
}
void UnboxSpecifiedParameter(collections::Array<Value>& arguments, vint index)
{
}
void AddValueToList(Ptr<IValueList> arguments)
{
}
void AddValueToArray(collections::Array<Value>& arguments, vint index)
{
}
}
}
}
}
/***********************************************************************
REFLECTION\GUITYPEDESCRIPTORPREDEFINED.CPP
***********************************************************************/
#include <limits.h>
#include <float.h>
namespace vl
{
using namespace collections;
using namespace regex;
namespace reflection
{
namespace description
{
/***********************************************************************
SerializableTypeDescriptorBase
***********************************************************************/
SerializableTypeDescriptorBase::SerializableTypeDescriptorBase(const WString& _typeName, const WString& _cppFullTypeName, Ptr<IValueSerializer> _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<vuint8_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<vuint8_t>::Serialize(const vuint8_t& input, WString& output)
{
output=u64tow(input);
return true;
}
bool TypedValueSerializerProvider<vuint8_t>::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<vuint16_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<vuint16_t>::Serialize(const vuint16_t& input, WString& output)
{
output=u64tow(input);
return true;
}
bool TypedValueSerializerProvider<vuint16_t>::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<vuint32_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<vuint32_t>::Serialize(const vuint32_t& input, WString& output)
{
output=u64tow(input);
return true;
}
bool TypedValueSerializerProvider<vuint32_t>::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<vuint64_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<vuint64_t>::Serialize(const vuint64_t& input, WString& output)
{
output=u64tow(input);
return true;
}
bool TypedValueSerializerProvider<vuint64_t>::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<vint8_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<vint8_t>::Serialize(const vint8_t& input, WString& output)
{
output=i64tow(input);
return true;
}
bool TypedValueSerializerProvider<vint8_t>::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<vint16_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<vint16_t>::Serialize(const vint16_t& input, WString& output)
{
output=i64tow(input);
return true;
}
bool TypedValueSerializerProvider<vint16_t>::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<vint32_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<vint32_t>::Serialize(const vint32_t& input, WString& output)
{
output=i64tow(input);
return true;
}
bool TypedValueSerializerProvider<vint32_t>::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<vint64_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<vint64_t>::Serialize(const vint64_t& input, WString& output)
{
output=i64tow(input);
return true;
}
bool TypedValueSerializerProvider<vint64_t>::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<float>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<float>::Serialize(const float& input, WString& output)
{
output=ftow(input);
return true;
}
bool TypedValueSerializerProvider<float>::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<double>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<double>::Serialize(const double& input, WString& output)
{
output=ftow(input);
return true;
}
bool TypedValueSerializerProvider<double>::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<wchar_t>::GetDefaultValue()
{
return 0;
}
bool TypedValueSerializerProvider<wchar_t>::Serialize(const wchar_t& input, WString& output)
{
output=input?WString(input):L"";
return true;
}
bool TypedValueSerializerProvider<wchar_t>::Deserialize(const WString& input, wchar_t& output)
{
if(input.Length()>1) return false;
output=input.Length()==0?0:input[0];
return true;
}
//---------------------------------------
WString TypedValueSerializerProvider<WString>::GetDefaultValue()
{
return L"";
}
bool TypedValueSerializerProvider<WString>::Serialize(const WString& input, WString& output)
{
output=input;
return true;
}
bool TypedValueSerializerProvider<WString>::Deserialize(const WString& input, WString& output)
{
output=input;
return true;
}
//---------------------------------------
Locale TypedValueSerializerProvider<Locale>::GetDefaultValue()
{
return Locale();
}
bool TypedValueSerializerProvider<Locale>::Serialize(const Locale& input, WString& output)
{
output=input.GetName();
return true;
}
bool TypedValueSerializerProvider<Locale>::Deserialize(const WString& input, Locale& output)
{
output=Locale(input);
return true;
}
/***********************************************************************
ObjectTypeDescriptor
***********************************************************************/
class ObjectTypeDescriptor : public SerializableTypeDescriptorBase
{
public:
ObjectTypeDescriptor()
:SerializableTypeDescriptorBase(TypeInfo<Value>::TypeName, TypeInfo<Value>::CppFullTypeName, 0)
{
}
};
/***********************************************************************
BoolValueSerializer
***********************************************************************/
class BoolValueSerializer : public EnumValueSerializer<bool, false>
{
public:
BoolValueSerializer(ITypeDescriptor* _ownerTypeDescriptor)
:EnumValueSerializer(_ownerTypeDescriptor, false)
{
candidates.Add(L"true", true);
candidates.Add(L"false", false);
}
};
/***********************************************************************
DateTimeValueSerializer
***********************************************************************/
class DateTimeValueSerializer : public GeneralValueSerializer<DateTime>
{
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<RegexMatch> 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<DateTime>(_ownerTypeDescriptor)
,regexDateTime(L"(<Y>/d/d/d/d)-(<M>/d/d)-(<D>/d/d) (<h>/d/d):(<m>/d/d):(<s>/d/d).(<ms>/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<IValueInterfaceProxy> proxy)
:ValueInterfaceRoot(proxy)
{
}
static Ptr<IValueEnumerator> Create(Ptr<IValueInterfaceProxy> 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<IValueInterfaceProxy> proxy)
:ValueInterfaceRoot(proxy)
{
}
static Ptr<IValueEnumerable> Create(Ptr<IValueInterfaceProxy> proxy)
{
return new description_IValueEnumerable(proxy);
}
Ptr<IValueEnumerator> CreateEnumerator()override
{
return INVOKEGET_INTERFACE_PROXY_NOPARAMS(CreateEnumerator);
}
};
class description_IValueReadonlyList : public description_IValueEnumerable, public virtual IValueReadonlyList
{
public:
description_IValueReadonlyList(Ptr<IValueInterfaceProxy> proxy)
:description_IValueEnumerable(proxy)
{
}
static Ptr<IValueReadonlyList> Create(Ptr<IValueInterfaceProxy> 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<IValueInterfaceProxy> proxy)
:description_IValueReadonlyList(proxy)
{
}
static Ptr<IValueList> Create(Ptr<IValueInterfaceProxy> 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<IValueInterfaceProxy> proxy)
:description_IValueReadonlyList(proxy)
{
}
static Ptr<IValueObservableList> Create(Ptr<IValueInterfaceProxy> proxy)
{
return new description_IValueObservableList(proxy);
}
};
class description_IValueReadonlyDictionary : public ValueInterfaceRoot, public virtual IValueReadonlyDictionary
{
public:
description_IValueReadonlyDictionary(Ptr<IValueInterfaceProxy> proxy)
:ValueInterfaceRoot(proxy)
{
}
static Ptr<IValueReadonlyDictionary> Create(Ptr<IValueInterfaceProxy> 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<IValueInterfaceProxy> proxy)
:description_IValueReadonlyDictionary(proxy)
{
}
static Ptr<IValueDictionary> Create(Ptr<IValueInterfaceProxy> 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<IValueInterfaceProxy> proxy)
:ValueInterfaceRoot(proxy)
{
}
static Ptr<IValueInterfaceProxy> Create(Ptr<IValueInterfaceProxy> proxy)
{
return new description_IValueInterfaceProxy(proxy);
}
Value Invoke(const WString& methodName, Ptr<IValueList> arguments)override
{
return INVOKEGET_INTERFACE_PROXY(Invoke, methodName, arguments);
}
};
class description_IValueFunctionProxy : public ValueInterfaceRoot, public virtual IValueFunctionProxy
{
public:
description_IValueFunctionProxy(Ptr<IValueInterfaceProxy> proxy)
:ValueInterfaceRoot(proxy)
{
}
static Ptr<IValueFunctionProxy> Create(Ptr<IValueInterfaceProxy> proxy)
{
return new description_IValueFunctionProxy(proxy);
}
Value Invoke(Ptr<IValueList> arguments)override
{
return INVOKEGET_INTERFACE_PROXY(Invoke, arguments);
}
};
class description_IValueListener : public ValueInterfaceRoot, public virtual IValueListener
{
public:
description_IValueListener(Ptr<IValueInterfaceProxy> proxy)
:ValueInterfaceRoot(proxy)
{
}
static Ptr<IValueListener> Create(Ptr<IValueInterfaceProxy> 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<IValueInterfaceProxy> proxy)
:ValueInterfaceRoot(proxy)
{
}
static Ptr<IValueSubscription> Create(Ptr<IValueInterfaceProxy> proxy)
{
return new description_IValueSubscription(proxy);
}
Ptr<IValueListener> Subscribe(const Func<void(Value)>& 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<DescriptableObject>
{
public:
class CustomTypeDescriptorImpl : public TypeDescriptorImpl
{
public:
CustomTypeDescriptorImpl()
:TypeDescriptorImpl(TypeInfo<DescriptableObject>::TypeName, TypeInfo<DescriptableObject>::CppFullTypeName)
{
Description<DescriptableObject>::SetAssociatedTypeDescroptor(this);
}
~CustomTypeDescriptorImpl()
{
Description<DescriptableObject>::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<IValueEnumerator>(Ptr<IValueInterfaceProxy>), {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<IValueEnumerable>(Ptr<IValueInterfaceProxy>), {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<IValueReadonlyList>(Ptr<IValueInterfaceProxy>), {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<IValueList>(), NO_PARAMETER, (Ptr<IValueList>(*)())&IValueList::Create)
CLASS_MEMBER_EXTERNALCTOR(Ptr<IValueList>(Ptr<IValueReadonlyList>), {L"values"}, (Ptr<IValueList>(*)(Ptr<IValueReadonlyList>))&IValueList::Create)
CLASS_MEMBER_EXTERNALCTOR(Ptr<IValueList>(Ptr<IValueInterfaceProxy>), {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<IValueObservableList>(Ptr<IValueInterfaceProxy>), {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<IValueReadonlyDictionary>(Ptr<IValueInterfaceProxy>), {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<IValueDictionary>(), NO_PARAMETER, (Ptr<IValueDictionary>(*)())&IValueDictionary::Create)
CLASS_MEMBER_EXTERNALCTOR(Ptr<IValueDictionary>(Ptr<IValueReadonlyDictionary>), {L"values"}, (Ptr<IValueDictionary>(*)(Ptr<IValueReadonlyDictionary>))&IValueDictionary::Create)
CLASS_MEMBER_EXTERNALCTOR(Ptr<IValueDictionary>(Ptr<IValueInterfaceProxy>), {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<IValueInterfaceProxy>(Ptr<IValueInterfaceProxy>), {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<IValueFunctionProxy>(Ptr<IValueInterfaceProxy>), {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<IValueListener>(Ptr<IValueInterfaceProxy>), {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<IValueSubscription>(Ptr<IValueInterfaceProxy>), {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<typename TSerializer>
void AddSerializableType(ITypeManager* manager)
{
manager->SetTypeDescriptor(TypeInfo<typename TSerializer::ValueType>::TypeName, new SerializableTypeDescriptor<TSerializer>);
}
void Load(ITypeManager* manager)override
{
manager->SetTypeDescriptor(TypeInfo<Value>::TypeName, new ObjectTypeDescriptor);
AddSerializableType<TypedDefaultValueSerializer<vuint8_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<vuint16_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<vuint32_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<vuint64_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<vint8_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<vint16_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<vint32_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<vint64_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<float>>(manager);
AddSerializableType<TypedDefaultValueSerializer<double>>(manager);
AddSerializableType<TypedDefaultValueSerializer<wchar_t>>(manager);
AddSerializableType<TypedDefaultValueSerializer<WString>>(manager);
AddSerializableType<TypedDefaultValueSerializer<Locale>>(manager);
AddSerializableType<BoolValueSerializer>(manager);
AddSerializableType<DateTimeValueSerializer>(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<ITypeLoader> 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<State*, State*> nfaStateMap;
Group<State*, State*> 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<State*, State*> nfaStateMap;
Group<State*, State*> 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<RegexToken>
{
protected:
RegexToken token;
vint index;
PureInterpretor* pure;
const Array<vint>& 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<vint>& _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<RegexToken>* 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<token.length;i++)
{
token.rowEnd=rowStart;
token.columnEnd=columnStart;
if(token.reading[i]==L'\n')
{
rowStart++;
columnStart=0;
}
else
{
columnStart++;
}
}
return true;
}
void Reset()
{
index=-1;
reading=start;
cacheAvailable=false;
}
void ReadToEnd(List<RegexToken>& tokens, bool(*discard)(vint))
{
while(Next())
{
if(!discard(token.token))
{
tokens.Add(token);
}
}
}
};
RegexTokens::RegexTokens(PureInterpretor* _pure, const Array<vint>& _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<RegexToken>* RegexTokens::CreateEnumerator()const
{
return new RegexTokenEnumerator(pure, stateTokens, code.Buffer(), codeIndex);
}
bool DefaultDiscard(vint token)
{
return false;
}
void RegexTokens::ReadToEnd(collections::List<RegexToken>& 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<vint>& _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;i<length;i++)
{
state=pure->Transit(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(index<length)
{
currentToken=-1;
finalState=false;
previousTokenStop=false;
walker.Walk(input[index], currentState, currentToken, finalState, previousTokenStop);
if(previousTokenStop)
{
vint tokenLength=stop-start;
if(tokenLength>0)
{
tokenProc(tokenProcArgument, start, tokenLength, token);
currentState=state;
start=stop;
index=stop-1;
state=-1;
token=-1;
finalState=false;
}
else if(stop<index)
{
stop=index+1;
tokenProc(tokenProcArgument, start, stop-start, -1);
start=index+1;
state=-1;
token=-1;
}
}
if(finalState)
{
stop=index+1;
state=currentState;
token=currentToken;
}
index++;
}
if(start<length)
{
if(finalState)
{
tokenProc(tokenProcArgument, start, length-start, token);
}
else
{
tokenProc(tokenProcArgument, start, length-start, walker.GetRelatedToken(currentState));
}
}
}
/***********************************************************************
RegexLexer
***********************************************************************/
RegexLexer::RegexLexer(const collections::IEnumerable<WString>& tokens)
:pure(0)
{
//构造所有DFA
List<Expression::Ref> expressions;
List<Automaton::Ref> dfas;
CharRange::List subsets;
Ptr<IEnumerator<WString>> 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<expressions.Count();i++)
{
Dictionary<State*, State*> nfaStateMap;
Group<State*, State*> 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;i<dfas.Count();i++)
{
Automaton::Ref dfa=dfas[i];
for(vint j=0;j<dfa->states.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;i<dfas.Count();i++)
{
CopyFrom(bigEnfa->states, dfas[i]->states);
CopyFrom(bigEnfa->transitions, dfas[i]->transitions);
}
bigEnfa->startState=bigEnfa->NewState();
for(vint i=0;i<dfas.Count();i++)
{
bigEnfa->NewEpsilon(bigEnfa->startState, dfas[i]->startState);
}
//转换成DFA
Dictionary<State*, State*> nfaStateMap;
Group<State*, State*> dfaStateMap;
Automaton::Ref bigNfa=EpsilonNfaToNfa(bigEnfa, PureEpsilonChecker, nfaStateMap);
for(vint i=0;i<nfaStateMap.Keys().Count();i++)
{
void* userData=nfaStateMap.Values().Get(i)->userData;
nfaStateMap.Keys()[i]->userData=userData;
}
Automaton::Ref bigDfa=NfaToDfa(bigNfa, dfaStateMap);
for(vint i=0;i<dfaStateMap.Keys().Count();i++)
{
void* userData=dfaStateMap.GetByIndex(i).Get(0)->userData;
for(vint j=1;j<dfaStateMap.GetByIndex(i).Count();j++)
{
void* newData=dfaStateMap.GetByIndex(i).Get(j)->userData;
if(userData>newData)
{
userData=newData;
}
}
dfaStateMap.Keys()[i]->userData=userData;
}
//构造状态机
pure=new PureInterpretor(bigDfa, subsets);
stateTokens.Resize(bigDfa->states.Count());
for(vint i=0;i<stateTokens.Count();i++)
{
void* userData=bigDfa->states[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<State*>& epsilonStates, List<Transition*>& transitions)
{
if(!epsilonStates.Contains(sourceState))
{
epsilonStates.Add(sourceState);
for(vint i=0;i<sourceState->transitions.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<State*, State*>& nfaStateMap)
{
Automaton::Ref target=new Automaton;
Dictionary<State*, State*> stateMap; //source->target
List<State*> epsilonStates; //每次迭代当前状态的epsilon闭包
List<Transition*> 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;i<target->states.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;j<transitions.Count();j++)
{
Transition* transition=transitions[j];
//寻找到一个非epsilon闭包的时候更新映射
if(!stateMap.Keys().Contains(transition->target))
{
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<State*, State*>& dfaStateMap)
{
Automaton::Ref target=new Automaton;
Group<Transition*, Transition*> nfaTransitions;
List<Transition*> transitionClasses;//保证转换先后顺序不被nfaTransitions.Keys破坏
CopyFrom(target->captureNames, source->captureNames);
State* startState=target->NewState();
target->startState=startState;
dfaStateMap.Add(startState, source->startState);
SortedList<State*> transitionTargets;
SortedList<State*> relativeStates;
transitionTargets.SetLessMemoryMode(false);
relativeStates.SetLessMemoryMode(false);
for(vint i=0;i<target->states.Count();i++)
{
State* currentState=target->states[i].Obj();
nfaTransitions.Clear();
transitionClasses.Clear();
//对该DFA状态的所有等价NFA状态进行遍历
const List<State*>& nfaStates=dfaStateMap[currentState];
for(vint j=0;j<nfaStates.Count();j++)
{
State* nfaState=nfaStates.Get(j);
//对每一个NFA状态的所有转换进行遍历
for(vint k=0;k<nfaState->transitions.Count();k++)
{
Transition* nfaTransition=nfaState->transitions[k];
//检查该NFA转换类型是否已经具有已经被记录
Transition* transitionClass=0;
for(vint l=0;l<nfaTransitions.Keys().Count();l++)
{
Transition* key=nfaTransitions.Keys()[l];
if(AreEqual(key, nfaTransition))
{
transitionClass=key;
break;
}
}
//不存在则创建一个转换类型
if(transitionClass==0)
{
transitionClass=nfaTransition;
transitionClasses.Add(transitionClass);
}
//注册转换
nfaTransitions.Add(transitionClass, nfaTransition);
}
}
//遍历所有种类的NFA转换
for(vint j=0;j<transitionClasses.Count();j++)
{
const List<Transition*>& transitionSet=nfaTransitions[transitionClasses[j]];
//对所有转换的NFA目标状态集合进行排序
transitionTargets.Clear();
for(vint l=0;l<transitionSet.Count();l++)
{
State* nfaState=transitionSet.Get(l)->target;
if(!transitionTargets.Contains(nfaState))
{
transitionTargets.Add(nfaState);
}
}
//判断转换类的所有转换的NFA目标状态组成的集合是否已经有一个对应的DFA状态
State* dfaState=0;
for(vint k=0;k<dfaStateMap.Count();k++)
{
//将DFA的等价NFA状态集合进行排序
CopyFrom(relativeStates, dfaStateMap.GetByIndex(k));
//比较两者是否相等
if(relativeStates.Count()==transitionTargets.Count())
{
bool equal=true;
for(vint l=0;l<relativeStates.Count();l++)
{
if(relativeStates[l]!=transitionTargets[l])
{
equal=false;
break;
}
}
if(equal)
{
dfaState=dfaStateMap.Keys()[k];
break;
}
}
}
//不存在等价DFA状态则创建一个
if(!dfaState)
{
dfaState=target->NewState();
for(vint k=0;k<transitionTargets.Count();k++)
{
dfaStateMap.Add(dfaState, transitionTargets[k]);
if(transitionTargets[k]->finalState)
{
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<item.begin;
}
bool CharRange::operator<=(CharRange item)const
{
return *this<item || *this==item;
}
bool CharRange::operator>(CharRange item)const
{
return item.end<begin;
}
bool CharRange::operator>=(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<item;
}
bool CharRange::operator<=(wchar_t item)const
{
return begin<=item;
}
bool CharRange::operator>(wchar_t item)const
{
return item<begin;
}
bool CharRange::operator>=(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<begin || end<item;
}
}
}
/***********************************************************************
REGEX\REGEXEXPRESSION.CPP
***********************************************************************/
namespace vl
{
namespace regex_internal
{
/***********************************************************************
IsEqualAlgorithm
***********************************************************************/
class IsEqualAlgorithm : public RegexExpressionAlgorithm<bool, Expression*>
{
public:
bool Apply(CharSetExpression* expression, Expression* target)
{
CharSetExpression* expected=dynamic_cast<CharSetExpression*>(target);
if(expected)
{
if(expression->reverse!=expected->reverse)return false;
if(expression->ranges.Count()!=expected->ranges.Count())return false;
for(vint i=0;i<expression->ranges.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<LoopExpression*>(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<SequenceExpression*>(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<AlternateExpression*>(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<BeginExpression*>(target);
if(expected)
{
return true;
}
return false;
}
bool Apply(EndExpression* expression, Expression* target)
{
EndExpression* expected=dynamic_cast<EndExpression*>(target);
if(expected)
{
return true;
}
return false;
}
bool Apply(CaptureExpression* expression, Expression* target)
{
CaptureExpression* expected=dynamic_cast<CaptureExpression*>(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<MatchExpression*>(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<PositiveExpression*>(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<NegativeExpression*>(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<UsingExpression*>(target);
if(expected)
{
if(expression->name!=expected->name)return false;
return true;
}
return false;
}
};
/***********************************************************************
HasNoExtensionAlgorithm
***********************************************************************/
class HasNoExtensionAlgorithm : public RegexExpressionAlgorithm<bool, void*>
{
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<bool, void*>
{
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<void, NormalizedCharSet*>
{
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;i<ranges.Count();i++)
{
CharRange range=ranges[i];
if(range.begin>begin)
{
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;i<ranges.Count();i++)
{
Process(expression, target, ranges[i]);
}
}
}
void Apply(LoopExpression* expression, NormalizedCharSet* target)
{
Invoke(expression->expression, 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(index<target->ranges.Count())
{
CharRange current=target->ranges[index];
if(current<range || current>range)
{
index++;
}
else if(current.begin<range.begin)
{
// range : [ ?
// current : [ ]
target->ranges.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.end<range.end)
{
// range : [ ]
// current : [ ]
range.begin=current.end+1;
index++;
}
else if(current.end>range.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;j<target->ranges.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<Expression::Ref, MergeParameter*>
{
public:
Expression::Ref Apply(CharSetExpression* expression, MergeParameter* target)
{
Ptr<CharSetExpression> result=new CharSetExpression;
CopyFrom(result->ranges, expression->ranges);
result->reverse=expression->reverse;
return result;
}
Expression::Ref Apply(LoopExpression* expression, MergeParameter* target)
{
Ptr<LoopExpression> 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<SequenceExpression> 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<AlternateExpression> 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<CaptureExpression> result=new CaptureExpression;
result->expression=Invoke(expression->expression, target);
result->name=expression->name;
return result;
}
Expression::Ref Apply(MatchExpression* expression, MergeParameter* target)
{
Ptr<MatchExpression> result=new MatchExpression;
result->name=expression->name;
result->index=expression->index;
return result;
}
Expression::Ref Apply(PositiveExpression* expression, MergeParameter* target)
{
Ptr<PositiveExpression> result=new PositiveExpression;
result->expression=Invoke(expression->expression, target);
return result;
}
Expression::Ref Apply(NegativeExpression* expression, MergeParameter* target)
{
Ptr<NegativeExpression> 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<EpsilonNfa, Automaton*>
{
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;i<expression->ranges.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;i<expression->min;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;i<expression->max;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;i<ranges.Count();i++)
{
if(!(range<ranges[i] || range>ranges[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<LoopExpression> 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<Expression> 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<CharSetExpression> 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<CharSetExpression> 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<Expression> ParseFunction(const wchar_t*& input)
{
if(IsStr(input, L"(="))
{
Ptr<Expression> 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<Expression> 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<Expression> 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<Expression> 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<Expression> 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<Expression> ParseUnit(const wchar_t*& input)
{
Ptr<Expression> unit=ParseCharSet(input);
if(!unit)
{
unit=ParseFunction(input);
}
if(!unit)
{
return 0;
}
Ptr<LoopExpression> loop;
while((loop=ParseLoop(input)))
{
loop->expression=unit;
unit=loop;
}
return unit;
}
Ptr<Expression> ParseJoin(const wchar_t*& input)
{
Ptr<Expression> expression=ParseUnit(input);
while(true)
{
Ptr<Expression> right=ParseUnit(input);
if(right)
{
SequenceExpression* sequence=new SequenceExpression;
sequence->left=expression;
sequence->right=right;
expression=sequence;
}
else
{
break;
}
}
return expression;
}
Ptr<Expression> ParseAlt(const wchar_t*& input)
{
Ptr<Expression> expression=ParseJoin(input);
while(true)
{
if(IsChar(input, L'|'))
{
Ptr<Expression> 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<Expression> 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<Expression> 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<literalString.Length();i++)
{
wchar_t c=literalString[i];
switch(c)
{
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'=':
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<escapedText.Length();i++)
{
wchar_t c=escapedText[i];
if(c==L'\\' || c==L'/')
{
if(i<escapedText.Length()-1)
{
i++;
c=escapedText[i];
switch(c)
{
case L'r':
result+=L"\r";
break;
case L'n':
result+=L"\n";
break;
case L't':
result+=L"\t";
break;
default:
result+=c;
}
continue;
}
}
result+=c;
}
return result;
}
WString NormalizeEscapedTextForRegex(const WString& escapedText)
{
WString result;
for(vint i=0;i<escapedText.Length();i++)
{
wchar_t c=escapedText[i];
if(c==L'\\' || c==L'/')
{
if(i<escapedText.Length()-1)
{
i++;
c=escapedText[i];
result+=WString(L"\\")+c;
continue;
}
}
result+=c;
}
return result;
}
bool IsRegexEscapedLiteralString(const WString& regex)
{
for(vint i=0;i<regex.Length();i++)
{
wchar_t c=regex[i];
if(c==L'\\' || c==L'/')
{
i++;
}
else
{
switch(c)
{
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'=':
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;i<SupportedCharCount;i++)
{
charMap[i]=charSetCount-1;
}
for(vint i=0;i<subsets.Count();i++)
{
CharRange range=subsets[i];
for(vint j=range.begin;j<=range.end;j++)
{
charMap[j]=i;
}
}
//构造状态转换表
transition=new vint*[stateCount];
for(vint i=0;i<stateCount;i++)
{
transition[i]=new vint[charSetCount];
for(vint j=0;j<charSetCount;j++)
{
transition[i][j]=-1;
}
State* state=dfa->states[i].Obj();
for(vint j=0;j<state->transitions.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;i<stateCount;i++)
{
finalState[i]=dfa->states[i]->finalState;
}
}
PureInterpretor::~PureInterpretor()
{
if(relatedFinalState) delete[] relatedFinalState;
delete[] finalState;
for(vint i=0;i<stateCount;i++)
{
delete[] transition[i];
}
delete[] transition;
}
bool PureInterpretor::MatchHead(const wchar_t* input, const wchar_t* start, PureResult& result)
{
result.start=input-start;
result.length=-1;
result.finalState=-1;
result.terminateState=-1;
vint currentState=startState;
vint terminateState=-1;
vint terminateLength=-1;
const wchar_t* read=input;
while(currentState!=-1)
{
terminateState=currentState;
terminateLength=read-input;
if(finalState[currentState])
{
result.length=terminateLength;
result.finalState=currentState;
}
if(!*read)break;
#ifdef VCZH_GCC
if(*read>=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<stateCount)
{
vint charIndex=charMap[input];
vint nextState=transition[state][charIndex];
return nextState;
}
else
{
return -1;
}
}
bool PureInterpretor::IsFinalState(vint state)
{
return 0<=state && state<stateCount && finalState[state];
}
bool PureInterpretor::IsDeadState(vint state)
{
if(state==-1) return true;
for(vint i=0;i<charSetCount;i++)
{
if(transition[state][i]!=-1)
{
return false;
}
}
return true;
}
void PureInterpretor::PrepareForRelatedFinalStateTable()
{
if(!relatedFinalState)
{
relatedFinalState=new vint[stateCount];
for(vint i=0;i<stateCount;i++)
{
relatedFinalState[i]=finalState[i]?i:-1;
}
while(true)
{
vint modifyCount=0;
for(vint i=0;i<stateCount;i++)
{
if(relatedFinalState[i]==-1)
{
vint state=-1;
for(vint j=0;j<charSetCount;j++)
{
vint nextState=transition[i][j];
if(nextState!=-1)
{
state=relatedFinalState[nextState];
if(state!=-1)
{
break;
}
}
}
if(state!=-1)
{
relatedFinalState[i]=state;
modifyCount++;
}
}
}
if(modifyCount==0)
{
break;
}
}
}
}
vint PureInterpretor::GetRelatedFinalState(vint state)
{
return relatedFinalState?relatedFinalState[state]:-1;
}
}
}
/***********************************************************************
REGEX\REGEXRICH.CPP
***********************************************************************/
namespace vl
{
namespace regex_internal
{
using namespace collections;
/***********************************************************************
回溯辅助数据结构
***********************************************************************/
class SaverBase
{
public:
bool available;
vint previous;
};
class StateSaver
{
public:
enum StateStoreType
{
Positive,
Negative,
Other
};
const wchar_t* reading; //当前字符串位置
State* currentState; //当前状态
vint minTransition; //最小可用转换
vint captureCount; //有效capture数量
vint stateSaverCount; //有效回溯状态数量
vint extensionSaverAvailable; //有效未封闭扩展功能数量
vint extensionSaverCount; //所有未封闭扩展功能数量
StateStoreType storeType; //保存状态的原因
bool operator==(const StateSaver& saver)const
{
return
reading==saver.reading &&
currentState==saver.currentState &&
minTransition==saver.minTransition &&
captureCount==saver.captureCount;
}
};
class ExtensionSaver : public SaverBase
{
public:
vint captureListIndex;
Transition* transition;
const wchar_t* reading;
bool operator==(const ExtensionSaver& saver)const
{
return
captureListIndex==saver.captureListIndex &&
transition==saver.transition &&
reading==saver.reading;
}
};
template<typename T, typename K>
void Push(List<T, K>& 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<typename T, typename K>
T Pop(List<T, K>& elements, vint& available, vint& count)
{
T& current=elements[available];
available=current.previous;
return current;
}
template<typename T, typename K>
void PushNonSaver(List<T, K>& elements, vint& count, const T& element)
{
if(elements.Count()==count)
{
elements.Add(element);
}
else
{
elements[count]=element;
}
count++;
}
template<typename T, typename K>
T PopNonSaver(List<T, K>& elements, vint& count)
{
return elements[--count];
}
}
template<>
struct POD<regex_internal::StateSaver>
{
static const bool Result=true;
};
template<>
struct POD<regex_internal::ExtensionSaver>
{
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;i<dfa->states.Count();i++)
{
State* state=dfa->states[i].Obj();
vint charEdges=0;
vint nonCharEdges=0;
bool mustSave=false;
for(vint j=0;j<state->transitions.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<StateSaver> stateSavers;
List<ExtensionSaver> 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;i<currentState.currentState->transitions.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;j<currentState.captureCount;j++)
{
CaptureRecord& capture=result.captures[j];
if(capture.capture==transition->capture)
{
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;i<currentState.currentState->transitions.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<WString>& 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<CharSetExpression*>(expression.Obj());
CHECK_ERROR(source, L"RegexNode::operator!()#operator ! can only applies on charset expressions.");
Ptr<CharSetExpression> 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<CharSetExpression*>(expression.Obj());
CharSetExpression* right=dynamic_cast<CharSetExpression*>(node.expression.Obj());
CHECK_ERROR(left && right && !left->reverse && !right->reverse, L"RegexNode::operator%(const RegexNode&)#operator % only connects non-reverse charset expressions.");
Ptr<CharSetExpression> target=new CharSetExpression;
target->reverse=false;
CopyFrom(target->ranges, left->ranges);
for(vint i=0;i<right->ranges.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(;i<length;i++)
{
if((buffer[i]=ReadChar())==L'\0')
{
break;
}
}
buffer[i]=L'\0';
WString result(buffer);
delete[] buffer;
return result;
}
WString TextReader::ReadLine()
{
WString result;
wchar_t buffer[65537];
buffer[0]=L'\0';
vint i=0;
while(true)
{
wchar_t c=ReadChar();
if(c==L'\n' || 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;
if(result.Length()>0 && 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<vint>& columnWidths, vint columns)
{
writer.WriteChar(L'+');
for(vint i=0;i<columns;i++)
{
vint c=columnWidths[i];
for(vint j=0;j<c;j++)
{
writer.WriteChar(L'-');
}
writer.WriteChar(L'+');
}
writer.WriteLine(L"");
}
void WriteContentLine(TextWriter& writer, Array<vint>& columnWidths, vint rowHeight, vint columns, Array<WString>& tableByRow, vint startRow)
{
vint cellStart=startRow*columns;
for(vint r=0;r<rowHeight;r++)
{
writer.WriteChar(L'|');
for(vint c=0;c<columns;c++)
{
const wchar_t* cell=tableByRow[cellStart+c].Buffer();
for(vint i=0;i<r;i++)
{
if(cell) cell=::wcsstr(cell, L"\r\n");
if(cell) cell+=2;
}
writer.WriteChar(L' ');
vint length=0;
if(cell)
{
const wchar_t* end=::wcsstr(cell, L"\r\n");
length=end?end-cell:(vint)wcslen(cell);
writer.WriteString(cell, length);
}
for(vint i=columnWidths[c]-2;i>=length;i--)
{
writer.WriteChar(L' ');
}
writer.WriteChar(L'|');
}
writer.WriteLine(L"");
}
}
}
using namespace monospace_tabling;
void TextWriter::WriteMonospacedEnglishTable(collections::Array<WString>& tableByRow, vint rows, vint columns)
{
Array<vint> rowHeights(rows);
Array<vint> columnWidths(columns);
for(vint i=0;i<rows;i++) rowHeights[i]=0;
for(vint j=0;j<columns;j++) columnWidths[j]=0;
for(vint i=0;i<rows;i++)
{
for(vint j=0;j<columns;j++)
{
WString text=tableByRow[i*columns+j];
const wchar_t* reading=text.Buffer();
vint width=0;
vint height=0;
while(reading)
{
height++;
const wchar_t* crlf=::wcsstr(reading, L"\r\n");
if(crlf)
{
vint length=crlf-reading+2;
if(width<length) width=length;
reading=crlf+2;
}
else
{
vint length=(vint)wcslen(reading)+2;
if(width<length) width=length;
reading=0;
}
}
if(rowHeights[i]<height) rowHeights[i]=height;
if(columnWidths[j]<width) columnWidths[j]=width;
}
}
WriteBorderLine(*this, columnWidths, columns);
for(vint i=0;i<rows;i++)
{
WriteContentLine(*this, columnWidths, rowHeights[i], columns, tableByRow, i);
WriteBorderLine(*this, columnWidths, columns);
}
}
/***********************************************************************
StringReader
***********************************************************************/
void StringReader::PrepareIfLastCallIsReadLine()
{
if(lastCallIsReadLine)
{
lastCallIsReadLine=false;
if(current<string.Length() && string[current]==L'\r') current++;
if(current<string.Length() && string[current]==L'\n') current++;
}
}
StringReader::StringReader(const WString& _string)
:string(_string)
,current(0)
,lastCallIsReadLine(false)
{
}
bool StringReader::IsEnd()
{
return current==string.Length();
}
wchar_t StringReader::ReadChar()
{
PrepareIfLastCallIsReadLine();
if(IsEnd())
{
return L'\0';
}
else
{
return string[current++];
}
}
WString StringReader::ReadString(vint length)
{
PrepareIfLastCallIsReadLine();
if(IsEnd())
{
return L"";
}
else
{
vint remain=string.Length()-current;
if(length>remain) 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(lineEnd<string.Length())
{
wchar_t c=string[lineEnd];
if(c==L'\r' || c==L'\n') break;
lineEnd++;
}
WString result=string.Sub(current, lineEnd-current);
current=lineEnd;
lastCallIsReadLine=true;
return result;
}
}
WString StringReader::ReadToEnd()
{
return ReadString(string.Length()-current);
}
/***********************************************************************
StreamReader
***********************************************************************/
StreamReader::StreamReader(IStream& _stream)
:stream(&_stream)
{
}
bool StreamReader::IsEnd()
{
return stream==0;
}
wchar_t StreamReader::ReadChar()
{
if(stream)
{
wchar_t buffer=0;
if(stream->Read(&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;i<streams.Count();i++)
{
streams[i]->Write(_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 && position<start+availableLength)
{
vint bufferMax=(vint)(start+availableLength-position);
vint min=bufferMax<_size?bufferMax:_size;
memcpy(_buffer, buffer+(position-start), min);
readed+=min;
_buffer=(char*)_buffer+min;
}
if(_size>readed)
{
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<remain?availableLength:remain;
memcpy(_buffer, buffer, min);
readed+=min;
}
}
return readed;
}
vint CacheStream::InternalWrite(void* _buffer, vint _size)
{
vint written=0;
if(position>=start && position<start+block)
{
vint bufferMax=(vint)(start+block-position);
vint writeLength=bufferMax<_size?bufferMax:_size;
vint writeStart=(vint)(position-start);
memcpy(buffer+writeStart, _buffer, writeLength);
written+=writeLength;
_buffer=(char*)_buffer+writeLength;
if(dirtyLength==0)
{
dirtyStart=writeStart;
dirtyLength=writeLength;
}
else
{
dirtyLength=writeStart+writeLength-dirtyStart;
}
vint availableOffset=writeStart+writeLength-availableLength;
if(availableOffset>0)
{
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<position)
{
operatedSize=position;
}
return _size;
}
vint CacheStream::Write(void* _buffer, vint _size)
{
CHECK_ERROR(CanWrite(), L"CacheStream::Write(void*, vint)#Stream is closed or operation not supported.");
CHECK_ERROR(_size>=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<position)
{
operatedSize=position;
}
return _size;
}
vint CacheStream::Peek(void* _buffer, vint _size)
{
CHECK_ERROR(CanPeek(), L"CacheStream::Peek(void*, vint)#Stream is closed or operation not supported.");
CHECK_ERROR(_size>=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(readed<chars)
{
if(stream->Read(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(writed<chars)
{
if(stream->Write(((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;i<chars;i++)
{
unsigned char t=unicode[0];
unicode[0]=unicode[1];
unicode[1]=t;
unicode++;
}
return chars;
#elif defined VCZH_GCC
wchar_t* writing = _buffer;
while (writing - _buffer < chars)
{
vuint16_t utf16_1 = 0;
vuint16_t utf16_2 = 0;
vuint8_t* utf16buf = 0;
vuint8_t utf16buf_temp = 0;
if (stream->Read(&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(readed<chars)
{
#if defined VCZH_MSVC
if(cacheAvailable)
{
*writing++=cache;
cache=0;
cacheAvailable=false;
}
else
{
#endif
if(stream->Read(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(bomPosition<bomLength)
{
vint remain=bomLength-bomPosition;
result=remain<_size?remain:_size;
memcpy(buffer, bom+bomPosition, result);
buffer+=result;
bomPosition+=result;
_size-=result;
}
if(_size)
{
result+=stream->Read(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<size;i++)
{
if(buffer[i]==0) return false;
if(needTrail)
{
needTrail=false;
}
else if(buffer[i]>=128)
{
needTrail=true;
}
}
return !needTrail;
}
bool CanBeUtf8(unsigned char* buffer, vint size)
{
for(vint i=0;i<size;i++)
{
unsigned char c=(unsigned char)buffer[i];
if(c==0)
{
return false;
}
else
{
vint count10xxxxxx=0;
if((c&0x80)==0x00) /* 0x0xxxxxxx */ count10xxxxxx=0;
else if((c&0xE0)==0xC0) /* 0x110xxxxx */ count10xxxxxx=1;
else if((c&0xF0)==0xE0) /* 0x1110xxxx */ count10xxxxxx=2;
else if((c&0xF8)==0xF0) /* 0x11110xxx */ count10xxxxxx=3;
else if((c&0xFC)==0xF8) /* 0x111110xx */ count10xxxxxx=4;
else if((c&0xFE)==0xFC) /* 0x1111110x */ count10xxxxxx=5;
if(size<=i+count10xxxxxx)
{
return false;
}
else
{
for(vint j=0;j<count10xxxxxx;j++)
{
c=(unsigned char)buffer[i+j+1];
if((c&0xC0)!=0x80) /* 0x10xxxxxx */ return false;
}
}
i+=count10xxxxxx;
}
}
return true;
}
bool CanBeUtf16(unsigned char* buffer, vint size)
{
if(size%2!=0) return false;
bool needTrail=false;
for(vint i=0;i<size;i+=2)
{
if(buffer[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<size;i+=2)
{
if(buffer[i+1]>=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<vint Count>
bool GetEncodingResult(int (&tests)[Count], bool(&results)[Count], int test)
{
for(vint i=0;i<Count;i++)
{
if(tests[i]&test)
{
if(results[i]) return true;
}
}
return false;
}
#endif
void TestEncoding(unsigned char* buffer, vint size, BomEncoder::Encoding& encoding, bool& containsBom)
{
if(size>=3 && strncmp((char*)buffer, "\xEF\xBB\xBF", 3)==0)
{
encoding=BomEncoder::Utf8;
containsBom=true;
}
else if(size>=2 && strncmp((char*)buffer, "\xFF\xFE", 2)==0)
{
encoding=BomEncoder::Utf16;
containsBom=true;
}
else if(size>=2 && strncmp((char*)buffer, "\xFE\xFF", 2)==0)
{
encoding=BomEncoder::Utf16BE;
containsBom=true;
}
else
{
encoding=BomEncoder::Mbcs;
containsBom=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<TestCount;i++)
{
int test=tests[i];
results[i]=IsTextUnicode(buffer, (int)size, &test)!=0;
}
if(size%2==0
&& !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_ASCII16)
&& !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_STATISTICS)
&& !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_CONTROLS)
)
{
for(vint i=0;i<size;i+=2)
{
unsigned char c=buffer[i];
buffer[i]=buffer[i+1];
buffer[i+1]=c;
}
// 3 = (count of reverse group) = (count of unicode group)
for(vint i=0;i<3;i++)
{
int test=tests[i+3];
results[i]=IsTextUnicode(buffer, (int)size, &test)!=0;
}
for(vint i=0;i<size;i+=2)
{
unsigned char c=buffer[i];
buffer[i]=buffer[i+1];
buffer[i+1]=c;
}
}
if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_UNICODE_MASK))
{
if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_ASCII_MASK))
{
encoding=BomEncoder::Utf8;
}
else if(roughUtf8||!roughMbcs)
{
encoding=BomEncoder::Utf8;
}
}
else if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_ASCII16))
{
encoding=BomEncoder::Utf16;
}
else if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_ASCII16))
{
encoding=BomEncoder::Utf16BE;
}
else if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_CONTROLS))
{
encoding=BomEncoder::Utf16;
}
else if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_CONTROLS))
{
encoding=BomEncoder::Utf16BE;
}
else
{
if(!roughUtf8)
{
if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_STATISTICS))
{
encoding=BomEncoder::Utf16;
}
else if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_STATISTICS))
{
encoding=BomEncoder::Utf16BE;
}
}
else if(GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_UNICODE_MASK))
{
encoding=BomEncoder::Utf8;
}
else if(roughUtf8||!roughMbcs)
{
encoding=BomEncoder::Utf8;
}
}
}
#endif
containsBom=encoding==BomEncoder::Mbcs;
}
}
}
}
/***********************************************************************
STREAM\COMPRESSIONSTREAM.CPP
***********************************************************************/
namespace vl
{
namespace stream
{
using namespace lzw;
/***********************************************************************
LzwBase
***********************************************************************/
void LzwBase::UpdateIndexBits()
{
if (nextIndex >=2 && (nextIndex & (nextIndex - 1)) == 0)
{
indexBits++;
}
}
lzw::Code* LzwBase::CreateCode(lzw::Code* prefix, vuint8_t byte)
{
if (nextIndex < MaxDictionarySize)
{
Code* code = codeAllocator.Create();
code->byte = byte;
code->code = nextIndex;
code->parent = prefix;
code->size = prefix->size + 1;
prefix->children.Set(byte, code, mapAllocator);
nextIndex++;
return code;
}
else
{
return 0;
}
}
LzwBase::LzwBase()
:codeAllocator(65536)
, mapAllocator(1048576)
{
root = codeAllocator.Create();
for (vint i = 0; i < 256; i++)
{
UpdateIndexBits();
CreateCode(root, (vuint8_t)i);
}
}
LzwBase::LzwBase(bool (&existingBytes)[256])
{
root = codeAllocator.Create();
for (vint i = 0; i < 256; i++)
{
if (existingBytes[i])
{
UpdateIndexBits();
CreateCode(root, (vuint8_t)i);
}
}
if (indexBits < 8)
{
eofIndex = nextIndex++;
}
}
LzwBase::~LzwBase()
{
}
/***********************************************************************
LzwEncoder
***********************************************************************/
void LzwEncoder::Flush()
{
vint written = 0;
vint bufferUsedSize = bufferUsedBits / 8;
if (bufferUsedBits % 8 != 0)
{
bufferUsedSize++;
}
while (written < bufferUsedSize)
{
vint size = stream->Write(buffer + written, bufferUsedSize - written);
CHECK_ERROR(size != 0, L"LzwEncoder::Flush()#Failed to flush the lzw buffer.");
written += size;
}
bufferUsedBits = 0;
}
vuint8_t highMarks[9] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
vuint8_t lowMarks[9] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
void LzwEncoder::WriteNumber(vint number, vint bitSize)
{
vint bitStart = 0;
vint bitStep = 8 - bufferUsedBits % 8;
if (bitStep > bitSize)
{
bitStep = bitSize;
}
while (bitStart < bitSize)
{
if(bufferUsedBits == BufferSize * 8)
{
Flush();
}
vint writeStart = bufferUsedBits % 8;
vint byteIndex = bufferUsedBits / 8;
vuint8_t byte = buffer[byteIndex];
byte &= highMarks[writeStart];
vuint8_t content = (vuint8_t)((number >> bitStart)&lowMarks[bitStep]) << (8 - writeStart - bitStep);
byte |= content;
buffer[byteIndex] = byte;
bufferUsedBits += bitStep;
bitStart += bitStep;
vint remain = bitSize - bitStart;
bitStep = remain < 8 ? remain : 8;
}
}
LzwEncoder::LzwEncoder()
{
prefix = root;
}
LzwEncoder::LzwEncoder(bool (&existingBytes)[256])
:LzwBase(existingBytes)
{
prefix = root;
}
LzwEncoder::~LzwEncoder()
{
}
void LzwEncoder::Setup(IStream* _stream)
{
stream = _stream;
}
void LzwEncoder::Close()
{
if (prefix != root)
{
WriteNumber(prefix->code, indexBits);
prefix = root;
}
vint remain = 8 - bufferUsedBits % 8;
if (remain != 8 && remain >= indexBits)
{
CHECK_ERROR(eofIndex != -1, L"LzwEncoder::Close()#Internal error.");
WriteNumber(eofIndex, indexBits);
}
Flush();
}
vint LzwEncoder::Write(void* _buffer, vint _size)
{
vuint8_t* bytes = (vuint8_t*)_buffer;
for (vint i = 0; i < _size; i++)
{
vuint8_t byte = bytes[i];
Code* next = prefix->children.Get(byte);
if (next)
{
prefix = next;
}
else
{
WriteNumber(prefix->code, indexBits);
if (nextIndex < MaxDictionarySize)
{
UpdateIndexBits();
CreateCode(prefix, byte);
}
prefix = root->children.Get(byte);
}
}
return _size;
}
/***********************************************************************
LzwDecoder
***********************************************************************/
bool LzwDecoder::ReadNumber(vint& number, vint bitSize)
{
number = 0;
if (inputBufferSize == -1)
{
return false;
}
vint remainBits = inputBufferSize * 8 - inputBufferUsedBits;
vint writtenBits = 0;
vint bitStep = 8 - inputBufferUsedBits % 8;
if (bitStep > bitSize)
{
bitStep = bitSize;
}
while (writtenBits < bitSize)
{
if (remainBits == 0)
{
inputBufferSize = stream->Read(inputBuffer, BufferSize);
if (inputBufferSize == 0)
{
inputBufferSize = -1;
return false;
}
remainBits = inputBufferSize * 8;
inputBufferUsedBits = 0;
}
vuint8_t byte = inputBuffer[inputBufferUsedBits / 8];
byte >>= (8 - inputBufferUsedBits % 8 - bitStep);
byte &= lowMarks[bitStep];
number |= byte << writtenBits;
inputBufferUsedBits += bitStep;
remainBits -= bitStep;
writtenBits += bitStep;
vint remain = bitSize - writtenBits;
bitStep = remain < 8 ? remain : 8;
}
return true;
}
void LzwDecoder::PrepareOutputBuffer(vint size)
{
if (outputBuffer.Count() < size)
{
outputBuffer.Resize(size);
}
outputBufferSize = size;
}
void LzwDecoder::ExpandCodeToOutputBuffer(lzw::Code* code)
{
vuint8_t* outputByte = &outputBuffer[0] + code->size;
Code* current = code;
while (current != root)
{
*(--outputByte) = current->byte;
current = current->parent;
}
outputBufferUsedBytes = 0;
}
LzwDecoder::LzwDecoder()
{
for (vint i = 0; i < 256; i++)
{
dictionary.Add(root->children.Get((vuint8_t)i));
}
}
LzwDecoder::LzwDecoder(bool (&existingBytes)[256])
:LzwBase(existingBytes)
{
for (vint i = 0; i < 256; i++)
{
if (existingBytes[i])
{
dictionary.Add(root->children.Get((vuint8_t)i));
}
}
if (eofIndex != -1)
{
dictionary.Add(0);
}
}
LzwDecoder::~LzwDecoder()
{
}
void LzwDecoder::Setup(IStream* _stream)
{
stream = _stream;
}
void LzwDecoder::Close()
{
}
vint LzwDecoder::Read(void* _buffer, vint _size)
{
vint written = 0;
vuint8_t* bytes = (vuint8_t*)_buffer;
while (written < _size)
{
vint expect = _size - written;
vint remain = outputBufferSize - outputBufferUsedBytes;
if (remain == 0)
{
vint index = 0;
if (!ReadNumber(index, indexBits) || index == eofIndex)
{
break;
}
Code* prefix = 0;
if (index == dictionary.Count())
{
prefix = lastCode;
PrepareOutputBuffer(prefix->size + 1);
ExpandCodeToOutputBuffer(prefix);
outputBuffer[outputBufferSize - 1] = outputBuffer[0];
}
else
{
prefix = dictionary[index];
PrepareOutputBuffer(prefix->size);
ExpandCodeToOutputBuffer(prefix);
}
if (nextIndex < MaxDictionarySize)
{
if (lastCode)
{
dictionary.Add(CreateCode(lastCode, outputBuffer[0]));
}
UpdateIndexBits();
}
lastCode = dictionary[index];
}
else
{
if (remain > expect)
{
remain = expect;
}
memcpy(bytes + written, &outputBuffer[outputBufferUsedBytes], remain);
outputBufferUsedBytes += remain;
written += remain;
}
}
return written;
}
}
}
/***********************************************************************
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<position)
{
size=position;
}
return _size;
}
vint MemoryStream::Peek(void* _buffer, vint _size)
{
CHECK_ERROR(block!=0, L"MemoryStream::Peek(pos_t)#Stream is closed, cannot perform this operation.");
CHECK_ERROR(_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;
}
}
}
}