mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-03-24 00:13:48 +08:00
6721 lines
225 KiB
C++
6721 lines
225 KiB
C++
/***********************************************************************
|
|
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
|
|
DEVELOPER: Zihan Chen(vczh)
|
|
***********************************************************************/
|
|
#include "VlppGlrParser.h"
|
|
|
|
/***********************************************************************
|
|
.\ASTBASE.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
using namespace collections;
|
|
using namespace stream;
|
|
|
|
/***********************************************************************
|
|
JsonVisitorBase
|
|
***********************************************************************/
|
|
|
|
void JsonVisitorBase::BeginObject()
|
|
{
|
|
writer.WriteString(L"{");
|
|
indentation++;
|
|
indices.Add(0);
|
|
}
|
|
|
|
void JsonVisitorBase::BeginField(const WString& field)
|
|
{
|
|
vint last = indices[indices.Count() - 1];
|
|
if (last > 0)
|
|
{
|
|
writer.WriteString(L",");
|
|
}
|
|
writer.WriteLine(L"");
|
|
WriteIndent();
|
|
writer.WriteChar(L'\"');
|
|
writer.WriteString(field);
|
|
writer.WriteChar(L'\"');
|
|
writer.WriteString(L": ");
|
|
}
|
|
|
|
void JsonVisitorBase::EndField()
|
|
{
|
|
indices[indices.Count() - 1]++;
|
|
}
|
|
|
|
void JsonVisitorBase::EndObject()
|
|
{
|
|
indices.RemoveAt(indices.Count() - 1);
|
|
indentation--;
|
|
writer.WriteLine(L"");
|
|
WriteIndent();
|
|
writer.WriteString(L"}");
|
|
}
|
|
|
|
void JsonVisitorBase::BeginArray()
|
|
{
|
|
writer.WriteString(L"[");
|
|
indices.Add(0);
|
|
}
|
|
|
|
void JsonVisitorBase::BeginArrayItem()
|
|
{
|
|
vint last = indices[indices.Count() - 1];
|
|
if (last > 0)
|
|
{
|
|
writer.WriteString(L", ");
|
|
}
|
|
}
|
|
|
|
void JsonVisitorBase::EndArrayItem()
|
|
{
|
|
indices[indices.Count() - 1]++;
|
|
}
|
|
|
|
void JsonVisitorBase::EndArray()
|
|
{
|
|
indices.RemoveAt(indices.Count() - 1);
|
|
writer.WriteString(L"]");
|
|
}
|
|
|
|
void JsonVisitorBase::WriteIndent()
|
|
{
|
|
for (vint i = 0; i < indentation; i++)
|
|
{
|
|
writer.WriteString(L" ");
|
|
}
|
|
}
|
|
|
|
void JsonVisitorBase::WriteRange(const ParsingTextRange& range)
|
|
{
|
|
writer.WriteString(L"{\"start\": {\"row\": ");
|
|
writer.WriteString(itow(range.start.row));
|
|
writer.WriteString(L", \"column\": ");
|
|
writer.WriteString(itow(range.start.column));
|
|
writer.WriteString(L", \"index\": ");
|
|
writer.WriteString(itow(range.start.index));
|
|
writer.WriteString(L"}, \"end\": {\"row\": ");
|
|
writer.WriteString(itow(range.end.row));
|
|
writer.WriteString(L", \"column\": ");
|
|
writer.WriteString(itow(range.end.column));
|
|
writer.WriteString(L", \"index\": ");
|
|
writer.WriteString(itow(range.end.index));
|
|
writer.WriteString(L"}, \"codeIndex\": ");
|
|
writer.WriteString(itow(range.codeIndex));
|
|
writer.WriteString(L"}");
|
|
}
|
|
|
|
void JsonVisitorBase::WriteToken(const ParsingToken& token)
|
|
{
|
|
if (printTokenCodeRange)
|
|
{
|
|
writer.WriteString(L"{ \"value\": ");
|
|
WriteString(token.value);
|
|
writer.WriteString(L", \"codeRange\": ");
|
|
WriteRange(token.codeRange);
|
|
writer.WriteString(L"}");
|
|
}
|
|
else
|
|
{
|
|
WriteString(token.value);
|
|
}
|
|
}
|
|
|
|
void JsonVisitorBase::WriteType(const WString& type, ParsingAstBase* node)
|
|
{
|
|
if (printAstType && printAstCodeRange)
|
|
{
|
|
BeginField(L"$ast");
|
|
writer.WriteString(L"{ \"type\": ");
|
|
WriteString(type);
|
|
writer.WriteString(L", \"codeRange\": ");
|
|
WriteRange(node->codeRange);
|
|
writer.WriteString(L"}");
|
|
EndField();
|
|
}
|
|
else if (printAstType)
|
|
{
|
|
BeginField(L"$ast");
|
|
WriteString(type);
|
|
EndField();
|
|
}
|
|
else if (printAstCodeRange)
|
|
{
|
|
BeginField(L"$ast");
|
|
writer.WriteString(L"{ \"codeRange\": ");
|
|
WriteRange(node->codeRange);
|
|
writer.WriteString(L"}");
|
|
EndField();
|
|
}
|
|
}
|
|
|
|
void JsonVisitorBase::WriteString(const WString& text)
|
|
{
|
|
writer.WriteChar(L'\"');
|
|
JsonEscapeString(text, writer);
|
|
writer.WriteChar(L'\"');
|
|
}
|
|
|
|
void JsonVisitorBase::WriteNull()
|
|
{
|
|
writer.WriteString(L"null");
|
|
}
|
|
|
|
JsonVisitorBase::JsonVisitorBase(stream::StreamWriter& _writer)
|
|
:writer(_writer)
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
Json Printing
|
|
***********************************************************************/
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
AstInsReceiverBase
|
|
***********************************************************************/
|
|
|
|
void AstInsReceiverBase::EnsureContinuable()
|
|
{
|
|
if (corrupted)
|
|
{
|
|
throw AstInsException(
|
|
L"An exception has been thrown therefore this receiver cannot be used anymore.",
|
|
AstInsErrorType::Corrupted
|
|
);
|
|
}
|
|
if (finished)
|
|
{
|
|
throw AstInsException(
|
|
L"The finished instruction has been executed therefore this receiver cannot be used anymore.",
|
|
AstInsErrorType::Finished
|
|
);
|
|
}
|
|
}
|
|
|
|
void AstInsReceiverBase::SetField(ParsingAstBase* object, vint32_t field, const ObjectOrToken& value)
|
|
{
|
|
if (value.object)
|
|
{
|
|
SetField(object, field, value.object);
|
|
}
|
|
else if (value.enumItem != -1)
|
|
{
|
|
SetField(object, field, value.enumItem);
|
|
}
|
|
else
|
|
{
|
|
SetField(object, field, value.token, value.tokenIndex);
|
|
}
|
|
}
|
|
|
|
AstInsReceiverBase::CreatedObject& AstInsReceiverBase::PushCreated(CreatedObject&& createdObject)
|
|
{
|
|
if (created.Count() == 0)
|
|
{
|
|
created.Add(std::move(createdObject));
|
|
}
|
|
else
|
|
{
|
|
auto& top = created[created.Count() - 1];
|
|
if (
|
|
!top.object &&
|
|
top.pushedCount == createdObject.pushedCount &&
|
|
top.delayedToken.reading == createdObject.delayedToken.reading &&
|
|
top.delayedFieldAssignments.Count() == 0
|
|
)
|
|
{
|
|
top.object = createdObject.object;
|
|
top.extraEmptyDfaBelow++;
|
|
}
|
|
else
|
|
{
|
|
created.Add(std::move(createdObject));
|
|
}
|
|
}
|
|
return created[created.Count() - 1];
|
|
}
|
|
|
|
const AstInsReceiverBase::CreatedObject& AstInsReceiverBase::TopCreated()
|
|
{
|
|
return created[created.Count() - 1];
|
|
}
|
|
|
|
void AstInsReceiverBase::PopCreated()
|
|
{
|
|
auto& top = created[created.Count() - 1];
|
|
if (top.extraEmptyDfaBelow == 0)
|
|
{
|
|
created.RemoveAt(created.Count() - 1);
|
|
}
|
|
else if (top.object)
|
|
{
|
|
top.object = nullptr;
|
|
top.delayedFieldAssignments.Clear();
|
|
top.extraEmptyDfaBelow--;
|
|
}
|
|
}
|
|
|
|
void AstInsReceiverBase::DelayAssign(FieldAssignment&& fa)
|
|
{
|
|
created[created.Count() - 1].delayedFieldAssignments.Add(std::move(fa));
|
|
}
|
|
|
|
void AstInsReceiverBase::Execute(AstIns instruction, const regex::RegexToken& token, vint32_t tokenIndex)
|
|
{
|
|
EnsureContinuable();
|
|
try
|
|
{
|
|
if (created.Count() == 0 && instruction.type != AstInsType::BeginObject)
|
|
{
|
|
switch (instruction.type)
|
|
{
|
|
case AstInsType::BeginObject:
|
|
case AstInsType::BeginObjectLeftRecursive:
|
|
case AstInsType::DelayFieldAssignment:
|
|
case AstInsType::ResolveAmbiguity:
|
|
case AstInsType::AccumulatedDfa:
|
|
break;
|
|
default:
|
|
throw AstInsException(
|
|
L"There is no created objects.",
|
|
AstInsErrorType::NoRootObject
|
|
);
|
|
}
|
|
}
|
|
|
|
vint expectedLeavings = 0;
|
|
if (created.Count() > 0)
|
|
{
|
|
expectedLeavings = TopCreated().pushedCount;
|
|
}
|
|
|
|
switch (instruction.type)
|
|
{
|
|
case AstInsType::Token:
|
|
{
|
|
pushed.Add(ObjectOrToken{ token,tokenIndex });
|
|
}
|
|
break;
|
|
case AstInsType::EnumItem:
|
|
{
|
|
pushed.Add(ObjectOrToken{ instruction.param });
|
|
}
|
|
break;
|
|
case AstInsType::BeginObject:
|
|
{
|
|
auto value = CreateAstNode(instruction.param);
|
|
value->codeRange = { &token,&token };
|
|
PushCreated(CreatedObject{ value,pushed.Count() });
|
|
}
|
|
break;
|
|
case AstInsType::BeginObjectLeftRecursive:
|
|
{
|
|
if (pushed.Count() < expectedLeavings + 1)
|
|
{
|
|
throw AstInsException(
|
|
L"There is no pushed value to create left recursive object.",
|
|
AstInsErrorType::MissingLeftRecursiveValue
|
|
);
|
|
}
|
|
|
|
auto subValue = pushed[pushed.Count() - 1];
|
|
if (subValue.object)
|
|
{
|
|
auto value = CreateAstNode(instruction.param);
|
|
value->codeRange = subValue.object->codeRange;
|
|
PushCreated(CreatedObject{ value,pushed.Count() - 1 });
|
|
}
|
|
else
|
|
{
|
|
throw AstInsException(
|
|
L"The pushed value to create left recursive object is not an object.",
|
|
AstInsErrorType::LeftRecursiveValueIsNotObject
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
case AstInsType::DelayFieldAssignment:
|
|
{
|
|
PushCreated(CreatedObject{ nullptr,pushed.Count(),token });
|
|
}
|
|
break;
|
|
case AstInsType::ReopenObject:
|
|
{
|
|
auto& createdObject = created[created.Count() - 1];
|
|
if (createdObject.object)
|
|
{
|
|
throw AstInsException(
|
|
L"DelayFieldAssignment is not submitted before ReopenObject.",
|
|
AstInsErrorType::MissingDfaBeforeReopen
|
|
);
|
|
}
|
|
if (pushed.Count() < expectedLeavings + 1)
|
|
{
|
|
throw AstInsException(
|
|
L"There is no pushed value to reopen.",
|
|
AstInsErrorType::MissingValueToReopen
|
|
);
|
|
}
|
|
if (pushed.Count() > expectedLeavings + 1)
|
|
{
|
|
throw AstInsException(
|
|
L"The value to reopen is not the only unassigned value.",
|
|
AstInsErrorType::TooManyUnassignedValues
|
|
);
|
|
}
|
|
|
|
auto value = pushed[pushed.Count() - 1];
|
|
if (value.object)
|
|
{
|
|
pushed.RemoveAt(pushed.Count() - 1);
|
|
createdObject.object = value.object;
|
|
createdObject.object->codeRange.start = ParsingTextPos::Start(&createdObject.delayedToken);
|
|
|
|
for (auto&& dfa : createdObject.delayedFieldAssignments)
|
|
{
|
|
SetField(createdObject.object.Obj(), dfa.field, dfa.value);
|
|
}
|
|
createdObject.delayedFieldAssignments.Clear();
|
|
}
|
|
else
|
|
{
|
|
throw AstInsException(
|
|
L"The pushed value to reopen is not an object.",
|
|
AstInsErrorType::ReopenedValueIsNotObject
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
case AstInsType::EndObject:
|
|
{
|
|
Ptr<ParsingAstBase> objectToPush;
|
|
{
|
|
auto& createdObject = TopCreated();
|
|
if (!createdObject.object)
|
|
{
|
|
throw AstInsException(
|
|
L"There is no created objects after DelayFieldAssignment.",
|
|
AstInsErrorType::NoRootObjectAfterDfa
|
|
);
|
|
}
|
|
if (pushed.Count() > createdObject.pushedCount)
|
|
{
|
|
throw AstInsException(
|
|
L"There are still values to assign to fields before finishing an object.",
|
|
AstInsErrorType::LeavingUnassignedValues
|
|
);
|
|
}
|
|
|
|
objectToPush = createdObject.object;
|
|
PopCreated();
|
|
}
|
|
|
|
objectToPush->codeRange.end = ParsingTextPos::End(&token);
|
|
pushed.Add(ObjectOrToken{ objectToPush });
|
|
}
|
|
break;
|
|
case AstInsType::DiscardValue:
|
|
{
|
|
auto& createdObject = TopCreated();
|
|
if (pushed.Count() <= createdObject.pushedCount)
|
|
{
|
|
throw AstInsException(
|
|
L"There is no pushed value to discard.",
|
|
AstInsErrorType::MissingValueToDiscard
|
|
);
|
|
}
|
|
pushed.RemoveAt(pushed.Count() - 1);
|
|
}
|
|
break;
|
|
case AstInsType::Field:
|
|
{
|
|
auto& createdObject = TopCreated();
|
|
if (pushed.Count() <= createdObject.pushedCount)
|
|
{
|
|
throw AstInsException(
|
|
L"There is no pushed value to be assigned to a field.",
|
|
AstInsErrorType::MissingFieldValue
|
|
);
|
|
}
|
|
|
|
auto value = pushed[pushed.Count() - 1];
|
|
pushed.RemoveAt(pushed.Count() - 1);
|
|
|
|
if (createdObject.object)
|
|
{
|
|
SetField(createdObject.object.Obj(), instruction.param, value);
|
|
}
|
|
else
|
|
{
|
|
DelayAssign({ value,instruction.param });
|
|
}
|
|
}
|
|
break;
|
|
case AstInsType::ResolveAmbiguity:
|
|
{
|
|
if (instruction.count <= 0 || pushed.Count() < expectedLeavings + instruction.count)
|
|
{
|
|
throw AstInsException(
|
|
L"There are not enough candidates to create an ambiguity node.",
|
|
AstInsErrorType::MissingAmbiguityCandidate
|
|
);
|
|
}
|
|
|
|
for (vint i = 0; i < instruction.count; i++)
|
|
{
|
|
if (!pushed[pushed.Count() - i - 1].object)
|
|
{
|
|
throw AstInsException(
|
|
L"Tokens or enum items cannot be ambiguity candidates.",
|
|
AstInsErrorType::AmbiguityCandidateIsNotObject
|
|
);
|
|
}
|
|
}
|
|
|
|
Array<Ptr<ParsingAstBase>> candidates(instruction.count);
|
|
for (vint i = 0; i < instruction.count; i++)
|
|
{
|
|
auto value = pushed[pushed.Count() - 1];
|
|
pushed.RemoveAt(pushed.Count() - 1);
|
|
candidates[i] = value.object;
|
|
}
|
|
|
|
pushed.Add(ObjectOrToken{ ResolveAmbiguity(instruction.param, candidates) });
|
|
}
|
|
break;
|
|
case AstInsType::AccumulatedDfa:
|
|
{
|
|
auto&& createdObject = PushCreated(CreatedObject{ nullptr,pushed.Count(),token });
|
|
createdObject.extraEmptyDfaBelow += instruction.count - 1;
|
|
}
|
|
break;
|
|
case AstInsType::AccumulatedEoRo:
|
|
{
|
|
while (instruction.count > 0)
|
|
{
|
|
auto& createdObject = created[created.Count() - 1];
|
|
if (!createdObject.object)
|
|
{
|
|
throw AstInsException(
|
|
L"There is no created objects after DelayFieldAssignment.",
|
|
AstInsErrorType::NoRootObjectAfterDfa
|
|
);
|
|
}
|
|
if (pushed.Count() > createdObject.pushedCount)
|
|
{
|
|
throw AstInsException(
|
|
L"There are still values to assign to fields before finishing an object.",
|
|
AstInsErrorType::LeavingUnassignedValues
|
|
);
|
|
}
|
|
|
|
if (createdObject.extraEmptyDfaBelow >= instruction.count)
|
|
{
|
|
createdObject.object->codeRange.start = ParsingTextPos::Start(&createdObject.delayedToken);
|
|
createdObject.object->codeRange.end = ParsingTextPos::End(&token);
|
|
createdObject.extraEmptyDfaBelow -= instruction.count;
|
|
instruction.count = 0;
|
|
}
|
|
else
|
|
{
|
|
instruction.count -= createdObject.extraEmptyDfaBelow + 1;
|
|
createdObject.extraEmptyDfaBelow = 0;
|
|
Execute({ AstInsType::EndObject }, token, tokenIndex);
|
|
Execute({ AstInsType::ReopenObject }, token, tokenIndex);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
CHECK_FAIL(L"vl::glr::AstInsReceiverBase::Execute(AstIns, const regex::RegexToken&)#Unknown Instruction.");
|
|
}
|
|
}
|
|
catch (const AstInsException&)
|
|
{
|
|
corrupted = true;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
Ptr<ParsingAstBase> AstInsReceiverBase::Finished()
|
|
{
|
|
EnsureContinuable();
|
|
try
|
|
{
|
|
if (created.Count() > 0 || pushed.Count() > 1)
|
|
{
|
|
throw AstInsException(
|
|
L"No more instruction but the root object has not been completed yet.",
|
|
AstInsErrorType::InstructionNotComplete
|
|
);
|
|
}
|
|
|
|
auto object = pushed[0].object;
|
|
if (!object)
|
|
{
|
|
throw AstInsException(
|
|
L"No more instruction but the root object has not been completed yet.",
|
|
AstInsErrorType::InstructionNotComplete
|
|
);
|
|
}
|
|
pushed.Clear();
|
|
finished = true;
|
|
return object;
|
|
}
|
|
catch (const AstInsException&)
|
|
{
|
|
corrupted = true;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
IAstInsReceiver (Code Generation Error Templates)
|
|
***********************************************************************/
|
|
|
|
Ptr<ParsingAstBase> AssemblyThrowCannotCreateAbstractType(vint32_t type, const wchar_t* cppTypeName)
|
|
{
|
|
if (cppTypeName)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Unable to create abstract class \"") +
|
|
WString::Unmanaged(cppTypeName) +
|
|
WString::Unmanaged(L"\"."),
|
|
AstInsErrorType::UnsupportedAbstractType, type);
|
|
}
|
|
else
|
|
{
|
|
throw AstInsException(L"The type id does not exist.", vl::glr::AstInsErrorType::UnknownType, type);
|
|
}
|
|
}
|
|
|
|
void AssemblyThrowFieldNotObject(vint32_t field, const wchar_t* cppFieldName)
|
|
{
|
|
if (cppFieldName)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" is not an object."),
|
|
AstInsErrorType::ObjectTypeMismatchedToField, field);
|
|
}
|
|
else
|
|
{
|
|
throw AstInsException(L"The field id does not exist.", vl::glr::AstInsErrorType::UnknownField, field);
|
|
}
|
|
}
|
|
|
|
void AssemblyThrowFieldNotToken(vint32_t field, const wchar_t* cppFieldName)
|
|
{
|
|
if (cppFieldName)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" is not a token."),
|
|
AstInsErrorType::ObjectTypeMismatchedToField, field);
|
|
}
|
|
else
|
|
{
|
|
throw AstInsException(L"The field id does not exist.", vl::glr::AstInsErrorType::UnknownField, field);
|
|
}
|
|
}
|
|
|
|
void AssemblyThrowFieldNotEnum(vint32_t field, const wchar_t* cppFieldName)
|
|
{
|
|
if (cppFieldName)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" is not an enum item."),
|
|
AstInsErrorType::ObjectTypeMismatchedToField, field);
|
|
}
|
|
else
|
|
{
|
|
throw AstInsException(L"The field id does not exist.", vl::glr::AstInsErrorType::UnknownField, field);
|
|
}
|
|
}
|
|
|
|
Ptr<ParsingAstBase> AssemblyThrowTypeNotAllowAmbiguity(vint32_t type, const wchar_t* cppTypeName)
|
|
{
|
|
if (cppTypeName)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Type \"") +
|
|
WString::Unmanaged(cppTypeName) +
|
|
WString::Unmanaged(L"\" is not configured to allow ambiguity."),
|
|
AstInsErrorType::UnsupportedAmbiguityType, type);
|
|
}
|
|
else
|
|
{
|
|
throw AstInsException(L"The type id does not exist.", vl::glr::AstInsErrorType::UnknownType, type);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
Compression
|
|
***********************************************************************/
|
|
|
|
void DecompressSerializedData(const char** buffer, bool decompress, vint solidRows, vint rows, vint block, vint remain, stream::IStream& outputStream)
|
|
{
|
|
if (decompress)
|
|
{
|
|
MemoryStream compressedStream;
|
|
DecompressSerializedData(buffer, false, solidRows, rows, block, remain, compressedStream);
|
|
compressedStream.SeekFromBegin(0);
|
|
DecompressStream(compressedStream, outputStream);
|
|
}
|
|
else
|
|
{
|
|
for (vint i = 0; i < rows; i++)
|
|
{
|
|
vint size = i == solidRows ? remain : block;
|
|
outputStream.Write((void*)buffer[i], size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
Reflection
|
|
***********************************************************************/
|
|
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::ParsingTextPos, system::ParsingTextPos)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::ParsingTextRange, system::ParsingTextRange)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::ParsingToken, system::ParsingToken)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::ParsingAstBase, system::ParsingAstBase)
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
BEGIN_STRUCT_MEMBER(vl::glr::ParsingTextPos)
|
|
STRUCT_MEMBER(index)
|
|
STRUCT_MEMBER(row)
|
|
STRUCT_MEMBER(column)
|
|
END_STRUCT_MEMBER(vl::glr::ParsingTextPos)
|
|
|
|
BEGIN_STRUCT_MEMBER(vl::glr::ParsingTextRange)
|
|
STRUCT_MEMBER(start)
|
|
STRUCT_MEMBER(end)
|
|
STRUCT_MEMBER(codeIndex)
|
|
END_STRUCT_MEMBER(vl::glr::ParsingTextRange)
|
|
|
|
BEGIN_STRUCT_MEMBER(vl::glr::ParsingToken)
|
|
STRUCT_MEMBER(codeRange)
|
|
STRUCT_MEMBER(index)
|
|
STRUCT_MEMBER(token)
|
|
STRUCT_MEMBER(value)
|
|
END_STRUCT_MEMBER(vl::glr::ParsingToken)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::ParsingAstBase)
|
|
CLASS_MEMBER_FIELD(codeRange)
|
|
END_CLASS_MEMBER(vl::glr::ParsingAstBase)
|
|
|
|
class Parsing2TypeLoader : public vl::Object, public ITypeLoader
|
|
{
|
|
public:
|
|
void Load(ITypeManager* manager)
|
|
{
|
|
ADD_TYPE_INFO(vl::glr::ParsingTextPos)
|
|
ADD_TYPE_INFO(vl::glr::ParsingTextRange)
|
|
ADD_TYPE_INFO(vl::glr::ParsingToken)
|
|
ADD_TYPE_INFO(vl::glr::ParsingAstBase)
|
|
}
|
|
|
|
void Unload(ITypeManager* manager)
|
|
{
|
|
}
|
|
};
|
|
#endif
|
|
#endif
|
|
bool LoadParsing2Types()
|
|
{
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
if (auto manager = GetGlobalTypeManager())
|
|
{
|
|
Ptr<ITypeLoader> loader = new Parsing2TypeLoader;
|
|
return manager->AddTypeLoader(loader);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\ASTPRINT.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
|
|
/***********************************************************************
|
|
ParsingEmptyPrintNodeRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingEmptyPrintNodeRecorder::ParsingEmptyPrintNodeRecorder()
|
|
{
|
|
}
|
|
|
|
ParsingEmptyPrintNodeRecorder::~ParsingEmptyPrintNodeRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingEmptyPrintNodeRecorder::Record(ParsingAstBase* node, const ParsingTextRange& range)
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingMultiplePrintNodeRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingMultiplePrintNodeRecorder::ParsingMultiplePrintNodeRecorder()
|
|
{
|
|
}
|
|
|
|
ParsingMultiplePrintNodeRecorder::~ParsingMultiplePrintNodeRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingMultiplePrintNodeRecorder::AddRecorder(Ptr<IParsingPrintNodeRecorder> recorder)
|
|
{
|
|
recorders.Add(recorder);
|
|
}
|
|
|
|
void ParsingMultiplePrintNodeRecorder::Record(ParsingAstBase* node, const ParsingTextRange& range)
|
|
{
|
|
for (auto recorder : recorders)
|
|
{
|
|
recorder->Record(node, range);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingOriginalLocationRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingOriginalLocationRecorder::ParsingOriginalLocationRecorder(Ptr<IParsingPrintNodeRecorder> _recorder)
|
|
:recorder(_recorder)
|
|
{
|
|
}
|
|
|
|
ParsingOriginalLocationRecorder::~ParsingOriginalLocationRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingOriginalLocationRecorder::Record(ParsingAstBase* node, const ParsingTextRange& range)
|
|
{
|
|
auto codeRange = node->codeRange;
|
|
codeRange.codeIndex = range.codeIndex;
|
|
recorder->Record(node, codeRange);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingGeneratedLocationRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingGeneratedLocationRecorder::ParsingGeneratedLocationRecorder(RangeMap& _rangeMap)
|
|
:rangeMap(_rangeMap)
|
|
{
|
|
}
|
|
|
|
ParsingGeneratedLocationRecorder::~ParsingGeneratedLocationRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingGeneratedLocationRecorder::Record(ParsingAstBase* node, const ParsingTextRange& range)
|
|
{
|
|
rangeMap.Add(node, range);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingUpdateLocationRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingUpdateLocationRecorder::ParsingUpdateLocationRecorder()
|
|
{
|
|
}
|
|
|
|
ParsingUpdateLocationRecorder::~ParsingUpdateLocationRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingUpdateLocationRecorder::Record(ParsingAstBase* node, const ParsingTextRange& range)
|
|
{
|
|
node->codeRange = range;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingWriter
|
|
***********************************************************************/
|
|
|
|
void ParsingWriter::HandleChar(wchar_t c)
|
|
{
|
|
lastPos = currentPos;
|
|
switch (c)
|
|
{
|
|
case L'\n':
|
|
currentPos.index++;
|
|
currentPos.row++;
|
|
currentPos.column = 0;
|
|
break;
|
|
default:
|
|
currentPos.index++;
|
|
currentPos.column++;
|
|
}
|
|
}
|
|
|
|
ParsingWriter::ParsingWriter(stream::TextWriter& _writer, Ptr<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(ParsingAstBase* node)
|
|
{
|
|
if (!recorder) return;
|
|
nodePositions.Add(NodePosPair(node, currentPos));
|
|
}
|
|
|
|
void ParsingWriter::AfterPrint(ParsingAstBase* 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\EXECUTABLE.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
namespace internal
|
|
{
|
|
using namespace glr;
|
|
using namespace glr::automaton;
|
|
|
|
SERIALIZE_ENUM(AstInsType)
|
|
SERIALIZE_ENUM(EdgePriority)
|
|
|
|
BEGIN_SERIALIZATION(AstIns)
|
|
SERIALIZE(type)
|
|
SERIALIZE(param)
|
|
SERIALIZE(count)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(InstructionArray)
|
|
SERIALIZE(start)
|
|
SERIALIZE(count)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ReturnIndexArray)
|
|
SERIALIZE(start)
|
|
SERIALIZE(count)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(EdgeArray)
|
|
SERIALIZE(start)
|
|
SERIALIZE(count)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ReturnDesc)
|
|
SERIALIZE(consumedRule)
|
|
SERIALIZE(returnState)
|
|
SERIALIZE(priority)
|
|
SERIALIZE(insAfterInput)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(EdgeDesc)
|
|
SERIALIZE(fromState)
|
|
SERIALIZE(toState)
|
|
SERIALIZE(priority)
|
|
SERIALIZE(insBeforeInput)
|
|
SERIALIZE(insAfterInput)
|
|
SERIALIZE(returnIndices)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(StateDesc)
|
|
SERIALIZE(rule)
|
|
SERIALIZE(clause)
|
|
SERIALIZE(endingState)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(Executable)
|
|
SERIALIZE(tokenCount)
|
|
SERIALIZE(ruleCount)
|
|
SERIALIZE(ruleStartStates)
|
|
SERIALIZE(transitions)
|
|
SERIALIZE(instructions)
|
|
SERIALIZE(returnIndices)
|
|
SERIALIZE(returns)
|
|
SERIALIZE(edges)
|
|
SERIALIZE(states)
|
|
END_SERIALIZATION
|
|
}
|
|
}
|
|
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
using namespace stream;
|
|
|
|
/***********************************************************************
|
|
Executable
|
|
***********************************************************************/
|
|
|
|
Executable::Executable(stream::IStream& inputStream)
|
|
{
|
|
internal::ContextFreeReader reader(inputStream);
|
|
reader << *this;
|
|
}
|
|
|
|
void Executable::Serialize(stream::IStream& outputStream)
|
|
{
|
|
internal::ContextFreeWriter writer(outputStream);
|
|
writer << *this;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\SYNTAXBASE.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
/***********************************************************************
|
|
ErrorArgs
|
|
***********************************************************************/
|
|
|
|
ErrorArgs ErrorArgs::UnrecognizedToken(const regex::RegexToken& token)
|
|
{
|
|
return {
|
|
true,
|
|
ErrorType::UnrecognizedToken,
|
|
token.codeIndex,
|
|
const_cast<regex::RegexToken&>(token),
|
|
*static_cast<collections::List<regex::RegexToken>*>(nullptr),
|
|
*static_cast<automaton::Executable*>(nullptr),
|
|
*static_cast<automaton::TraceManager*>(nullptr),
|
|
nullptr
|
|
};
|
|
}
|
|
|
|
ErrorArgs ErrorArgs::InvalidToken(regex::RegexToken& token, collections::List<regex::RegexToken>& tokens, automaton::Executable& executable, automaton::TraceManager& traceManager)
|
|
{
|
|
return {
|
|
true,
|
|
ErrorType::InvalidToken,
|
|
token.codeIndex,
|
|
token,
|
|
tokens,
|
|
executable,
|
|
traceManager,
|
|
nullptr
|
|
};
|
|
}
|
|
|
|
ErrorArgs ErrorArgs::InputIncomplete(vint codeIndex, collections::List<regex::RegexToken>& tokens, automaton::Executable& executable, automaton::TraceManager& traceManager)
|
|
{
|
|
return {
|
|
true,
|
|
ErrorType::InputIncomplete,
|
|
codeIndex,
|
|
*static_cast<regex::RegexToken*>(nullptr),
|
|
tokens,
|
|
executable,
|
|
traceManager,
|
|
nullptr
|
|
};
|
|
}
|
|
|
|
ErrorArgs ErrorArgs::UnexpectedAstType(collections::List<regex::RegexToken>& tokens, automaton::Executable& executable, automaton::TraceManager& traceManager, Ptr<ParsingAstBase> ast)
|
|
{
|
|
return {
|
|
true,
|
|
ErrorType::UnexpectedAstType,
|
|
ast->codeRange.codeIndex,
|
|
*static_cast<regex::RegexToken*>(nullptr),
|
|
tokens,
|
|
executable,
|
|
traceManager,
|
|
ast
|
|
};
|
|
}
|
|
|
|
ParsingError ErrorArgs::ToParsingError()
|
|
{
|
|
switch (error)
|
|
{
|
|
case ErrorType::UnrecognizedToken:
|
|
return {
|
|
nullptr,
|
|
{&token,&token},
|
|
WString::Unmanaged(L"Unrecognized token: \"") + WString::CopyFrom(token.reading,token.length) + WString::Unmanaged(L"\".")
|
|
};
|
|
case ErrorType::InvalidToken:
|
|
return {
|
|
nullptr,
|
|
{&token,&token},
|
|
WString::Unmanaged(L"Parser stops at incorrect input: \"") + WString::CopyFrom(token.reading,token.length) + WString::Unmanaged(L"\".")
|
|
};
|
|
case ErrorType::InputIncomplete:
|
|
if (tokens.Count() == 0)
|
|
{
|
|
return {
|
|
nullptr,
|
|
{&tokens[tokens.Count()-1],&tokens[tokens.Count() - 1]},
|
|
L"Input is incomplete."
|
|
};
|
|
}
|
|
else
|
|
{
|
|
return {
|
|
nullptr,
|
|
{{0,0,0},{0,0,0},codeIndex},
|
|
L"Input is incomplete."
|
|
};
|
|
}
|
|
case ErrorType::UnexpectedAstType:
|
|
return {
|
|
nullptr,
|
|
ast->codeRange,
|
|
L"Unexpected type of the created AST."
|
|
};
|
|
default:
|
|
CHECK_FAIL(L"vl::glr::ErrorArgs::ToParsingError()#Unknown error type.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\JSON\GLRJSON.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
using namespace stream;
|
|
using namespace collections;
|
|
|
|
/***********************************************************************
|
|
JsonUnescapeVisitor
|
|
***********************************************************************/
|
|
|
|
class JsonUnescapeVisitor : public traverse_visitor::AstVisitor
|
|
{
|
|
protected:
|
|
void Traverse(JsonObjectField* node) override
|
|
{
|
|
node->name.value = GenerateToStream(
|
|
[node](TextWriter& writer)
|
|
{
|
|
JsonUnescapeString(node->name.value.Sub(1, node->name.value.Length() - 2), writer);
|
|
});
|
|
}
|
|
|
|
void Traverse(JsonString* node) override
|
|
{
|
|
node->content.value = GenerateToStream(
|
|
[node](TextWriter& writer)
|
|
{
|
|
JsonUnescapeString(node->content.value.Sub(1, node->content.value.Length() - 2), writer);
|
|
});
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
JsonPrintVisitor
|
|
***********************************************************************/
|
|
|
|
class JsonPrintVisitor : public Object, public JsonNode::IVisitor
|
|
{
|
|
public:
|
|
TextWriter& writer;
|
|
|
|
JsonPrintVisitor(TextWriter& _writer)
|
|
:writer(_writer)
|
|
{
|
|
}
|
|
|
|
void Visit(JsonLiteral* node) override
|
|
{
|
|
switch(node->value)
|
|
{
|
|
case JsonLiteralValue::True:
|
|
writer.WriteString(L"true");
|
|
break;
|
|
case JsonLiteralValue::False:
|
|
writer.WriteString(L"false");
|
|
break;
|
|
case JsonLiteralValue::Null:
|
|
writer.WriteString(L"null");
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
|
|
void Visit(JsonString* node) override
|
|
{
|
|
writer.WriteChar(L'\"');
|
|
JsonEscapeString(node->content.value, writer);
|
|
writer.WriteChar(L'\"');
|
|
}
|
|
|
|
void Visit(JsonNumber* node) override
|
|
{
|
|
writer.WriteString(node->content.value);
|
|
}
|
|
|
|
void Visit(JsonArray* node) override
|
|
{
|
|
writer.WriteChar(L'[');
|
|
for (auto [item, i] : indexed(node->items))
|
|
{
|
|
if(i>0) writer.WriteChar(L',');
|
|
item->Accept(this);
|
|
}
|
|
writer.WriteChar(L']');
|
|
}
|
|
|
|
void Visit(JsonObject* node) override
|
|
{
|
|
writer.WriteChar(L'{');
|
|
for (auto [field, i] : indexed(node->fields))
|
|
{
|
|
if(i>0) writer.WriteChar(L',');
|
|
writer.WriteChar(L'\"');
|
|
JsonEscapeString(field->name.value, writer);
|
|
writer.WriteString(L"\":");
|
|
field->value->Accept(this);
|
|
}
|
|
writer.WriteChar(L'}');
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
API
|
|
***********************************************************************/
|
|
|
|
Ptr<JsonNode> JsonParse(const WString& input, const Parser& parser)
|
|
{
|
|
auto ast = parser.ParseJRoot(input);
|
|
JsonUnescapeVisitor().InspectInto(ast.Obj());
|
|
return ast;
|
|
}
|
|
|
|
void JsonPrint(Ptr<JsonNode> node, stream::TextWriter& writer)
|
|
{
|
|
JsonPrintVisitor visitor(writer);
|
|
node->Accept(&visitor);
|
|
}
|
|
|
|
WString JsonToString(Ptr<JsonNode> node)
|
|
{
|
|
return GenerateToStream([&](StreamWriter& writer)
|
|
{
|
|
JsonPrint(node, writer);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
/***********************************************************************
|
|
Visitor Pattern Implementation
|
|
***********************************************************************/
|
|
|
|
void JsonLiteral::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonString::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonNumber::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonArray::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonObject::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonNode, system::JsonNode)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonNode::IVisitor, system::JsonNode::IVisitor)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonLiteralValue, system::JsonLiteralValue)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonLiteral, system::JsonLiteral)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonString, system::JsonString)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonNumber, system::JsonNumber)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonArray, system::JsonArray)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonObjectField, system::JsonObjectField)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::json::JsonObject, system::JsonObject)
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::json::JsonNode)
|
|
CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)
|
|
|
|
END_CLASS_MEMBER(vl::glr::json::JsonNode)
|
|
|
|
BEGIN_ENUM_ITEM(vl::glr::json::JsonLiteralValue)
|
|
ENUM_ITEM_NAMESPACE(vl::glr::json::JsonLiteralValue)
|
|
ENUM_NAMESPACE_ITEM(True)
|
|
ENUM_NAMESPACE_ITEM(False)
|
|
ENUM_NAMESPACE_ITEM(Null)
|
|
END_ENUM_ITEM(vl::glr::json::JsonLiteralValue)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::json::JsonLiteral)
|
|
CLASS_MEMBER_BASE(vl::glr::json::JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::json::JsonLiteral>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(value)
|
|
END_CLASS_MEMBER(vl::glr::json::JsonLiteral)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::json::JsonString)
|
|
CLASS_MEMBER_BASE(vl::glr::json::JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::json::JsonString>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(content)
|
|
END_CLASS_MEMBER(vl::glr::json::JsonString)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::json::JsonNumber)
|
|
CLASS_MEMBER_BASE(vl::glr::json::JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::json::JsonNumber>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(content)
|
|
END_CLASS_MEMBER(vl::glr::json::JsonNumber)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::json::JsonArray)
|
|
CLASS_MEMBER_BASE(vl::glr::json::JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::json::JsonArray>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(items)
|
|
END_CLASS_MEMBER(vl::glr::json::JsonArray)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::json::JsonObjectField)
|
|
CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::json::JsonObjectField>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(name)
|
|
CLASS_MEMBER_FIELD(value)
|
|
END_CLASS_MEMBER(vl::glr::json::JsonObjectField)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::json::JsonObject)
|
|
CLASS_MEMBER_BASE(vl::glr::json::JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::json::JsonObject>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(fields)
|
|
END_CLASS_MEMBER(vl::glr::json::JsonObject)
|
|
|
|
BEGIN_INTERFACE_MEMBER(vl::glr::json::JsonNode::IVisitor)
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::json::JsonNode::IVisitor::*)(vl::glr::json::JsonLiteral* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::json::JsonNode::IVisitor::*)(vl::glr::json::JsonString* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::json::JsonNode::IVisitor::*)(vl::glr::json::JsonNumber* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::json::JsonNode::IVisitor::*)(vl::glr::json::JsonArray* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::json::JsonNode::IVisitor::*)(vl::glr::json::JsonObject* node))
|
|
END_INTERFACE_MEMBER(vl::glr::json::JsonNode)
|
|
|
|
#endif
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
class JsonAstTypeLoader : public vl::Object, public ITypeLoader
|
|
{
|
|
public:
|
|
void Load(ITypeManager* manager)
|
|
{
|
|
ADD_TYPE_INFO(vl::glr::json::JsonNode)
|
|
ADD_TYPE_INFO(vl::glr::json::JsonNode::IVisitor)
|
|
ADD_TYPE_INFO(vl::glr::json::JsonLiteralValue)
|
|
ADD_TYPE_INFO(vl::glr::json::JsonLiteral)
|
|
ADD_TYPE_INFO(vl::glr::json::JsonString)
|
|
ADD_TYPE_INFO(vl::glr::json::JsonNumber)
|
|
ADD_TYPE_INFO(vl::glr::json::JsonArray)
|
|
ADD_TYPE_INFO(vl::glr::json::JsonObjectField)
|
|
ADD_TYPE_INFO(vl::glr::json::JsonObject)
|
|
}
|
|
|
|
void Unload(ITypeManager* manager)
|
|
{
|
|
}
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
bool JsonAstLoadTypes()
|
|
{
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
if (auto manager = GetGlobalTypeManager())
|
|
{
|
|
Ptr<ITypeLoader> loader = new JsonAstTypeLoader;
|
|
return manager->AddTypeLoader(loader);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_BUILDER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
namespace builder
|
|
{
|
|
|
|
/***********************************************************************
|
|
MakeArray
|
|
***********************************************************************/
|
|
|
|
MakeArray& MakeArray::items(const vl::Ptr<JsonNode>& value)
|
|
{
|
|
node->items.Add(value);
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeLiteral
|
|
***********************************************************************/
|
|
|
|
MakeLiteral& MakeLiteral::value(JsonLiteralValue value)
|
|
{
|
|
node->value = value;
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeNumber
|
|
***********************************************************************/
|
|
|
|
MakeNumber& MakeNumber::content(const vl::WString& value)
|
|
{
|
|
node->content.value = value;
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeObject
|
|
***********************************************************************/
|
|
|
|
MakeObject& MakeObject::fields(const vl::Ptr<JsonObjectField>& value)
|
|
{
|
|
node->fields.Add(value);
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeObjectField
|
|
***********************************************************************/
|
|
|
|
MakeObjectField& MakeObjectField::name(const vl::WString& value)
|
|
{
|
|
node->name.value = value;
|
|
return *this;
|
|
}
|
|
|
|
MakeObjectField& MakeObjectField::value(const vl::Ptr<JsonNode>& value)
|
|
{
|
|
node->value = value;
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeString
|
|
***********************************************************************/
|
|
|
|
MakeString& MakeString::content(const vl::WString& value)
|
|
{
|
|
node->content.value = value;
|
|
return *this;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_COPY.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
namespace copy_visitor
|
|
{
|
|
void AstVisitor::CopyFields(JsonArray* from, JsonArray* to)
|
|
{
|
|
CopyFields(static_cast<JsonNode*>(from), static_cast<JsonNode*>(to));
|
|
for (auto&& listItem : from->items)
|
|
{
|
|
to->items.Add(CopyNode(listItem.Obj()));
|
|
}
|
|
}
|
|
|
|
void AstVisitor::CopyFields(JsonLiteral* from, JsonLiteral* to)
|
|
{
|
|
CopyFields(static_cast<JsonNode*>(from), static_cast<JsonNode*>(to));
|
|
to->value = from->value;
|
|
}
|
|
|
|
void AstVisitor::CopyFields(JsonNode* from, JsonNode* to)
|
|
{
|
|
}
|
|
|
|
void AstVisitor::CopyFields(JsonNumber* from, JsonNumber* to)
|
|
{
|
|
CopyFields(static_cast<JsonNode*>(from), static_cast<JsonNode*>(to));
|
|
to->content = from->content;
|
|
}
|
|
|
|
void AstVisitor::CopyFields(JsonObject* from, JsonObject* to)
|
|
{
|
|
CopyFields(static_cast<JsonNode*>(from), static_cast<JsonNode*>(to));
|
|
for (auto&& listItem : from->fields)
|
|
{
|
|
to->fields.Add(CopyNode(listItem.Obj()));
|
|
}
|
|
}
|
|
|
|
void AstVisitor::CopyFields(JsonObjectField* from, JsonObjectField* to)
|
|
{
|
|
to->name = from->name;
|
|
to->value = CopyNode(from->value.Obj());
|
|
}
|
|
|
|
void AstVisitor::CopyFields(JsonString* from, JsonString* to)
|
|
{
|
|
CopyFields(static_cast<JsonNode*>(from), static_cast<JsonNode*>(to));
|
|
to->content = from->content;
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonObjectField* node)
|
|
{
|
|
auto newNode = vl::MakePtr<JsonObjectField>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonLiteral* node)
|
|
{
|
|
auto newNode = vl::MakePtr<JsonLiteral>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonString* node)
|
|
{
|
|
auto newNode = vl::MakePtr<JsonString>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonNumber* node)
|
|
{
|
|
auto newNode = vl::MakePtr<JsonNumber>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonArray* node)
|
|
{
|
|
auto newNode = vl::MakePtr<JsonArray>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonObject* node)
|
|
{
|
|
auto newNode = vl::MakePtr<JsonObject>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
vl::Ptr<JsonNode> AstVisitor::CopyNode(JsonNode* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
node->Accept(static_cast<JsonNode::IVisitor*>(this));
|
|
return this->result.Cast<JsonNode>();
|
|
}
|
|
|
|
vl::Ptr<JsonObjectField> AstVisitor::CopyNode(JsonObjectField* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
Visit(node);
|
|
return this->result.Cast<JsonObjectField>();
|
|
}
|
|
|
|
vl::Ptr<JsonArray> AstVisitor::CopyNode(JsonArray* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<JsonNode*>(node)).Cast<JsonArray>();
|
|
}
|
|
|
|
vl::Ptr<JsonLiteral> AstVisitor::CopyNode(JsonLiteral* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<JsonNode*>(node)).Cast<JsonLiteral>();
|
|
}
|
|
|
|
vl::Ptr<JsonNumber> AstVisitor::CopyNode(JsonNumber* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<JsonNode*>(node)).Cast<JsonNumber>();
|
|
}
|
|
|
|
vl::Ptr<JsonObject> AstVisitor::CopyNode(JsonObject* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<JsonNode*>(node)).Cast<JsonObject>();
|
|
}
|
|
|
|
vl::Ptr<JsonString> AstVisitor::CopyNode(JsonString* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<JsonNode*>(node)).Cast<JsonString>();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_EMPTY.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
namespace empty_visitor
|
|
{
|
|
|
|
/***********************************************************************
|
|
NodeVisitor
|
|
***********************************************************************/
|
|
|
|
// Visitor Members -----------------------------------
|
|
|
|
void NodeVisitor::Visit(JsonLiteral* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(JsonString* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(JsonNumber* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(JsonArray* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(JsonObject* node)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_JSON.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
namespace json_visitor
|
|
{
|
|
void AstVisitor::PrintFields(JsonArray* node)
|
|
{
|
|
BeginField(L"items");
|
|
BeginArray();
|
|
for (auto&& listItem : node->items)
|
|
{
|
|
BeginArrayItem();
|
|
Print(listItem.Obj());
|
|
EndArrayItem();
|
|
}
|
|
EndArray();
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(JsonLiteral* node)
|
|
{
|
|
BeginField(L"value");
|
|
switch (node->value)
|
|
{
|
|
case vl::glr::json::JsonLiteralValue::False:
|
|
WriteString(L"False");
|
|
break;
|
|
case vl::glr::json::JsonLiteralValue::Null:
|
|
WriteString(L"Null");
|
|
break;
|
|
case vl::glr::json::JsonLiteralValue::True:
|
|
WriteString(L"True");
|
|
break;
|
|
default:
|
|
WriteNull();
|
|
}
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(JsonNode* node)
|
|
{
|
|
}
|
|
void AstVisitor::PrintFields(JsonNumber* node)
|
|
{
|
|
BeginField(L"content");
|
|
WriteToken(node->content);
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(JsonObject* node)
|
|
{
|
|
BeginField(L"fields");
|
|
BeginArray();
|
|
for (auto&& listItem : node->fields)
|
|
{
|
|
BeginArrayItem();
|
|
Print(listItem.Obj());
|
|
EndArrayItem();
|
|
}
|
|
EndArray();
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(JsonObjectField* node)
|
|
{
|
|
BeginField(L"name");
|
|
WriteToken(node->name);
|
|
EndField();
|
|
BeginField(L"value");
|
|
Print(node->value.Obj());
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(JsonString* node)
|
|
{
|
|
BeginField(L"content");
|
|
WriteToken(node->content);
|
|
EndField();
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonLiteral* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Literal", node);
|
|
PrintFields(static_cast<JsonNode*>(node));
|
|
PrintFields(static_cast<JsonLiteral*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonString* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"String", node);
|
|
PrintFields(static_cast<JsonNode*>(node));
|
|
PrintFields(static_cast<JsonString*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonNumber* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Number", node);
|
|
PrintFields(static_cast<JsonNode*>(node));
|
|
PrintFields(static_cast<JsonNumber*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonArray* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Array", node);
|
|
PrintFields(static_cast<JsonNode*>(node));
|
|
PrintFields(static_cast<JsonArray*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonObject* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Object", node);
|
|
PrintFields(static_cast<JsonNode*>(node));
|
|
PrintFields(static_cast<JsonObject*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
AstVisitor::AstVisitor(vl::stream::StreamWriter& _writer)
|
|
: vl::glr::JsonVisitorBase(_writer)
|
|
{
|
|
}
|
|
|
|
void AstVisitor::Print(JsonNode* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
node->Accept(static_cast<JsonNode::IVisitor*>(this));
|
|
}
|
|
|
|
void AstVisitor::Print(JsonObjectField* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"ObjectField", node);
|
|
PrintFields(static_cast<JsonObjectField*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_TRAVERSE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
namespace traverse_visitor
|
|
{
|
|
void AstVisitor::Traverse(vl::glr::ParsingToken& token) {}
|
|
void AstVisitor::Traverse(vl::glr::ParsingAstBase* node) {}
|
|
void AstVisitor::Traverse(JsonArray* node) {}
|
|
void AstVisitor::Traverse(JsonLiteral* node) {}
|
|
void AstVisitor::Traverse(JsonNode* node) {}
|
|
void AstVisitor::Traverse(JsonNumber* node) {}
|
|
void AstVisitor::Traverse(JsonObject* node) {}
|
|
void AstVisitor::Traverse(JsonObjectField* node) {}
|
|
void AstVisitor::Traverse(JsonString* node) {}
|
|
|
|
void AstVisitor::Finishing(vl::glr::ParsingAstBase* node) {}
|
|
void AstVisitor::Finishing(JsonArray* node) {}
|
|
void AstVisitor::Finishing(JsonLiteral* node) {}
|
|
void AstVisitor::Finishing(JsonNode* node) {}
|
|
void AstVisitor::Finishing(JsonNumber* node) {}
|
|
void AstVisitor::Finishing(JsonObject* node) {}
|
|
void AstVisitor::Finishing(JsonObjectField* node) {}
|
|
void AstVisitor::Finishing(JsonString* node) {}
|
|
|
|
void AstVisitor::Visit(JsonLiteral* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<JsonNode*>(node));
|
|
Traverse(static_cast<JsonLiteral*>(node));
|
|
Finishing(static_cast<JsonLiteral*>(node));
|
|
Finishing(static_cast<JsonNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonString* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<JsonNode*>(node));
|
|
Traverse(static_cast<JsonString*>(node));
|
|
Traverse(node->content);
|
|
Finishing(static_cast<JsonString*>(node));
|
|
Finishing(static_cast<JsonNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonNumber* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<JsonNode*>(node));
|
|
Traverse(static_cast<JsonNumber*>(node));
|
|
Traverse(node->content);
|
|
Finishing(static_cast<JsonNumber*>(node));
|
|
Finishing(static_cast<JsonNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonArray* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<JsonNode*>(node));
|
|
Traverse(static_cast<JsonArray*>(node));
|
|
for (auto&& listItem : node->items)
|
|
{
|
|
InspectInto(listItem.Obj());
|
|
}
|
|
Finishing(static_cast<JsonArray*>(node));
|
|
Finishing(static_cast<JsonNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(JsonObject* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<JsonNode*>(node));
|
|
Traverse(static_cast<JsonObject*>(node));
|
|
for (auto&& listItem : node->fields)
|
|
{
|
|
InspectInto(listItem.Obj());
|
|
}
|
|
Finishing(static_cast<JsonObject*>(node));
|
|
Finishing(static_cast<JsonNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::InspectInto(JsonNode* node)
|
|
{
|
|
if (!node) return;
|
|
node->Accept(static_cast<JsonNode::IVisitor*>(this));
|
|
}
|
|
|
|
void AstVisitor::InspectInto(JsonObjectField* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<JsonObjectField*>(node));
|
|
Traverse(node->name);
|
|
InspectInto(node->value.Obj());
|
|
Finishing(static_cast<JsonObjectField*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONPARSER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Json
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
void JsonParserData(vl::stream::IStream& outputStream)
|
|
{
|
|
static const vl::vint dataLength = 1866; // 16217 bytes before compressing
|
|
static const vl::vint dataBlock = 256;
|
|
static const vl::vint dataRemain = 74;
|
|
static const vl::vint dataSolidRows = 7;
|
|
static const vl::vint dataRows = 8;
|
|
static const char* compressed[] = {
|
|
"\x59\x3F\x00\x00\x42\x07\x00\x00\x0C\x00\x01\x82\x80\x06\x03\x82\x81\x82\x06\x89\x82\x87\x0A\x80\x81\x84\x09\x0A\x98\x0A\x9D\x0A\x86\x65\x01\x84\xFF\x19\x9A\x99\x8A\x80\x03\x8D\x8D\x1D\x9D\x97\x89\x83\x96\x81\x93\x81\x02\x0A\xA7\x82\x8F\x8A\x8D\x8F\x96\x1C\x8A\xB0\x9F\x7F\x90\x99\x9B\x96\x37\x9F\x9D\x83\x0A\x92\x84\x03\x9E\x18\xB6\xB2\x82\xA1\xA0\x9F\xA0\xA3\x45\xBA\x87\xAA\xA9\xA0\x93\xA4\xA7\x4D\xAE\x8F\xB2\xA1\xA9\x99\xAA\x9A\x53\xD6\x86\x93\x99\x98\xAA\x83\x02\x40\xDB\x84\xA2\xB8\xA4\xB0\xA6\xB3\x5E\x83\x9C\xB9\xA8\xAF\xA9\xAE\xAA\x68\xF0\xAA\xA3\xB3\xBD\xB1\xBB\xB3\x77\xE9\x87\x81\xB9\xBA\xB8\x96\xBA\x7F\xF6\x81\xD8\xB3\xC2\xBD\x81\xB5\x6E\xEC\xAF\xBA\xAD\xBC\xC5\xC2\xBF\x87\x80\xD1\xC2\xC1\x84\x84\x92\xC5\x98\x89\xDA\xD1\xBE\xC3\xC8\xC2\xCF\x86\x9E\x92\xC2\xD4\xCC\xD3\xCE\xD3\xA1\x88\xDC\xCD\xB6\x80\x04\xBF\xC7\x9D\xA8\xD0\xD2\xD1\xDA\xD5\xC6\xD6\xB7\x8B\xF8\xD0\xDB\xD8\xD3\xD8\xDB\xBC\xBA\xC2\xEA\x89\x07\xD6\xDF\xDA\xA3\xC0\xC7\xFD\xD4\xDC\xE6\xE5\xE6\xC3\x9B\xF9\xD9\xCB\xD1\xE9\xEA\xEA\xD3\xD2\xC1\xF8",
|
|
"\xEB\xEA\xEF\xE4\xEB\xD9\xD7\xC9\x8A\x06\xE0\xE8\xEF\xEF\xE7\xE6\xDE\xEA\xF2\xF5\xF5\xF1\xF7\xDD\xEE\xF1\xF0\xF8\xF3\xF7\x05\xF2\x0E\xA6\x8A\x8D\x05\xF6\x05\xF3\xE7\x0F\x3F\x79\x73\x80\xA5\x50\x05\x79\x04\x02\xA5\x60\x47\x65\xEB\x4F\x7E\x80\x81\xA7\x4F\x85\x6A\x84\x11\x90\x89\x6A\x85\xBF\x58\x88\x73\x84\x1A\x8E\x7D\x84\x78\xF3\x61\x81\x43\x04\x09\x95\x8C\x87\x89\x26\xA9\x87\x84\x8A\xA1\x54\x05\x8B\x8A\x2A\x99\x8C\x8A\x8C\x31\x9B\x85\x8E\x87\x33\xB6\x80\x8F\x8E\x34\xBC\x8A\x8D\x8F\x40\xBF\x82\x90\x8E\x37\xA0\x85\x7E\x7C\x47\xB4\x70\x01\x05\x2F\x81\x94\x92\x8F\x4F\xB3\x66\x05\x93\x43\x86\x9C\x7A\x92\x14\x90\x96\x95\x96\x4E\x96\x97\x04\x95\xCC\x52\x4C\x80\x92\x57\xA2\x85\x99\x92\x66\x9C\x95\x95\x7A\x6A\x91\x9B\x99\x83\x1F\xAC\x93\x69\x06\x60\x96\x9A\x05\x9D\x72\xB9\x8E\x9B\x9E\x5B\xB1\x90\x9D\x69\x1B\x38\x9F\x9D\x91\x79\x84\xA3\xA2\x96\x85\x88\xA7\xA1\x97\x89\x8C\xAB\xA3\x9B\x06\x5C\x05\x78\x45\x63\x83\x4E\x05\x79\x1F\x02\xA6\x40\x08\xE5\x61\x0A\xA6\x92\x22\x25\x73\x0B\xA7\x69\xA3\x64\x09\x79\x25\x25\x76\x09\x79",
|
|
"\x27\x24\xA1\x40\x0A\xAE\xA7\x92\xAD\x0A\xE5\x6A\x01\xAF\x0A\xB1\xAD\x9D\x9E\x9E\xBB\x86\xA4\x9A\xAE\x8D\x90\xA8\x96\x9F\xBF\x84\xB3\x40\x0B\xE5\x6D\x09\xAE\xB1\xA5\xBC\xAA\x42\x0B\xE5\x6F\x05\x78\x0C\xE5\x71\x01\xAE\x0C\xCB\x8E\xB9\x43\x0C\xE5\x74\x09\xB6\xAF\xC3\x9A\xB5\xB2\xB8\xE1\xA0\xBD\xB2\xB9\x01\x75\x0F\xB6\xA2\xE3\xA8\xB2\xAC\xB0\x8F\xBC\x99\x7A\x0D\xEB\x8E\xAD\xB8\xBB\xE5\xB8\xB7\xBA\xBE\x68\x81\x47\x0D\xBD\xC2\xBB\xB6\xBD\xBE\x03\xC2\xC1\xC1\xBF\xEF\x8C\xB8\xC3\x73\x38\x31\xA9\x0C\xC0\xF2\xB1\xBD\xAC\xBF\x09\xE4\xB6\xC1\xC4\xF7\x85\xCB\xC2\xC2\x00\x3A\x00\xC7\xC4\x1A\xD5\xCE\xB8\xBC\x19\xC7\xC0\x03\x0E\x1F\xC1\xB8\xC4\xC1\x26\xE4\xCC\xCB\xCA\x02\x7D\x1A\x41\x4A\x95\xBC\x64\xCE\x7E\x57\x77\xC3\x43\x4A\xCB\x7A\xC2\x40\x4F\xF1\xB3\x4E\x69\x42\x3E\xFD\xCA\x40\x42\x25\xF3\x4F\x3F\xD0\x06\x48\xD7\x6C\xCF\x00\x10\xD2\xD0\x98\x4E\xFC\x63\x4C\xD4\x45\xCD\x7C\xD3\xCE\x6C\x55\xDB\x73\xD5\x21\x57\x5B\xD6\x40\x52\xF0\x4E\xD5\x73\x33\x67\xDA\xD2\xD9\x6C\x73\x49\xD4\x58\x41\xF0\x43\xD9\x40\x3F\x57\x55\xDF\x6A\x6E",
|
|
"\xE0\x97\xDF\x6D\x79\xF5\xCB\x73\xDE\x56\xF0\x49\xD5\xD9\x2D\x40\xEF\xD6\xE0\x3E\x6C\x56\xE0\xDA\x88\xE1\xD7\x6F\xE2\x6B\xED\x49\xD4\xD0\x49\xD3\xD4\xD2\xE2\x6D\xCD\xED\xD2\xCA\x96\xDB\xE7\x56\xDA\x91\xDB\x49\xD4\xE4\x9A\xC3\x40\xDD\xE5\x72\xC9\xE9\xCE\x42\xA7\xEF\xCD\xE7\x40\xA4\xED\x40\xE9\xE8\x19\x59\xDA\x6D\xEC\xB4\xC3\xE8\xE7\x55\x7D\xF8\xCB\x68\xEE\xA1\xFA\xE6\xDD\xE6\x92\xEA\xEF\xEC\xF1\x1F\x76\xEB\xEC\xDE\xA5\xFF\xCC\xE5\xEA\x97\xC3\xFC\xED\xF3\x01\x73\xE7\x8F\xEB\x7B\x52\xFC\xF1\xF1\x7E\xCD\x70\xF1\xE4\xC2\xC7\xF3\xF4\xF7\xBE\xCF\xE8\xF2\xE8\xC6\xE6\xF3\xF9\xF2\x8E\xEA\xFB\xF4\xFB\x09\x54\xEE\xE8\xF4\x06\x59\xD3\x4F\xF7\x6B\xD9\xD6\xF4\x94\xD8\xD5\xFD\xD7\xF9\x1A\x38\x7E\xD2\x61\x7E\x7C\xBE\x54\x79\x6A\xCB\x66\x80\xF9\x5C\x6A\x7A\x05\xB0\x7E\x20\x02\x82\x81\xEF\x6D\x77\x7E\x00\xB5\x72\x21\xF2\x77\x61\xFF\x00\x06\x7E\x98\x12\x87\x80\xFB\x6E\x4B\x06\xA1\x89\x22\x12\x8A\x6E\x84\x69\x76\x83\x3F\x1F\x8B\x80\x81\x11\x82\x85\xCA\x7F\x72\x0A\xA8\x84\x7E\xD3\x6C\x2D\x75\x81\x6D\x24\x0E\x87\x7A\x86\x15\xB3\x68",
|
|
"\x00\x19\x8B\x3B\x0F\xC1\x8A\x6B\xF6\x7C\x37\x87\xBA\x3B\x84\xE3\x3D\x8B\x7D\x8D\x2A\x5E\x88\x08\x90\x88\xD4\x22\x20\x8A\x0E\x95\x8C\x88\x54\x92\x89\xFA\x02\x2A\x89\xB3\x50\x6E\x8B\x47\x65\x3F\xD9\x7A\x78\x83\x30\x9D\x78\x8C\x09\x36\x31\xF9\x0B\x25\x3C\x35\x8C\x86\x20\x6E\x82\x21\xD6\x71\x81\x20\x22\xB4\x89\x8A\x70\x85\x3C\xD4\x7B\x83\x67\x32\x9D\x78\x6A\x3F\x85\x3B\x78\x5B\x81\x20\xF2\x10\x8B\x0E\xE5\x3D\x21\xA0\x50\x84\x0F\xF2\x19\x6A\x52\x50\x95\x0D\x79\x44\x87\x4E\x28\xB6\x0A\x8F\x0A\x28\x40\x14\xF7\x08\x93\x84\x1A\x96\x88\x78\x05\x3F\xE2\x5F\x40\x8B\x3C\x22\x92\x21\xA4\x86\x8A\x1E\x0E\x9A\x20\x4E\x50\x8B\x0F\x93\x8A\x21\xA6\x50\x8C\x0F\xF2\x3C\x05\x8A\x8B\x75\x88\x1E\xAF\x6A\x97\x18\xAB\x89\x20\x84\x6E\x5F\x4E\x55\x84\x81\x8B\x7A\x92\x89\xC3\x9D\x7B\xE2\x1D\x85\x35\x8E\x27\x6E\x99\x6D\x9D\x8F\x7A\x45\x91\x6C\x41\x86\x24\x88\x2E\x6E\x79\xF7\x1D\x29\x3F\x81\x18\x9C\x63\x8B\x73\x8A\x42\x01\x41\x7E\x95\x5D\x22\x89\xE2\x8F\x21\xCA\x09\x28\x8C\x23\xA4\x45\x7B\xD9\x95\x32\x42\x77\x30\x8A\x17\x5D\x7C\x49\xD1\x64",
|
|
"\x4E\x35\xB0\x75\x8B\x54\xA8\x21\x3D\x1D\x39\x6B\x3E\xF2\x85\x8A\x3A\x79\x9A\x49\x59\x62\xA2\x1F\xC6\x8B\x91\xFA\x69\x3B\x99\xC4\x2A\x22\x7F\x50\x84\x52\x87\xAB\x3B\x8C\x11\xA9\x22\x3D\xC6\x83\x96\x8B\xA4\x4F\x87\x0A\xA9\x20\x32\x8A\x2E\x53\x83\x82\x23\x54\x26\xA5\x92\x34\x86\x23\xA0\xFF\x50\x89\x55\x29\xA0\x01\xAB\x31\xAD\x9A\x82\x83\x91\x21\x48\x8A\x20\xAD\x70\x9C\x62\x7A\xAC\xA5\x8A\xF1\x92\x55\x4D\x81\x23\xA2\x23\xB6\x54\xA7\x16\x64\xAA\x42\x06\x40\x8B\xA0\x8F\x3D\xA8\x03\x3E\xA5\xFB\x38\x5D\x7A\x64\x71\xA0\xAA\x64\x63\x9F\x3C\xD5\x80\x5B\xEE\x52\x59\xA6\xE4\x9F\x94\x00\x4C\xA6\x20\xFE\x10\x8E\x5A\x48\xAE\x5F\x27\x83\x24\xAC\x0A\x9C\x67\x39\x6B\xA2\x21\x58\xEE\xA9\xA8\x59\x4B\x46\x20\x1B\xAD\x7C\xB6\x69\xA4\x63\xBC\xAE\x85\x8A\xDC\x51\xA7\x73\x6D\xA6\xA6\xBC\xAB\xA5\x7D\x4F\x9E\xA2\x92\x77\xAF\x9E\x8D\x8B\xA5\x7D\xFF\x42\xB3\x68\x7E\xA1\x21\xAC\x54\xB0\x00\x58\xA1\x6F\xC3\x12\xB5\x35\x29\x71\xA7\xB2\x97\xBD\x20\xCA\x1C\xB7\x34\x31\x4A\xB2\x20\x97\xBE\xB2\x11\xCE\xA3\xB2\xD6\x55\x8D\x07\x87\xA2\x23\x0F\x31",
|
|
"\xB1\x21\x4A\xA7\xB1\x20\x97\xAF\x9A\x42\x41\x04\xB6\x00\x03\x0D\xB7\x90\x97\xB7\x92\x04\x91\x25\x22\x3D\xB7\x39\x97\x51\xA4\x3E\xC2\xBD\x23\x23\x07\xBB\x34\xAE\x82\xBB\x72\xDE\x95\x8B\x24\x0F\xBD\x34\xA1\x4A\xBA\x44\xD5\x8B\x09\xEB\xA7\x37\x54\xDA\xAE\xB0\x14\xCD\x0E\xBB\xD0\x2B\x51\xBC\x5F\x35\x8B\x13\x3D\xB1\x0B\xDE\xB0\x50\xBD\x03\x3A\xB5\x42\x53\x0D\xB7\x2A\x3D\xB7\xA8\xC2\xAA\xB7\x40\x6F\x96\x89\x2B\x2B\x9E\x20\xFE\x82\x22\x7E\x8E\x7C\xB5\xD2\x01\xC1\x20\xD3\xA4\xC3\x5B\xA3\x36\xB4\x7E\x90\x88\x0B\xE5\xB3\x36\x55\xE2\xAD\xC1\xC2\xAD\x7A\x0B\x11\xD1\x36\xB2\x5D\x75\xC3\x3A\x95\x8C\x0B\x19\xCC\x39\x57\x94\xCB\xBA\x28\x9E\x09\xC4\x1D\x3F\xA8\x89\xE2\xB6\x88\x30\x28\xC2\x21\xD4\x5C\xC2\x6B\xD0\x82\x0D\xDE\xA4\x0D\xB7\x68\xAB\xC6\xE7\x46\x86\x0D\xDE\xA8\x0D\xB7\x7B\xA2\xAE\x6D\x83\x26\xA0\x23\xAA\x0F\xBF\x03\x2D\xA0\x91\xD5\x8B\x0C\x24\xC2\x21\xB8\x4B\xD0\x88\x1B\x4E\xC1\x21\x8A\x83\x21\xB3\x21\x2D\x0F\x8B\xDB\x53\x52\x85\x21\xB2\x21\x6F\x1B\xCA\x41\x5E\x5D\x7B\x8E\x96\x55\x8A\x71\x14\xC8\x00\x51\xB7\xCC\x28",
|
|
"\xB2\x0A\xCD\x25\xAB\xB7\x68\x68\x69\x98\x28\xB9\x91\xA0\xBA\x89\x9D\x15\xC1\x90\x24\x3E\xDB\x22\xCF\x62\xA1\x24\xA0\x8D\xB5\x3A\x66\xAD\x86\x71\xBE\x8C\xB8\x9E\xD7\x8A\x31\x6F\xB0\x20\x8B\x75\xC6\x88\xA4\x8F\xBD\x7C\x01\x80\x02\x82\x10\xA4\xB9\x48\x61\x97\x9C\xC5\x0A\x8A\x69\xE8\x9D\xD1\x15\x80",
|
|
};
|
|
vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream);
|
|
}
|
|
|
|
const wchar_t* ParserRuleName(vl::vint index)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"JLiteral",
|
|
L"JField",
|
|
L"JObject",
|
|
L"JArray",
|
|
L"JValue",
|
|
L"JRoot",
|
|
};
|
|
return results[index];
|
|
}
|
|
|
|
const wchar_t* ParserStateLabel(vl::vint index)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"[0][JLiteral] BEGIN ",
|
|
L"[1][JLiteral] END [ENDING]",
|
|
L"[2][JLiteral]< \"false\" @ >",
|
|
L"[3][JLiteral]< \"null\" @ >",
|
|
L"[4][JLiteral]< \"true\" @ >",
|
|
L"[5][JLiteral]< NUMBER @ >",
|
|
L"[6][JLiteral]< STRING @ >",
|
|
L"[7][JField] BEGIN ",
|
|
L"[8][JField] END [ENDING]",
|
|
L"[9][JField]< STRING \":\" @ JValue >",
|
|
L"[10][JField]< STRING \":\" JValue @ >",
|
|
L"[11][JField]< STRING @ \":\" JValue >",
|
|
L"[12][JObject] BEGIN ",
|
|
L"[13][JObject] END [ENDING]",
|
|
L"[14][JObject]< \"{\" @ { JField ; \",\" } \"}\" >",
|
|
L"[15][JObject]< \"{\" { JField ; \",\" @ } \"}\" >",
|
|
L"[16][JObject]< \"{\" { JField ; \",\" } \"}\" @ >",
|
|
L"[17][JObject]< \"{\" { JField @ ; \",\" } \"}\" >",
|
|
L"[18][JArray] BEGIN ",
|
|
L"[19][JArray] END [ENDING]",
|
|
L"[20][JArray]< \"[\" @ { JValue ; \",\" } \"]\" >",
|
|
L"[21][JArray]< \"[\" { JValue ; \",\" @ } \"]\" >",
|
|
L"[22][JArray]< \"[\" { JValue ; \",\" } \"]\" @ >",
|
|
L"[23][JArray]< \"[\" { JValue @ ; \",\" } \"]\" >",
|
|
L"[24][JValue] BEGIN ",
|
|
L"[25][JValue] END [ENDING]",
|
|
L"[26][JValue]<< !JArray @ >>",
|
|
L"[27][JValue]<< !JLiteral @ >>",
|
|
L"[28][JValue]<< !JObject @ >>",
|
|
L"[29][JRoot] BEGIN ",
|
|
L"[30][JRoot] END [ENDING]",
|
|
L"[31][JRoot]<< !JArray @ >>",
|
|
L"[32][JRoot]<< !JObject @ >>",
|
|
};
|
|
return results[index];
|
|
}
|
|
|
|
Parser::Parser()
|
|
: vl::glr::ParserBase<JsonTokens, ParserStates, JsonAstInsReceiver>(&JsonTokenDeleter, &JsonLexerData, &JsonParserData)
|
|
{
|
|
};
|
|
|
|
vl::vint32_t Parser::FindCommonBaseClass(vl::vint32_t class1, vl::vint32_t class2) const
|
|
{
|
|
return -1;
|
|
};
|
|
|
|
vl::Ptr<vl::glr::json::JsonNode> Parser::ParseJRoot(const vl::WString& input, vl::vint codeIndex) const
|
|
{
|
|
return ParseWithString<vl::glr::json::JsonNode, ParserStates::JRoot>(input, this, codeIndex);
|
|
};
|
|
|
|
vl::Ptr<vl::glr::json::JsonNode> Parser::ParseJRoot(vl::collections::List<vl::regex::RegexToken>& tokens, vl::vint codeIndex) const
|
|
{
|
|
return ParseWithTokens<vl::glr::json::JsonNode, ParserStates::JRoot>(tokens, this, codeIndex);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSON_ASSEMBLER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Json
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
|
|
/***********************************************************************
|
|
JsonAstInsReceiver : public vl::glr::AstInsReceiverBase
|
|
***********************************************************************/
|
|
|
|
vl::Ptr<vl::glr::ParsingAstBase> JsonAstInsReceiver::CreateAstNode(vl::vint32_t type)
|
|
{
|
|
auto cppTypeName = JsonCppTypeName((JsonClasses)type);
|
|
switch((JsonClasses)type)
|
|
{
|
|
case JsonClasses::Array:
|
|
return new vl::glr::json::JsonArray();
|
|
case JsonClasses::Literal:
|
|
return new vl::glr::json::JsonLiteral();
|
|
case JsonClasses::Number:
|
|
return new vl::glr::json::JsonNumber();
|
|
case JsonClasses::Object:
|
|
return new vl::glr::json::JsonObject();
|
|
case JsonClasses::ObjectField:
|
|
return new vl::glr::json::JsonObjectField();
|
|
case JsonClasses::String:
|
|
return new vl::glr::json::JsonString();
|
|
default:
|
|
return vl::glr::AssemblyThrowCannotCreateAbstractType(type, cppTypeName);
|
|
}
|
|
}
|
|
|
|
void JsonAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::Ptr<vl::glr::ParsingAstBase> value)
|
|
{
|
|
auto cppFieldName = JsonCppFieldName((JsonFields)field);
|
|
switch((JsonFields)field)
|
|
{
|
|
case JsonFields::Array_items:
|
|
return vl::glr::AssemblerSetObjectField(&vl::glr::json::JsonArray::items, object, field, value, cppFieldName);
|
|
case JsonFields::Object_fields:
|
|
return vl::glr::AssemblerSetObjectField(&vl::glr::json::JsonObject::fields, object, field, value, cppFieldName);
|
|
case JsonFields::ObjectField_value:
|
|
return vl::glr::AssemblerSetObjectField(&vl::glr::json::JsonObjectField::value, object, field, value, cppFieldName);
|
|
default:
|
|
return vl::glr::AssemblyThrowFieldNotObject(field, cppFieldName);
|
|
}
|
|
}
|
|
|
|
void JsonAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, const vl::regex::RegexToken& token, vl::vint32_t tokenIndex)
|
|
{
|
|
auto cppFieldName = JsonCppFieldName((JsonFields)field);
|
|
switch((JsonFields)field)
|
|
{
|
|
case JsonFields::Number_content:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::json::JsonNumber::content, object, field, token, tokenIndex, cppFieldName);
|
|
case JsonFields::ObjectField_name:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::json::JsonObjectField::name, object, field, token, tokenIndex, cppFieldName);
|
|
case JsonFields::String_content:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::json::JsonString::content, object, field, token, tokenIndex, cppFieldName);
|
|
default:
|
|
return vl::glr::AssemblyThrowFieldNotToken(field, cppFieldName);
|
|
}
|
|
}
|
|
|
|
void JsonAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::vint32_t enumItem)
|
|
{
|
|
auto cppFieldName = JsonCppFieldName((JsonFields)field);
|
|
switch((JsonFields)field)
|
|
{
|
|
case JsonFields::Literal_value:
|
|
return vl::glr::AssemblerSetEnumField(&vl::glr::json::JsonLiteral::value, object, field, enumItem, cppFieldName);
|
|
default:
|
|
return vl::glr::AssemblyThrowFieldNotEnum(field, cppFieldName);
|
|
}
|
|
}
|
|
|
|
const wchar_t* JsonTypeName(JsonClasses type)
|
|
{
|
|
const wchar_t* results[] = {
|
|
L"Array",
|
|
L"Literal",
|
|
L"Node",
|
|
L"Number",
|
|
L"Object",
|
|
L"ObjectField",
|
|
L"String",
|
|
};
|
|
vl::vint index = (vl::vint)type;
|
|
return 0 <= index && index < 7 ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* JsonCppTypeName(JsonClasses type)
|
|
{
|
|
const wchar_t* results[] = {
|
|
L"vl::glr::json::JsonArray",
|
|
L"vl::glr::json::JsonLiteral",
|
|
L"vl::glr::json::JsonNode",
|
|
L"vl::glr::json::JsonNumber",
|
|
L"vl::glr::json::JsonObject",
|
|
L"vl::glr::json::JsonObjectField",
|
|
L"vl::glr::json::JsonString",
|
|
};
|
|
vl::vint index = (vl::vint)type;
|
|
return 0 <= index && index < 7 ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* JsonFieldName(JsonFields field)
|
|
{
|
|
const wchar_t* results[] = {
|
|
L"Array::items",
|
|
L"Literal::value",
|
|
L"Number::content",
|
|
L"Object::fields",
|
|
L"ObjectField::name",
|
|
L"ObjectField::value",
|
|
L"String::content",
|
|
};
|
|
vl::vint index = (vl::vint)field;
|
|
return 0 <= index && index < 7 ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* JsonCppFieldName(JsonFields field)
|
|
{
|
|
const wchar_t* results[] = {
|
|
L"vl::glr::json::JsonArray::items",
|
|
L"vl::glr::json::JsonLiteral::value",
|
|
L"vl::glr::json::JsonNumber::content",
|
|
L"vl::glr::json::JsonObject::fields",
|
|
L"vl::glr::json::JsonObjectField::name",
|
|
L"vl::glr::json::JsonObjectField::value",
|
|
L"vl::glr::json::JsonString::content",
|
|
};
|
|
vl::vint index = (vl::vint)field;
|
|
return 0 <= index && index < 7 ? results[index] : nullptr;
|
|
}
|
|
|
|
vl::Ptr<vl::glr::ParsingAstBase> JsonAstInsReceiver::ResolveAmbiguity(vl::vint32_t type, vl::collections::Array<vl::Ptr<vl::glr::ParsingAstBase>>& candidates)
|
|
{
|
|
auto cppTypeName = JsonCppTypeName((JsonClasses)type);
|
|
return vl::glr::AssemblyThrowTypeNotAllowAmbiguity(type, cppTypeName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSON_LEXER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Json
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
bool JsonTokenDeleter(vl::vint token)
|
|
{
|
|
switch((JsonTokens)token)
|
|
{
|
|
case JsonTokens::SPACE:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const wchar_t* JsonTokenId(JsonTokens token)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"TRUE_VALUE",
|
|
L"FALSE_VALUE",
|
|
L"NULL_VALUE",
|
|
L"OBJOPEN",
|
|
L"OBJCLOSE",
|
|
L"ARROPEN",
|
|
L"ARRCLOSE",
|
|
L"COMMA",
|
|
L"COLON",
|
|
L"NUMBER",
|
|
L"STRING",
|
|
L"SPACE",
|
|
};
|
|
vl::vint index = (vl::vint)token;
|
|
return 0 <= index && index < JsonTokenCount ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* JsonTokenDisplayText(JsonTokens token)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"true",
|
|
L"false",
|
|
L"null",
|
|
L"{",
|
|
L"}",
|
|
L"[",
|
|
L"]",
|
|
L",",
|
|
L":",
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
};
|
|
vl::vint index = (vl::vint)token;
|
|
return 0 <= index && index < JsonTokenCount ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* JsonTokenRegex(JsonTokens token)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"true",
|
|
L"false",
|
|
L"null",
|
|
L"\\{",
|
|
L"\\}",
|
|
L"\\[",
|
|
L"\\]",
|
|
L",",
|
|
L":",
|
|
L"[\\-]?\\d+(.\\d+)?([eE][+\\-]?\\d+)?",
|
|
L"\"([^\\\\\"]|\\\\[^u]|\\\\u\\d{4})*\"",
|
|
L"\\s+",
|
|
};
|
|
vl::vint index = (vl::vint)token;
|
|
return 0 <= index && index < JsonTokenCount ? results[index] : nullptr;
|
|
}
|
|
|
|
void JsonLexerData(vl::stream::IStream& outputStream)
|
|
{
|
|
static const vl::vint dataLength = 690; // 7754 bytes before compressing
|
|
static const vl::vint dataBlock = 256;
|
|
static const vl::vint dataRemain = 178;
|
|
static const vl::vint dataSolidRows = 2;
|
|
static const vl::vint dataRows = 3;
|
|
static const char* compressed[] = {
|
|
"\x4A\x1E\x00\x00\xAA\x02\x00\x00\x2A\x00\x01\xAB\x01\x84\x81\x80\x81\x80\x01\x04\x88\x04\x89\x04\x84\x82\x05\x0F\x84\x8B\x04\x8C\x04\x81\x06\x8B\x04\x8E\x04\x9F\x04\x80\x11\x8E\x82\x21\x20\x84\x82\x13\x94\x83\x10\x82\x07\x80\x03\x82\x84\x84\x15\x96\x82\x2D\x30\x84\x8E\x13\x9C\x83\x16\x9B\x04\xB0\x04\x99\x14\x82\x1D\x9E\x82\x3B\x04\x84\x24\x85\x24\xA0\x82\x23\x04\xDA\x04\x9B\x2B\xA4\x80\x2E\xA7\x04\xDD\x11\xA4\x8E\x2C\x80\x30\x82\x61\x58\x84\x82\x34\x84\x30\x83\x32\x5F\x84\xA6\x22\xB4\x87\x30\x83\x35\x04\xEC\x29\xA4\x8D\x34\xB4\x82\x37\x6F\x84\xAF\x24\x81\x3C\x82\x38\xBB\x04\xF3\x39\xA4\x84\x3C\xBC\x83\x3A\x7F\x84\xB6\x24\x8A\x3C\x83\x3C\xC3\x04\xFC\x09\xC4\x8D\x3C\xC4\x82\x3F\x04\xFF\x7F\x70\x00\x02\xCA\xC9\x8B\x01\x98\xD5\xD6\xCA\xCE\xCB\x7F\xCE\x96\x95\x81\x9E\xCE\xCB\x85\x80\x88\xA3\xA4\xD2\xD3\x81\x85\x85\xD4\xD5\x9E\x86\x11\xD6\xC7\x03\xD8\xD8\xD8\x02\x36\xF7\xDF\x73\x02\xDF\xDB\x84\xAF\xA4\xC4\x1A\xD5\x06\xDF\xDD\xE3\xC8\xC9\xCA\xEB\xEC\xE5\xE6\xE7\xE7\x1A\xC1\xCF\xF3\xE4\xED\xEA\xEB\xEB\xA4\x8F\x06\xF8",
|
|
"\xEC\xED\xEE\xEF\xEF\xE0\xE1\xD5\xF4\xC2\xEA\xF2\xF3\xF3\xE8\xE9\xEA\xEB\xFC\xF5\xF6\xF7\xF7\xF0\xF1\xF2\xF3\xF4\xFD\xFA\xFB\xFB\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xF4\xD6\x9B\x7E\x72\x83\x7C\x12\x3A\x61\x07\x76\xFF\x13\x08\x80\x75\x0A\xA5\x73\x80\x05\x04\x50\x81\x42\x84\x00\x14\x86\x85\x84\x18\x81\x46\x05\x86\x15\x9C\x87\x87\x84\x1E\xA1\x80\x8B\x88\x00\x15\x02\x89\x87\x24\x9F\x88\x8B\x8A\x2A\xAD\x87\x8A\x8B\x29\x88\x87\x04\x41\x33\x81\x75\x8D\x80\xFF\x37\x83\x83\x8E\x3C\xBD\x88\x7C\x06\x0B\xBE\x82\x92\x6A\x19\x01\x93\x93\x91\xE0\x5A\x06\x90\x92\xDE\x45\x81\x73\x81\x0E\x89\x8B\x91\x73\x0D\xB8\x8C\x93\x7E\x1B\x13\x97\x94\x93\x1C\x3A\x6D\x95\x94\x1D\x1A\x9B\x94\x77\x30\xAC\x8F\x88\x41\x1B\xB1\x8A\x9A\x99\x6B\xA5\x94\x86\x89\x6D\xA7\x91\x9F\x9C\x6C\xB5\x9E\x9A\x6E\x1E\x04\x49\x9D\x40\x7B\x80\x0D\x9F\x9F\x7A\x81\xAC\x9E\xA0\x7E\x84\xA0\xA3\xA0\x88\x85\xA9\xA3\xA1\x8A\x8D\xAC\xA3\xA3\x86\x91\xAB\xA2\xA4\x8D\x9C\x43\xA7\xA5\x8D\xA3\x9A\xA5\x7B\x37\xBA\x86\x66\xA7\x92\x60\xAB\xA7\xA8\xA4\x9D\x7E\x45\x94\xA5\xA9\xAF\x79\x48",
|
|
"\xA8\xAA\xAE\x8C\x49\xAD\xAE\xA8\x77\x49\x51\x95\x9F\x76\xAD\xB2\xB2\x71\x99\xAC\xB9\xAA\xA4\x0A\x98\xBD\x89\x77\x9C\x9D\x14\xA9\x96\x9E\x9C\xC7\xB4\x90\x9D\xB2\xCC\x83\xBD\xB0\xB2\x65\x83\x95\x08\xB0\xC1\x95\xB6\xB7\xB5\xE8\x66\x04\xB4\xB6\xDC\x9D\xBF\x70\xAD\x56\x96\x68\xAD\x77\xE3\x9E\xB6\x7B\xAF\xBC\xA6\xB8\x93\x09\xDB\xAA\xBE\xBB\xBB\xF4\x68\x0D\xB8\xBC\xFD\x69\x03\xBD\xB7\xCE\x8E\xB6\xB1\xBE\xD0\x88\xBB\xB0\xBF\xC4\xBD\xB1\xC0\x9D\x9E\x70\x3B\x0A\x30\x28\x12\x59\x49\x41\xA2\x40\x0D\xC1\xC3\xBD\x41\x43\x71\x40\xC5\x41\x42\x6D\x40\xB5\x41\x46\x6A\xC3\x0E\x41\x4D\xC0\x80\x0F\xD4\x4D\xC4\xC7\x1E\xE2\xC5\xCB\x69\x12\x66\xC4\xCB\xCA\xAE\x6C\xCA\xC9\xC3\x0C\xC4\x49\x6D\x6B\x23\xCD\xC0\x73\xCA\x21\xC1\x40",
|
|
};
|
|
vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
|
|
/***********************************************************************
|
|
TraceManager
|
|
***********************************************************************/
|
|
|
|
void TraceManager::BeginSwap()
|
|
{
|
|
concurrentCount = 0;
|
|
}
|
|
|
|
void TraceManager::AddTrace(Trace* trace)
|
|
{
|
|
if (concurrentCount < backupTraces->Count())
|
|
{
|
|
backupTraces->Set(concurrentCount, trace);
|
|
}
|
|
else
|
|
{
|
|
backupTraces->Add(trace);
|
|
}
|
|
concurrentCount++;
|
|
}
|
|
|
|
void TraceManager::EndSwap()
|
|
{
|
|
auto t = concurrentTraces;
|
|
concurrentTraces = backupTraces;
|
|
backupTraces = t;
|
|
}
|
|
|
|
void TraceManager::AddTraceToCollection(Trace* owner, Trace* element, TraceCollection(Trace::* collection))
|
|
{
|
|
auto errorMessage = L"vl::glr::automaton::TraceManager::AddTraceToCollection(Trace*, Trace*, TraceCollection(Trace::*))#Multiple to multiple predecessor-successor relationship is not supported.";
|
|
auto&& elementCollection = element->*collection;
|
|
if (elementCollection.siblingNext == -1 && elementCollection.siblingPrev == -1)
|
|
{
|
|
auto&& ownerCollection = owner->*collection;
|
|
if (ownerCollection.first == -1)
|
|
{
|
|
ownerCollection.first = element->allocatedIndex;
|
|
ownerCollection.last = element->allocatedIndex;
|
|
}
|
|
else
|
|
{
|
|
auto sibling = GetTrace(ownerCollection.last);
|
|
auto&& siblingCollection = sibling->*collection;
|
|
CHECK_ERROR(siblingCollection.siblingNext == -1, errorMessage);
|
|
|
|
siblingCollection.siblingNext = element->allocatedIndex;
|
|
elementCollection.siblingPrev = sibling->allocatedIndex;
|
|
ownerCollection.last = element->allocatedIndex;
|
|
}
|
|
}
|
|
else if (collection == &Trace::predecessors)
|
|
{
|
|
// there is a valid scenario when
|
|
// B(ending) ---+
|
|
// |
|
|
// O(origin) -+-> A(ending) -+-+-> C(merged)
|
|
// |
|
|
// +---> D(token)
|
|
|
|
// in this case, we need to copy A(ending) to avoid the multiple to multiple relationship
|
|
// the reason we cannot have such relationship is that
|
|
// TraceCollection::(siblingPrev|siblingNext) is a linked list
|
|
// it represents a predecessor collections of owner
|
|
// if a trace is shared in two predecessor collections
|
|
// there is no place for a second linked list
|
|
// the data structure is not able to represent such relationship
|
|
|
|
// but this it is not doable if A also has multiple predecessors
|
|
// because copying A replaces a new multiple to multiple relationship to an old one like this
|
|
// O1(origin) -+-+ B(ending) -+
|
|
// | | |
|
|
// O2(origin) -+-+-> A(ending) -+-> C(merged)
|
|
// |
|
|
// +---> X(ending) ---> D(token)
|
|
CHECK_ERROR(element->predecessors.first == element->predecessors.last, errorMessage);
|
|
|
|
auto copiedElement = AllocateTrace();
|
|
{
|
|
vint32_t copiedId = copiedElement->allocatedIndex;
|
|
*copiedElement = *element;
|
|
copiedElement->allocatedIndex = copiedId;
|
|
}
|
|
|
|
// clear sibilingPrev and sibilingNext because it belongs to no collection at this moment
|
|
// keep first and last so that it still knows its predecessors
|
|
copiedElement->predecessors.siblingPrev = -1;
|
|
copiedElement->predecessors.siblingNext = -1;
|
|
|
|
// now it becomes
|
|
// B(ending) -+
|
|
// |
|
|
// O(origin) -+-> A(ending) -+-> C(merged)
|
|
// |
|
|
// +-> X(ending) ---> D(token)
|
|
AddTraceToCollection(owner, copiedElement, collection);
|
|
}
|
|
else
|
|
{
|
|
// Trace::predecessors is filled by Input
|
|
// Trace::successors is filled by PrepareTraceRoute
|
|
// if Input and EndOfInput succeeded
|
|
// there should not be any multiple to multiple relationship
|
|
CHECK_FAIL(errorMessage);
|
|
}
|
|
}
|
|
|
|
TraceManager::TraceManager(Executable& _executable, const ITypeCallback* _typeCallback)
|
|
: executable(_executable)
|
|
, typeCallback(_typeCallback)
|
|
{
|
|
}
|
|
|
|
ReturnStack* TraceManager::GetReturnStack(vint32_t index)
|
|
{
|
|
return returnStacks.Get(index);
|
|
}
|
|
|
|
ReturnStack* TraceManager::AllocateReturnStack()
|
|
{
|
|
return returnStacks.Get(returnStacks.Allocate());
|
|
}
|
|
|
|
Trace* TraceManager::GetTrace(vint32_t index)
|
|
{
|
|
return traces.Get(index);
|
|
}
|
|
|
|
Trace* TraceManager::AllocateTrace()
|
|
{
|
|
return traces.Get(traces.Allocate());
|
|
}
|
|
|
|
Competition* TraceManager::GetCompetition(vint32_t index)
|
|
{
|
|
return competitions.Get(index);
|
|
}
|
|
|
|
Competition* TraceManager::AllocateCompetition()
|
|
{
|
|
return competitions.Get(competitions.Allocate());
|
|
}
|
|
|
|
AttendingCompetitions* TraceManager::GetAttendingCompetitions(vint32_t index)
|
|
{
|
|
return attendingCompetitions.Get(index);
|
|
}
|
|
|
|
AttendingCompetitions* TraceManager::AllocateAttendingCompetitions()
|
|
{
|
|
return attendingCompetitions.Get(attendingCompetitions.Allocate());
|
|
}
|
|
|
|
void TraceManager::Initialize(vint32_t startState)
|
|
{
|
|
state = TraceManagerState::WaitingForInput;
|
|
|
|
returnStacks.Clear();
|
|
traces.Clear();
|
|
competitions.Clear();
|
|
attendingCompetitions.Clear();
|
|
|
|
traces1.Clear();
|
|
traces2.Clear();
|
|
concurrentTraces = &traces1;
|
|
backupTraces = &traces2;
|
|
|
|
activeCompetitions = -1;
|
|
initialReturnStackSuccessors = {};
|
|
|
|
initialTrace = AllocateTrace();
|
|
initialTrace->state = startState;
|
|
concurrentCount = 1;
|
|
concurrentTraces->Add(initialTrace);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER_EXECUTETRACE.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
/***********************************************************************
|
|
TraceManager::ExecuteTrace
|
|
***********************************************************************/
|
|
|
|
struct TraceManagerSubmitter
|
|
{
|
|
// AccumulatedDfa
|
|
vint32_t adfaCount = 0;
|
|
vint32_t adfaIndex = -1;
|
|
regex::RegexToken* adfaToken = nullptr;
|
|
|
|
// AccumulatedEoRo
|
|
vint32_t aeoroCount = 0;
|
|
vint32_t aeoroIndex = -1;
|
|
regex::RegexToken* aeoroToken = nullptr;
|
|
|
|
// Caching
|
|
AstIns cachedIns;
|
|
vint32_t cachedIndex = -1;
|
|
regex::RegexToken* cachedToken = nullptr;
|
|
|
|
IAstInsReceiver* receiver = nullptr;
|
|
|
|
void Submit(AstIns& ins, regex::RegexToken& token, vint32_t tokenIndex)
|
|
{
|
|
// multiple DelayFieldAssignment are compressed to single AccumulatedDfa
|
|
// multiple EndObject+ReopenObject are compressed to single AccumulatedEoRo
|
|
|
|
switch (ins.type)
|
|
{
|
|
case AstInsType::DelayFieldAssignment:
|
|
if (aeoroToken == nullptr && cachedToken == nullptr && (adfaToken == nullptr || adfaToken == &token))
|
|
{
|
|
adfaCount++;
|
|
adfaIndex = tokenIndex;
|
|
adfaToken = &token;
|
|
}
|
|
else
|
|
{
|
|
ExecuteSubmitted();
|
|
adfaCount = 1;
|
|
adfaIndex = tokenIndex;
|
|
adfaToken = &token;
|
|
}
|
|
break;
|
|
case AstInsType::EndObject:
|
|
if (adfaToken == nullptr && cachedToken == nullptr)
|
|
{
|
|
cachedIns = ins;
|
|
cachedIndex = tokenIndex;
|
|
cachedToken = &token;
|
|
}
|
|
else
|
|
{
|
|
ExecuteSubmitted();
|
|
cachedIns = ins;
|
|
cachedIndex = tokenIndex;
|
|
cachedToken = &token;
|
|
}
|
|
break;
|
|
case AstInsType::ReopenObject:
|
|
if (adfaToken != nullptr || cachedToken == nullptr || cachedIns.type != AstInsType::EndObject)
|
|
{
|
|
ExecuteSubmitted();
|
|
receiver->Execute(ins, token, tokenIndex);
|
|
}
|
|
else if ((aeoroToken == nullptr || aeoroToken == &token) && cachedToken == &token)
|
|
{
|
|
aeoroCount++;
|
|
aeoroIndex = tokenIndex;
|
|
aeoroToken = &token;
|
|
cachedToken = nullptr;
|
|
}
|
|
else if (cachedToken == &token)
|
|
{
|
|
cachedToken = nullptr;
|
|
ExecuteSubmitted();
|
|
aeoroCount = 1;
|
|
aeoroIndex = tokenIndex;
|
|
aeoroToken = &token;
|
|
}
|
|
else
|
|
{
|
|
ExecuteSubmitted();
|
|
receiver->Execute(ins, token, tokenIndex);
|
|
}
|
|
break;
|
|
default:
|
|
ExecuteSubmitted();
|
|
receiver->Execute(ins, token, tokenIndex);
|
|
}
|
|
}
|
|
|
|
void ExecuteSubmitted()
|
|
{
|
|
if (adfaToken)
|
|
{
|
|
if (adfaCount == 1)
|
|
{
|
|
AstIns ins = { AstInsType::DelayFieldAssignment };
|
|
receiver->Execute(ins, *adfaToken, adfaIndex);
|
|
}
|
|
else
|
|
{
|
|
AstIns ins = { AstInsType::AccumulatedDfa,-1,adfaCount };
|
|
receiver->Execute(ins, *adfaToken, adfaIndex);
|
|
}
|
|
adfaCount = 0;
|
|
adfaToken = nullptr;
|
|
}
|
|
if (aeoroToken)
|
|
{
|
|
AstIns ins = { AstInsType::AccumulatedEoRo,-1,aeoroCount };
|
|
receiver->Execute(ins, *aeoroToken, aeoroIndex);
|
|
aeoroCount = 0;
|
|
aeoroToken = nullptr;
|
|
}
|
|
if (cachedToken)
|
|
{
|
|
receiver->Execute(cachedIns, *cachedToken, aeoroIndex);
|
|
cachedToken = nullptr;
|
|
}
|
|
}
|
|
};
|
|
|
|
Ptr<ParsingAstBase> TraceManager::ExecuteTrace(Trace* trace, IAstInsReceiver& receiver, collections::List<regex::RegexToken>& tokens)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::ExecuteTrace(Trace*, IAstInsReceiver&, List<RegexToken>&)#"
|
|
CHECK_ERROR(state == TraceManagerState::PreparedTraceRoute, ERROR_MESSAGE_PREFIX L"Wrong timing to call this function.");
|
|
|
|
TraceManagerSubmitter submitter;
|
|
submitter.receiver = &receiver;
|
|
|
|
// execute from the root trace
|
|
|
|
vint32_t startIns = 0;
|
|
while (trace)
|
|
{
|
|
TraceInsLists insLists;
|
|
ReadInstructionList(trace, insLists);
|
|
|
|
vint32_t minIns = 0;
|
|
vint32_t maxIns = insLists.c3 - 1;
|
|
if (trace->ambiguityMergeInsPostfix != -1)
|
|
{
|
|
minIns = insLists.c3 - trace->ambiguityMergeInsPostfix;
|
|
}
|
|
if (trace->ambiguityBranchInsPostfix != -1)
|
|
{
|
|
maxIns = insLists.c3 - trace->ambiguityBranchInsPostfix - 1;
|
|
}
|
|
|
|
// if the current trace is an ambiguity resolving trace
|
|
// we check if all predecessors has been visited
|
|
// if yes, we continue
|
|
// if no, we jump to the BeginObject and repeat it again
|
|
|
|
if (trace->ambiguity.traceBeginObject != -1 && trace->ambiguityRouting.predecessorCount == -1)
|
|
{
|
|
// we need to know how many predecessors there
|
|
// the number is calculated and cached when an ambiguity resolving trace is visited for the first time
|
|
trace->ambiguityRouting.predecessorCount = 0;
|
|
auto predecessorId = trace->predecessors.first;
|
|
while (predecessorId != -1)
|
|
{
|
|
trace->ambiguityRouting.predecessorCount++;
|
|
predecessorId = GetTrace(predecessorId)->predecessors.siblingNext;
|
|
}
|
|
}
|
|
|
|
if (trace->ambiguity.traceBeginObject != -1)
|
|
{
|
|
if (0 <= trace->ambiguity.insEndObject && trace->ambiguity.insEndObject < insLists.c3)
|
|
{
|
|
// execute from the beginning to EndObject instruction if it exists
|
|
// if ambiguityMergeInsPostfix exists
|
|
// then insEndObject will be the last instruction in the prefix
|
|
// so it is skipped and this loop does nothing
|
|
// the EndObject instruction has already been executed by its predecessors
|
|
for (vint32_t i = minIns; i <= trace->ambiguity.insEndObject; i++)
|
|
{
|
|
auto& ins = ReadInstruction(i, insLists);
|
|
auto& token = tokens[trace->currentTokenIndex];
|
|
submitter.Submit(ins, token, trace->currentTokenIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// otherwise this must be the trace created by CreateLastMergingTrace
|
|
CHECK_ERROR(insLists.c3 == 0 && trace->successors.first == -1 && trace->successors.last == -1, ERROR_MESSAGE_PREFIX L"Instruction index out of range.");
|
|
}
|
|
|
|
// for any ambiguity resolving trace
|
|
// we check all predecessors has been visited
|
|
trace->ambiguityRouting.branchVisited++;
|
|
auto traceBeginObject = GetTrace(trace->ambiguity.traceBeginObject);
|
|
|
|
if (trace->ambiguityRouting.branchVisited == trace->ambiguityRouting.predecessorCount)
|
|
{
|
|
// if all predecessors has been visited
|
|
// we reset the number to 0
|
|
// because TraceManager::ExecuteTrace could be called multiple time
|
|
trace->ambiguityRouting.branchVisited = 0;
|
|
{
|
|
// submit a ResolveAmbiguity instruction
|
|
auto& token = tokens[trace->currentTokenIndex];
|
|
AstIns insResolve = { AstInsType::ResolveAmbiguity,trace->ambiguity.ambiguityType,trace->ambiguityRouting.predecessorCount };
|
|
submitter.Submit(insResolve, token, trace->currentTokenIndex);
|
|
}
|
|
|
|
// execute all instructions after EndObject
|
|
// these part should not be repeated
|
|
for (vint32_t i = trace->ambiguity.insEndObject + 1; i <= maxIns; i++)
|
|
{
|
|
auto& ins = ReadInstruction(i, insLists);
|
|
auto& token = tokens[trace->currentTokenIndex];
|
|
submitter.Submit(ins, token, trace->currentTokenIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if there are unvisited predecessors
|
|
// we jump to the BeginObject instruction and repeat it again
|
|
startIns = trace->ambiguity.insBeginObject;
|
|
trace = traceBeginObject;
|
|
goto FOUND_NEXT_TRACE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// otherwise, just submit instructions
|
|
CHECK_ERROR(minIns <= startIns, ERROR_MESSAGE_PREFIX L"startIns corrupted.");
|
|
for (vint32_t i = startIns; i <= maxIns; i++)
|
|
{
|
|
auto& ins = ReadInstruction(i, insLists);
|
|
auto& token = tokens[trace->currentTokenIndex];
|
|
submitter.Submit(ins, token, trace->currentTokenIndex);
|
|
}
|
|
}
|
|
|
|
if (trace->successors.first == -1)
|
|
{
|
|
trace = nullptr;
|
|
startIns = 0;
|
|
}
|
|
else if (trace->successors.first == trace->successors.last)
|
|
{
|
|
trace = GetTrace(trace->successors.first);
|
|
startIns = 0;
|
|
}
|
|
else
|
|
{
|
|
// if there are multiple successors
|
|
// whenever this trace is visited
|
|
// we pick a different successor to continue
|
|
auto nextSuccessorId = trace->successors.first;
|
|
Trace* successor = nullptr;
|
|
for (vint i = 0; i <= trace->ambiguityRouting.branchVisited; i++)
|
|
{
|
|
CHECK_ERROR(nextSuccessorId != -1, ERROR_MESSAGE_PREFIX L"branchVisited corrupted.");
|
|
successor = GetTrace(nextSuccessorId);
|
|
nextSuccessorId = successor->successors.siblingNext;
|
|
}
|
|
|
|
if (nextSuccessorId == -1)
|
|
{
|
|
trace->ambiguityRouting.branchVisited = 0;
|
|
}
|
|
else
|
|
{
|
|
trace->ambiguityRouting.branchVisited++;
|
|
}
|
|
|
|
// this could happen when all BeginObject are in successors
|
|
// if the current successor is the first successor
|
|
// then we need to execute the prefix
|
|
if (startIns >= insLists.c3)
|
|
{
|
|
startIns -= insLists.c3;
|
|
if (trace->successors.first == successor->allocatedIndex)
|
|
{
|
|
ReadInstructionList(successor, insLists);
|
|
for (vint32_t i = 0; i < startIns; i++)
|
|
{
|
|
auto& ins = ReadInstruction(i, insLists);
|
|
auto& token = tokens[successor->currentTokenIndex];
|
|
submitter.Submit(ins, token, trace->currentTokenIndex);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
startIns = 0;
|
|
}
|
|
trace = successor;
|
|
}
|
|
FOUND_NEXT_TRACE:;
|
|
}
|
|
|
|
submitter.ExecuteSubmitted();
|
|
return receiver.Finished();
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER_INPUT.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
|
|
/***********************************************************************
|
|
Input
|
|
***********************************************************************/
|
|
|
|
void TraceManager::Input(vint32_t currentTokenIndex, vint32_t token, vint32_t lookAhead)
|
|
{
|
|
CHECK_ERROR(state == TraceManagerState::WaitingForInput, L"vl::glr::automaton::TraceManager::Input(vint, vint)#Wrong timing to call this function.");
|
|
vint32_t traceCount = concurrentCount;
|
|
vint32_t input = Executable::TokenBegin + token;
|
|
|
|
BeginSwap();
|
|
|
|
// for each surviving trace
|
|
// step one TokenInput transition
|
|
// followed by multiple and EndingInput, LeftrecInput and their combination
|
|
// one surviving trace could create multiple surviving trace
|
|
for (vint32_t traceIndex = 0; traceIndex < traceCount; traceIndex++)
|
|
{
|
|
auto trace = concurrentTraces->Get(traceIndex);
|
|
vint32_t transitionIndex = executable.GetTransitionIndex(trace->state, input);
|
|
auto&& edgeArray = executable.transitions[transitionIndex];
|
|
WalkAlongTokenEdges(currentTokenIndex, input, lookAhead, trace, edgeArray);
|
|
}
|
|
|
|
// if competitions happen between new surviving traces
|
|
// remove traces that known to have lost the competition
|
|
CheckBackupTracesBeforeSwapping(currentTokenIndex);
|
|
|
|
EndSwap();
|
|
|
|
// if there are unused spaces in concurrentTraces
|
|
// set them to nullptr to clear out traces from the last round
|
|
for (vint32_t traceIndex = concurrentCount; traceIndex < concurrentTraces->Count(); traceIndex++)
|
|
{
|
|
concurrentTraces->Set(traceIndex, nullptr);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
EndOfInput
|
|
***********************************************************************/
|
|
|
|
void TraceManager::EndOfInput()
|
|
{
|
|
CHECK_ERROR(state == TraceManagerState::WaitingForInput, L"vl::glr::automaton::TraceManager::EndOfInput()#Wrong timing to call this function.");
|
|
state = TraceManagerState::Finished;
|
|
|
|
vint32_t traceCount = concurrentCount;
|
|
BeginSwap();
|
|
|
|
// check all surviving traces and remove all that
|
|
// 1) does not stay in an ending state
|
|
// 2) return stack is not empty
|
|
// the remaining are all traces that successfully walked to the ending state of the root rule
|
|
for (vint32_t traceIndex = 0; traceIndex < traceCount; traceIndex++)
|
|
{
|
|
auto trace = concurrentTraces->Get(traceIndex);
|
|
auto& stateDesc = executable.states[trace->state];
|
|
if (trace->returnStack == -1 && stateDesc.endingState)
|
|
{
|
|
AddTrace(trace);
|
|
}
|
|
}
|
|
|
|
EndSwap();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER_INPUT_AMBIGUITY.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
|
|
/***********************************************************************
|
|
AreTwoTraceEqual
|
|
***********************************************************************/
|
|
|
|
bool TraceManager::AreTwoEndingInputTraceEqual(vint32_t state, vint32_t returnStack, vint32_t executedReturnStack, vint32_t acId, Trace* candidate)
|
|
{
|
|
// two traces equal to each other if
|
|
// 1) they are in the same state
|
|
// 2) they have the same executedReturnStack (and therefore the same returnStack)
|
|
// 3) they are attending same competitions
|
|
// 4) the candidate has an ending input
|
|
// TODO: verify if we can do "acId == candidate->runtimeRouting.attendingCompetitions" or not
|
|
|
|
if (state != candidate->state) return false;
|
|
if (acId != candidate->competitionRouting.attendingCompetitions) return false;
|
|
if (candidate->byInput != Executable::EndingInput) return false;
|
|
|
|
if (executedReturnStack != candidate->executedReturnStack) return false;
|
|
if (returnStack != candidate->returnStack) return false;
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************
|
|
GetInstructionPostfix
|
|
***********************************************************************/
|
|
|
|
vint32_t TraceManager::GetInstructionPostfix(EdgeDesc& oldEdge, EdgeDesc& newEdge)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::GetInstructionPostfix(EdgeDesc&, EdgeDesc&)#"
|
|
// given two equal traces, calculate their common instruction postfix length in insBeforeInput
|
|
// EndObject is the last instruction of the prefix
|
|
|
|
// EndObject may not be the first instruction in both edges
|
|
// and instructions before EndObject could be different
|
|
// the most common case is different {field = value} before EndObject
|
|
// if the ambiguity is created by two left recursive clauses which consume the same series of tokens
|
|
|
|
CHECK_ERROR(oldEdge.insAfterInput.count == 0, ERROR_MESSAGE_PREFIX L"EndingInput edge is not allowed to have insAfterInput.");
|
|
CHECK_ERROR(newEdge.insAfterInput.count == 0, ERROR_MESSAGE_PREFIX L"EndingInput edge is not allowed to have insAfterInput.");
|
|
|
|
// find the first EndObject instruction
|
|
vint32_t i1 = -1;
|
|
vint32_t i2 = -1;
|
|
|
|
for (vint32_t insRef = 0; insRef < oldEdge.insBeforeInput.count; insRef++)
|
|
{
|
|
auto&& ins = executable.instructions[oldEdge.insBeforeInput.start + insRef];
|
|
if (ins.type == AstInsType::EndObject)
|
|
{
|
|
i1 = insRef;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (vint32_t insRef = 0; insRef < newEdge.insBeforeInput.count; insRef++)
|
|
{
|
|
auto&& ins = executable.instructions[newEdge.insBeforeInput.start + insRef];
|
|
if (ins.type == AstInsType::EndObject)
|
|
{
|
|
i2 = insRef;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CHECK_ERROR(i1 != -1, ERROR_MESSAGE_PREFIX L"EndObject from oldEdge not found.");
|
|
CHECK_ERROR(i2 != -1, ERROR_MESSAGE_PREFIX L"EndObject from newEdge not found.");
|
|
|
|
// ensure they have the same instruction postfix starting from EndObject
|
|
CHECK_ERROR(oldEdge.insBeforeInput.count - i1 == newEdge.insBeforeInput.count - i2, L"Two instruction postfix after EndObject not equal.");
|
|
|
|
vint32_t postfix = oldEdge.insBeforeInput.count - i1 - 1;
|
|
for (vint32_t postfixRef = 0; postfixRef < postfix; postfixRef++)
|
|
{
|
|
auto&& ins1 = executable.instructions[oldEdge.insBeforeInput.start + i1 + 1 + postfixRef];
|
|
auto&& ins2 = executable.instructions[newEdge.insBeforeInput.start + i2 + 1 + postfixRef];
|
|
CHECK_ERROR(ins1 == ins2, L"Two instruction postfix after EndObject not equal.");
|
|
}
|
|
return postfix;
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
MergeTwoEndingInputTrace
|
|
***********************************************************************/
|
|
|
|
void TraceManager::MergeTwoEndingInputTrace(
|
|
Trace* trace,
|
|
Trace* ambiguityTraceToMerge,
|
|
vint32_t currentTokenIndex,
|
|
vint32_t input,
|
|
vint32_t byEdge,
|
|
EdgeDesc& edgeDesc,
|
|
vint32_t state,
|
|
vint32_t returnStack,
|
|
vint32_t attendingCompetitions,
|
|
vint32_t carriedCompetitions,
|
|
vint32_t executedReturnStack)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::MergeTwoEndingInputTrace(...)#"
|
|
// if ambiguity resolving happens
|
|
// find the instruction postfix
|
|
// the instruction prefix ends at EndObject of a trace
|
|
// and both instruction postfix should equal
|
|
|
|
// old == ambiguityTraceToMerge
|
|
// new == the trace that is being created (could skip)
|
|
auto& oldEdge = executable.edges[ambiguityTraceToMerge->byEdge];
|
|
vint32_t oldInsCount = oldEdge.insBeforeInput.count + oldEdge.insAfterInput.count;
|
|
vint32_t newInsCount = edgeDesc.insBeforeInput.count + edgeDesc.insAfterInput.count;
|
|
vint32_t returnInsCount = 0;
|
|
vint32_t postfix = GetInstructionPostfix(oldEdge, edgeDesc);
|
|
|
|
// if two state can merge
|
|
// then executedReturnStack == ambiguityTraceToMerge.executedReturnStack
|
|
// so two ReturnDesc.insAfterInput.count are identical
|
|
// and also instructions
|
|
if (executedReturnStack != -1)
|
|
{
|
|
auto rs = GetReturnStack(executedReturnStack);
|
|
auto& rd = executable.returns[rs->returnIndex];
|
|
returnInsCount = rd.insAfterInput.count;
|
|
postfix += returnInsCount;
|
|
oldInsCount += returnInsCount;
|
|
newInsCount += returnInsCount;
|
|
}
|
|
|
|
// a trace needs to be cut if EndObject is not its first instruction
|
|
bool needCut = oldInsCount > postfix + 1 || newInsCount > postfix + 1;
|
|
|
|
if (ambiguityTraceToMerge->ambiguityMergeInsPostfix == -1 && needCut)
|
|
{
|
|
// append an extra trace after predecessors of ambiguityTraceToMerge
|
|
Trace* firstFormer = nullptr;
|
|
Trace* lastFormer = nullptr;
|
|
vint32_t predecessorId = ambiguityTraceToMerge->predecessors.first;
|
|
while (predecessorId != -1)
|
|
{
|
|
auto predecessor = GetTrace(predecessorId);
|
|
predecessorId = predecessor->predecessors.siblingNext;
|
|
|
|
auto formerTrace = AllocateTrace();
|
|
{
|
|
vint32_t formerId = formerTrace->allocatedIndex;
|
|
*formerTrace = *ambiguityTraceToMerge;
|
|
formerTrace->allocatedIndex = formerId;
|
|
}
|
|
|
|
// connect predecessor and formerTrace
|
|
formerTrace->predecessors.first = predecessor->allocatedIndex;
|
|
formerTrace->predecessors.last = predecessor->allocatedIndex;
|
|
formerTrace->predecessors.siblingPrev = -1;
|
|
formerTrace->predecessors.siblingNext = -1;
|
|
|
|
// connect ambiguityTraceToMerge and formerTrace
|
|
if (firstFormer == nullptr)
|
|
{
|
|
firstFormer = formerTrace;
|
|
lastFormer = formerTrace;
|
|
}
|
|
else
|
|
{
|
|
lastFormer->predecessors.siblingNext = formerTrace->allocatedIndex;
|
|
formerTrace->predecessors.siblingPrev = lastFormer->allocatedIndex;
|
|
lastFormer = formerTrace;
|
|
}
|
|
|
|
// executedReturnStack is from the EndObject instruction
|
|
// which is available in the instruction postfix
|
|
// so formerTrace->executedReturnStack should be -1 and keep the previous return stack
|
|
formerTrace->executedReturnStack = -1;
|
|
formerTrace->returnStack = predecessor->returnStack;
|
|
|
|
// ambiguity is filled by PrepareTraceRoute, skipped
|
|
// runtimeRouting.holdingCompetition always belong to the second trace
|
|
// runtimeRouting.attendingCompetitions is inherited
|
|
// runtimeRouting.carriedCompetitions is inherited
|
|
formerTrace->competitionRouting = {};
|
|
formerTrace->competitionRouting.attendingCompetitions = ambiguityTraceToMerge->competitionRouting.attendingCompetitions;
|
|
formerTrace->competitionRouting.carriedCompetitions = ambiguityTraceToMerge->competitionRouting.carriedCompetitions;
|
|
|
|
// both traces need to have the same postfix
|
|
// since formerTrace doesn't have executedReturnStack but ambiguityTraceToMerge has
|
|
// the amount of returnInsCount need to cut from the postfix
|
|
formerTrace->ambiguityBranchInsPostfix = postfix - returnInsCount;
|
|
}
|
|
|
|
ambiguityTraceToMerge->ambiguityMergeInsPostfix = postfix;
|
|
ambiguityTraceToMerge->predecessors.first = firstFormer->allocatedIndex;
|
|
ambiguityTraceToMerge->predecessors.last = lastFormer->allocatedIndex;
|
|
}
|
|
|
|
if (needCut)
|
|
{
|
|
// otherwise, create a new trace with the instruction prefix
|
|
auto newTrace = AllocateTrace();
|
|
AddTraceToCollection(newTrace, trace, &Trace::predecessors);
|
|
newTrace->state = state;
|
|
newTrace->returnStack = returnStack;
|
|
newTrace->byEdge = byEdge;
|
|
newTrace->byInput = input;
|
|
newTrace->currentTokenIndex = currentTokenIndex;
|
|
|
|
// executedReturnStack == ambiguityTraceToMerge->executedReturnStack is ensured
|
|
// so no need to assign executedReturnStack to newTrace
|
|
// acid == ambiguityTraceToMerge->runtimeRouting.attendingCompetitions is ensure
|
|
// this is affected by TODO: in TraceManager::AreTwoEndingInputTraceEqual
|
|
// and ambiguityTraceToMerge is supposed to inherit this value
|
|
newTrace->competitionRouting.attendingCompetitions = attendingCompetitions;
|
|
newTrace->competitionRouting.carriedCompetitions = carriedCompetitions;
|
|
|
|
// both traces need to have the same postfix
|
|
// since newTrace doesn't have executedReturnStack but ambiguityTraceToMerge has
|
|
// the amount of returnInsCount need to cut from the postfix
|
|
newTrace->ambiguityBranchInsPostfix = postfix - returnInsCount;
|
|
|
|
AddTraceToCollection(ambiguityTraceToMerge, newTrace, &Trace::predecessors);
|
|
}
|
|
else
|
|
{
|
|
// if EndObject is the first instruction of the new trace
|
|
// then no need to create the new trace
|
|
AddTraceToCollection(ambiguityTraceToMerge, trace, &Trace::predecessors);
|
|
}
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER_INPUT_COMPETITION.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
|
|
/***********************************************************************
|
|
AttendCompetition
|
|
***********************************************************************/
|
|
|
|
void TraceManager::AttendCompetition(Trace* trace, vint32_t& newAttendingCompetitions, vint32_t& newCarriedCompetitions, vint32_t returnStack, vint32_t ruleId, vint32_t clauseId, bool forHighPriority)
|
|
{
|
|
// a competition is defined by its rule, clause and the owner trace
|
|
// but we don't need to compare the trace
|
|
// since only transitions starting from that trace will search competitions in that trace
|
|
// we only create a new Competition object if it has not been created for the trace yet
|
|
Competition* competition = nullptr;
|
|
{
|
|
vint32_t cid = trace->competitionRouting.holdingCompetitions;
|
|
while (cid != -1)
|
|
{
|
|
auto cpt = GetCompetition(cid);
|
|
if (cpt->ruleId == ruleId && cpt->clauseId == clauseId)
|
|
{
|
|
competition = cpt;
|
|
break;
|
|
}
|
|
cid = cpt->nextHoldCompetition;
|
|
}
|
|
}
|
|
|
|
if (!competition)
|
|
{
|
|
// create a Competition object
|
|
competition = AllocateCompetition();
|
|
competition->nextHoldCompetition = trace->competitionRouting.holdingCompetitions;
|
|
trace->competitionRouting.holdingCompetitions = competition->allocatedIndex;
|
|
|
|
competition->currentTokenIndex = trace->currentTokenIndex;
|
|
competition->ruleId = ruleId;
|
|
competition->clauseId = clauseId;
|
|
|
|
competition->nextActiveCompetition = activeCompetitions;
|
|
activeCompetitions = competition->allocatedIndex;
|
|
}
|
|
|
|
// target traces from the current trace could attend different competitions
|
|
// but they also inherit all attending competitions from the current trace
|
|
// it is fine for different traces share all or part of AttendingCompetitions in their RuntimeRouting::attendingCompetitions linked list
|
|
// because if a competition is settled in the future
|
|
// AttendingCompetitions objects for this competition is going to be removed anyway
|
|
// sharing a linked list doesn't change the result
|
|
|
|
auto ac = AllocateAttendingCompetitions();
|
|
ac->competition = competition->allocatedIndex;
|
|
ac->forHighPriority = forHighPriority;
|
|
ac->returnStack = returnStack;
|
|
|
|
ac->nextActiveAC = newAttendingCompetitions;
|
|
newAttendingCompetitions = ac->allocatedIndex;
|
|
|
|
ac->nextCarriedAC = newCarriedCompetitions;
|
|
newCarriedCompetitions = ac->allocatedIndex;
|
|
}
|
|
|
|
/***********************************************************************
|
|
AttendCompetitionIfNecessary
|
|
***********************************************************************/
|
|
|
|
ReturnStack* TraceManager::PushReturnStack(vint32_t base, vint32_t returnIndex, vint32_t currentTokenIndex)
|
|
{
|
|
auto siblings = base == -1 ? &initialReturnStackSuccessors : &GetReturnStack(base)->successors;
|
|
|
|
if (siblings->successorTokenIndex == -1 && currentTokenIndex - siblings->createdTokenIndex <= 1)
|
|
{
|
|
siblings->successorTokenIndex = currentTokenIndex;
|
|
}
|
|
|
|
if (siblings->successorTokenIndex == currentTokenIndex)
|
|
{
|
|
vint32_t successorId = siblings->first;
|
|
while (successorId != -1)
|
|
{
|
|
auto successor = GetReturnStack(successorId);
|
|
successorId = successor->successors.next;
|
|
|
|
if (successor->returnIndex == returnIndex)
|
|
{
|
|
return successor;
|
|
}
|
|
}
|
|
}
|
|
|
|
auto returnStack = AllocateReturnStack();
|
|
returnStack->previous = base;
|
|
returnStack->returnIndex = returnIndex;
|
|
returnStack->successors.createdTokenIndex = currentTokenIndex;
|
|
|
|
if (siblings->successorTokenIndex == currentTokenIndex)
|
|
{
|
|
if (siblings->first == -1)
|
|
{
|
|
siblings->first = returnStack->allocatedIndex;
|
|
siblings->last = returnStack->allocatedIndex;
|
|
}
|
|
else
|
|
{
|
|
GetReturnStack(siblings->last)->successors.next = returnStack->allocatedIndex;
|
|
returnStack->successors.prev = siblings->last;
|
|
siblings->last = returnStack->allocatedIndex;
|
|
}
|
|
}
|
|
return returnStack;
|
|
}
|
|
|
|
/***********************************************************************
|
|
AttendCompetitionIfNecessary
|
|
***********************************************************************/
|
|
|
|
void TraceManager::AttendCompetitionIfNecessary(Trace* trace, vint32_t currentTokenIndex, EdgeDesc& edgeDesc, vint32_t& newAttendingCompetitions, vint32_t& newCarriedCompetitions, vint32_t& newReturnStack)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::AttendCompetitionIfNecessary(Trace*, EdgeDesc&, vint32_t&, vint32_t&)#"
|
|
newAttendingCompetitions = trace->competitionRouting.attendingCompetitions;
|
|
newCarriedCompetitions = trace->competitionRouting.carriedCompetitions;
|
|
newReturnStack = trace->returnStack;
|
|
|
|
// visit each compact transition in order
|
|
// 1) returns + token
|
|
// 2) ending
|
|
// 3) leftrec
|
|
// find out if any of them attends a competition
|
|
|
|
vint32_t edgeFromState = edgeDesc.fromState;
|
|
for (vint32_t returnRef = 0; returnRef < edgeDesc.returnIndices.count; returnRef++)
|
|
{
|
|
auto returnIndex = executable.returnIndices[edgeDesc.returnIndices.start + returnRef];
|
|
auto&& returnDesc = executable.returns[returnIndex];
|
|
|
|
if (returnDesc.priority != EdgePriority::NoCompetition)
|
|
{
|
|
// attend a competition from a ReturnDesc edge
|
|
// find out the rule id and the clause id for this competition
|
|
// a ReturnDesc is a compact transition which consumes a rule
|
|
// so it does not points to the ending state
|
|
// therefore we just need the toState of this ReturnDesc for reference
|
|
auto&& stateForClause = executable.states[returnDesc.returnState];
|
|
vint32_t competitionRule = stateForClause.rule;
|
|
vint32_t competitionClause = stateForClause.clause;
|
|
CHECK_ERROR(competitionRule != -1 && competitionClause != -1, ERROR_MESSAGE_PREFIX L"Illegal rule or clause id.");
|
|
AttendCompetition(trace, newAttendingCompetitions, newCarriedCompetitions, newReturnStack, competitionRule, competitionClause, returnDesc.priority == EdgePriority::HighPriority);
|
|
}
|
|
|
|
// push this ReturnDesc to the ReturnStack
|
|
newReturnStack = PushReturnStack(newReturnStack, returnIndex, currentTokenIndex)->allocatedIndex;
|
|
edgeFromState = executable.ruleStartStates[returnDesc.consumedRule];
|
|
}
|
|
|
|
if (edgeDesc.priority != EdgePriority::NoCompetition)
|
|
{
|
|
// attend a competition from a EdgeDesc edge
|
|
// find out the rule id and the clause id for this competition
|
|
auto&& fromState = executable.states[edgeFromState];
|
|
auto&& toState = executable.states[edgeDesc.toState];
|
|
vint32_t competitionRule = toState.rule;
|
|
vint32_t competitionClause = toState.clause;
|
|
if (toState.endingState)
|
|
{
|
|
competitionRule = fromState.rule;
|
|
competitionClause = fromState.clause;
|
|
}
|
|
CHECK_ERROR(competitionRule != -1 && competitionClause != -1, ERROR_MESSAGE_PREFIX L"Illegal rule or clause id.");
|
|
AttendCompetition(trace, newAttendingCompetitions, newCarriedCompetitions, newReturnStack, competitionRule, competitionClause, edgeDesc.priority == EdgePriority::HighPriority);
|
|
}
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
CheckAttendingCompetitionsOnEndingEdge
|
|
***********************************************************************/
|
|
|
|
void TraceManager::CheckAttendingCompetitionsOnEndingEdge(Trace* trace, EdgeDesc& edgeDesc, vint32_t acId, vint32_t returnStack)
|
|
{
|
|
while (acId != -1)
|
|
{
|
|
// when executing an EndingInput transition, we announce high priority win a competition if
|
|
// 1) such EndingInput transitions ends the clause, and the state of the trace holding competition belongs to the same clause
|
|
// we ensure this by comparing rule id, clause id in Competition
|
|
// and compare ReturnStack object (not content) in AttendingCompetitions
|
|
// the reason returnStack is not in Competition is that
|
|
// different transitions always create new ReturnStack objects
|
|
// 2) this trace bets high
|
|
// 3) the competition has not been settled
|
|
auto ac = GetAttendingCompetitions(acId);
|
|
if (ac->returnStack == returnStack)
|
|
{
|
|
auto cpt = GetCompetition(ac->competition);
|
|
// ensure that this EndingInput edge and the competition belong to the same clause
|
|
auto&& stateDesc = executable.states[edgeDesc.fromState];
|
|
if (cpt->ruleId == stateDesc.rule && cpt->clauseId == stateDesc.clause)
|
|
{
|
|
// check if it is a high bet
|
|
if (ac->forHighPriority && cpt->status == CompetitionStatus::Holding)
|
|
{
|
|
cpt->status = CompetitionStatus::HighPriorityWin;
|
|
}
|
|
}
|
|
}
|
|
acId = ac->nextActiveAC;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
CheckBackupTracesBeforeSwapping
|
|
***********************************************************************/
|
|
|
|
void TraceManager::CheckBackupTracesBeforeSwapping(vint32_t currentTokenIndex)
|
|
{
|
|
// try to find if any competition could be settled at this moment
|
|
|
|
{
|
|
// reset highCounter and lowCounter for any active competitions
|
|
auto cId = activeCompetitions;
|
|
while (cId != -1)
|
|
{
|
|
auto cpt = GetCompetition(cId);
|
|
cpt->highCounter = 0;
|
|
cpt->lowCounter = 0;
|
|
cId = cpt->nextActiveCompetition;
|
|
}
|
|
}
|
|
|
|
// for any surviving traces
|
|
// add itself to the appriopriate counter for all attending competitions
|
|
for (vint i = 0; i < concurrentCount; i++)
|
|
{
|
|
auto trace = backupTraces->Get(i);
|
|
auto acId = trace->competitionRouting.attendingCompetitions;
|
|
while (acId != -1)
|
|
{
|
|
auto ac = GetAttendingCompetitions(acId);
|
|
auto cpt = GetCompetition(ac->competition);
|
|
(ac->forHighPriority ? cpt->highCounter : cpt->lowCounter)++;
|
|
acId = ac->nextActiveAC;
|
|
}
|
|
}
|
|
|
|
// revisit all active competitions
|
|
// some competitions could have been settled
|
|
// but settled competitions will only be removed before consuming the next token
|
|
{
|
|
auto cId = activeCompetitions;
|
|
while (cId != -1)
|
|
{
|
|
auto cpt = GetCompetition(cId);
|
|
if (cpt->status == CompetitionStatus::Holding)
|
|
{
|
|
if (cpt->highCounter > 0 && cpt->lowCounter == 0)
|
|
{
|
|
// if only high bet traces survive, high priority win
|
|
cpt->status = CompetitionStatus::HighPriorityWin;
|
|
}
|
|
else if (cpt->highCounter == 0 && cpt->lowCounter > 0)
|
|
{
|
|
// if only low bet traces survive
|
|
// low priority win after at least one token is consumed from when the competition is created
|
|
// low priority epsilon transitions could have been visited right after a competition is created
|
|
// but high priority token transitions could only be visited when consuming the next token
|
|
// if all high priority transitions are token transitions
|
|
// and all low priority transitions are epsilon transitions
|
|
// closing the competition too early will direct to a wrong result
|
|
// so we need to wait at least one step to see if any trace will visit the high priority transition in the future
|
|
if (cpt->currentTokenIndex != currentTokenIndex)
|
|
{
|
|
cpt->status = CompetitionStatus::LowPriorityWin;
|
|
}
|
|
}
|
|
}
|
|
cId = cpt->nextActiveCompetition;
|
|
}
|
|
}
|
|
|
|
// for any surviving traces
|
|
// if it loses any one of its attending competitions
|
|
// this trace will be removed
|
|
for (vint i = concurrentCount - 1; i >= 0; i--)
|
|
{
|
|
auto trace = backupTraces->Get(i);
|
|
auto acId = trace->competitionRouting.attendingCompetitions;
|
|
while (acId != -1)
|
|
{
|
|
auto ac = GetAttendingCompetitions(acId);
|
|
auto cpt = GetCompetition(ac->competition);
|
|
if (cpt->status != CompetitionStatus::Holding)
|
|
{
|
|
ac->closed = true;
|
|
if (ac->forHighPriority != (cpt->status == CompetitionStatus::HighPriorityWin))
|
|
{
|
|
concurrentCount--;
|
|
backupTraces->RemoveAt(i);
|
|
goto TRACE_REMOVED;
|
|
}
|
|
}
|
|
acId = ac->nextActiveAC;
|
|
}
|
|
TRACE_REMOVED:;
|
|
}
|
|
|
|
// remove all settled competition from the active competitions linked list
|
|
{
|
|
vint32_t* pnext = &activeCompetitions;
|
|
while (*pnext != -1)
|
|
{
|
|
auto cpt = GetCompetition(*pnext);
|
|
if (cpt->status != CompetitionStatus::Holding || (cpt->highCounter == 0 && cpt->lowCounter == 0))
|
|
{
|
|
*pnext = cpt->nextActiveCompetition;
|
|
}
|
|
else
|
|
{
|
|
pnext = &cpt->nextActiveCompetition;
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove all settled AttendingCompetitions object from linked lists of any surviving trace
|
|
for (vint i = 0; i < concurrentCount; i++)
|
|
{
|
|
auto trace = backupTraces->Get(i);
|
|
vint32_t* pnext = &trace->competitionRouting.attendingCompetitions;
|
|
while (*pnext != -1)
|
|
{
|
|
auto ac = GetAttendingCompetitions(*pnext);
|
|
if (ac->closed)
|
|
{
|
|
*pnext = ac->nextActiveAC;
|
|
}
|
|
else
|
|
{
|
|
pnext = &ac->nextActiveAC;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER_INPUT_WALK.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
|
|
/***********************************************************************
|
|
TraceManager::WalkAlongSingleEdge
|
|
***********************************************************************/
|
|
|
|
Trace* TraceManager::WalkAlongSingleEdge(
|
|
vint32_t currentTokenIndex,
|
|
vint32_t input,
|
|
Trace* trace,
|
|
vint32_t byEdge,
|
|
EdgeDesc& edgeDesc
|
|
)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::WalkAlongSingleEdge(vint, vint, vint, Trace*, vint, EdgeDesc&)#"
|
|
vint32_t state = edgeDesc.toState;
|
|
vint32_t returnStack = -1;
|
|
vint32_t attendingCompetitions = -1;
|
|
vint32_t carriedCompetitions = -1;
|
|
vint32_t executedReturnStack = -1;
|
|
Trace* ambiguityTraceToMerge = nullptr;
|
|
|
|
// attend a competition hold by the current trace if the priority is set for this output transition
|
|
AttendCompetitionIfNecessary(trace, currentTokenIndex, edgeDesc, attendingCompetitions, carriedCompetitions, returnStack);
|
|
|
|
if (input == Executable::EndingInput)
|
|
{
|
|
// an EndingInput transition consume return record in the return stack
|
|
// such return will be popped from the return stack and stored in Trace::executedReturnStack
|
|
CHECK_ERROR(edgeDesc.returnIndices.count == 0, ERROR_MESSAGE_PREFIX L"Ending input edge is not allowed to push something into the return stack.");
|
|
if (returnStack != -1)
|
|
{
|
|
executedReturnStack = returnStack;
|
|
auto rs = GetReturnStack(returnStack);
|
|
returnStack = rs->previous;
|
|
state = executable.returns[rs->returnIndex].returnState;
|
|
}
|
|
|
|
// an EndingInput transition also settle a competition if
|
|
// 1) there is a competition
|
|
// 2) the returnStack of the trace holding the competition is the same to the current returnStack
|
|
// 3) the target trace bets high priority
|
|
// in this case, high priority traces wins the competition
|
|
// but no traces are being removed for now, just mark the competition
|
|
CheckAttendingCompetitionsOnEndingEdge(trace, edgeDesc, attendingCompetitions, trace->returnStack);
|
|
|
|
// if the target trace has exactly the same to another surviving trace
|
|
// stop creating a Trace instance for the target trace
|
|
// instead connect the correct trace to that surviving trace and form a ambiguity resolving structure
|
|
for (vint i = 0; i < concurrentCount; i++)
|
|
{
|
|
auto candidate = backupTraces->Get(i);
|
|
if (AreTwoEndingInputTraceEqual(state, returnStack, executedReturnStack, attendingCompetitions, candidate))
|
|
{
|
|
ambiguityTraceToMerge = candidate;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ambiguityTraceToMerge)
|
|
{
|
|
MergeTwoEndingInputTrace(
|
|
trace,
|
|
ambiguityTraceToMerge,
|
|
currentTokenIndex,
|
|
input,
|
|
byEdge,
|
|
edgeDesc,
|
|
state,
|
|
returnStack,
|
|
attendingCompetitions,
|
|
carriedCompetitions,
|
|
executedReturnStack);
|
|
|
|
// return nullptr so that there is no WalkAlongEpsilonEdges following WalkAlongSingleEdge
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
// if ambiguity resolving doesn't happen
|
|
// create an instance of the target trace
|
|
// and connect the current trace to this target trace
|
|
auto newTrace = AllocateTrace();
|
|
AddTrace(newTrace);
|
|
AddTraceToCollection(newTrace, trace, &Trace::predecessors);
|
|
newTrace->state = state;
|
|
newTrace->returnStack = returnStack;
|
|
newTrace->executedReturnStack = executedReturnStack;
|
|
newTrace->byEdge = byEdge;
|
|
newTrace->byInput = input;
|
|
newTrace->currentTokenIndex = currentTokenIndex;
|
|
newTrace->competitionRouting.attendingCompetitions = attendingCompetitions;
|
|
newTrace->competitionRouting.carriedCompetitions = carriedCompetitions;
|
|
|
|
return newTrace;
|
|
}
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
TraceManager::WalkAlongEpsilonEdges
|
|
***********************************************************************/
|
|
|
|
void TraceManager::WalkAlongLeftrecEdges(
|
|
vint32_t currentTokenIndex,
|
|
vint32_t lookAhead,
|
|
Trace* trace,
|
|
EdgeArray& edgeArray
|
|
)
|
|
{
|
|
// if there is no more token
|
|
// then it is not possible for more left recursions
|
|
if (lookAhead == -1) return;
|
|
|
|
for (vint32_t edgeRef = 0; edgeRef < edgeArray.count; edgeRef++)
|
|
{
|
|
vint32_t byEdge = edgeArray.start + edgeRef;
|
|
auto& edgeDesc = executable.edges[byEdge];
|
|
|
|
// see if the target state could consume that token
|
|
vint32_t lookAheadTransitionIndex = executable.GetTransitionIndex(edgeDesc.toState, Executable::TokenBegin + lookAhead);
|
|
auto& lookAheadEdgeArray = executable.transitions[lookAheadTransitionIndex];
|
|
if (lookAheadEdgeArray.count == 0) continue;
|
|
|
|
// proceed only if it can
|
|
WalkAlongSingleEdge(currentTokenIndex, Executable::LeftrecInput, trace, byEdge, edgeDesc);
|
|
|
|
// A LeftrecInput transition points to a non ending state in another clause
|
|
// so there is no need to find other epsilon transitions after LeftrecInput
|
|
}
|
|
}
|
|
|
|
void TraceManager::WalkAlongEpsilonEdges(
|
|
vint32_t currentTokenIndex,
|
|
vint32_t lookAhead,
|
|
Trace* trace
|
|
)
|
|
{
|
|
// if we could walk along multiple EndingInput transition
|
|
// but the last several transition will fail
|
|
// then creating them is wasting the performance
|
|
// so we count how many EndingInput transition we could walk along first
|
|
|
|
vint32_t endingCount = -1;
|
|
|
|
if (lookAhead == -1)
|
|
{
|
|
// if there is no more tokens
|
|
// then we have to go all the way to the end anyway
|
|
vint32_t currentState = trace->state;
|
|
vint32_t currentReturnStack = trace->returnStack;
|
|
|
|
while (currentState != -1)
|
|
{
|
|
vint32_t transitionIndex = executable.GetTransitionIndex(currentState, Executable::EndingInput);
|
|
auto&& edgeArray = executable.transitions[transitionIndex];
|
|
|
|
// at most one EndingInput transition could exist from any state
|
|
CHECK_ERROR(edgeArray.count < 2, L"vl::glr::automaton::TraceManager::WalkAlongEpsilonEdges(vint32_t, vint32_t, Trace*)#Too many EndingInput transitions.");
|
|
|
|
if (edgeArray.count == 0)
|
|
{
|
|
// if there is no more EndingInput to go
|
|
// and the current state is not an ending state
|
|
// then we just give up
|
|
|
|
auto&& stateDesc = executable.states[currentState];
|
|
if (stateDesc.endingState)
|
|
{
|
|
currentState = -1;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if (currentReturnStack == -1)
|
|
{
|
|
vint32_t byEdge = edgeArray.start;
|
|
auto& edgeDesc = executable.edges[byEdge];
|
|
currentState = edgeDesc.toState;
|
|
}
|
|
else
|
|
{
|
|
auto rs = GetReturnStack(currentReturnStack);
|
|
currentReturnStack = rs->previous;
|
|
currentState = executable.returns[rs->returnIndex].returnState;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// otherwise we see how many EndingInput transition we need to walk along
|
|
vint32_t currentCount = 0;
|
|
vint32_t currentState = trace->state;
|
|
vint32_t currentReturnStack = trace->returnStack;
|
|
|
|
while (currentState != -1)
|
|
{
|
|
currentCount++;
|
|
|
|
// try LeftrecInput + lookAhead
|
|
{
|
|
vint32_t transitionIndex = executable.GetTransitionIndex(currentState, Executable::LeftrecInput);
|
|
auto&& edgeArray = executable.transitions[transitionIndex];
|
|
for (vint32_t edgeRef = 0; edgeRef < edgeArray.count; edgeRef++)
|
|
{
|
|
vint32_t byEdge = edgeArray.start + edgeRef;
|
|
auto& edgeDesc = executable.edges[byEdge];
|
|
vint32_t lookAheadTransitionIndex = executable.GetTransitionIndex(edgeDesc.toState, Executable::TokenBegin + lookAhead);
|
|
auto& lookAheadEdgeArray = executable.transitions[lookAheadTransitionIndex];
|
|
|
|
// mark this EndingInput if any LeftrecInput + lookAhead transition exists
|
|
if (lookAheadEdgeArray.count > 0)
|
|
{
|
|
endingCount = currentCount;
|
|
goto TRY_ENDING_INPUT;
|
|
}
|
|
}
|
|
}
|
|
|
|
// try lookAhead
|
|
{
|
|
vint32_t transitionIndex = executable.GetTransitionIndex(currentState, Executable::TokenBegin + lookAhead);
|
|
auto&& edgeArray = executable.transitions[transitionIndex];
|
|
|
|
// mark this EndingInput if lookAhead transition exists
|
|
if (edgeArray.count > 0)
|
|
{
|
|
endingCount = currentCount;
|
|
}
|
|
}
|
|
|
|
// try EndingInput
|
|
TRY_ENDING_INPUT:
|
|
{
|
|
vint32_t transitionIndex = executable.GetTransitionIndex(currentState, Executable::EndingInput);
|
|
auto&& edgeArray = executable.transitions[transitionIndex];
|
|
|
|
// at most one EndingInput transition could exist from any state
|
|
CHECK_ERROR(edgeArray.count < 2, L"vl::glr::automaton::TraceManager::WalkAlongEpsilonEdges(vint32_t, vint32_t, Trace*)#Too many EndingInput transitions.");
|
|
|
|
if (edgeArray.count == 0 || currentReturnStack == -1)
|
|
{
|
|
// currentReturnStack == -1 means this is the last possible EndingInput
|
|
// no need to test forward
|
|
// because if the current EndingInput is doable
|
|
// it would have already been marked
|
|
currentState = -1;
|
|
}
|
|
else
|
|
{
|
|
auto rs = GetReturnStack(currentReturnStack);
|
|
currentReturnStack = rs->previous;
|
|
currentState = executable.returns[rs->returnIndex].returnState;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (vint32_t i = 0; trace && (i < endingCount || endingCount == -1); i++)
|
|
{
|
|
{
|
|
// LeftrecInput transition is an epsilon transition
|
|
vint32_t transitionIndex = executable.GetTransitionIndex(trace->state, Executable::LeftrecInput);
|
|
auto&& edgeArray = executable.transitions[transitionIndex];
|
|
WalkAlongLeftrecEdges(currentTokenIndex, lookAhead, trace, edgeArray);
|
|
}
|
|
|
|
// EndingInput transition is an epsilon transition
|
|
vint32_t transitionIndex = executable.GetTransitionIndex(trace->state, Executable::EndingInput);
|
|
auto&& edgeArray = executable.transitions[transitionIndex];
|
|
|
|
// it has been ensured that edgeArray.count < 2
|
|
if (edgeArray.count == 0)
|
|
{
|
|
trace = nullptr;
|
|
}
|
|
else
|
|
{
|
|
vint32_t byEdge = edgeArray.start;
|
|
auto& edgeDesc = executable.edges[byEdge];
|
|
trace = WalkAlongSingleEdge(currentTokenIndex, Executable::EndingInput, trace, byEdge, edgeDesc);
|
|
|
|
// EndingInput could be followed by EndingInput or LeftrecInput
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
TraceManager::WalkAlongTokenEdges
|
|
***********************************************************************/
|
|
|
|
void TraceManager::WalkAlongTokenEdges(
|
|
vint32_t currentTokenIndex,
|
|
vint32_t input,
|
|
vint32_t lookAhead,
|
|
Trace* trace,
|
|
EdgeArray& edgeArray
|
|
)
|
|
{
|
|
// find all transitions that has the expected input
|
|
// there could be multiple transitions with the same input
|
|
// but with different instructions and destinations
|
|
for (vint32_t edgeRef = 0; edgeRef < edgeArray.count; edgeRef++)
|
|
{
|
|
vint32_t byEdge = edgeArray.start + edgeRef;
|
|
auto& edgeDesc = executable.edges[edgeArray.start + edgeRef];
|
|
if (auto newTrace = WalkAlongSingleEdge(currentTokenIndex, input, trace, byEdge, edgeDesc))
|
|
{
|
|
// continue with as much EndingInput and LeftrecInput transitions as possible
|
|
// TokenInput could be followed by EndingInput or LeftrecInput
|
|
WalkAlongEpsilonEdges(currentTokenIndex, lookAhead, newTrace);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER_PREPARETRACEROUTE.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
using namespace collections;
|
|
|
|
/***********************************************************************
|
|
ReadInstructionList
|
|
***********************************************************************/
|
|
|
|
void TraceManager::ReadInstructionList(Trace* trace, TraceInsLists& insLists)
|
|
{
|
|
// this function collects the following instructions in order:
|
|
// 1) byEdge.insBeforeInput
|
|
// 2) byEdge.insAfterInput
|
|
// 3) executedReturnStack.returnIndex.insAfterInput in order
|
|
if (trace->byEdge != -1)
|
|
{
|
|
auto& edgeDesc = executable.edges[trace->byEdge];
|
|
insLists.edgeInsBeforeInput = edgeDesc.insBeforeInput;
|
|
insLists.edgeInsAfterInput = edgeDesc.insAfterInput;
|
|
}
|
|
else
|
|
{
|
|
insLists.edgeInsBeforeInput = {};
|
|
insLists.edgeInsAfterInput = {};
|
|
}
|
|
if (trace->executedReturnStack != -1)
|
|
{
|
|
auto returnStack = GetReturnStack(trace->executedReturnStack);
|
|
auto& returnDesc = executable.returns[returnStack->returnIndex];
|
|
insLists.returnInsAfterInput = returnDesc.insAfterInput;
|
|
}
|
|
else
|
|
{
|
|
insLists.returnInsAfterInput = {};
|
|
}
|
|
|
|
insLists.c1 = (vint32_t)(insLists.edgeInsBeforeInput.count);
|
|
insLists.c2 = (vint32_t)(insLists.c1 + insLists.edgeInsAfterInput.count);
|
|
insLists.c3 = (vint32_t)(insLists.c2 + insLists.returnInsAfterInput.count);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ReadInstruction
|
|
***********************************************************************/
|
|
|
|
AstIns& TraceManager::ReadInstruction(vint32_t instruction, TraceInsLists& insLists)
|
|
{
|
|
// access the instruction object from a trace
|
|
// the index is the instruction in a virtual instruction array
|
|
// defined by all InstructionArray in TraceInsLists combined together
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::ReadInstruction(vint, TraceInsLists&)#"
|
|
CHECK_ERROR(0 <= instruction && instruction <= insLists.c3, ERROR_MESSAGE_PREFIX L"Instruction index out of range.");
|
|
|
|
vint insRef = -1;
|
|
if (instruction < insLists.c1)
|
|
{
|
|
insRef = insLists.edgeInsBeforeInput.start + instruction;
|
|
}
|
|
else if (instruction < insLists.c2)
|
|
{
|
|
insRef = insLists.edgeInsAfterInput.start + (instruction - insLists.c1);
|
|
}
|
|
else if (instruction < insLists.c3)
|
|
{
|
|
insRef = insLists.returnInsAfterInput.start + (instruction - insLists.c2);
|
|
}
|
|
else
|
|
{
|
|
CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Instruction index out of range.");
|
|
}
|
|
|
|
return executable.instructions[insRef];
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
RunInstruction
|
|
***********************************************************************/
|
|
|
|
bool TraceManager::RunInstruction(vint32_t instruction, TraceInsLists& insLists, vint32_t& objectCount, vint32_t& reopenCount)
|
|
{
|
|
// run an instruction to simulate the number of extra constructing AST objects in the stack
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::SearchSingleTraceForBeginObject(Trace*&, vint&, vint&)#"
|
|
auto& ins = ReadInstruction(instruction, insLists);
|
|
switch (ins.type)
|
|
{
|
|
case AstInsType::EndObject:
|
|
objectCount++;
|
|
break;
|
|
case AstInsType::ReopenObject:
|
|
case AstInsType::BeginObject:
|
|
case AstInsType::BeginObjectLeftRecursive:
|
|
CHECK_ERROR(objectCount > 0, ERROR_MESSAGE_PREFIX L"Encountered unbalanced instructions.");
|
|
objectCount--;
|
|
break;
|
|
default:;
|
|
}
|
|
|
|
switch (ins.type)
|
|
{
|
|
case AstInsType::ReopenObject:
|
|
reopenCount++;
|
|
break;
|
|
case AstInsType::DelayFieldAssignment:
|
|
reopenCount--;
|
|
break;
|
|
default:;
|
|
}
|
|
|
|
// if we found a ReopenObject
|
|
// we should continue to search until we reach BeginObject or BeginObjectLeftRecursive
|
|
return objectCount == 0 && (ins.type == AstInsType::BeginObject || ins.type == AstInsType::BeginObjectLeftRecursive);
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
AdjustToRealTrace
|
|
***********************************************************************/
|
|
|
|
void TraceManager::AdjustToRealTrace(SharedBeginObject& shared)
|
|
{
|
|
TraceInsLists insLists;
|
|
ReadInstructionList(shared.traceBeginObject, insLists);
|
|
if (shared.insBeginObject >= insLists.c3)
|
|
{
|
|
shared.traceBeginObject = GetTrace(shared.traceBeginObject->successors.first);
|
|
shared.insBeginObject -= insLists.c3;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
FindBalancedBoOrBolr
|
|
***********************************************************************/
|
|
|
|
void TraceManager::FindBalancedBoOrBolr(SharedBeginObject& balanced, vint32_t& objectCount, vint32_t& reopenCount)
|
|
{
|
|
// given the current instruction and the current constructing AST objects
|
|
// find the nearlest BeginObject or BeginObjectLeftRecursive before the current instruction
|
|
// that creates the bottom object
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::FindBalancedBoOrBolr(Trace*&, vint&, vint&)#"
|
|
TraceInsLists insLists;
|
|
ReadInstructionList(balanced.traceBeginObject, insLists);
|
|
|
|
while (true)
|
|
{
|
|
if (balanced.traceBeginObject->predecessors.first != balanced.traceBeginObject->predecessors.last)
|
|
{
|
|
// if there are multiple predecessors
|
|
// then this is a ambiguity resolving trace
|
|
auto ambiguityBegin = FillAmbiguityInfoForMergingTrace(balanced.traceBeginObject);
|
|
|
|
// execute all instructions until it reaches the first EndObject instruction
|
|
// and this EndObject instruction is not executed
|
|
for (auto i = balanced.insBeginObject; i > balanced.traceBeginObject->ambiguity.insEndObject; i--)
|
|
{
|
|
if (RunInstruction(i, insLists, objectCount, reopenCount))
|
|
{
|
|
balanced.insBeginObject = i;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// since the BeginObject instruction for this EndObject instruction will be executed after calling FillAmbiguityInfoForMergingTrace
|
|
// must jump to the instruction before that BeginObject instruction
|
|
|
|
balanced = ambiguityBegin;
|
|
if (objectCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
AdjustToRealTrace(balanced);
|
|
balanced.insBeginObject--;
|
|
ReadInstructionList(balanced.traceBeginObject, insLists);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if there is only one predecessor
|
|
// run all instructions until we find the correct BeginObject or BeginObjectLeftRecursive instruction
|
|
|
|
vint32_t minIns = 0;
|
|
vint32_t maxIns = insLists.c3;
|
|
if (balanced.traceBeginObject->ambiguityMergeInsPostfix != -1)
|
|
{
|
|
minIns = insLists.c3 - balanced.traceBeginObject->ambiguityMergeInsPostfix;
|
|
}
|
|
if (balanced.traceBeginObject->ambiguityBranchInsPostfix != -1)
|
|
{
|
|
maxIns = insLists.c3 - balanced.traceBeginObject->ambiguityBranchInsPostfix - 1;
|
|
}
|
|
if (balanced.insBeginObject > maxIns)
|
|
{
|
|
balanced.insBeginObject = maxIns;
|
|
}
|
|
|
|
for (auto i = balanced.insBeginObject; i >= minIns; i--)
|
|
{
|
|
if (RunInstruction(i, insLists, objectCount, reopenCount))
|
|
{
|
|
balanced.insBeginObject = i;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if not found, then we continue searching in the predecessor trace
|
|
CHECK_ERROR(balanced.traceBeginObject->predecessors.first != -1, ERROR_MESSAGE_PREFIX L"Encountered unbalanced instructions.");
|
|
|
|
balanced.traceBeginObject = GetTrace(balanced.traceBeginObject->predecessors.first);
|
|
ReadInstructionList(balanced.traceBeginObject, insLists);
|
|
balanced.insBeginObject = insLists.c3 - 1;
|
|
}
|
|
}
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
FindBalancedBoOrDfa
|
|
***********************************************************************/
|
|
|
|
void TraceManager::FindBalancedBoOrDfa(Trace* trace, vint32_t objectCount, SharedBeginObject& branch)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::FindBalancedBoOrDfa(Trace*, vint32_t, Trace*&, vint32_t&, vint32_t&)#"
|
|
// find the first balanced BeginObject or BeginObjectLeftRecursive
|
|
TraceInsLists branchInsLists;
|
|
ReadInstructionList(trace, branchInsLists);
|
|
branch.traceBeginObject = trace;
|
|
branch.insBeginObject = branchInsLists.c3 - 1;
|
|
vint32_t branchObjectCount = objectCount;
|
|
vint32_t branchReopenCount = 0;
|
|
FindBalancedBoOrBolr(branch, branchObjectCount, branchReopenCount);
|
|
|
|
// no matter if we found BeginObject or BeginObjectLeftRecursive
|
|
// we now know what type of the AST we need to resolve
|
|
AdjustToRealTrace(branch);
|
|
ReadInstructionList(branch.traceBeginObject, branchInsLists);
|
|
auto ins = ReadInstruction(branch.insBeginObject, branchInsLists);
|
|
branch.type = ins.param;
|
|
|
|
// if we found a BeginObjectLeftRecursive which creates the bottom object in stack
|
|
// then we should continue until we reach the BeginObject
|
|
// because such BeginObject creates objects that eventually become part of BeginObjectLeftRecursive created objects
|
|
// we cannot allow sharing the same child AST object in different parent AST objects.
|
|
while (ins.type == AstInsType::BeginObjectLeftRecursive)
|
|
{
|
|
branch.insBeginObject--;
|
|
FindBalancedBoOrBolr(branch, branchObjectCount, branchReopenCount);
|
|
AdjustToRealTrace(branch);
|
|
ReadInstructionList(branch.traceBeginObject, branchInsLists);
|
|
ins = ReadInstruction(branch.insBeginObject, branchInsLists);
|
|
}
|
|
|
|
// if branchReopenCount > 0
|
|
// it means there must be this amount of DelayFieldAssignment instruction before BeginOpen
|
|
// the first DelayFieldAssignment must be located
|
|
if (branchReopenCount > 0)
|
|
{
|
|
ReadInstructionList(branch.traceBeginObject, branchInsLists);
|
|
while (true)
|
|
{
|
|
branch.insBeginObject--;
|
|
if (branch.insBeginObject == -1)
|
|
{
|
|
// a merging trace must at least have one EndObject before the balanced BeginObject
|
|
// so it is not possible to see it here
|
|
|
|
CHECK_ERROR(
|
|
branch.traceBeginObject->predecessors.first == branch.traceBeginObject->predecessors.last,
|
|
ERROR_MESSAGE_PREFIX L"Unexpected merging trace when searching for DelayFieldAssignment."
|
|
);
|
|
CHECK_ERROR(
|
|
branch.traceBeginObject->predecessors.first != -1,
|
|
ERROR_MESSAGE_PREFIX L"Unexpected root trace when searching for DelayFieldAssignment."
|
|
);
|
|
|
|
branch.traceBeginObject = GetTrace(branch.traceBeginObject->predecessors.first);
|
|
ReadInstructionList(branch.traceBeginObject, branchInsLists);
|
|
branch.insBeginObject = branchInsLists.c3;
|
|
}
|
|
else
|
|
{
|
|
auto& ins = ReadInstruction(branch.insBeginObject, branchInsLists);
|
|
switch (ins.type)
|
|
{
|
|
case AstInsType::EndObject:
|
|
// if we see EndObject, find its balanced BeginObject or BeginObjectLeftRecursive
|
|
FindBalancedBoOrBolr(branch, branchObjectCount, branchReopenCount);
|
|
AdjustToRealTrace(branch);
|
|
ReadInstructionList(branch.traceBeginObject, branchInsLists);
|
|
break;
|
|
case AstInsType::ReopenObject:
|
|
branchReopenCount++;
|
|
break;
|
|
case AstInsType::DelayFieldAssignment:
|
|
branchReopenCount--;
|
|
if (branchReopenCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
MergeAmbiguityType
|
|
***********************************************************************/
|
|
|
|
void TraceManager::MergeAmbiguityType(vint32_t& ambiguityType, vint32_t branchType)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::MergeAmbiguityType(vint32_t&, vint32_t)#"
|
|
if (ambiguityType == -1)
|
|
{
|
|
ambiguityType = branchType;
|
|
}
|
|
else if (typeCallback)
|
|
{
|
|
vint32_t newType = typeCallback->FindCommonBaseClass(ambiguityType, branchType);
|
|
CHECK_ERROR(newType != -1, ERROR_MESSAGE_PREFIX L"Failed to merge from ambiguity types.");
|
|
ambiguityType = newType;
|
|
}
|
|
else
|
|
{
|
|
CHECK_ERROR(ambiguityType == branchType, ERROR_MESSAGE_PREFIX L"TraceManager::ITypeCallback is not installed, unable to merge from ambiguity types.");
|
|
}
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
MergeSharedBeginObjectsSingleRoot
|
|
***********************************************************************/
|
|
|
|
TraceManager::SharedBeginObject TraceManager::MergeSharedBeginObjectsSingleRoot(Trace* trace, collections::Dictionary<Trace*, SharedBeginObject>& predecessorToBranches)
|
|
{
|
|
// predecessorToBranches.Count() == 1
|
|
// it means all values in predecessorToBranches must be identical
|
|
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::MergeSharedBeginObjectsSingleRoot(Trace*, Dictionary<Trace*, SharedBeginObject>&)#"
|
|
SharedBeginObject shared;
|
|
vint32_t predecessorId = trace->predecessors.first;
|
|
while (predecessorId != -1)
|
|
{
|
|
auto predecessor = GetTrace(predecessorId);
|
|
auto branch = predecessorToBranches[predecessor];
|
|
predecessorId = predecessor->predecessors.siblingNext;
|
|
|
|
// BeginObject found from different predecessors must be the same
|
|
if (shared.traceBeginObject == nullptr)
|
|
{
|
|
shared = branch;
|
|
}
|
|
else
|
|
{
|
|
CHECK_ERROR(shared.traceBeginObject == branch.traceBeginObject && shared.insBeginObject == branch.insBeginObject, ERROR_MESSAGE_PREFIX L"BeginObject searched from different branches are not the same.");
|
|
}
|
|
}
|
|
|
|
shared.type = -1;
|
|
return shared;
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
MergeSharedBeginObjectsMultipleRoot
|
|
***********************************************************************/
|
|
|
|
TraceManager::SharedBeginObject TraceManager::MergeSharedBeginObjectsMultipleRoot(Trace* trace, collections::Dictionary<Trace*, SharedBeginObject>& predecessorToBranches)
|
|
{
|
|
// predecessorToBranches.Count() == number of predecessors
|
|
// it means all values in predecessorToBranches must be identical
|
|
// after they are adjusted to locate in the common predecessor
|
|
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::MergeSharedBeginObjectsMultipleRoot(Trace*, Dictionary<Trace*, SharedBeginObject>&)#"
|
|
SharedBeginObject shared;
|
|
vint32_t predecessorId = trace->predecessors.first;
|
|
|
|
Trace* firstBranch = nullptr;
|
|
while (predecessorId != -1)
|
|
{
|
|
auto predecessor = GetTrace(predecessorId);
|
|
auto branch = predecessorToBranches[predecessor];
|
|
predecessorId = predecessor->predecessors.siblingNext;
|
|
|
|
if (firstBranch == nullptr)
|
|
{
|
|
firstBranch = branch.traceBeginObject;
|
|
}
|
|
Trace* currentBranch = branch.traceBeginObject;
|
|
|
|
// adjust branch to locate in its predecessor
|
|
{
|
|
TraceInsLists parentInsLists;
|
|
Trace* parentTrace = GetTrace(branch.traceBeginObject->predecessors.first);
|
|
|
|
ReadInstructionList(parentTrace, parentInsLists);
|
|
branch.traceBeginObject = parentTrace;
|
|
branch.insBeginObject += parentInsLists.c3;
|
|
}
|
|
|
|
// multiple BeginObject must belong to successors of the same trace
|
|
// and the instructions prefix before these BeginObject must be identical
|
|
if (shared.traceBeginObject == nullptr)
|
|
{
|
|
shared = branch;
|
|
}
|
|
else
|
|
{
|
|
#define ERROR_MESSAGE ERROR_MESSAGE_PREFIX L"Failed to merge prefix from BeginObject of multiple successors."
|
|
CHECK_ERROR(shared.traceBeginObject == branch.traceBeginObject && shared.insBeginObject == branch.insBeginObject, ERROR_MESSAGE);
|
|
|
|
TraceInsLists sharedInsLists, firstInsLists, currentInsLists;
|
|
ReadInstructionList(shared.traceBeginObject, sharedInsLists);
|
|
ReadInstructionList(firstBranch, firstInsLists);
|
|
ReadInstructionList(currentBranch, currentInsLists);
|
|
|
|
vint32_t insBeginObject = shared.insBeginObject - sharedInsLists.c3;
|
|
CHECK_ERROR(insBeginObject < firstInsLists.c3, ERROR_MESSAGE);
|
|
CHECK_ERROR(insBeginObject < currentInsLists.c3, ERROR_MESSAGE);
|
|
|
|
for (vint32_t i = 0; i < insBeginObject; i++)
|
|
{
|
|
auto& ins1 = ReadInstruction(i, firstInsLists);
|
|
auto& ins2 = ReadInstruction(i, currentInsLists);
|
|
CHECK_ERROR(ins1 == ins2, ERROR_MESSAGE);
|
|
}
|
|
#undef ERROR_MESSAGE
|
|
}
|
|
}
|
|
|
|
shared.type = -1;
|
|
return shared;
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
MergeSharedBeginObjectsMultipleRoot
|
|
***********************************************************************/
|
|
|
|
TraceManager::SharedBeginObject TraceManager::MergeSharedBeginObjectsPartialMultipleRoot(Trace* trace, vint32_t ambiguityType, collections::Group<Trace*, Trace*>& beginToPredecessors, collections::Dictionary<Trace*, SharedBeginObject>& predecessorToBranches)
|
|
{
|
|
// some values in predecessorToBranches are the same but some are not
|
|
// the result is the same to one when all values in predecessorToBranches are different
|
|
// but we need to merge subset of predecessors which share the same value
|
|
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::MergeSharedBeginObjectsPartialMultipleRoot(Trace*, vint32_t, Group<Trace*, Trace*>&, Dictionary<Trace*, SharedBeginObject>&)#"
|
|
vint32_t predecessorId = trace->predecessors.first;
|
|
while (predecessorId != -1)
|
|
{
|
|
auto predecessor = GetTrace(predecessorId);
|
|
auto branch = predecessorToBranches[predecessor];
|
|
predecessorId = predecessor->predecessors.siblingNext;
|
|
|
|
// we start with the first predecessor from all subset
|
|
auto& subset = beginToPredecessors[branch.traceBeginObject];
|
|
if (subset.Count()==1 || predecessor != subset[0]) continue;
|
|
|
|
#define ERROR_MESSAGE ERROR_MESSAGE_PREFIX L"Failed to merge prefix from BeginObject of multiple successors."
|
|
// ensure all value in the subset are identical
|
|
for (vint i = 1; i < subset.Count(); i++)
|
|
{
|
|
auto anotherBranch = predecessorToBranches[subset[i]];
|
|
CHECK_ERROR(branch.traceBeginObject == anotherBranch.traceBeginObject && branch.insBeginObject == anotherBranch.insBeginObject, ERROR_MESSAGE);
|
|
}
|
|
|
|
// ensure all predecessor in the subset are identical in their critical content
|
|
TraceInsLists insLists;
|
|
ReadInstructionList(predecessor, insLists);
|
|
for (vint i = 1; i < subset.Count(); i++)
|
|
{
|
|
auto anotherPredecessor = subset[i];
|
|
CHECK_ERROR(predecessor->state == anotherPredecessor->state, ERROR_MESSAGE);
|
|
CHECK_ERROR(predecessor->byInput == anotherPredecessor->byInput, ERROR_MESSAGE);
|
|
CHECK_ERROR(predecessor->currentTokenIndex == anotherPredecessor->currentTokenIndex, ERROR_MESSAGE);
|
|
CHECK_ERROR(predecessor->returnStack == anotherPredecessor->returnStack, ERROR_MESSAGE);
|
|
|
|
TraceInsLists anotherInsLists;
|
|
ReadInstructionList(anotherPredecessor, anotherInsLists);
|
|
CHECK_ERROR(insLists.c3 == anotherInsLists.c3, ERROR_MESSAGE);
|
|
for (vint32_t j = 0; j < insLists.c3; j++)
|
|
{
|
|
auto& ins1 = ReadInstruction(j, insLists);
|
|
auto& ins2 = ReadInstruction(j, anotherInsLists);
|
|
CHECK_ERROR(ins1 == ins2, ERROR_MESSAGE);
|
|
}
|
|
}
|
|
|
|
// ensure all predecessor in the subset has only one predecessor
|
|
// otherwise we are replacing the current issue with another same issue
|
|
for (vint i = 0; i < subset.Count(); i++)
|
|
{
|
|
auto anotherPredecessor = subset[i];
|
|
CHECK_ERROR(anotherPredecessor->predecessors.first == anotherPredecessor->predecessors.last, ERROR_MESSAGE);
|
|
}
|
|
|
|
// connect all predecessors of predecessors in the subset to the first one
|
|
for (vint i = 1; i < subset.Count(); i++)
|
|
{
|
|
auto p1 = subset[i];
|
|
auto p2 = GetTrace(p1->predecessors.first);
|
|
p2->successors = {};
|
|
AddTraceToCollection(predecessor, p2, &Trace::predecessors);
|
|
AddTraceToCollection(p2, predecessor, &Trace::successors);
|
|
}
|
|
|
|
// remove all predecessors in the subset except the first one
|
|
for (vint i = 1; i < subset.Count(); i++)
|
|
{
|
|
auto p = subset[i];
|
|
if (p->predecessors.siblingPrev != -1)
|
|
{
|
|
GetTrace(p->predecessors.siblingPrev)->predecessors.siblingNext = p->predecessors.siblingNext;
|
|
}
|
|
if (p->predecessors.siblingNext != -1)
|
|
{
|
|
GetTrace(p->predecessors.siblingNext)->predecessors.siblingPrev = p->predecessors.siblingPrev;
|
|
}
|
|
if (trace->predecessors.first == p->allocatedIndex)
|
|
{
|
|
trace->predecessors.first = p->predecessors.siblingNext;
|
|
}
|
|
if (trace->predecessors.last == p->allocatedIndex)
|
|
{
|
|
trace->predecessors.last = p->predecessors.siblingPrev;
|
|
}
|
|
}
|
|
|
|
// fix predecessor->ambiguity
|
|
predecessor->ambiguity.traceBeginObject = branch.traceBeginObject->allocatedIndex;
|
|
predecessor->ambiguity.insBeginObject = branch.insBeginObject;
|
|
predecessor->ambiguity.ambiguityType = ambiguityType;
|
|
|
|
for (vint32_t i = 0; i < insLists.c3; i++)
|
|
{
|
|
auto& ins = ReadInstruction(i, insLists);
|
|
if (ins.type == AstInsType::EndObject)
|
|
{
|
|
predecessor->ambiguity.insEndObject = i;
|
|
break;
|
|
}
|
|
}
|
|
CHECK_ERROR(predecessor->ambiguity.insEndObject != -1, ERROR_MESSAGE);
|
|
#undef ERROR_MESSAGE
|
|
}
|
|
return MergeSharedBeginObjectsMultipleRoot(trace, predecessorToBranches);
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
FillAmbiguityInfoForMergingTrace
|
|
***********************************************************************/
|
|
|
|
TraceManager::SharedBeginObject TraceManager::FillAmbiguityInfoForMergingTrace(Trace* trace)
|
|
{
|
|
// assuming that this is a ambiguity resolving trace
|
|
// find the first instruction that accesses the object which is closed by the first EndObject in this trace
|
|
// such instruction must be BeginObject
|
|
// it is possible that the object closed by EndObject is created by a BeginObjectLeftRecursive
|
|
// in this case we need to keep searching
|
|
// until we find the BeginObject which creates the object that is consumed by BeginObjectLeftRecursive
|
|
// by executing from such BeginObject instead of BeginObjectLeftRecursive for all branches
|
|
// we prevent the object created by such BeginObject to be shared in multiple other objects
|
|
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::FillAmbiguityInfoForMergingTrace(Trace*)#"
|
|
// skip if the instruction has been found
|
|
if (trace->ambiguity.traceBeginObject != -1)
|
|
{
|
|
SharedBeginObject shared;
|
|
shared.traceBeginObject = GetTrace(trace->ambiguity.traceBeginObject);
|
|
shared.insBeginObject = trace->ambiguity.insBeginObject;
|
|
shared.type = trace->ambiguity.ambiguityType;
|
|
return shared;
|
|
}
|
|
|
|
CHECK_ERROR(trace->predecessors.first != trace->predecessors.last, L"This function is not allowed to run on non-merging traces.");
|
|
|
|
// find the first EndObject instruction
|
|
TraceInsLists insLists;
|
|
ReadInstructionList(trace, insLists);
|
|
|
|
vint32_t insEndObject = -1;
|
|
for (vint32_t i = 0; i < insLists.c3; i++)
|
|
{
|
|
auto& ins = ReadInstruction(i, insLists);
|
|
if (ins.type == AstInsType::EndObject)
|
|
{
|
|
insEndObject = i;
|
|
break;
|
|
}
|
|
}
|
|
CHECK_ERROR(insEndObject != -1, ERROR_MESSAGE_PREFIX L"Cannot find EndObject instruction in the merging trace.");
|
|
if (trace->ambiguityMergeInsPostfix != -1)
|
|
{
|
|
CHECK_ERROR(insEndObject == insLists.c3 - trace->ambiguityMergeInsPostfix - 1, L"ambiguityMergeInsPostfix and insEndObject does not match.");
|
|
}
|
|
|
|
vint32_t ambiguityType = -1;
|
|
Group<Trace*, Trace*> beginToPredecessors;
|
|
Dictionary<Trace*, SharedBeginObject> predecessorToBranches;
|
|
|
|
// call FindBalancedBoOrBolr on all predecessors
|
|
auto predecessorId = trace->predecessors.first;
|
|
vint predecessorCount = 0;
|
|
while (predecessorId != -1)
|
|
{
|
|
predecessorCount++;
|
|
auto predecessor = GetTrace(predecessorId);
|
|
|
|
SharedBeginObject branch;
|
|
if (trace->ambiguityMergeInsPostfix == -1)
|
|
{
|
|
// theoretically we need to run from EndObject to the first instruction
|
|
// but there will be nothing interested before EndObject
|
|
// so just set objectCount to 1
|
|
FindBalancedBoOrDfa(predecessor, 1, branch);
|
|
}
|
|
else
|
|
{
|
|
// having a postfix means the predecessor is another half of this trace
|
|
// the EndObject instruction is in the predecessor
|
|
FindBalancedBoOrDfa(predecessor, 0, branch);
|
|
}
|
|
|
|
beginToPredecessors.Add(branch.traceBeginObject, predecessor);
|
|
predecessorToBranches.Add(predecessor, branch);
|
|
|
|
// if EndObject is not the first instruction
|
|
// then the all instruction prefix are stored in predecessors
|
|
// so no need to really touch the prefix in this trace.
|
|
|
|
MergeAmbiguityType(ambiguityType, branch.type);
|
|
|
|
predecessorId = predecessor->predecessors.siblingNext;
|
|
}
|
|
|
|
SharedBeginObject shared;
|
|
if (beginToPredecessors.Count() == 1)
|
|
{
|
|
shared = MergeSharedBeginObjectsSingleRoot(trace, predecessorToBranches);
|
|
}
|
|
else if (beginToPredecessors.Count() == predecessorCount)
|
|
{
|
|
shared = MergeSharedBeginObjectsMultipleRoot(trace, predecessorToBranches);
|
|
}
|
|
else
|
|
{
|
|
shared = MergeSharedBeginObjectsPartialMultipleRoot(trace, ambiguityType, beginToPredecessors, predecessorToBranches);
|
|
}
|
|
|
|
trace->ambiguity.insEndObject = insEndObject;
|
|
trace->ambiguity.insBeginObject = shared.insBeginObject;
|
|
trace->ambiguity.traceBeginObject = shared.traceBeginObject->allocatedIndex;
|
|
trace->ambiguity.ambiguityType = ambiguityType;
|
|
return shared;
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
FillAmbiguityInfoForPredecessorTraces
|
|
***********************************************************************/
|
|
|
|
void TraceManager::FillAmbiguityInfoForPredecessorTraces(Trace* trace)
|
|
{
|
|
// fill Trace::ambiguity in any traces that could be reached by the current trace
|
|
while (trace)
|
|
{
|
|
if (trace->predecessors.first != trace->predecessors.last)
|
|
{
|
|
// if an ambiguity resolving trace has been filled
|
|
// then we could stop here
|
|
// because a previous call should have visited from this trace all the way to the root trace
|
|
if (trace->ambiguity.traceBeginObject == -1)
|
|
{
|
|
FillAmbiguityInfoForMergingTrace(trace);
|
|
trace = GetTrace(trace->ambiguity.traceBeginObject);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (trace->predecessors.first == -1) break;
|
|
trace = GetTrace(trace->predecessors.first);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
CreateLastMergingTrace
|
|
***********************************************************************/
|
|
|
|
void TraceManager::CreateLastMergingTrace(Trace* rootTraceCandidate)
|
|
{
|
|
// if there are multiple surviving traces
|
|
// they are all EndingInput transition to the ending state
|
|
// and their last instruction are EndObject
|
|
// so we could merge every surviving trace to one
|
|
|
|
// first, we need to determine the ambiguity type
|
|
vint32_t ambiguityType = -1;
|
|
for (vint i = 0; i < concurrentCount; i++)
|
|
{
|
|
auto trace = concurrentTraces->Get(i);
|
|
if (trace->predecessors.first == trace->predecessors.last)
|
|
{
|
|
// if this trace has only one predecessor
|
|
// find its BeginObject or BeginObjectLeftRecursive instruction for the type
|
|
TraceInsLists insLists;
|
|
ReadInstructionList(trace, insLists);
|
|
|
|
SharedBeginObject balanced;
|
|
balanced.traceBeginObject = trace;
|
|
balanced.insBeginObject = insLists.c3 - 1;
|
|
vint32_t objectCount = 0;
|
|
vint32_t reopenCount = 0;
|
|
FindBalancedBoOrBolr(balanced, objectCount, reopenCount);
|
|
|
|
AdjustToRealTrace(balanced);
|
|
ReadInstructionList(balanced.traceBeginObject, insLists);
|
|
auto ins = ReadInstruction(balanced.insBeginObject, insLists);
|
|
MergeAmbiguityType(ambiguityType, ins.param);
|
|
}
|
|
else
|
|
{
|
|
// otherwise, the type has been calculated before
|
|
MergeAmbiguityType(ambiguityType, trace->ambiguity.ambiguityType);
|
|
}
|
|
}
|
|
|
|
// second, create a merging ending trace
|
|
// such merging ending trace has no instruction
|
|
// it just merges all ending traces
|
|
auto mergingTrace = AllocateTrace();
|
|
for (vint i = 0; i < concurrentCount; i++)
|
|
{
|
|
auto trace = concurrentTraces->Get(i);
|
|
if (i == 0)
|
|
{
|
|
// copy data from the first one
|
|
mergingTrace->state = trace->state;
|
|
mergingTrace->byInput = trace->byInput;
|
|
mergingTrace->currentTokenIndex = trace->currentTokenIndex;
|
|
|
|
// set the ambiguity data
|
|
// rootTraceCandidate has no instruction
|
|
// the first instructions of all successors are all we need
|
|
TraceInsLists insLists;
|
|
ReadInstructionList(mergingTrace, insLists);
|
|
mergingTrace->ambiguity.traceBeginObject = rootTraceCandidate->allocatedIndex;
|
|
mergingTrace->ambiguity.insBeginObject = 0;
|
|
mergingTrace->ambiguity.insEndObject = 0;
|
|
mergingTrace->ambiguity.ambiguityType = ambiguityType;
|
|
}
|
|
|
|
AddTraceToCollection(mergingTrace, trace, &Trace::predecessors);
|
|
AddTraceToCollection(trace, mergingTrace, &Trace::successors);
|
|
}
|
|
|
|
// finally, the new merging trace should be the only surviving trace
|
|
concurrentCount = 1;
|
|
concurrentTraces->Set(0, mergingTrace);
|
|
for (vint i = 1; i < concurrentTraces->Count(); i++)
|
|
{
|
|
concurrentTraces->Set(i, nullptr);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
PrepareTraceRoute
|
|
***********************************************************************/
|
|
|
|
Trace* TraceManager::PrepareTraceRoute()
|
|
{
|
|
if (state == TraceManagerState::PreparedTraceRoute) return initialTrace;
|
|
CHECK_ERROR(state == TraceManagerState::Finished, L"vl::glr::automaton::TraceManager::PrepareTraceRoute()#Wrong timing to call this function.");
|
|
state = TraceManagerState::PreparedTraceRoute;
|
|
|
|
// we starts from all surviving traces
|
|
// and visit all predecessors
|
|
// until we reach the end
|
|
// so that we could skip all failed traces
|
|
|
|
SortedList<Trace*> available;
|
|
List<Trace*> visited;
|
|
|
|
for (vint i = 0; i < concurrentCount; i++)
|
|
{
|
|
auto trace = concurrentTraces->Get(i);
|
|
visited.Add(trace);
|
|
}
|
|
|
|
for (vint i = 0; i < visited.Count(); i++)
|
|
{
|
|
auto visiting = visited[i];
|
|
if (available.Contains(visiting)) continue;
|
|
available.Add(visiting);
|
|
|
|
// add the current trace to its predecessors' successors collection
|
|
// so that a succeeded trace only have other succeeded successors in its successor collection
|
|
auto predecessorId = visiting->predecessors.first;
|
|
while (predecessorId != -1)
|
|
{
|
|
auto predecessor = GetTrace(predecessorId);
|
|
AddTraceToCollection(predecessor, visiting, &Trace::successors);
|
|
predecessorId = predecessor->predecessors.siblingNext;
|
|
visited.Add(predecessor);
|
|
}
|
|
}
|
|
|
|
// find all ambiguity resolving traces and fill their Trace::ambiguity
|
|
for (vint i = 0; i < concurrentCount; i++)
|
|
{
|
|
auto trace = concurrentTraces->Get(i);
|
|
FillAmbiguityInfoForPredecessorTraces(trace);
|
|
}
|
|
|
|
// if there are multiple surviving traces
|
|
// check if the ambiguity happens in the root AST
|
|
if (concurrentCount > 1)
|
|
{
|
|
CreateLastMergingTrace(initialTrace);
|
|
}
|
|
|
|
return initialTrace;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\XML\GLRXML.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
using namespace stream;
|
|
using namespace collections;
|
|
using namespace regex;
|
|
|
|
/***********************************************************************
|
|
XmlUnescapeVisitor
|
|
***********************************************************************/
|
|
|
|
class XmlUnescapeVisitor : public traverse_visitor::AstVisitor
|
|
{
|
|
protected:
|
|
List<RegexToken>& tokens;
|
|
|
|
public:
|
|
XmlUnescapeVisitor(List<RegexToken>& _tokens)
|
|
:tokens(_tokens)
|
|
{
|
|
}
|
|
|
|
protected:
|
|
void Traverse(XmlAttribute* node) override
|
|
{
|
|
node->value.value = XmlUnescapeValue(node->value.value.Sub(1, node->value.value.Length() - 2));
|
|
}
|
|
|
|
void Traverse(XmlCData* node) override
|
|
{
|
|
node->content.value = XmlUnescapeCData(node->content.value);
|
|
}
|
|
|
|
void Traverse(XmlComment* node) override
|
|
{
|
|
node->content.value = XmlUnescapeComment(node->content.value);
|
|
}
|
|
|
|
void Traverse(XmlElement* node) override
|
|
{
|
|
vint begin = -1;
|
|
vint end = -1;
|
|
for (vint i = node->subNodes.Count() - 1; i >= -1; i--)
|
|
{
|
|
if (i == -1)
|
|
{
|
|
if (end != -1) begin = 0;
|
|
}
|
|
else if (node->subNodes[i].Cast<XmlText>())
|
|
{
|
|
if (end == -1) end = i;
|
|
}
|
|
else
|
|
{
|
|
if (end != -1) begin = i + 1;
|
|
}
|
|
if (begin != -1 && end != -1)
|
|
{
|
|
vint beginTokenIndex = node->subNodes[begin].Cast<XmlText>()->content.index;
|
|
vint endTokenIndex = node->subNodes[end].Cast<XmlText>()->content.index;
|
|
|
|
auto& beginToken = tokens[beginTokenIndex];
|
|
auto& endToken = tokens[endTokenIndex];
|
|
|
|
auto textBegin = beginToken.reading;
|
|
auto textEnd = endToken.reading + endToken.length;
|
|
|
|
if (beginTokenIndex > 0)
|
|
{
|
|
auto& previousToken = tokens[beginTokenIndex - 1];
|
|
textBegin = previousToken.reading + previousToken.length;
|
|
}
|
|
|
|
if (endTokenIndex < tokens.Count() - 1)
|
|
{
|
|
auto& nextToken = tokens[endTokenIndex + 1];
|
|
textEnd = nextToken.reading;
|
|
}
|
|
|
|
WString text = WString::CopyFrom(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);
|
|
|
|
node->subNodes.RemoveRange(begin, end - begin + 1);
|
|
node->subNodes.Insert(begin, xmlText);
|
|
|
|
begin = -1;
|
|
end = -1;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
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);
|
|
for (auto att : node->attributes)
|
|
{
|
|
writer.WriteChar(L' ');
|
|
Visit(att.Obj());
|
|
}
|
|
if(node->subNodes.Count()==0)
|
|
{
|
|
writer.WriteString(L"/>");
|
|
}
|
|
else
|
|
{
|
|
writer.WriteChar(L'>');
|
|
for (auto 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);
|
|
for (auto att : node->attributes)
|
|
{
|
|
writer.WriteChar(L' ');
|
|
Visit(att.Obj());
|
|
}
|
|
writer.WriteString(L"?>");
|
|
}
|
|
|
|
void Visit(XmlDocument* node)
|
|
{
|
|
for (auto prolog : node->prologs)
|
|
{
|
|
prolog->Accept(this);
|
|
}
|
|
node->rootElement->Accept(this);
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Escaping and Unescaping
|
|
***********************************************************************/
|
|
|
|
WString XmlEscapeValue(const WString& value)
|
|
{
|
|
WString result;
|
|
const wchar_t* reading = value.Buffer();
|
|
while (wchar_t c = *reading++)
|
|
{
|
|
switch (c)
|
|
{
|
|
case L'<':
|
|
result += L"<";
|
|
break;
|
|
case L'>':
|
|
result += L">";
|
|
break;
|
|
case L'&':
|
|
result += L"&";
|
|
break;
|
|
case L'\'':
|
|
result += L"'";
|
|
break;
|
|
case L'\"':
|
|
result += L""";
|
|
break;
|
|
default:
|
|
result += WString::FromChar(c);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
WString XmlUnescapeValue(const WString& value)
|
|
{
|
|
WString result;
|
|
const wchar_t* reading = value.Buffer();
|
|
while (*reading)
|
|
{
|
|
if (wcsncmp(reading, L"<", 4) == 0)
|
|
{
|
|
result += WString::FromChar(L'<');
|
|
reading += 4;
|
|
}
|
|
else if (wcsncmp(reading, L">", 4) == 0)
|
|
{
|
|
result += WString::FromChar(L'>');
|
|
reading += 4;
|
|
}
|
|
else if (wcsncmp(reading, L"&", 5) == 0)
|
|
{
|
|
result += WString::FromChar(L'&');
|
|
reading += 5;
|
|
}
|
|
else if (wcsncmp(reading, L"'", 6) == 0)
|
|
{
|
|
result += WString::FromChar(L'\'');
|
|
reading += 6;
|
|
}
|
|
else if (wcsncmp(reading, L""", 6) == 0)
|
|
{
|
|
result += WString::FromChar(L'\"');
|
|
reading += 6;
|
|
}
|
|
else
|
|
{
|
|
result += WString::FromChar(*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);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Parsing and Printing
|
|
***********************************************************************/
|
|
|
|
Ptr<XmlDocument> XmlParseDocument(const WString& input, const Parser& parser)
|
|
{
|
|
List<RegexToken> tokens;
|
|
parser.Tokenize(input, tokens);
|
|
auto ast = parser.ParseXDocument(tokens);
|
|
XmlUnescapeVisitor(tokens).InspectInto(ast.Obj());
|
|
return ast;
|
|
}
|
|
|
|
Ptr<XmlElement> XmlParseElement(const WString& input, const Parser& parser)
|
|
{
|
|
List<RegexToken> tokens;
|
|
parser.Tokenize(input, tokens);
|
|
auto ast = parser.ParseXElement(tokens);
|
|
XmlUnescapeVisitor(tokens).InspectInto(ast.Obj());
|
|
return ast;
|
|
}
|
|
|
|
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);
|
|
for (auto node : element->subNodes)
|
|
{
|
|
node->Accept(&visitor);
|
|
}
|
|
}
|
|
|
|
WString XmlToString(Ptr<XmlNode> node)
|
|
{
|
|
return GenerateToStream([&](StreamWriter& writer)
|
|
{
|
|
XmlPrint(node, writer);
|
|
});
|
|
}
|
|
|
|
/***********************************************************************
|
|
Utility
|
|
***********************************************************************/
|
|
|
|
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)
|
|
{
|
|
for (auto att : element->attributes)
|
|
{
|
|
if (att->name.value == name)
|
|
{
|
|
return att;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Ptr<XmlElement> XmlGetElement(XmlElement* element, const WString& name)
|
|
{
|
|
for (auto node : element->subNodes)
|
|
{
|
|
Ptr<XmlElement> subElement = node.Cast<XmlElement>();
|
|
if (subElement && subElement->name.value == name)
|
|
{
|
|
return subElement;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element)
|
|
{
|
|
return From(element->subNodes).FindType<XmlElement>();
|
|
}
|
|
|
|
collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element, const WString& name)
|
|
{
|
|
return XmlGetElements(element)
|
|
.Where([name](auto&& e) {return e->name.value == name; });
|
|
}
|
|
|
|
WString XmlGetValue(XmlElement* element)
|
|
{
|
|
WString result;
|
|
for (auto node : element->subNodes)
|
|
{
|
|
if (auto text = node.Cast<XmlText>())
|
|
{
|
|
result += text->content.value;
|
|
}
|
|
else if (auto 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
/***********************************************************************
|
|
Visitor Pattern Implementation
|
|
***********************************************************************/
|
|
|
|
void XmlText::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlCData::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlComment::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlElement::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlInstruction::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlDocument::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlNode, system::XmlNode)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlNode::IVisitor, system::XmlNode::IVisitor)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlText, system::XmlText)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlCData, system::XmlCData)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlAttribute, system::XmlAttribute)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlComment, system::XmlComment)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlElement, system::XmlElement)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlInstruction, system::XmlInstruction)
|
|
IMPL_TYPE_INFO_RENAME(vl::glr::xml::XmlDocument, system::XmlDocument)
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::xml::XmlNode)
|
|
CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)
|
|
|
|
END_CLASS_MEMBER(vl::glr::xml::XmlNode)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::xml::XmlText)
|
|
CLASS_MEMBER_BASE(vl::glr::xml::XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::xml::XmlText>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(content)
|
|
END_CLASS_MEMBER(vl::glr::xml::XmlText)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::xml::XmlCData)
|
|
CLASS_MEMBER_BASE(vl::glr::xml::XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::xml::XmlCData>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(content)
|
|
END_CLASS_MEMBER(vl::glr::xml::XmlCData)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::xml::XmlAttribute)
|
|
CLASS_MEMBER_BASE(vl::glr::ParsingAstBase)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::xml::XmlAttribute>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(name)
|
|
CLASS_MEMBER_FIELD(value)
|
|
END_CLASS_MEMBER(vl::glr::xml::XmlAttribute)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::xml::XmlComment)
|
|
CLASS_MEMBER_BASE(vl::glr::xml::XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::xml::XmlComment>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(content)
|
|
END_CLASS_MEMBER(vl::glr::xml::XmlComment)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::xml::XmlElement)
|
|
CLASS_MEMBER_BASE(vl::glr::xml::XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::xml::XmlElement>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(name)
|
|
CLASS_MEMBER_FIELD(closingName)
|
|
CLASS_MEMBER_FIELD(attributes)
|
|
CLASS_MEMBER_FIELD(subNodes)
|
|
END_CLASS_MEMBER(vl::glr::xml::XmlElement)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::xml::XmlInstruction)
|
|
CLASS_MEMBER_BASE(vl::glr::xml::XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::xml::XmlInstruction>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(name)
|
|
CLASS_MEMBER_FIELD(attributes)
|
|
END_CLASS_MEMBER(vl::glr::xml::XmlInstruction)
|
|
|
|
BEGIN_CLASS_MEMBER(vl::glr::xml::XmlDocument)
|
|
CLASS_MEMBER_BASE(vl::glr::xml::XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<vl::glr::xml::XmlDocument>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(prologs)
|
|
CLASS_MEMBER_FIELD(rootElement)
|
|
END_CLASS_MEMBER(vl::glr::xml::XmlDocument)
|
|
|
|
BEGIN_INTERFACE_MEMBER(vl::glr::xml::XmlNode::IVisitor)
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::xml::XmlNode::IVisitor::*)(vl::glr::xml::XmlText* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::xml::XmlNode::IVisitor::*)(vl::glr::xml::XmlCData* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::xml::XmlNode::IVisitor::*)(vl::glr::xml::XmlComment* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::xml::XmlNode::IVisitor::*)(vl::glr::xml::XmlElement* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::xml::XmlNode::IVisitor::*)(vl::glr::xml::XmlInstruction* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(vl::glr::xml::XmlNode::IVisitor::*)(vl::glr::xml::XmlDocument* node))
|
|
END_INTERFACE_MEMBER(vl::glr::xml::XmlNode)
|
|
|
|
#endif
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
class XmlAstTypeLoader : public vl::Object, public ITypeLoader
|
|
{
|
|
public:
|
|
void Load(ITypeManager* manager)
|
|
{
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlNode)
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlNode::IVisitor)
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlText)
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlCData)
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlAttribute)
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlComment)
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlElement)
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlInstruction)
|
|
ADD_TYPE_INFO(vl::glr::xml::XmlDocument)
|
|
}
|
|
|
|
void Unload(ITypeManager* manager)
|
|
{
|
|
}
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
bool XmlAstLoadTypes()
|
|
{
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
if (auto manager = GetGlobalTypeManager())
|
|
{
|
|
Ptr<ITypeLoader> loader = new XmlAstTypeLoader;
|
|
return manager->AddTypeLoader(loader);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_BUILDER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
namespace builder
|
|
{
|
|
|
|
/***********************************************************************
|
|
MakeAttribute
|
|
***********************************************************************/
|
|
|
|
MakeAttribute& MakeAttribute::name(const vl::WString& value)
|
|
{
|
|
node->name.value = value;
|
|
return *this;
|
|
}
|
|
|
|
MakeAttribute& MakeAttribute::value(const vl::WString& value)
|
|
{
|
|
node->value.value = value;
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeCData
|
|
***********************************************************************/
|
|
|
|
MakeCData& MakeCData::content(const vl::WString& value)
|
|
{
|
|
node->content.value = value;
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeComment
|
|
***********************************************************************/
|
|
|
|
MakeComment& MakeComment::content(const vl::WString& value)
|
|
{
|
|
node->content.value = value;
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeDocument
|
|
***********************************************************************/
|
|
|
|
MakeDocument& MakeDocument::prologs(const vl::Ptr<XmlNode>& value)
|
|
{
|
|
node->prologs.Add(value);
|
|
return *this;
|
|
}
|
|
|
|
MakeDocument& MakeDocument::rootElement(const vl::Ptr<XmlElement>& value)
|
|
{
|
|
node->rootElement = value;
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeElement
|
|
***********************************************************************/
|
|
|
|
MakeElement& MakeElement::attributes(const vl::Ptr<XmlAttribute>& value)
|
|
{
|
|
node->attributes.Add(value);
|
|
return *this;
|
|
}
|
|
|
|
MakeElement& MakeElement::closingName(const vl::WString& value)
|
|
{
|
|
node->closingName.value = value;
|
|
return *this;
|
|
}
|
|
|
|
MakeElement& MakeElement::name(const vl::WString& value)
|
|
{
|
|
node->name.value = value;
|
|
return *this;
|
|
}
|
|
|
|
MakeElement& MakeElement::subNodes(const vl::Ptr<XmlNode>& value)
|
|
{
|
|
node->subNodes.Add(value);
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeInstruction
|
|
***********************************************************************/
|
|
|
|
MakeInstruction& MakeInstruction::attributes(const vl::Ptr<XmlAttribute>& value)
|
|
{
|
|
node->attributes.Add(value);
|
|
return *this;
|
|
}
|
|
|
|
MakeInstruction& MakeInstruction::name(const vl::WString& value)
|
|
{
|
|
node->name.value = value;
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MakeText
|
|
***********************************************************************/
|
|
|
|
MakeText& MakeText::content(const vl::WString& value)
|
|
{
|
|
node->content.value = value;
|
|
return *this;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_COPY.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
namespace copy_visitor
|
|
{
|
|
void AstVisitor::CopyFields(XmlAttribute* from, XmlAttribute* to)
|
|
{
|
|
to->name = from->name;
|
|
to->value = from->value;
|
|
}
|
|
|
|
void AstVisitor::CopyFields(XmlCData* from, XmlCData* to)
|
|
{
|
|
CopyFields(static_cast<XmlNode*>(from), static_cast<XmlNode*>(to));
|
|
to->content = from->content;
|
|
}
|
|
|
|
void AstVisitor::CopyFields(XmlComment* from, XmlComment* to)
|
|
{
|
|
CopyFields(static_cast<XmlNode*>(from), static_cast<XmlNode*>(to));
|
|
to->content = from->content;
|
|
}
|
|
|
|
void AstVisitor::CopyFields(XmlDocument* from, XmlDocument* to)
|
|
{
|
|
CopyFields(static_cast<XmlNode*>(from), static_cast<XmlNode*>(to));
|
|
for (auto&& listItem : from->prologs)
|
|
{
|
|
to->prologs.Add(CopyNode(listItem.Obj()));
|
|
}
|
|
to->rootElement = CopyNode(from->rootElement.Obj());
|
|
}
|
|
|
|
void AstVisitor::CopyFields(XmlElement* from, XmlElement* to)
|
|
{
|
|
CopyFields(static_cast<XmlNode*>(from), static_cast<XmlNode*>(to));
|
|
for (auto&& listItem : from->attributes)
|
|
{
|
|
to->attributes.Add(CopyNode(listItem.Obj()));
|
|
}
|
|
to->closingName = from->closingName;
|
|
to->name = from->name;
|
|
for (auto&& listItem : from->subNodes)
|
|
{
|
|
to->subNodes.Add(CopyNode(listItem.Obj()));
|
|
}
|
|
}
|
|
|
|
void AstVisitor::CopyFields(XmlInstruction* from, XmlInstruction* to)
|
|
{
|
|
CopyFields(static_cast<XmlNode*>(from), static_cast<XmlNode*>(to));
|
|
for (auto&& listItem : from->attributes)
|
|
{
|
|
to->attributes.Add(CopyNode(listItem.Obj()));
|
|
}
|
|
to->name = from->name;
|
|
}
|
|
|
|
void AstVisitor::CopyFields(XmlNode* from, XmlNode* to)
|
|
{
|
|
}
|
|
|
|
void AstVisitor::CopyFields(XmlText* from, XmlText* to)
|
|
{
|
|
CopyFields(static_cast<XmlNode*>(from), static_cast<XmlNode*>(to));
|
|
to->content = from->content;
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlAttribute* node)
|
|
{
|
|
auto newNode = vl::MakePtr<XmlAttribute>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlText* node)
|
|
{
|
|
auto newNode = vl::MakePtr<XmlText>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlCData* node)
|
|
{
|
|
auto newNode = vl::MakePtr<XmlCData>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlComment* node)
|
|
{
|
|
auto newNode = vl::MakePtr<XmlComment>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlElement* node)
|
|
{
|
|
auto newNode = vl::MakePtr<XmlElement>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlInstruction* node)
|
|
{
|
|
auto newNode = vl::MakePtr<XmlInstruction>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlDocument* node)
|
|
{
|
|
auto newNode = vl::MakePtr<XmlDocument>();
|
|
CopyFields(node, newNode.Obj());
|
|
this->result = newNode;
|
|
}
|
|
|
|
vl::Ptr<XmlNode> AstVisitor::CopyNode(XmlNode* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
node->Accept(static_cast<XmlNode::IVisitor*>(this));
|
|
return this->result.Cast<XmlNode>();
|
|
}
|
|
|
|
vl::Ptr<XmlAttribute> AstVisitor::CopyNode(XmlAttribute* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
Visit(node);
|
|
return this->result.Cast<XmlAttribute>();
|
|
}
|
|
|
|
vl::Ptr<XmlCData> AstVisitor::CopyNode(XmlCData* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<XmlNode*>(node)).Cast<XmlCData>();
|
|
}
|
|
|
|
vl::Ptr<XmlComment> AstVisitor::CopyNode(XmlComment* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<XmlNode*>(node)).Cast<XmlComment>();
|
|
}
|
|
|
|
vl::Ptr<XmlDocument> AstVisitor::CopyNode(XmlDocument* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<XmlNode*>(node)).Cast<XmlDocument>();
|
|
}
|
|
|
|
vl::Ptr<XmlElement> AstVisitor::CopyNode(XmlElement* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<XmlNode*>(node)).Cast<XmlElement>();
|
|
}
|
|
|
|
vl::Ptr<XmlInstruction> AstVisitor::CopyNode(XmlInstruction* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<XmlNode*>(node)).Cast<XmlInstruction>();
|
|
}
|
|
|
|
vl::Ptr<XmlText> AstVisitor::CopyNode(XmlText* node)
|
|
{
|
|
if (!node) return nullptr;
|
|
return CopyNode(static_cast<XmlNode*>(node)).Cast<XmlText>();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_EMPTY.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
namespace empty_visitor
|
|
{
|
|
|
|
/***********************************************************************
|
|
NodeVisitor
|
|
***********************************************************************/
|
|
|
|
// Visitor Members -----------------------------------
|
|
|
|
void NodeVisitor::Visit(XmlText* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(XmlCData* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(XmlComment* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(XmlElement* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(XmlInstruction* node)
|
|
{
|
|
}
|
|
|
|
void NodeVisitor::Visit(XmlDocument* node)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_JSON.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
namespace json_visitor
|
|
{
|
|
void AstVisitor::PrintFields(XmlAttribute* node)
|
|
{
|
|
BeginField(L"name");
|
|
WriteToken(node->name);
|
|
EndField();
|
|
BeginField(L"value");
|
|
WriteToken(node->value);
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(XmlCData* node)
|
|
{
|
|
BeginField(L"content");
|
|
WriteToken(node->content);
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(XmlComment* node)
|
|
{
|
|
BeginField(L"content");
|
|
WriteToken(node->content);
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(XmlDocument* node)
|
|
{
|
|
BeginField(L"prologs");
|
|
BeginArray();
|
|
for (auto&& listItem : node->prologs)
|
|
{
|
|
BeginArrayItem();
|
|
Print(listItem.Obj());
|
|
EndArrayItem();
|
|
}
|
|
EndArray();
|
|
EndField();
|
|
BeginField(L"rootElement");
|
|
Print(node->rootElement.Obj());
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(XmlElement* node)
|
|
{
|
|
BeginField(L"attributes");
|
|
BeginArray();
|
|
for (auto&& listItem : node->attributes)
|
|
{
|
|
BeginArrayItem();
|
|
Print(listItem.Obj());
|
|
EndArrayItem();
|
|
}
|
|
EndArray();
|
|
EndField();
|
|
BeginField(L"closingName");
|
|
WriteToken(node->closingName);
|
|
EndField();
|
|
BeginField(L"name");
|
|
WriteToken(node->name);
|
|
EndField();
|
|
BeginField(L"subNodes");
|
|
BeginArray();
|
|
for (auto&& listItem : node->subNodes)
|
|
{
|
|
BeginArrayItem();
|
|
Print(listItem.Obj());
|
|
EndArrayItem();
|
|
}
|
|
EndArray();
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(XmlInstruction* node)
|
|
{
|
|
BeginField(L"attributes");
|
|
BeginArray();
|
|
for (auto&& listItem : node->attributes)
|
|
{
|
|
BeginArrayItem();
|
|
Print(listItem.Obj());
|
|
EndArrayItem();
|
|
}
|
|
EndArray();
|
|
EndField();
|
|
BeginField(L"name");
|
|
WriteToken(node->name);
|
|
EndField();
|
|
}
|
|
void AstVisitor::PrintFields(XmlNode* node)
|
|
{
|
|
}
|
|
void AstVisitor::PrintFields(XmlText* node)
|
|
{
|
|
BeginField(L"content");
|
|
WriteToken(node->content);
|
|
EndField();
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlText* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Text", node);
|
|
PrintFields(static_cast<XmlNode*>(node));
|
|
PrintFields(static_cast<XmlText*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlCData* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"CData", node);
|
|
PrintFields(static_cast<XmlNode*>(node));
|
|
PrintFields(static_cast<XmlCData*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlComment* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Comment", node);
|
|
PrintFields(static_cast<XmlNode*>(node));
|
|
PrintFields(static_cast<XmlComment*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlElement* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Element", node);
|
|
PrintFields(static_cast<XmlNode*>(node));
|
|
PrintFields(static_cast<XmlElement*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlInstruction* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Instruction", node);
|
|
PrintFields(static_cast<XmlNode*>(node));
|
|
PrintFields(static_cast<XmlInstruction*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlDocument* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Document", node);
|
|
PrintFields(static_cast<XmlNode*>(node));
|
|
PrintFields(static_cast<XmlDocument*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
AstVisitor::AstVisitor(vl::stream::StreamWriter& _writer)
|
|
: vl::glr::JsonVisitorBase(_writer)
|
|
{
|
|
}
|
|
|
|
void AstVisitor::Print(XmlNode* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
node->Accept(static_cast<XmlNode::IVisitor*>(this));
|
|
}
|
|
|
|
void AstVisitor::Print(XmlAttribute* node)
|
|
{
|
|
if (!node)
|
|
{
|
|
WriteNull();
|
|
return;
|
|
}
|
|
BeginObject();
|
|
WriteType(L"Attribute", node);
|
|
PrintFields(static_cast<XmlAttribute*>(node));
|
|
EndObject();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_TRAVERSE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
namespace traverse_visitor
|
|
{
|
|
void AstVisitor::Traverse(vl::glr::ParsingToken& token) {}
|
|
void AstVisitor::Traverse(vl::glr::ParsingAstBase* node) {}
|
|
void AstVisitor::Traverse(XmlAttribute* node) {}
|
|
void AstVisitor::Traverse(XmlCData* node) {}
|
|
void AstVisitor::Traverse(XmlComment* node) {}
|
|
void AstVisitor::Traverse(XmlDocument* node) {}
|
|
void AstVisitor::Traverse(XmlElement* node) {}
|
|
void AstVisitor::Traverse(XmlInstruction* node) {}
|
|
void AstVisitor::Traverse(XmlNode* node) {}
|
|
void AstVisitor::Traverse(XmlText* node) {}
|
|
|
|
void AstVisitor::Finishing(vl::glr::ParsingAstBase* node) {}
|
|
void AstVisitor::Finishing(XmlAttribute* node) {}
|
|
void AstVisitor::Finishing(XmlCData* node) {}
|
|
void AstVisitor::Finishing(XmlComment* node) {}
|
|
void AstVisitor::Finishing(XmlDocument* node) {}
|
|
void AstVisitor::Finishing(XmlElement* node) {}
|
|
void AstVisitor::Finishing(XmlInstruction* node) {}
|
|
void AstVisitor::Finishing(XmlNode* node) {}
|
|
void AstVisitor::Finishing(XmlText* node) {}
|
|
|
|
void AstVisitor::Visit(XmlText* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<XmlNode*>(node));
|
|
Traverse(static_cast<XmlText*>(node));
|
|
Traverse(node->content);
|
|
Finishing(static_cast<XmlText*>(node));
|
|
Finishing(static_cast<XmlNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlCData* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<XmlNode*>(node));
|
|
Traverse(static_cast<XmlCData*>(node));
|
|
Traverse(node->content);
|
|
Finishing(static_cast<XmlCData*>(node));
|
|
Finishing(static_cast<XmlNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlComment* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<XmlNode*>(node));
|
|
Traverse(static_cast<XmlComment*>(node));
|
|
Traverse(node->content);
|
|
Finishing(static_cast<XmlComment*>(node));
|
|
Finishing(static_cast<XmlNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlElement* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<XmlNode*>(node));
|
|
Traverse(static_cast<XmlElement*>(node));
|
|
for (auto&& listItem : node->attributes)
|
|
{
|
|
InspectInto(listItem.Obj());
|
|
}
|
|
Traverse(node->closingName);
|
|
Traverse(node->name);
|
|
for (auto&& listItem : node->subNodes)
|
|
{
|
|
InspectInto(listItem.Obj());
|
|
}
|
|
Finishing(static_cast<XmlElement*>(node));
|
|
Finishing(static_cast<XmlNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlInstruction* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<XmlNode*>(node));
|
|
Traverse(static_cast<XmlInstruction*>(node));
|
|
for (auto&& listItem : node->attributes)
|
|
{
|
|
InspectInto(listItem.Obj());
|
|
}
|
|
Traverse(node->name);
|
|
Finishing(static_cast<XmlInstruction*>(node));
|
|
Finishing(static_cast<XmlNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::Visit(XmlDocument* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<XmlNode*>(node));
|
|
Traverse(static_cast<XmlDocument*>(node));
|
|
for (auto&& listItem : node->prologs)
|
|
{
|
|
InspectInto(listItem.Obj());
|
|
}
|
|
InspectInto(node->rootElement.Obj());
|
|
Finishing(static_cast<XmlDocument*>(node));
|
|
Finishing(static_cast<XmlNode*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
void AstVisitor::InspectInto(XmlNode* node)
|
|
{
|
|
if (!node) return;
|
|
node->Accept(static_cast<XmlNode::IVisitor*>(this));
|
|
}
|
|
|
|
void AstVisitor::InspectInto(XmlAttribute* node)
|
|
{
|
|
if (!node) return;
|
|
Traverse(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
Traverse(static_cast<XmlAttribute*>(node));
|
|
Traverse(node->name);
|
|
Traverse(node->value);
|
|
Finishing(static_cast<XmlAttribute*>(node));
|
|
Finishing(static_cast<vl::glr::ParsingAstBase*>(node));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLPARSER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Xml
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
void XmlParserData(vl::stream::IStream& outputStream)
|
|
{
|
|
static const vl::vint dataLength = 2446; // 22181 bytes before compressing
|
|
static const vl::vint dataBlock = 256;
|
|
static const vl::vint dataRemain = 142;
|
|
static const vl::vint dataSolidRows = 9;
|
|
static const vl::vint dataRows = 10;
|
|
static const char* compressed[] = {
|
|
"\xA5\x56\x00\x00\x86\x09\x00\x00\x0D\x00\x01\x82\x80\x08\x03\x82\x81\x82\x06\x89\x82\x85\x0A\x83\x06\x84\x07\x0A\x91\x0A\x9C\x0A\x82\x12\x84\x14\x0A\xA3\x42\x09\x8F\x7D\x8E\x8F\x8E\x0A\x80\x1F\x9F\x81\x93\x92\x8F\x92\x26\xFF\x68\x86\x9B\x93\x91\x96\x92\x0A\xA9\xAA\x91\x99\x91\x91\x91\x00\x34\xAC\xB9\x8E\x9B\x98\x98\x8F\x9A\x3D\xA7\x81\xA0\x93\xA3\x9B\x9E\x9D\x47\xBC\x89\xBE\x96\x82\x9B\x96\xA1\x4B\xD0\x8D\xA0\xA1\xAC\xA1\xAA\xA3\x53\xC8\x99\xAA\xAB\xAC\xA7\x80\xA7\x45\xCF\x96\xBD\xA2\xAF\xAC\xAA\xB2\x63\xE6\x9A\xAA\xBC\xAC\xB6\xAE\x81\x60\xD7\xB7\x8A\x88\x9A\xB9\xB1\xBB\x76\x89\x9B\x89\x85\xB8\xB4\xAC\xB7\x65\xF0\xA7\xA0\xC9\xB2\xC3\xB4\xC3\x6D\x88\xEF\xA1\x81\xBE\xBE\xB1\xBF\x8A\x81\xCC\xC3\xC1\xCD\xC3\xC9\xC3\x97\x89\xD9\xCB\xC2\x94\xCB\xCC\xC9\x9D\x98\xE1\xDA\xC3\xD4\xCD\xC7\x81\x03\x74\xB8\xAE\xCB\xD4\xC0\xC9\xCF\x96\xA5\xE0\xC7\xD5\xCF\xD6\xD9\xD8\xB4\xB0\xF6\xD9\xD7\xDB\xDE\xCE\x00\x04\x2A\xC9\x8C\x8C\xBA\x86\x02\xE1\xAC\xF9\x86\x87\x08\xE6\xD7\xC7\xE7\xAD\xB5\xD0\xEA\xEE\xE1\xEA\xDD\xE9\xC9\xD9\xD5\xF4",
|
|
"\xE2\xEA\x84\x84\x83\x7D\xDB\xDA\xFD\xEC\xEF\xEA\xEB\xDE\xD8\xE2\xEA\xE4\xF3\xF6\xF1\xF2\x00\x09\x4D\xEC\xEB\xFE\xF5\xF4\xF5\xF3\xBC\xF9\xFF\xDA\xF2\xD4\xFC\xD2\xDE\x0A\x32\x75\x7C\x7D\xF7\x6F\x7E\x7E\x69\xFB\x49\x8D\x7E\x82\xFF\x4C\x88\x82\x68\x0E\x45\x76\x82\x83\xB3\x54\x88\x6E\x85\xBE\x4B\x8A\x85\x83\x1B\x8F\x8C\x87\x87\x1E\xA1\x85\x85\x87\x23\xA0\x85\x8A\x88\x17\xA4\x89\x88\x69\x0C\x02\x85\x82\x7D\x07\xA7\x82\x8F\x8A\x28\x99\x86\x88\x8D\x33\xB6\x85\x8D\x7A\xF3\x7D\x81\x40\x40\x12\xB0\x88\x84\x8F\x03\xBE\x8F\x88\x81\x31\xB8\x8A\x92\x8E\x39\x84\x97\x92\x91\x49\x8C\x9B\x92\x93\x51\x8E\x90\x45\x90\x48\x83\x98\x7E\x96\x13\xAA\x82\x97\x97\x54\x9C\x92\x92\x97\x4E\x8F\x0E\x89\x95\x5B\xA4\x99\x9B\x8D\x60\xAB\x9B\x8E\x9B\x4D\xB0\x93\x96\x9C\xB6\x50\x07\x9A\x98\x59\xAA\x9D\x94\x9B\x61\xBA\x93\x98\x9F\x74\xBD\x90\xA3\x9E\x6F\x84\xA1\x9E\xA1\x73\x88\xAD\x9B\x7B\x12\x58\x90\x94\x9E\x8F\xBE\x99\x9F\xA0\xF6\x52\x07\x9E\x68\x13\x17\xA4\x68\x05\x9A\x85\xAF\x9E\xA7\x93\xA0\xA1\xA4\x69\x15\x1D\xA0\x6A\x05\xA6\xB1\x67\x05\xAA",
|
|
"\x8B\x9F\xA7\xA2\x41\x18\x2C\xA2\xA2\xA8\x45\xB5\xAF\x92\xAD\x68\x8A\xA3\xAF\xAB\xA1\xBC\xA2\x41\x06\xB2\x8A\x4A\x05\xB0\x09\x5B\x0E\x88\x45\x8E\x81\x4D\x06\x8B\x1E\x2E\x8F\x06\x8B\x20\x04\xBE\xA9\xA2\xF6\x61\x02\xB7\x40\x16\x49\xB7\xAC\x00\x23\x2E\x84\x0A\x8B\x25\x2E\x86\x0A\x8B\x27\x2E\x88\x46\xB6\xB9\x93\xBD\xA9\xAF\xD4\xAC\xB6\x6D\x0A\xD7\xA3\xA4\xAF\xB6\x2A\x31\xB8\xAC\xA4\xF7\x92\xA2\xBE\xAF\xF9\x94\xAE\xBB\xAE\xED\xBB\xB1\xC1\x40\x2B\x36\xBB\xB5\xBA\xFF\x81\xAA\xC2\xAE\xE7\x6C\x06\xC1\x0B\x2E\xAE\x0E\x8B\x0B\x2E\xB0\x0E\x89\x0C\x2E\xB2\x06\xC0\xC2\x02\xEB\xBD\xC4\xC0\x1E\xFD\xB3\xBC\xC7\x01\x73\x0B\xC4\xBE\x07\xE8\xC4\xC9\xCA\xFA\xA2\xCC\xBC\x00\x34\x27\xCD\xC8\xCB\xFE\x9F\xCB\xC2\xBA\x20\xE1\x45\x0E\xCC\x35\xEE\xC3\xC0\xCD\x23\xEA\xC2\xD2\x68\x36\x3C\xC1\xD3\xCC\x2B\xC9\xD3\xD1\xCF\x40\xEF\xC7\x0E\xD1\x2F\xCA\xD8\xD3\xD2\x47\xCC\xD2\xD6\xD5\x54\xD1\xD9\xD7\xCF\x57\xD5\xDE\xD6\xD6\x53\xE2\x68\x0C\xD4\x5C\xDB\xD1\xCB\xB6\x39\x24\xD7\xDB\xCA\x3A\x2A\xD9\xCF\xCD\x09\xC9\x4B\x0E\xDB\x70\xC6\x9C\x0C\xDD\x0C",
|
|
"\xEF\x7D\x0C\xDE\x38\xF5\xDE\xCF\xDA\x66\xEF\xD9\xDE\x41\x3E\x3C\xD4\x83\x0F\x86\xF6\xC9\x40\x10\x89\xFF\xD2\xE1\xDF\x83\xF1\xD0\xE7\xE4\x92\xD5\xE2\x41\x10\x8D\xDB\xB2\x11\xE6\x2B\xC3\x1C\xE7\x6F\x44\x1F\xE1\xD8\xD6\xA3\xDF\xD5\xD9\xE9\x2F\xC5\x12\xE8\x69\x46\x2B\xE3\xBF\x11\xAE\xE0\x6D\x2A\x42\x7B\x76\x4E\xBA\x4C\xDF\x76\xEF\xDC\xEE\xAC\x87\x77\x56\x4C\xB5\xC3\x4C\x72\xA2\xBC\xC9\x4D\x8B\x55\xC1\xC2\x43\xF2\xBA\xC5\xC6\x47\xF2\x5F\xC9\xC1\x4B\xF3\xED\x29\x79\xE2\x43\xF3\xAE\x51\xF0\x03\xF4\x1D\xCD\xF3\x40\xF6\xB5\x7E\xEE\x5E\x4C\xE2\xEE\x64\xF9\x51\xE7\xFF\xE9\x4A\xF6\xE1\x5D\xF5\xF4\xED\x45\x65\xF5\x6C\xF0\xF0\xC4\xFF\xF9\x42\xA9\x57\x52\xFE\x6E\xF4\xC9\x41\x72\xFD\x26\x36\x79\x40\x02\x8D\x36\xED\x60\x66\x7B\xBA\x7D\x7E\xEE\x3B\x77\x7F\x05\xBD\x33\x7F\xBD\x32\x27\xFF\x63\x7B\x7C\x85\x13\x86\x35\x17\x93\x7D\x05\x89\x2C\x7A\x06\x81\x82\x21\xE0\x7A\x35\x06\xFC\x7B\x83\xE5\x34\x48\x81\x01\x21\x85\x6F\x23\x81\x83\x12\x82\x7F\x84\x0D\x9F\x79\x51\x2C\x82\x26\x05\x83\x22\x7B\x51\x48\x84\x00\x79\x7E\x2E\x1A\xB5\x86",
|
|
"\x24\xEC\x70\x87\x07\xFA\x23\x86\xF4\x6E\x82\x79\x42\x83\x24\x01\xAA\x82\x82\x23\x80\x8E\x82\x45\x8A\x7F\x13\x9C\x89\x89\x8F\x0B\x89\x8A\x14\x93\x8A\x09\x80\x8A\x88\x10\x98\x8E\x7C\x47\x92\x79\x15\x9E\x27\x8B\xAB\x3E\x87\x87\x1F\x3A\x78\x0E\x98\x4A\x86\x1E\x98\x86\x89\x23\x21\x88\x17\xD6\x85\x7F\x1E\xB0\x89\x8D\x0A\x3D\x81\xD3\x3F\x85\x8C\xE6\x71\x80\x89\xFA\x77\x8E\x47\x67\x88\x8D\x8E\x1A\x7C\x90\x1F\x28\x90\x1A\xDA\x7A\x8F\x1C\xBF\x89\x85\x5F\x9A\x82\x16\xAF\x83\x8E\x32\x9E\x8E\x8C\x82\x86\x91\x1E\xE3\x8D\x23\x3E\xAF\x8A\x8A\x71\x95\x8C\xF5\x43\x86\x20\x37\xB5\x32\x91\x3F\x92\x8E\x1F\xA4\x97\x87\x48\xA4\x83\x92\x80\x8B\x95\x17\xC6\x71\x7F\x4C\xBF\x18\x82\x85\x9F\x20\x2E\xB9\x9D\x23\x5D\xBC\x92\x7B\xC4\x32\x94\x1D\x89\x21\x42\xE8\x4E\x86\x83\xB3\x8E\x82\x0D\x89\x8C\x8D\x47\xB6\x21\x7D\x59\x81\x94\xFE\x45\x20\x98\x6A\x8A\x26\x94\xBA\x27\x92\x35\xD3\x98\x78\x51\xAE\x7C\x95\x02\x38\x99\x01\x8A\x21\x99\xEC\x50\x8D\x9B\x44\x95\x91\x27\xD7\x95\x96\x50\xB8\x8B\x38\xDB\x86\x20\x2A\xFF\x1A\x8C\x4E\xBF\x1C\x80\xE2\x9A",
|
|
"\x86\x2F\xC9\x93\x21\x7D\x83\x9E\x20\xF1\x37\x29\x39\x92\x93\x25\x81\xAF\x95\xA0\xB6\x86\xA1\x0B\xE0\x91\x21\x80\xBE\x2C\x80\x01\x57\x28\x44\xC5\x24\x81\x79\x84\x82\xA1\x3A\x96\xA3\x39\x8F\xA4\x9C\x8A\x9B\xA6\x35\x15\xBE\xA0\x3C\x92\xAF\xA3\xDA\x16\x67\x98\xED\x61\x22\xF6\x62\x9A\x9B\x74\xB2\x9E\x9B\x01\x2C\x85\x35\xAE\xAD\x9E\x98\x80\x3B\x93\xDC\x9B\x8B\x4B\xD4\x8E\x7E\x9C\xBB\xA2\xA7\x03\x2A\xA2\x1E\x90\x8A\x8E\x16\xA2\x9C\x85\x48\xBD\xA1\x42\x10\x8C\x84\x02\x8E\xA3\x20\x11\xA6\x21\x31\xB2\x89\x20\x20\x46\x27\x4A\x06\x26\x4D\x42\x76\x49\x21\x46\x46\x26\x52\x09\x39\x53\x31\xA5\x57\x98\x4D\x2E\x41\x24\x64\xAE\x83\x26\x2E\x4A\xA1\x58\x47\x9C\x13\x2E\x4C\x87\xB3\x47\x9D\x12\x17\x69\xA0\x00\xCD\x47\x9A\x27\x2E\x42\x9D\x68\x47\x9F\x13\x2E\x5A\x7A\xB5\x47\x90\x14\xB6\x8A\x26\xAD\x0E\x81\x17\x59\x8A\x23\x5D\x63\xA2\x13\xB1\x09\x2D\xB2\x03\xA3\x1E\x44\x08\xB5\x5F\x98\xA4\x11\xAE\x42\x05\x67\x99\x52\x3C\xAA\x21\x0E\x67\x9A\x29\x15\xBA\x21\xCB\x8E\x87\x14\x9A\xA9\x20\x67\x8E\x88\x15\xCF\x89\x21\xB4\x0E\x89\x14\x69\x89",
|
|
"\x26\xB5\x05\xAA\x11\xB5\x06\x2B\xB7\x02\xAB\x1E\xB4\x83\x30\xB3\x81\xAC\x0E\x44\x12\x47\x97\xA6\xE2\xB6\xAE\xA6\xBC\x2B\xA4\x71\xBC\x3C\xA5\xF3\x22\x9F\xAE\x21\x2A\xA3\x5D\xAB\x62\xA7\xE5\x81\x72\xA9\x40\xBA\x74\x04\xF7\xAA\x8F\x35\xA2\x32\xA1\x4F\xBA\x75\x78\x81\x27\xAF\xA8\xAD\x97\x3D\x0A\xA4\x81\x48\x2A\x87\xAE\xAB\xA7\xBE\x3E\x0A\xA6\xBE\xEE\x5A\xA0\x3C\x85\x1C\xAE\x20\xDE\xA4\x37\x50\xC4\xB0\xAD\xFA\x91\x77\x20\xC6\x24\xBA\x58\xFE\xB4\x72\x81\x23\xB8\x00\x10\x81\x24\xA7\x68\x58\x64\xF9\x81\x21\xC1\x0A\x29\xAF\x40\x53\xB8\x65\xA9\x82\x26\xBD\xBA\x68\x56\xB6\x2B\x54\xA6\x23\x58\xC0\x92\xC7\x80\x58\x83\xB3\x68\xAB\x81\x37\xBB\x81\xC3\x5A\x5A\xB1\x1D\xC6\x57\x13\xC2\x24\xBE\x0B\x8B\x5B\x88\xCC\x6E\xAB\x81\x03\xC3\x81\x79\xA4\xC2\xE5\x01\x27\xC6\x81\x0B\xC2\x99\xBF\x33\xAC\x7E\xE7\x3F\xC7\x81\x1A\xC0\xC8\xA8\x71\x35\x91\x82\x2C\xC2\x24\xE4\x73\x53\x25\xB6\x77\x60\xBA\xC2\x21\x6C\x43\xC8\xA5\x11\xCA\x23\x91\x8B\x8D\x6A\xD0\x12\xC4\xC9\xD6\xA9\xCA\x6D\x5F\xC1\xA6\xE2\x9F\x5A\x5B\xE1\x4C\xC4\x00\x77\xA7\xAF\x2D",
|
|
"\xC2\x25\xBF\x0B\x85\x5F\x8C\xF3\x5D\xC9\x81\x22\xC6\xC9\xA6\x76\x35\x9D\x82\x2D\xC6\xDB\x67\x5F\xCA\xF6\x35\x9D\x42\x7B\xC2\x8D\x63\xB5\xB2\x20\xDA\x7F\xB4\xA2\xD1\xC0\x00\xED\x44\xD0\x3E\xC4\xB2\x62\x9A\xA7\xA0\xD1\x9A\xAA\xCF\xD1\xEA\xAA\x22\xC6\x6A\xC1\x66\x35\xC4\x86\xD1\xF6\xA4\xB9\xD1\x6A\xC3\x6C\x35\xCE\xC5\xD1\x0A\x2F\xD3\x87\xB6\x2D\x6C\x35\xF7\x6A\xCD\x2A\x80\xD5\x42\x27\xD1\x25\xC2\x6A\xCC\x71\x6A\xC5\xC7\xA2\x89\x28\xB0\x3B\xE1\xCF\xC9\x9C\x3D\xD4\x9F\xC4\xBB\x72\x35\xFC\x36\xC5\x2A\xA7\xB2\x4F\x8B\x81\x74\x35\xED\x72\xCD\x70\xDB\xD4\xAC\x0A\x27\xC1\x90\x03\xBA\xCD\x4A\x16\xA7\x92\xC9\xDC\xD6\xEF\x04\xBC\x09\x36\xAE\x0A\x4D\xEE\xCC\xDB\x69\xDB\xAC\xB8\x50\x16\xA6\x14\x36\xA2\xD9\x72\xC3\x25\xDD\x00\x0B\xD5\x48\x54\x06\xA6\x2B\x36\xA1\xC5\x95\xC2\x20\xBC\xB4\xDA\x20\x2C\x36\xA2\x0B\x36\xA8\x59\xBE\x81\x27\xCF\x81\x2B\xC0\xCF\xA0\x3C\x08\x72\xBF\x38\xDF\x81\x11\xDE\x76\x5E\x19\x73\xC1\x83\x2D\xE0\x66\xA2\xC9\x24\x02\xF6\xC4\x71\xDF\x0B\xE0\xD1\x39\xC3\xC2\x13\x2B\xDA\xEE\x61\x06\xA7\x31\x36\xA2\xC8",
|
|
"\x20\xE9\x21\xC6\x86\xC4\xB9\x32\x36\xA7\x0C\x36\xBE\xAC\x95\x81\x2B\xE5\x01\x84\xB9\x0D\x36\xAB\x0E\x4D\xD3\xC9\xE4\x83\x35\xE0\x00\xC8\xD6\x25\x1B\x36\xAF\x0C\x9B\x96\xCD\xE7\x03\x3F\xE6\xBC\x8A\x21\x0E\x9B\xB3\x0E\xA6\xDD\x5A\x5B\xCF\xFC\xD9\x21\x3A\x36\xA7\x0E\x36\xA7\xCF\xCC\xF8\xAA\x20\x19\xCE\x81\x0F\x99\x68\xE6\x40\x5E\xEB\x80\x3D\x19\x72\xE6\x03\x24\xEE\xEE\x7B\x09\x72\x9E\xE3\xEC\xB8\x7C\x19\x73\xD1\x82\x2A\xEB\x05\xBD\x09\x73\x75\xE2\x21\x9A\x88\xE1\x36\x3F\x1D\xE4\x34\x7B\xE3\x22\x9C\xFC\xE0\x70\xD1\x01\xF2\x20\x2C\x81\x24\x20\x2E\x41\x10\x9B\x87\xF4\xBC\x8C\xAA\x23\xE0\xDC\xC7\xBB\xC8\x8C\xD1\x24\x83\x0E\x44\x21\x36\xA2\xB2\xA4\xC2\x23\xF2\x02\x31\xEA\x03\x86\x19\x73\x3F\xC3\x21\xEF\xB6\x67\x13\xDF\x9C\x30\xF4\xC8\xC9\x26\xF4\xC3\xC7\x99\x22\x2B\xF0\x34\xD8\xEE\xF6\x20\xB6\xE0\xE8\x71\x8B\x16\xA7\x46\x36\xA0\x5E\xDA\x47\xD1\x40\x28\xF6\x27\x47\x06\x62\xF8\x6B\xC5\xB6\x42\x7D\xC6\x26\x48\x06\x62\xB7\x02\x37\xAC\xF2\xC1\xE1\x25\x48\x2E\x42\x12\x36\xAA\xD3\xED\x83\x20\xFB\x80\x00\xFE\x81\x94\x19\x72",
|
|
"\xF6\x80\x04\xF9\x90\x15\x17\x61\x2E\x43\xFC\xF3\xA1\x26\x12\x83\x52\xD3\xEB\xE3\xF4\xFA\x42\x17\x1E\x44\x4C\x36\xA4\x62\xDA\x50\x63\x31\xBC\x31\x82\xE3\xBE\xFF\xFF\x14\x6C\x12\x01\x86\x12\x6C\x63\x17\x6A\x69\x7C\xC4\x57\x57\xE2\x48\x6A\x72\x19\x5F\xD2\x47\x4C\xF9\x45\x13\x11\x89\x12\x0B\x81\x12\xF3\x45\x5C\xE3\x39\x78\x16\x86\x5C\x1A\x87\x79\x1B\x84\x5C\x1D\x8D\x53\x20\x8C\x81\xC6\x58\x51\x35\x16\x82\x29\x1A\x50\x36\x1A\x82\xD1\x55\x82\xC6\x5E\x4F\x27\x10\x83\x1E\x10\x61\x01\x64\x5C\x34\x8B\x54\xC6\x5D\x48\x35\x1A\x83\x29\x1A\x47\x36\x1E\x83\x21\x10\x84\x0A\x10",
|
|
};
|
|
vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream);
|
|
}
|
|
|
|
const wchar_t* ParserRuleName(vl::vint index)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"XAttribute",
|
|
L"XText",
|
|
L"XCData",
|
|
L"XComment",
|
|
L"XElement",
|
|
L"XSubNode",
|
|
L"XInstruction",
|
|
L"XDocument",
|
|
};
|
|
return results[index];
|
|
}
|
|
|
|
const wchar_t* ParserStateLabel(vl::vint index)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"[0][XAttribute] BEGIN ",
|
|
L"[1][XAttribute] END [ENDING]",
|
|
L"[2][XAttribute]< NAME \"=\" @ ATTVALUE >",
|
|
L"[3][XAttribute]< NAME \"=\" ATTVALUE @ >",
|
|
L"[4][XAttribute]< NAME @ \"=\" ATTVALUE >",
|
|
L"[5][XText] BEGIN ",
|
|
L"[6][XText] END [ENDING]",
|
|
L"[7][XText]< \"=\" @ >",
|
|
L"[8][XText]< ATTVALUE @ >",
|
|
L"[9][XText]< NAME @ >",
|
|
L"[10][XText]< TEXT @ >",
|
|
L"[11][XCData] BEGIN ",
|
|
L"[12][XCData] END [ENDING]",
|
|
L"[13][XCData]< CDATA @ >",
|
|
L"[14][XComment] BEGIN ",
|
|
L"[15][XComment] END [ENDING]",
|
|
L"[16][XComment]< COMMENT @ >",
|
|
L"[17][XElement] BEGIN ",
|
|
L"[18][XElement] END [ENDING]",
|
|
L"[19][XElement]< \"<\" @ NAME { XAttribute } ( \"/>\" | \">\" { XSubNode } \"</\" NAME \">\" ) >",
|
|
L"[20][XElement]< \"<\" NAME @ { XAttribute } ( \"/>\" | \">\" { XSubNode } \"</\" NAME \">\" ) >",
|
|
L"[21][XElement]< \"<\" NAME { XAttribute @ } ( \"/>\" | \">\" { XSubNode } \"</\" NAME \">\" ) >",
|
|
L"[22][XElement]< \"<\" NAME { XAttribute } ( \"/>\" @ | \">\" { XSubNode } \"</\" NAME \">\" ) >",
|
|
L"[23][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" @ { XSubNode } \"</\" NAME \">\" ) >",
|
|
L"[24][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" { XSubNode @ } \"</\" NAME \">\" ) >",
|
|
L"[25][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" { XSubNode } \"</\" @ NAME \">\" ) >",
|
|
L"[26][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" { XSubNode } \"</\" NAME \">\" @ ) >",
|
|
L"[27][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" { XSubNode } \"</\" NAME @ \">\" ) >",
|
|
L"[28][XSubNode] BEGIN ",
|
|
L"[29][XSubNode] END [ENDING]",
|
|
L"[30][XSubNode]<< ( ( ( !XText @ | !XCData ) | !XComment ) | !XElement ) >>",
|
|
L"[31][XSubNode]<< ( ( ( !XText | !XCData ) | !XComment ) | !XElement @ ) >>",
|
|
L"[32][XSubNode]<< ( ( ( !XText | !XCData ) | !XComment @ ) | !XElement ) >>",
|
|
L"[33][XSubNode]<< ( ( ( !XText | !XCData @ ) | !XComment ) | !XElement ) >>",
|
|
L"[34][XInstruction] BEGIN ",
|
|
L"[35][XInstruction] END [ENDING]",
|
|
L"[36][XInstruction]< \"<?\" @ NAME { XAttribute } \"?>\" >",
|
|
L"[37][XInstruction]< \"<?\" NAME @ { XAttribute } \"?>\" >",
|
|
L"[38][XInstruction]< \"<?\" NAME { XAttribute @ } \"?>\" >",
|
|
L"[39][XInstruction]< \"<?\" NAME { XAttribute } \"?>\" @ >",
|
|
L"[40][XDocument] BEGIN ",
|
|
L"[41][XDocument] END [ENDING]",
|
|
L"[42][XDocument]< { ( XInstruction @ | XComment ) } XElement >",
|
|
L"[43][XDocument]< { ( XInstruction | XComment ) } XElement @ >",
|
|
L"[44][XDocument]< { ( XInstruction | XComment @ ) } XElement >",
|
|
};
|
|
return results[index];
|
|
}
|
|
|
|
Parser::Parser()
|
|
: vl::glr::ParserBase<XmlTokens, ParserStates, XmlAstInsReceiver>(&XmlTokenDeleter, &XmlLexerData, &XmlParserData)
|
|
{
|
|
};
|
|
|
|
vl::vint32_t Parser::FindCommonBaseClass(vl::vint32_t class1, vl::vint32_t class2) const
|
|
{
|
|
return -1;
|
|
};
|
|
|
|
vl::Ptr<vl::glr::xml::XmlElement> Parser::ParseXElement(const vl::WString& input, vl::vint codeIndex) const
|
|
{
|
|
return ParseWithString<vl::glr::xml::XmlElement, ParserStates::XElement>(input, this, codeIndex);
|
|
};
|
|
|
|
vl::Ptr<vl::glr::xml::XmlElement> Parser::ParseXElement(vl::collections::List<vl::regex::RegexToken>& tokens, vl::vint codeIndex) const
|
|
{
|
|
return ParseWithTokens<vl::glr::xml::XmlElement, ParserStates::XElement>(tokens, this, codeIndex);
|
|
};
|
|
|
|
vl::Ptr<vl::glr::xml::XmlDocument> Parser::ParseXDocument(const vl::WString& input, vl::vint codeIndex) const
|
|
{
|
|
return ParseWithString<vl::glr::xml::XmlDocument, ParserStates::XDocument>(input, this, codeIndex);
|
|
};
|
|
|
|
vl::Ptr<vl::glr::xml::XmlDocument> Parser::ParseXDocument(vl::collections::List<vl::regex::RegexToken>& tokens, vl::vint codeIndex) const
|
|
{
|
|
return ParseWithTokens<vl::glr::xml::XmlDocument, ParserStates::XDocument>(tokens, this, codeIndex);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XML_ASSEMBLER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Xml
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
|
|
/***********************************************************************
|
|
XmlAstInsReceiver : public vl::glr::AstInsReceiverBase
|
|
***********************************************************************/
|
|
|
|
vl::Ptr<vl::glr::ParsingAstBase> XmlAstInsReceiver::CreateAstNode(vl::vint32_t type)
|
|
{
|
|
auto cppTypeName = XmlCppTypeName((XmlClasses)type);
|
|
switch((XmlClasses)type)
|
|
{
|
|
case XmlClasses::Attribute:
|
|
return new vl::glr::xml::XmlAttribute();
|
|
case XmlClasses::CData:
|
|
return new vl::glr::xml::XmlCData();
|
|
case XmlClasses::Comment:
|
|
return new vl::glr::xml::XmlComment();
|
|
case XmlClasses::Document:
|
|
return new vl::glr::xml::XmlDocument();
|
|
case XmlClasses::Element:
|
|
return new vl::glr::xml::XmlElement();
|
|
case XmlClasses::Instruction:
|
|
return new vl::glr::xml::XmlInstruction();
|
|
case XmlClasses::Text:
|
|
return new vl::glr::xml::XmlText();
|
|
default:
|
|
return vl::glr::AssemblyThrowCannotCreateAbstractType(type, cppTypeName);
|
|
}
|
|
}
|
|
|
|
void XmlAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::Ptr<vl::glr::ParsingAstBase> value)
|
|
{
|
|
auto cppFieldName = XmlCppFieldName((XmlFields)field);
|
|
switch((XmlFields)field)
|
|
{
|
|
case XmlFields::Document_prologs:
|
|
return vl::glr::AssemblerSetObjectField(&vl::glr::xml::XmlDocument::prologs, object, field, value, cppFieldName);
|
|
case XmlFields::Document_rootElement:
|
|
return vl::glr::AssemblerSetObjectField(&vl::glr::xml::XmlDocument::rootElement, object, field, value, cppFieldName);
|
|
case XmlFields::Element_attributes:
|
|
return vl::glr::AssemblerSetObjectField(&vl::glr::xml::XmlElement::attributes, object, field, value, cppFieldName);
|
|
case XmlFields::Element_subNodes:
|
|
return vl::glr::AssemblerSetObjectField(&vl::glr::xml::XmlElement::subNodes, object, field, value, cppFieldName);
|
|
case XmlFields::Instruction_attributes:
|
|
return vl::glr::AssemblerSetObjectField(&vl::glr::xml::XmlInstruction::attributes, object, field, value, cppFieldName);
|
|
default:
|
|
return vl::glr::AssemblyThrowFieldNotObject(field, cppFieldName);
|
|
}
|
|
}
|
|
|
|
void XmlAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, const vl::regex::RegexToken& token, vl::vint32_t tokenIndex)
|
|
{
|
|
auto cppFieldName = XmlCppFieldName((XmlFields)field);
|
|
switch((XmlFields)field)
|
|
{
|
|
case XmlFields::Attribute_name:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::xml::XmlAttribute::name, object, field, token, tokenIndex, cppFieldName);
|
|
case XmlFields::Attribute_value:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::xml::XmlAttribute::value, object, field, token, tokenIndex, cppFieldName);
|
|
case XmlFields::CData_content:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::xml::XmlCData::content, object, field, token, tokenIndex, cppFieldName);
|
|
case XmlFields::Comment_content:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::xml::XmlComment::content, object, field, token, tokenIndex, cppFieldName);
|
|
case XmlFields::Element_closingName:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::xml::XmlElement::closingName, object, field, token, tokenIndex, cppFieldName);
|
|
case XmlFields::Element_name:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::xml::XmlElement::name, object, field, token, tokenIndex, cppFieldName);
|
|
case XmlFields::Instruction_name:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::xml::XmlInstruction::name, object, field, token, tokenIndex, cppFieldName);
|
|
case XmlFields::Text_content:
|
|
return vl::glr::AssemblerSetTokenField(&vl::glr::xml::XmlText::content, object, field, token, tokenIndex, cppFieldName);
|
|
default:
|
|
return vl::glr::AssemblyThrowFieldNotToken(field, cppFieldName);
|
|
}
|
|
}
|
|
|
|
void XmlAstInsReceiver::SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::vint32_t enumItem)
|
|
{
|
|
auto cppFieldName = XmlCppFieldName((XmlFields)field);
|
|
return vl::glr::AssemblyThrowFieldNotEnum(field, cppFieldName);
|
|
}
|
|
|
|
const wchar_t* XmlTypeName(XmlClasses type)
|
|
{
|
|
const wchar_t* results[] = {
|
|
L"Attribute",
|
|
L"CData",
|
|
L"Comment",
|
|
L"Document",
|
|
L"Element",
|
|
L"Instruction",
|
|
L"Node",
|
|
L"Text",
|
|
};
|
|
vl::vint index = (vl::vint)type;
|
|
return 0 <= index && index < 8 ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* XmlCppTypeName(XmlClasses type)
|
|
{
|
|
const wchar_t* results[] = {
|
|
L"vl::glr::xml::XmlAttribute",
|
|
L"vl::glr::xml::XmlCData",
|
|
L"vl::glr::xml::XmlComment",
|
|
L"vl::glr::xml::XmlDocument",
|
|
L"vl::glr::xml::XmlElement",
|
|
L"vl::glr::xml::XmlInstruction",
|
|
L"vl::glr::xml::XmlNode",
|
|
L"vl::glr::xml::XmlText",
|
|
};
|
|
vl::vint index = (vl::vint)type;
|
|
return 0 <= index && index < 8 ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* XmlFieldName(XmlFields field)
|
|
{
|
|
const wchar_t* results[] = {
|
|
L"Attribute::name",
|
|
L"Attribute::value",
|
|
L"CData::content",
|
|
L"Comment::content",
|
|
L"Document::prologs",
|
|
L"Document::rootElement",
|
|
L"Element::attributes",
|
|
L"Element::closingName",
|
|
L"Element::name",
|
|
L"Element::subNodes",
|
|
L"Instruction::attributes",
|
|
L"Instruction::name",
|
|
L"Text::content",
|
|
};
|
|
vl::vint index = (vl::vint)field;
|
|
return 0 <= index && index < 13 ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* XmlCppFieldName(XmlFields field)
|
|
{
|
|
const wchar_t* results[] = {
|
|
L"vl::glr::xml::XmlAttribute::name",
|
|
L"vl::glr::xml::XmlAttribute::value",
|
|
L"vl::glr::xml::XmlCData::content",
|
|
L"vl::glr::xml::XmlComment::content",
|
|
L"vl::glr::xml::XmlDocument::prologs",
|
|
L"vl::glr::xml::XmlDocument::rootElement",
|
|
L"vl::glr::xml::XmlElement::attributes",
|
|
L"vl::glr::xml::XmlElement::closingName",
|
|
L"vl::glr::xml::XmlElement::name",
|
|
L"vl::glr::xml::XmlElement::subNodes",
|
|
L"vl::glr::xml::XmlInstruction::attributes",
|
|
L"vl::glr::xml::XmlInstruction::name",
|
|
L"vl::glr::xml::XmlText::content",
|
|
};
|
|
vl::vint index = (vl::vint)field;
|
|
return 0 <= index && index < 13 ? results[index] : nullptr;
|
|
}
|
|
|
|
vl::Ptr<vl::glr::ParsingAstBase> XmlAstInsReceiver::ResolveAmbiguity(vl::vint32_t type, vl::collections::Array<vl::Ptr<vl::glr::ParsingAstBase>>& candidates)
|
|
{
|
|
auto cppTypeName = XmlCppTypeName((XmlClasses)type);
|
|
return vl::glr::AssemblyThrowTypeNotAllowAmbiguity(type, cppTypeName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XML_LEXER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Xml
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
bool XmlTokenDeleter(vl::vint token)
|
|
{
|
|
switch((XmlTokens)token)
|
|
{
|
|
case XmlTokens::SPACE:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const wchar_t* XmlTokenId(XmlTokens token)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"INSTRUCTION_OPEN",
|
|
L"INSTRUCTION_CLOSE",
|
|
L"COMPLEX_ELEMENT_OPEN",
|
|
L"SINGLE_ELEMENT_CLOSE",
|
|
L"ELEMENT_OPEN",
|
|
L"ELEMENT_CLOSE",
|
|
L"EQUAL",
|
|
L"NAME",
|
|
L"ATTVALUE",
|
|
L"COMMENT",
|
|
L"CDATA",
|
|
L"TEXT",
|
|
L"SPACE",
|
|
};
|
|
vl::vint index = (vl::vint)token;
|
|
return 0 <= index && index < XmlTokenCount ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* XmlTokenDisplayText(XmlTokens token)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"<?",
|
|
L"?>",
|
|
L"</",
|
|
L"/>",
|
|
L"<",
|
|
L">",
|
|
L"=",
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
};
|
|
vl::vint index = (vl::vint)token;
|
|
return 0 <= index && index < XmlTokenCount ? results[index] : nullptr;
|
|
}
|
|
|
|
const wchar_t* XmlTokenRegex(XmlTokens token)
|
|
{
|
|
static const wchar_t* results[] = {
|
|
L"/</?",
|
|
L"/?/>",
|
|
L"/<//",
|
|
L"///>",
|
|
L"/<",
|
|
L"/>",
|
|
L"/=",
|
|
L"[a-zA-Z0-9:._/-]+",
|
|
L"\"[^<>\"]*\"|\'[^<>\']*\'",
|
|
L"/</!--([^/-]|-[^/-]|--[^>])*--/>",
|
|
L"/</!/[CDATA/[([^/]]|/][^/]]|/]/][^>])*/]/]/>",
|
|
L"([^<>=\"\' /r/n/ta-zA-Z0-9:._/-])+|\"|\'",
|
|
L"/s+",
|
|
};
|
|
vl::vint index = (vl::vint)token;
|
|
return 0 <= index && index < XmlTokenCount ? results[index] : nullptr;
|
|
}
|
|
|
|
void XmlLexerData(vl::stream::IStream& outputStream)
|
|
{
|
|
static const vl::vint dataLength = 1076; // 7370 bytes before compressing
|
|
static const vl::vint dataBlock = 256;
|
|
static const vl::vint dataRemain = 52;
|
|
static const vl::vint dataSolidRows = 4;
|
|
static const vl::vint dataRows = 5;
|
|
static const char* compressed[] = {
|
|
"\xCA\x1C\x00\x00\x2C\x04\x00\x00\x2C\x00\x01\xA7\x01\x84\x81\x82\x12\x82\x01\x04\x88\x04\x89\x04\x84\x82\x05\x0F\x84\x8B\x04\x8C\x04\x81\x06\x8B\x04\x8E\x04\x9F\x04\x80\x11\x8E\x82\x21\x20\x84\x82\x13\x94\x83\x10\x82\x07\x82\x84\x83\x81\x80\x14\x82\x80\x01\xAD\x04\x92\x91\x86\x14\x82\x9B\x01\xAF\x04\x9A\x91\x80\x18\x83\x1C\x04\xBA\x01\xA4\x8B\x1C\xA0\x82\x1E\x47\x84\xBD\x0A\xA4\x86\x1D\xA6\x82\x3F\x50\x84\x80\x23\xAC\x81\x20\xAB\x04\xC2\x19\xA4\x83\x24\xAC\x82\x22\x5F\x84\x85\x24\x83\x2C\x80\x2A\xB3\x04\xD5\x04\x9A\x24\x83\x2D\xB6\x82\x5C\x70\x84\x9D\x23\xBC\x82\x2E\xBB\x04\xDF\x39\xA4\x80\x34\xBC\x83\x30\x04\xFA\x04\x9B\x34\x87\x7F\x7E\x08\x00\x0D\x81\x90\x8B\xC6\x85\xC7\x80\x8A\x80\x0C\xC9\xC4\x87\x02\xC6\x00\x0B\x90\xC4\x86\x0B\xCC\x83\x01\xCE\x01\x9C\xDA\xC1\x89\x81\x81\x02\x82\x04\x04\x82\x17\xC2\xD0\x01\xD7\xD7\xA0\xAE\xF1\xD1\xC4\xDC\xD6\xDB\xD1\x00\x06\xFA\xDB\xDC\xDD\xDE\xDE\xDE\x17\x81\xBF\xC3\xEE\xDD\x8A\xE0\xE2\xC8\x86\xD3\x87\xE9\xE5\xE6\xE7\xE7\xC9\x8F\x05\xDE\xD2\xEC\xE7\x7F\xEA\xB9\xBA\xD8\xFB",
|
|
"\xDB\xEA\xEF\xE9\xDE\xDD\xE0\xDF\xFC\xDA\x89\x80\xED\xF0\xD0\xC3\xE7\xE4\x8B\xF6\xE8\xF5\xF7\xE3\xDC\xE3\xF0\xFE\xF3\xF9\xF8\xEF\xD6\xF2\xF9\xFA\xD8\xC6\xF0\xF7\xFB\xE9\x7C\x6D\x78\x00\x03\xBA\x79\x76\x61\xE8\x41\x8A\x83\x82\x0C\x8D\x8E\x83\x83\x10\x91\x82\x87\x84\x14\x95\x86\x85\x7A\x11\x04\x49\x86\x75\x1B\x80\x0D\x87\x83\x1D\xA1\x8A\x87\x88\x01\x62\x8B\x7C\x71\x1F\xBA\x69\x89\x6F\x12\x04\x4D\x89\x40\x2F\x80\x01\x8F\x8C\x2E\xB5\x81\x43\x04\x36\xB2\x89\x8C\x8D\x30\xBB\x89\x8F\x6E\x31\x80\x9E\x8D\x8F\x44\xBA\x85\x90\x8F\x46\x89\x98\x93\x92\x3F\xBA\x64\x04\x41\x4F\x81\x41\x94\x00\x53\x95\x90\x97\x95\x52\x98\x90\x01\x05\x5A\x96\x99\x97\x97\x54\x9A\x9B\x6F\x94\x63\x9D\x96\x98\x98\x5E\xA1\x98\x9B\x99\x6A\xAD\x99\x9A\x81\xBF\x74\x77\x83\x75\xF6\x75\x77\x88\x9D\x77\x89\x84\x77\x7F\x77\x8B\x83\x81\x81\xF8\x73\x9A\x9E\x61\x16\x04\x45\xA2\x75\x87\xB3\x99\xA3\x85\x8C\x8D\xAE\xA3\xA3\x90\x91\xA2\xA7\xA4\x94\x95\xA6\xA5\xA4\x17\x00\x87\xA5\x7A\x18\x1A\xAB\xA7\xA7\xA0\x95\xA3\xA0\x9E\x82\xB5\x95\xAA\x9D\x73\xB0\x9B\x9D\x9F",
|
|
"\x81\xA3\xAE\x9C\x9F\x04\xB0\xAA\xA8\x82\x9E\xA1\xA6\xAF\xAD\xB8\xBF\x36\x8B\x9C\xBB\xA0\x84\x8A\x87\xBF\xBB\xAB\x89\x73\xC3\x83\xB2\x93\x91\x43\x8A\x99\x8C\x8E\xC8\x8D\xBA\xB2\xB3\x41\xBA\x61\xB6\x61\x4C\x90\xB9\xB1\xB5\xCF\x99\xB8\x91\xAE\xDC\x9D\xBF\x3D\x9A\xE0\xAC\x91\xB9\x40\x5C\xAB\x96\xBA\x9B\x62\x8E\x93\x7B\xB8\xE8\xA7\xBC\xBB\xBB\xE2\xB5\xAE\xB7\xBC\x96\x89\xAB\xA2\x6E\xF7\x84\xA2\xBC\xBD\xFC\xB7\xA9\x07\xBE\xFD\x81\xC2\xC1\x72\x1A\x00\xC2\xA7\x06\x04\x48\xC1\x42\xC2\x00\x0C\xCE\xC1\xC2\x10\xCB\xC1\xC5\xC3\x13\xDC\x03\xC7\xC3\x12\xD9\xC4\xC6\xC6\x18\xDB\xCE\xC5\xC7\x20\xD7\xC2\xC8\xC7\x23\xDE\xC3\xC3\xA7\x1D\x06\xCD\xA1\xC8\x24\xED\xCF\xC5\xC9\x0C\xD6\xCE\xC8\xCB\x2F\xF3\xC0\xCF\xCD\x36\xF9\xC5\xCE\xC9\xBA\x5E\x04\x42\xCF\x01\x40\xD0\x02\xD0\x44\xFF\xC6\xD1\xD0\x47\xC3\xD9\xD0\x47\x48\xCD\xDA\xD2\xD3\x45\xD0\xD9\xD1\xD4\x4F\xD5\xD4\xD7\xD5\x53\xD9\xD2\xD6\xD3\x27\xCC\xAE\x44\xAB\xB7\xB4\xC2\xD8\xCE\x3B\xF2\xCB\xCF\xD8\x3A\xE8\xD7\xD8\xD9\x6A\xDD\xCB\x6D\x48\x01\x70\xD0\x02\xDC\x74\xE2\x41\xDE\xDD\x73",
|
|
"\xF8\xD5\xDF\xDD\x7C\xF9\xDD\xDF\xDE\x7E\xC1\xE4\x4B\xDF\x7A\xC5\xE4\xE3\xE1\x81\xC0\xEA\xE0\xDE\x5D\xF9\xA7\x48\xD8\x14\xAD\xDC\xD8\xD9\x66\xD2\xE9\xDB\xE4\x97\xD9\xEB\xDA\xC6\x8D\xDD\xEE\xE5\xB7\x24\x2A\xCF\xE7\xE8\x13\xA5\x02\xE8\x74\x29\x40\x09\xEB\xEA\x28\x6D\xE6\x42\xEB\xAA\xF0\xEC\xEB\xEB\xB4\xF1\xE5\xEF\xEC\xB6\xF9\xE8\xEF\xEE\xB2\xFD\xE7\xEC\xEC\x2C\x7A\xEE\xED\xEE\xBB\x7C\xEF\xEF\xF1\xC2\xC8\xF6\xF1\xF2\xCC\xCB\xFE\xF3\xF0\xCF\xF5\xE1\xF1\xF4\xC4\xFA\x6E\x49\x4B\x04\x57\xF0\x02\xF6\xDC\xD9\xFE\xF4\xF6\xE0\xDB\xFF\xF6\xF8\xE1\xDD\xF5\xFB\xF8\xE6\xE4\xFA\xF9\xFA\xEC\xE8\xFE\xF9\x40\x29\x2F\xFB\xFB\xF8\xC5\xD0\xF6\xFE\xF2\xF7\xCD\xF9\xFC\xF5\xFC\xFB\xFB\x4A\xFF\xB5\x7B\x36\x0A\x04\x23\x81\x80\x05\x80\x00\x07\x89\x80\x01\x8B\x86\x80\x06\x88\x86\x81\x0A\x8D\x82\x04\x8F\x83\x83\x08\x80\x03\x05\x10\x99\x81\x05\x9A\x84\x83\x0E\x96\x87\x83\x1C\x95\x7C\xFE\x23\x8A\x7E\x12\xBD\x7E\x84\x00\x85\x86\x0A\xD3\x79\x84\xD2\x6E\x82\x41\xFE\x1F\x1B\x1A\x00\x04\x00\x04\x30\x25\x20\x34\x92\x22\x0E\xA6\x31\x36\xCB\x01\x23",
|
|
"\x39\x00\x00\x88\x10\xC6\x38\x87\xD5\x01\x21\x38\x00\x05\x35\x10\x9E\x35\x32\x8C\x01\x21\x33\x00\x08\x88\x14\xC4\x88\x89\x2A\x8E\x89\x8A\x57\x96\x8B\x11\xD9\x87\x32\x2D\x98\x8B\x8B\x60\x9F\x8A\x18\xC8\x83\x32",
|
|
};
|
|
vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|