/*********************************************************************** 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; using namespace astins_slots; /*********************************************************************** 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 SlotValue& value, bool weakAssignment) { value.Apply(Overloading( [&](const TokenSlot& tokenSlot) { if (weakAssignment) { throw AstInsException( L"Weak assignment only available for field of enum type", AstInsErrorType::FieldWeakAssignmentOnNonEnum, field ); } SetField(object, field, tokenSlot.token, tokenSlot.index); }, [&](const EnumItemSlot& enumItemSlot) { SetField(object, field, enumItemSlot.value, weakAssignment); }, [&](const Ptr< ParsingAstBase>& objectSlot) { if (weakAssignment) { throw AstInsException( L"Weak assignment only available for field of enum type", AstInsErrorType::FieldWeakAssignmentOnNonEnum, field ); } SetField(object, field, objectSlot); } )); } void AstInsReceiverBase::Execute(AstIns instruction, const regex::RegexToken& token, vint32_t tokenIndex) { EnsureContinuable(); try { switch (instruction.type) { case AstInsType::Token: case AstInsType::EnumItem: case AstInsType::StackSlot: { if (stackFrames.Count() == 0) { throw AstInsException( L"There is no stack frame to store slot values.", AstInsErrorType::NoStackFrame ); } auto&& frame = stackFrames[stackFrames.Count() - 1]; SlotValue slotValue; switch (instruction.type) { case AstInsType::Token: slotValue = SlotValue(TokenSlot{ token,tokenIndex }); break; case AstInsType::EnumItem: slotValue = SlotValue(EnumItemSlot{ instruction.param }); break; case AstInsType::StackSlot: { if (creatingObjects.Count() == 0) { throw AstInsException( L"There is no creating object to store in a stack slot.", AstInsErrorType::NoCreatingObjectForStackSlot ); } auto astNode = creatingObjects[creatingObjects.Count() - 1].object; creatingObjects.RemoveAt(creatingObjects.Count() - 1); slotValue = SlotValue(astNode); if (frame.codeRangeStart > astNode->codeRange.start) { frame.codeRangeStart = astNode->codeRange.start; } } break; default:; } auto keyIndex = frame.slots.Keys().IndexOf(instruction.count); if (keyIndex == -1) { SlotStorage storage; storage.value = slotValue; frame.slots.Add(instruction.count, storage); } else { auto&& storage = const_cast(frame.slots.Values()[keyIndex]); if (!storage.additionalValues) { storage.additionalValues = Ptr(new List); } storage.additionalValues->Add(slotValue); } } break; case AstInsType::StackBegin: { stackFrames.Add({ {},ParsingTextPos::Start(&token) }); } break; case AstInsType::CreateObject: { if (stackFrames.Count() == 0) { throw AstInsException( L"There is no stack frame to store slot values.", AstInsErrorType::NoStackFrame ); } auto&& frame = stackFrames[stackFrames.Count() - 1]; auto astNode = CreateAstNode(instruction.param); astNode->codeRange = { &token,&token }; if (astNode->codeRange.start > frame.codeRangeStart) { astNode->codeRange.start = frame.codeRangeStart; } CreatingObject info; info.object = astNode; info.type = instruction.param; creatingObjects.Add(info); } break; case AstInsType::Field: case AstInsType::FieldIfUnassigned: { if (creatingObjects.Count() == 0) { throw AstInsException( L"There is no creating object to assign fields.", AstInsErrorType::NoCreatingObjectForField, instruction.param ); } if (stackFrames.Count() == 0) { throw AstInsException( L"There is no stack frame to provide values for field assignment.", AstInsErrorType::NoStackFrame ); } auto&& frame = stackFrames[stackFrames.Count() - 1]; auto slotKeyIndex = frame.slots.Keys().IndexOf(instruction.count); if (slotKeyIndex == -1) { break; } auto storage = frame.slots.Values()[slotKeyIndex]; auto object = creatingObjects[creatingObjects.Count() - 1].object.Obj(); const bool weakAssignment = instruction.type == AstInsType::FieldIfUnassigned; auto assignValue = [&](const SlotValue& slotValue) { SetField(object, instruction.param, slotValue, weakAssignment); }; SetField(object, instruction.param, storage.value, weakAssignment); if (storage.additionalValues) { for (auto&& additionalValue : *storage.additionalValues.Obj()) { SetField(object, instruction.param, additionalValue, weakAssignment); } } } break; case AstInsType::StackEnd: { if (stackFrames.Count() == 0) { throw AstInsException( L"There is no stack frame to end.", AstInsErrorType::NoStackFrameForStackEnd ); } if (creatingObjects.Count() == 0) { throw AstInsException( L"There is no creating object when ending the current stack frame.", AstInsErrorType::NoCreatingObjectForStackEnd ); } auto&& frame = stackFrames[stackFrames.Count() - 1]; auto astNode = creatingObjects[creatingObjects.Count() - 1].object.Obj(); if (astNode->codeRange.start > frame.codeRangeStart) { astNode->codeRange.start = frame.codeRangeStart; } auto codeRangeEnd = ParsingTextPos::End(&token); if (astNode->codeRange.end < codeRangeEnd) { astNode->codeRange.end = codeRangeEnd; } stackFrames.RemoveAt(stackFrames.Count() - 1); } break; case AstInsType::ResolveAmbiguity: { if (stackFrames.Count() == 0) { throw AstInsException( L"There is no stack frame to resolve ambiguity.", AstInsErrorType::NoStackFrame ); } auto&& frame = stackFrames[stackFrames.Count() - 1]; auto slotKeyIndex = frame.slots.Keys().IndexOf(ResolveAmbiguitySlotIndex); if (slotKeyIndex == -1) { throw AstInsException( L"There are not enough candidates to create an ambiguity node.", AstInsErrorType::MissingAmbiguityCandidate ); } auto storage = frame.slots.Values()[slotKeyIndex]; vint candidateCount = 1; if (storage.additionalValues) { candidateCount += storage.additionalValues->Count(); } if (candidateCount < 2) { throw AstInsException( L"There are not enough candidates to create an ambiguity node.", AstInsErrorType::MissingAmbiguityCandidate ); } Array> candidates(candidateCount); auto readCandidate = [&](const SlotValue& slotValue, vint index) { slotValue.Apply(Overloading( [&](const TokenSlot&) { throw AstInsException( L"Tokens cannot be ambiguity candidates.", AstInsErrorType::AmbiguityCandidateIsNotObject ); }, [&](const EnumItemSlot&) { throw AstInsException( L"Enum items cannot be ambiguity candidates.", AstInsErrorType::AmbiguityCandidateIsNotObject ); }, [&](const Ptr& objectSlot) { candidates[index] = objectSlot; } )); }; readCandidate(storage.value, 0); if (storage.additionalValues) { for (vint i = 0; i < storage.additionalValues->Count(); i++) { readCandidate(storage.additionalValues->Get(i), i + 1); } } auto resolved = ResolveAmbiguity(instruction.param, candidates); CreatingObject info; info.object = resolved; info.type = instruction.param; creatingObjects.Add(info); } break; } } catch (const AstInsException&) { corrupted = true; throw; } } Ptr AstInsReceiverBase::Finished() { EnsureContinuable(); try { if (stackFrames.Count() > 0 || creatingObjects.Count() != 1) { throw AstInsException( L"No more instruction but the root object has not been completed yet.", AstInsErrorType::InstructionNotComplete ); } auto object = creatingObjects[0].object; creatingObjects.RemoveAt(0); finished = true; return object; } catch (const AstInsException&) { corrupted = true; throw; } } /*********************************************************************** IAstInsReceiver (Code Generation Error Templates) ***********************************************************************/ Ptr 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"\" cannot be assigned with 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"\" cannot be assigned with 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"\" cannot be assigned with an enum item."), AstInsErrorType::ObjectTypeMismatchedToField, field); } else { throw AstInsException(L"The field id does not exist.", vl::glr::AstInsErrorType::UnknownField, field); } } Ptr 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()) { auto loader = Ptr(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 recorder) { recorders.Add(recorder); } void ParsingMultiplePrintNodeRecorder::Record(ParsingAstBase* node, const ParsingTextRange& range) { for (auto recorder : recorders) { recorder->Record(node, range); } } /*********************************************************************** ParsingOriginalLocationRecorder ***********************************************************************/ ParsingOriginalLocationRecorder::ParsingOriginalLocationRecorder(Ptr _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 _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; BEGIN_SERIALIZATION(AstIns) SERIALIZE(type) SERIALIZE(param) SERIALIZE(count) END_SERIALIZATION BEGIN_SERIALIZATION(InstructionArray) SERIALIZE(start) SERIALIZE(count) END_SERIALIZATION BEGIN_SERIALIZATION(StringLiteral) SERIALIZE(start) SERIALIZE(count) END_SERIALIZATION BEGIN_SERIALIZATION(CompetitionArray) SERIALIZE(start) SERIALIZE(count) END_SERIALIZATION BEGIN_SERIALIZATION(CompetitionDesc) SERIALIZE(competitionId) SERIALIZE(highPriority) 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(competitions) SERIALIZE(ruleType) SERIALIZE(insAfterInput) END_SERIALIZATION BEGIN_SERIALIZATION(EdgeDesc) SERIALIZE(fromState) SERIALIZE(toState) SERIALIZE(condition) SERIALIZE(competitions) SERIALIZE(insAfterInput) SERIALIZE(returnIndices) END_SERIALIZATION BEGIN_SERIALIZATION(StateDesc) SERIALIZE(rule) SERIALIZE(endingState) END_SERIALIZATION BEGIN_SERIALIZATION(Executable) SERIALIZE(tokenCount) SERIALIZE(ruleCount) SERIALIZE(ruleStartStates) SERIALIZE(transitions) SERIALIZE(astInstructions) SERIALIZE(returnIndices) SERIALIZE(competitions) SERIALIZE(returns) SERIALIZE(edges) SERIALIZE(states) SERIALIZE(stringLiteralBuffer) 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 ***********************************************************************/ #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnull-dereference" #elif defined (__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnull-dereference" #endif ErrorArgs ErrorArgs::UnrecognizedToken(const regex::RegexToken& token) { return { true, ErrorType::UnrecognizedToken, token.codeIndex, const_cast(token), *static_cast*>(nullptr), *static_cast(nullptr), nullptr, nullptr }; } ErrorArgs ErrorArgs::InvalidToken(regex::RegexToken& token, collections::List& tokens, automaton::Executable& executable, automaton::IExecutor* executor) { return { true, ErrorType::InvalidToken, token.codeIndex, token, tokens, executable, executor, nullptr }; } ErrorArgs ErrorArgs::InputIncomplete(vint codeIndex, collections::List& tokens, automaton::Executable& executable, automaton::IExecutor* executor) { return { true, ErrorType::InputIncomplete, codeIndex, *static_cast(nullptr), tokens, executable, executor, nullptr }; } ErrorArgs ErrorArgs::UnexpectedAstType(collections::List& tokens, automaton::Executable& executable, automaton::IExecutor* executor, Ptr ast) { return { true, ErrorType::UnexpectedAstType, ast->codeRange.codeIndex, *static_cast(nullptr), tokens, executable, executor, ast }; } #if defined (__clang__) #pragma clang diagnostic pop #elif defined (__GNUC__) #pragma GCC diagnostic pop #endif 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); }); } }; /*********************************************************************** JsonFormatting ***********************************************************************/ JsonFormatting::JsonFormatting() : indentation(L" ") { } /*********************************************************************** JsonIsCompactVisitor ***********************************************************************/ class JsonIsCompactVisitorBase : public Object, public JsonNode::IVisitor { public: bool result = true; void Visit(JsonLiteral* node) override { } void Visit(JsonString* node) override { } void Visit(JsonNumber* node) override { } }; class JsonIsCompactFieldVisitor : public JsonIsCompactVisitorBase { public: void Visit(JsonArray* node) override { result = node->items.Count() == 0; } void Visit(JsonObject* node) override { result = node->fields.Count() == 0; } }; class JsonIsCompactVisitor : public JsonIsCompactVisitorBase { public: void Visit(JsonArray* node) override { for (auto item : node->items) { JsonIsCompactFieldVisitor visitor; item->Accept(&visitor); if (!visitor.result) { result = false; break; } } } void Visit(JsonObject* node) override { for (auto field : node->fields) { JsonIsCompactFieldVisitor visitor; field->value->Accept(&visitor); if (!visitor.result) { result = false; break; } } } }; /*********************************************************************** JsonPrintVisitor ***********************************************************************/ class JsonPrintVisitor : public Object, public JsonNode::IVisitor { public: JsonFormatting formatting; TextWriter& writer; vint indent = 0; JsonPrintVisitor(JsonFormatting _formatting, TextWriter& _writer) : formatting(_formatting) , writer(_writer) { } void WriteIndentation() { for (vint i = 0; i < indent; i++) { writer.WriteString(formatting.indentation); } } bool IsCompact(JsonNode* node) { JsonIsCompactVisitor visitor; node->Accept(&visitor); return visitor.result; } 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 AfterOpeningObject(bool insertCrlf) { if (insertCrlf) { writer.WriteString(L"\r\n"); indent++; } } void BeforeClosingObject(bool insertCrlf) { if (insertCrlf) { indent--; WriteIndentation(); } } void BeforeChildNode(bool insertCrlf) { if (insertCrlf) WriteIndentation(); } void AfterChildNode(bool insertCrlf, bool lastNode) { if (!lastNode) { if ((!insertCrlf || !formatting.crlf) && formatting.spaceAfterComma) { writer.WriteString(L", "); } else { writer.WriteChar(L','); } } if (insertCrlf) writer.WriteString(L"\r\n"); } void Visit(JsonArray* node) override { writer.WriteChar(L'['); if (node->items.Count() > 0) { bool insertCrlf = formatting.crlf && !(formatting.compact && IsCompact(node)); AfterOpeningObject(insertCrlf); for (auto [item, i] : indexed(node->items)) { BeforeChildNode(insertCrlf); item->Accept(this); AfterChildNode(insertCrlf, i == node->items.Count() - 1); } BeforeClosingObject(insertCrlf); } writer.WriteChar(L']'); } void Visit(JsonObject* node) override { writer.WriteChar(L'{'); if (node->fields.Count() > 0) { bool insertCrlf = formatting.crlf && !(formatting.compact && IsCompact(node)); AfterOpeningObject(insertCrlf); for (auto [field, i] : indexed(node->fields)) { BeforeChildNode(insertCrlf); writer.WriteChar(L'\"'); JsonEscapeString(field->name.value, writer); if (formatting.spaceAfterColon) { writer.WriteString(L"\": "); } else { writer.WriteString(L"\":"); } field->value->Accept(this); AfterChildNode(insertCrlf, i == node->fields.Count() - 1); } BeforeClosingObject(insertCrlf); } writer.WriteChar(L'}'); } }; /*********************************************************************** API ***********************************************************************/ Ptr JsonParse(const WString& input, const Parser& parser) { auto ast = parser.ParseJRoot(input); JsonUnescapeVisitor().InspectInto(ast.Obj()); return ast; } void JsonPrint(Ptr node, stream::TextWriter& writer, JsonFormatting formatting) { JsonPrintVisitor visitor(formatting, writer); node->Accept(&visitor); } WString JsonToString(Ptr node, JsonFormatting formatting) { return GenerateToStream([&](StreamWriter& writer) { JsonPrint(node, writer, formatting); }); } } } } /*********************************************************************** .\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::glr::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::reflection::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(), 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(), 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(), 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(), 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(), 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(), 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()) { auto loader = Ptr(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::glr::json::builder { /*********************************************************************** MakeArray ***********************************************************************/ MakeArray& MakeArray::items(const vl::Ptr& 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& 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& 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::glr::json::copy_visitor { void AstVisitor::CopyFields(JsonArray* from, JsonArray* to) { CopyFields(static_cast(from), static_cast(to)); for (auto&& listItem : from->items) { to->items.Add(CopyNode(listItem.Obj())); } } void AstVisitor::CopyFields(JsonLiteral* from, JsonLiteral* to) { CopyFields(static_cast(from), static_cast(to)); to->value = from->value; } void AstVisitor::CopyFields(JsonNode* from, JsonNode* to) { } void AstVisitor::CopyFields(JsonNumber* from, JsonNumber* to) { CopyFields(static_cast(from), static_cast(to)); to->content = from->content; } void AstVisitor::CopyFields(JsonObject* from, JsonObject* to) { CopyFields(static_cast(from), static_cast(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(from), static_cast(to)); to->content = from->content; } void AstVisitor::Visit(JsonObjectField* node) { auto newNode = vl::Ptr(new JsonObjectField); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(JsonLiteral* node) { auto newNode = vl::Ptr(new JsonLiteral); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(JsonString* node) { auto newNode = vl::Ptr(new JsonString); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(JsonNumber* node) { auto newNode = vl::Ptr(new JsonNumber); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(JsonArray* node) { auto newNode = vl::Ptr(new JsonArray); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(JsonObject* node) { auto newNode = vl::Ptr(new JsonObject); CopyFields(node, newNode.Obj()); this->result = newNode; } vl::Ptr AstVisitor::CopyNode(JsonNode* node) { if (!node) return nullptr; node->Accept(static_cast(this)); this->result->codeRange = node->codeRange; return this->result.Cast(); } vl::Ptr AstVisitor::CopyNode(JsonObjectField* node) { if (!node) return nullptr; Visit(node); this->result->codeRange = node->codeRange; return this->result.Cast(); } vl::Ptr AstVisitor::CopyNode(JsonArray* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(JsonLiteral* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(JsonNumber* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(JsonObject* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(JsonString* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } } /*********************************************************************** .\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::glr::json::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::glr::json::json_visitor { void AstVisitor::PrintFields(JsonArray* node) { BeginField(vl::WString::Unmanaged(L"items")); BeginArray(); for (auto&& listItem : node->items) { BeginArrayItem(); Print(listItem.Obj()); EndArrayItem(); } EndArray(); EndField(); } void AstVisitor::PrintFields(JsonLiteral* node) { BeginField(vl::WString::Unmanaged(L"value")); switch (node->value) { case vl::glr::json::JsonLiteralValue::False: WriteString(vl::WString::Unmanaged(L"False")); break; case vl::glr::json::JsonLiteralValue::Null: WriteString(vl::WString::Unmanaged(L"Null")); break; case vl::glr::json::JsonLiteralValue::True: WriteString(vl::WString::Unmanaged(L"True")); break; default: WriteNull(); } EndField(); } void AstVisitor::PrintFields(JsonNode* node) { } void AstVisitor::PrintFields(JsonNumber* node) { BeginField(vl::WString::Unmanaged(L"content")); WriteToken(node->content); EndField(); } void AstVisitor::PrintFields(JsonObject* node) { BeginField(vl::WString::Unmanaged(L"fields")); BeginArray(); for (auto&& listItem : node->fields) { BeginArrayItem(); Print(listItem.Obj()); EndArrayItem(); } EndArray(); EndField(); } void AstVisitor::PrintFields(JsonObjectField* node) { BeginField(vl::WString::Unmanaged(L"name")); WriteToken(node->name); EndField(); BeginField(vl::WString::Unmanaged(L"value")); Print(node->value.Obj()); EndField(); } void AstVisitor::PrintFields(JsonString* node) { BeginField(vl::WString::Unmanaged(L"content")); WriteToken(node->content); EndField(); } void AstVisitor::Visit(JsonLiteral* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Literal"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(JsonString* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"String"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(JsonNumber* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Number"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(JsonArray* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Array"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(JsonObject* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Object"), node); PrintFields(static_cast(node)); PrintFields(static_cast(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(this)); } void AstVisitor::Print(JsonObjectField* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"ObjectField"), node); PrintFields(static_cast(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::glr::json::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(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(JsonString* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(node->content); Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(JsonNumber* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(node->content); Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(JsonArray* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); for (auto&& listItem : node->items) { InspectInto(listItem.Obj()); } Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(JsonObject* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); for (auto&& listItem : node->fields) { InspectInto(listItem.Obj()); } Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::InspectInto(JsonNode* node) { if (!node) return; node->Accept(static_cast(this)); } void AstVisitor::InspectInto(JsonObjectField* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(node->name); InspectInto(node->value.Obj()); Finishing(static_cast(node)); Finishing(static_cast(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::glr::json { void JsonParserData(vl::stream::IStream& outputStream) { static const vl::vint dataLength = 1790; // 16729 bytes before compressing static const vl::vint dataBlock = 256; static const vl::vint dataRemain = 254; static const vl::vint dataSolidRows = 6; static const vl::vint dataRows = 7; static const char* compressed[] = { "\x59\x41\x00\x00\xF6\x06\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\x42\x2A\x41\x4A\x57\x6E\xC2\x40\xCD\xAB\x76\xC1\x40\xCE\xB7\x7A\xC0\x00\xCF\xBC\x7E\xC0\xD3\x72\x3E\xEB\x41\x42\xD1\x00\x08\xDF\x4D\xA5\xBC\x60\x5C\xD3\xD1\x0A\x56\x69\xCC\x4C\x48\xC3\xD9\xD2\x4F\x60\x8E\xDA\x7F\xD3\x00\x12\xDD\xCC\xD5\x21\x5C\xDB\xD3\xD6\xAB\x5A\xD3\x40\xD2\x48\xDE\xD1\xD0\x4C\x63\xC3\x4C\x4F\x55\x66\xF7\xC1\xDA\x41\x6A\xC4\xDC\xDA\x42\x08", "\x65\xD8\xDF\xDC\x03\x75\xDD\x73\x4C\x56\xF3\x42\xD0\x5B\x83\xF5\xCC\xC5\xE0\x82\xD6\xCB\xCC\xE1\x87\xCC\xEA\xE3\xCF\x8E\xEE\xB8\xE1\xE2\x14\xED\xD2\x41\xDC\xCB\x58\xE0\x02\xE5\x61\xDA\xEA\xE6\xD5\x7E\xD4\xE7\x8D\xD5\x91\xD4\xCA\x6F\xDB\x06\x53\xE2\xE8\xCC\x8B\xC6\xEF\xE0\xE7\x9B\xEC\x5A\xE4\xEA\x67\xD1\xD5\xEA\x93\xB4\xF3\xD0\xE3\xCC\xB7\xE6\xCA\xEA\xE8\x56\xBF\xE4\xE5\xF0\xBD\xEC\xE0\xE6\xEB\x92\xC5\xF6\x97\xE9\xBC\xC8\xF4\xC6\xF0\x89\xC4\xFE\xF1\xC8\xD0\xC2\xE2\xF7\xD4\x8F\xD5\xF5\xE0\xF6\xC9\xD3\xFE\xEE\xF2\xE9\x70\xEA\x6E\xE6\x22\x76\xEE\xF7\x9E\xB9\xE1\xDB\xED\x42\xDA\xCD\xE7\xFB\xF5\x5F\xD9\xF0\xFB\x7A\xED\xF2\xFF\xF9\x7A\xF5\xEE\xB1\xEB\xEA\x19\x7B\xFC\xFE\xFF\xAB\x79\x7F\xF3\x73\x74\x4C\x00\xA2\x76\x80\x94\x69\x7D\x73\x56\x62\x80\x8D\x0D\x81\x23\x0F\x9F\x1E\x02\xB3\x28\x69\x09\xA0\x69\x21\x16\x8D\x25\x05\xEC\x24\x75\xF3\x51\x82\x5D\x7C\x70\x69\x08\xD7\x63\x84\xA4\x5D\x26\x6A\x3B\x23\x84\x09\xA1\x8A\x68\x85\x1A\x71\x6F\xB5\x69\x20\x0C\x82\x28\x69\x19\xA2\x86\x20\x36\x87\x78\x0E\x8A\x2A\x81\x1C\xB5\x85", "\x3C\x7E\x69\x6C\x10\xC3\x8C\x7C\xF3\x46\x22\x81\x41\x86\x89\x0C\xE4\x6B\x89\x26\xB2\x68\x83\xE5\x28\x6A\x6B\x09\x25\x39\x11\xA4\x39\x21\xB0\x77\x88\x99\x1D\x28\x0F\xF2\x1D\x21\x50\xEB\x2A\x81\x1E\x65\x36\x6A\x49\x61\x8A\x21\x7A\x05\x3E\x02\xF7\x47\x8D\x84\x3B\x09\x8A\x0A\x28\x43\x7A\x1D\x2C\x0E\x38\x89\x22\x8E\x5B\x8A\x21\x1F\x65\x30\x77\x2F\x73\x8A\x21\x7E\x1C\x8E\x42\x7E\x89\x8F\x84\x3F\x0C\x8C\x0A\x3C\x51\x1B\x86\x20\x10\x35\x8A\x21\x53\x8B\x83\x21\x20\x65\x3C\x06\x15\xB0\x76\x67\x27\x89\x3D\x26\x92\x6D\x79\xD4\x5A\x94\x87\x2A\x7D\x20\xEC\x55\x7A\x84\x00\x1A\x76\x67\x39\x84\x96\x0A\xB9\x8E\x67\x29\x9E\x94\x7E\x29\x63\x3C\xD6\x11\x94\x87\x50\x8A\x26\x3F\x58\x81\x7D\x2C\x86\x2B\x40\x83\x17\x93\x34\x9A\x68\x6A\xCF\x53\x40\x8B\xF5\x3E\x86\x96\x09\x34\x4D\x31\x85\x8A\x21\xFB\x1C\x91\x21\x66\x8F\x94\x99\x55\x8E\x96\x64\x86\x27\x52\x45\x83\x86\xD5\x54\x98\x24\x6B\x83\x22\x91\xD2\x9D\x99\x36\x86\x2C\x9A\x81\x19\x86\x5D\xA1\x43\x9F\x40\x23\x94\x39\x5B\x9E\x9A\x20\xA7\x4A\x9F\x5E\x72\x91\x21\x72\x81\x26\x45\xCF\x86", "\x23\xAA\x74\x90\x00\x57\xA2\x9C\x9C\x2E\x8F\x9F\xAB\x1D\x93\x20\x2D\xBF\x9B\x20\xF6\x84\x22\x40\x80\x06\x56\x7E\xB9\x3F\xA0\x02\x26\xA2\x40\x7E\x97\x63\x8E\x08\x59\x97\xF6\x2D\x9D\x3E\x83\x24\x5A\xAE\x4F\x3F\xA1\x02\x38\x95\xC9\x4C\x36\x5A\x7E\x8F\x3A\xA4\x03\x26\x43\x46\x82\x2C\x5A\x8F\xA3\x30\xA5\x02\x2E\x9B\x48\x9D\x2E\x5A\x7E\xB0\xA7\x86\x03\x21\x41\x42\x32\xAF\x65\x8E\x34\x5C\x9F\x3A\xAC\x8A\x40\x2A\xA6\x20\xFE\x2B\xA1\x20\x0D\x6B\x9A\x92\x78\x89\xA5\x85\xA8\x66\xA5\xA5\x2C\xAA\x40\x41\xAD\xA6\x85\x15\x90\xAA\xA7\x3D\x97\x40\x78\x93\xA6\x85\x3D\x04\xA0\x66\x5C\xAB\x3A\x8B\xAF\x06\xB0\x81\x24\xA8\x10\xB7\x9E\x59\xA2\x61\x35\x20\x2B\xAA\xAB\x4F\x86\x22\x58\xE6\x9B\xA1\x21\x2B\xAB\xAE\xAD\x72\xAE\x3B\xC7\xA0\x01\x22\x2B\xAC\x98\xE1\x82\x20\x5E\x80\x03\xB0\x9F\x47\x0B\xAD\x62\x41\xB2\x5A\x89\x20\xB1\xAA\x89\x21\x09\xB1\x43\xB3\x29\x9C\x6A\x09\xB5\xAC\x8A\xB1\x84\xBB\x6C\x5F\xCC\x0B\xAD\x68\xA9\xAB\x49\xB3\x9D\xA9\x42\x4E\x0B\xAC\x6C\x98\xB4\x49\x26\xBC\x60\x14\x6B\xA0\x9D\xCF\xA8\xB7\x88\x0B\xB2\x0B\x5A\xE9", "\x97\xB5\xBD\xA2\xB6\x20\x54\x0B\xAD\x3C\xB5\xB9\x21\xC2\x9C\x66\x0A\x6B\xBB\x9C\x6F\xDF\x2B\xA0\x2C\x2B\xA8\x56\xFC\x8F\xB7\x40\x2C\x9C\x62\x2D\x2B\xAD\xA1\x98\xAD\xB2\x40\x24\x4C\xAE\x2E\x20\x93\x3D\x84\x83\x22\x74\x9B\x65\x35\x2F\x31\x51\xBB\x02\x2A\xB9\x45\x8A\x20\x0D\x58\x49\xB3\xAC\x7C\xA1\x0F\x5A\x97\xA2\xA9\x80\x27\xB9\xAE\x8E\xA6\x23\x18\x6B\xAA\x58\xAE\x6F\xB9\x20\xE7\x94\x61\x19\x6B\xA0\x5A\xFB\xB6\xB1\xBE\x03\x27\x0F\x5A\xD2\x5E\xBF\xDE\x8B\xA1\x0D\x6B\xBD\xA1\x7B\x80\x07\xBE\x53\x8B\xA3\x0D\x6B\xA5\xA7\x82\x8D\xCC\xB9\xC7\x6D\x0B\xAD\xD8\x5C\x6B\x65\x83\x2A\x99\xDB\x83\x27\x0D\xB1\x40\x8E\x41\x1D\xC0\xC0\x81\x30\x09\x56\x9E\xA2\x20\x89\xE3\xB9\x21\x38\x31\x54\x52\x06\x37\xA4\x5B\xB3\x32\x0F\xB5\xAD\xA3\xC1\x30\xDB\xAB\x42\xF4\x0B\xAD\x9A\x8B\xC0\x92\xD7\x8B\xA2\x1D\x31\x5D\xB4\x81\x26\xB5\xC4\x01\x37\x0D\xAC\x1E\x55\x94\x99\x0D\xCF\xC9\x61\x66\x86\x30\xD2\xC5\x7D\xB5\xBA\x82\x2D\x28\x99\xCB\x26\xCA\xAE\x6C\x99\x0A\x80\x00\x5F\xC1\xCE\x28\xE3\xC8\x22\xF1\x66\xCD\x23\xE4\x67\x95\x9A\xA5\x90", }; 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]", L"[27][JValue]", L"[28][JValue]", L"[29][JRoot] BEGIN ", L"[30][JRoot] END [ENDING]", L"[31][JRoot]", L"[32][JRoot]", }; return results[index]; } Parser::Parser() : vl::glr::ParserBase(&JsonTokenDeleter, &JsonLexerData, &JsonParserData) { } vl::WString Parser::GetClassName(vl::vint32_t classIndex) const { return vl::WString::Unmanaged(JsonTypeName((JsonClasses)classIndex)); } vl::vint32_t Parser::FindCommonBaseClass(vl::vint32_t class1, vl::vint32_t class2) const { return -1; } vl::Ptr Parser::ParseJRoot(const vl::WString& input, vl::vint codeIndex) const { return ParseWithString(input, this, codeIndex); } vl::Ptr Parser::ParseJRoot(vl::collections::List& tokens, vl::vint codeIndex) const { return ParseWithTokens(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::glr::json { /*********************************************************************** JsonAstInsReceiver : public vl::glr::AstInsReceiverBase ***********************************************************************/ vl::Ptr JsonAstInsReceiver::CreateAstNode(vl::vint32_t type) { auto cppTypeName = JsonCppTypeName((JsonClasses)type); switch((JsonClasses)type) { case JsonClasses::Array: return vl::Ptr(new vl::glr::json::JsonArray); case JsonClasses::Literal: return vl::Ptr(new vl::glr::json::JsonLiteral); case JsonClasses::Number: return vl::Ptr(new vl::glr::json::JsonNumber); case JsonClasses::Object: return vl::Ptr(new vl::glr::json::JsonObject); case JsonClasses::ObjectField: return vl::Ptr(new vl::glr::json::JsonObjectField); case JsonClasses::String: return vl::Ptr(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 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, bool weakAssignment) { auto cppFieldName = JsonCppFieldName((JsonFields)field); switch((JsonFields)field) { case JsonFields::Literal_value: return vl::glr::AssemblerSetEnumField(&vl::glr::json::JsonLiteral::value, object, field, enumItem, weakAssignment, 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 JsonAstInsReceiver::ResolveAmbiguity(vl::vint32_t type, vl::collections::Array>& 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::glr::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\TMINPUT.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { using namespace collections; /*********************************************************************** Initialize ***********************************************************************/ 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 = nullref; initialReturnStackCache = {}; temporaryConditionStack.Clear(); temporaryConditionStackSize = 0; MergeStack_MagicCounter = 0; traceExecs.Clear(); insExecs.Resize(0); insExec_Stacks.Clear(); insExec_InsRefLinks.Clear(); insExec_StackRefLinks.Clear(); insExec_StackArrayRefLinks.Clear(); firstBranchTrace = nullref; firstMergeTrace = nullref; firstStack = nullref; firstStep = nullref; traceAmbiguities.Clear(); traceAmbiguityLinks.Clear(); executionSteps.Clear(); initialTrace = AllocateTrace(); initialTrace->state = startState; concurrentCount = 1; concurrentCountBeforeError.Reset(); concurrentTraces->Add(initialTrace); } /*********************************************************************** GetInitialTrace ***********************************************************************/ Trace* TraceManager::GetInitialTrace() { return initialTrace; } /*********************************************************************** GetInitialTrace ***********************************************************************/ ExecutionStep* TraceManager::GetInitialExecutionStep() { return firstStep == nullref ? nullptr : GetExecutionStep(firstStep); } /*********************************************************************** Input ***********************************************************************/ bool TraceManager::Input(vint32_t currentTokenIndex, regex::RegexToken* token, regex::RegexToken* 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 + (vint32_t)token->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 currentTrace = concurrentTraces->Get(traceIndex); auto stateTrace = EnsureTraceWithValidStates(currentTrace); vint32_t transitionIndex = executable.GetTransitionIndex(stateTrace->state, input); auto&& edgeArray = executable.transitions[transitionIndex]; WalkAlongTokenEdges(currentTokenIndex, input, token, lookAhead, { currentTrace, stateTrace }, edgeArray); } // if competitions happen between new surviving traces // remove traces that known to have lost the competition if (CheckBackupTracesBeforeSwapping(currentTokenIndex)) { // after competition are closed // different surviving traces might be mergable // merge them and remove unnecessary traces TryMergeSurvivingTraces(); } 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); } if (concurrentCount == 0) { bool ambiguityInvolved = false; concurrentCountBeforeError = traceCount; FillSuccessorsAfterEndOfInput(ambiguityInvolved); } return concurrentCount > 0; } /*********************************************************************** FillSuccessorsAfterEndOfInput ***********************************************************************/ void TraceManager::FillSuccessorsAfterEndOfInput(bool& ambiguityInvolved) { ambiguityInvolved = false; List visiting; if (concurrentCountBeforeError) { for (vint i = 0; i < concurrentCountBeforeError.Value(); i++) { visiting.Add(backupTraces->Get(i)); } } else { // create a merge trace for multiple surviving traces if (concurrentCount > 1) { auto newTrace = GetTrace(traces.Allocate()); for (vint32_t traceIndex = 0; traceIndex < concurrentCount; traceIndex++) { auto trace = concurrentTraces->Get(traceIndex); auto first = trace; auto last = trace; if (trace->state == -1) { // a surviving trace could also be a merge trace // in this case we move predecessors to the new trace first = GetTrace(trace->predecessors.first); last = GetTrace(trace->predecessors.last); } if (newTrace->predecessors.first == nullref) { newTrace->predecessors.first = first; newTrace->predecessors.last = last; } else { GetTrace(newTrace->predecessors.last)->predecessors.siblingNext = first; first->predecessors.siblingPrev = newTrace->predecessors.last; newTrace->predecessors.last = last; } } BeginSwap(); AddTrace(newTrace); EndSwap(); } visiting.Add(concurrentTraces->Get(0)); } // fill successors based on predecessors bool initialTraceVisited = false; while (visiting.Count() > 0) { auto current = visiting[visiting.Count() - 1]; visiting.RemoveAt(visiting.Count() - 1); // if (current->predecessorCount != 0) // it means this trace has been processed when comming from another sibling // but initialTrace->predecessorCount is always 0 // so initialTraceVisited is introduced if (current == initialTrace) { if (initialTraceVisited) continue; initialTraceVisited = true; } else if (current->predecessorCount != 0) { continue; } // fill successors { auto predecessorId = current->predecessors.first; while (predecessorId != nullref) { auto predecessor = GetTrace(predecessorId); predecessorId = predecessor->predecessors.siblingNext; current->predecessorCount++; predecessor->successorCount++; AddTraceToCollection(predecessor, current, &Trace::successors); } } // add predecessors to the list to continue { auto predecessorId = current->predecessors.last; while (predecessorId != nullref) { auto predecessor = GetTrace(predecessorId); predecessorId = predecessor->predecessors.siblingPrev; visiting.Add(predecessor); } } // set ambiguityInvolved when a trace has multiple predecessors if (current->predecessorCount > 1) { ambiguityInvolved = true; } } } /*********************************************************************** EndOfInput ***********************************************************************/ bool TraceManager::EndOfInput(bool& ambiguityInvolved) { 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 actualTrace = EnsureTraceWithValidStates(trace); auto& stateDesc = executable.states[actualTrace->state]; if (actualTrace->returnStack == nullref && stateDesc.endingState) { AddTrace(trace); } } EndSwap(); if (concurrentCount == 0) { concurrentCountBeforeError = traceCount; FillSuccessorsAfterEndOfInput(ambiguityInvolved); return false; } FillSuccessorsAfterEndOfInput(ambiguityInvolved); if (!ambiguityInvolved) { state = TraceManagerState::ResolvedAmbiguity; auto step = GetExecutionStep(executionSteps.Allocate()); firstStep = step; auto lastTrace = concurrentTraces->Get(0); TraceInsLists insList; ReadInstructionList(lastTrace, insList); step->et_i.startTrace = initialTrace->allocatedIndex; step->et_i.startIns = 0; step->et_i.endTrace = lastTrace->allocatedIndex; step->et_i.endIns = insList.countAll - 1; } return initialTrace; } } } } /*********************************************************************** .\TRACEMANAGER\TMINPUT_AMBIGUITY.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { using namespace collections; /*********************************************************************** EnsureTraceWithValidStates ***********************************************************************/ Trace* TraceManager::EnsureTraceWithValidStates(Trace* trace) { if (trace->state == -1) { return GetTrace(trace->predecessors.first); } else { return trace; } } /*********************************************************************** AreTwoEndingInputTraceEqual ***********************************************************************/ bool TraceManager::AreTwoEndingInputTraceEqual(Trace* newTrace, Trace* candidate) { // two traces equal to each other if // 1) they are in the same state // 2) they have the same executedReturnStack and returnStack // 3) they are attending same competitions // 4) they have the same switchValues // 5) the candidate has an ending input candidate = EnsureTraceWithValidStates(candidate); if (candidate->byInput != Executable::EndingInput) return false; if (newTrace->state != candidate->state) return false; if (newTrace->executedReturnStack != candidate->executedReturnStack) return false; if (newTrace->returnStack != candidate->returnStack) return false; if (newTrace->competitionRouting.attendingCompetitions != candidate->competitionRouting.attendingCompetitions) return false; return true; } /*********************************************************************** MergeTwoEndingInputTrace ***********************************************************************/ Trace* TraceManager::MergeTwoEndingInputTrace(Trace* newTrace, Trace* candidate) { // goal of this function is to create a structure // NEWTRACE ---+->AMBIGUITY // | // CANDIDATE --+ // if CANDIDATE is not a merged trace // a former trace will copy CANDIDATE and insert before CANDIDATE // and CANDIDATE will be initialized to an empty trace // if a former trace is created to replace the candidate // in which case the candidate becomes a merge trace // the former trace is returned if (candidate->state == -1) { AddTraceToCollection(candidate, newTrace, &Trace::predecessors); return nullptr; } else { auto formerTrace = AllocateTrace(); auto formerTraceId = formerTrace->allocatedIndex; auto candidateId = candidate->allocatedIndex; *formerTrace = *candidate; formerTrace->allocatedIndex = formerTraceId; *candidate = {}; candidate->allocatedIndex = candidateId; AddTraceToCollection(candidate, formerTrace, &Trace::predecessors); AddTraceToCollection(candidate, newTrace, &Trace::predecessors); return formerTrace; } } /*********************************************************************** TryMergeSurvivingTraces ***********************************************************************/ void TraceManager::TryMergeSurvivingTraces() { #define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::TryMergeSurvivingTraces()#" if (concurrentCount == 0) return; struct EndingOrMergeTraceData { bool surviving = true; // becomes false when this trace does not survive anymore }; vint32_t removedTracesCount = 0; Dictionary endingOrMergeTraces; Group endingOrMergeTracesByState; // index surviving traces for (vint32_t i = 0; i < concurrentCount; i++) { auto trace = backupTraces->Get(i); endingOrMergeTraces.Add(trace, {}); if (trace->state == -1) { endingOrMergeTracesByState.Add(EnsureTraceWithValidStates(trace)->state, trace); } else if (trace->byInput == Executable::EndingInput) { endingOrMergeTracesByState.Add(trace->state, trace); } } #if defined VCZH_MSVC && defined _DEBUG // check assumptions for (vint32_t i = 0; i < concurrentCount; i++) { auto trace = backupTraces->Get(i); if (trace->state == -1) { auto predecessorId = trace->predecessors.first; while (predecessorId != nullref) { auto predecessor = GetTrace(predecessorId); predecessorId = predecessor->predecessors.siblingNext; CHECK_ERROR(endingOrMergeTraces.Keys().IndexOf(predecessor) == -1, ERROR_MESSAGE_PREFIX L"Internal error: Predecessors of a merge trace should not survive."); } } else if (trace->byInput == Executable::EndingInput) { CHECK_ERROR(trace->predecessors.first == trace->predecessors.last, ERROR_MESSAGE_PREFIX L"Internal error: Executable::EndingInput trace could not have multiple predecessors."); } } #endif // unsurvive a trace auto unsurviveTrace = [&](Trace* trace, EndingOrMergeTraceData& data) { if (data.surviving) { data.surviving = false; removedTracesCount++; } }; // check if a trace survived // if an Executable::EndingInput trace survived but its only predecessor does not // it becomes not survived auto ensureEndingTraceSurvived = [&](Trace* trace) { if (trace == initialTrace) return true; auto& data = const_cast(endingOrMergeTraces[trace]); if (!data.surviving) return false; if (trace->state != -1) { auto predecessorId = trace->predecessors.first; if (predecessorId != nullref) { auto predecessor = GetTrace(predecessorId); if (!endingOrMergeTraces[predecessor].surviving) { unsurviveTrace(trace, data); } } } return data.surviving; }; // find surviving traces that merge for (vint32_t i = 0; i < concurrentCount; i++) { // get the next surviving Executable::EndingInput trace auto trace = backupTraces->Get(i); if (trace->state != -1 && trace->byInput != Executable::EndingInput) continue; if (!ensureEndingTraceSurvived(trace)) continue; auto realTrace = EnsureTraceWithValidStates(trace); // find all traces Executable::EndingInput traces with the same state that after it auto&& candidates = endingOrMergeTracesByState[realTrace->state]; vint index = candidates.IndexOf(trace); for (vint j = index + 1; j < candidates.Count(); j++) { // ensure the candidate also survived auto candidate = candidates[j]; if (!ensureEndingTraceSurvived(candidate)) continue; auto realCandidate = EnsureTraceWithValidStates(candidate); if (AreTwoEndingInputTraceEqual(realTrace, realCandidate)) { // merge two traces if (trace == realTrace) { // if trace is an ordinary trace if (candidate == realCandidate) { // if candidate is an ordinary trace // turn trace into a merge trace auto formerTrace = MergeTwoEndingInputTrace(candidate, trace); CHECK_ERROR(formerTrace != nullptr, ERROR_MESSAGE_PREFIX L"Internal error: formerTrace should not be null."); realTrace = formerTrace; } else { // if candidate is a merge trace // turn trace into a merge trace // give the rest of predecessors of candidate to trace auto candidateHead = GetTrace(candidate->predecessors.first); auto candidateNextId = candidateHead->predecessors.siblingNext; candidateHead->predecessors.siblingNext = nullref; auto formerTrace = MergeTwoEndingInputTrace(candidateHead, trace); CHECK_ERROR(formerTrace != nullptr, ERROR_MESSAGE_PREFIX L"Internal error: formerTrace should not be null."); realTrace = formerTrace; candidateHead->predecessors.siblingNext = candidateNextId; trace->predecessors.last = candidate->predecessors.last; candidate->predecessors.first = nullref; candidate->predecessors.last = nullref; } } else { // if trace is a merge trace if (candidate == realCandidate) { // if candidate is an ordinary trace // merge candidate into trace auto formerTrace = MergeTwoEndingInputTrace(candidate, trace); CHECK_ERROR(formerTrace == nullptr, ERROR_MESSAGE_PREFIX L"Internal error: formerTrace should be null."); } else { // if candidate is an ordinary trace // give all predecessors of candidate to trace auto traceTail = GetTrace(trace->predecessors.last); auto candidateHead = GetTrace(candidate->predecessors.first); traceTail->predecessors.siblingNext = candidateHead; candidateHead->predecessors.siblingPrev = traceTail; trace->predecessors.last = candidate->predecessors.last; candidate->predecessors.first = nullref; candidate->predecessors.last = nullref; } } auto& data = const_cast(endingOrMergeTraces[candidate]); unsurviveTrace(candidate, data); } } } if (removedTracesCount > 0) { // mark all unsurviving traces for (vint32_t i = 0; i < concurrentCount; i++) { auto trace = backupTraces->Get(i); vint index = endingOrMergeTraces.Keys().IndexOf(trace); if (index == -1) continue; if (endingOrMergeTraces.Values()[index].surviving) continue; backupTraces->Set(i, nullptr); } // clean up surviving trace list vint writing = 0; for (vint32_t i = 0; i < concurrentCount; i++) { auto trace = backupTraces->Get(i); if (!trace) continue; backupTraces->Set(writing++, trace); } concurrentCount -= removedTracesCount; } #undef ERROR_MESSAGE_PREFIX } } } } /*********************************************************************** .\TRACEMANAGER\TMINPUT_COMPETITION.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** AttendCompetition ***********************************************************************/ void TraceManager::AttendCompetition( Trace* trace, Ref& newAttendingCompetitions, Ref& newCarriedCompetitions, Ref returnStack, vint32_t ruleId, CompetitionDesc comp ) { // a competition is defined by its rule, competition id 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; { auto cid = trace->competitionRouting.holdingCompetitions; while (cid != nullref) { auto cpt = GetCompetition(cid); if (cpt->ruleId == ruleId && cpt->competitionId == comp.competitionId) { competition = cpt; break; } cid = cpt->nextHoldCompetition; } } if (!competition) { // create a Competition object competition = AllocateCompetition(); competition->nextHoldCompetition = trace->competitionRouting.holdingCompetitions; trace->competitionRouting.holdingCompetitions = competition; competition->currentTokenIndex = trace->currentTokenIndex; competition->ruleId = ruleId; competition->competitionId = comp.competitionId; competition->nextActiveCompetition = activeCompetitions; activeCompetitions = competition; } // 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; ac->forHighPriority = comp.highPriority; ac->returnStack = returnStack; ac->nextActiveAC = newAttendingCompetitions; newAttendingCompetitions = ac; ac->nextCarriedAC = newCarriedCompetitions; newCarriedCompetitions = ac; } /*********************************************************************** AttendCompetitionIfNecessary ***********************************************************************/ void TraceManager::AttendCompetitionIfNecessary( Trace* trace, vint32_t currentTokenIndex, EdgeDesc& edgeDesc, Ref& newAttendingCompetitions, Ref& newCarriedCompetitions, Ref& 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]; for (vint compRef = 0; compRef < returnDesc.competitions.count; compRef++) { auto&& comp = executable.competitions[returnDesc.competitions.start + compRef]; // attend a competition from a ReturnDesc edge // find out the rule id and the competition 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&& returnState = executable.states[returnDesc.returnState]; vint32_t competitionRule = returnState.rule; CHECK_ERROR(competitionRule != -1, ERROR_MESSAGE_PREFIX L"Illegal rule id."); CHECK_ERROR(comp.competitionId != -1, ERROR_MESSAGE_PREFIX L"Illegal competition id."); AttendCompetition(trace, newAttendingCompetitions, newCarriedCompetitions, newReturnStack, competitionRule, comp); } // push this ReturnDesc to the ReturnStack newReturnStack = PushReturnStack( newReturnStack, returnIndex, trace, currentTokenIndex, (returnDesc.ruleType != ReturnRuleType::Reuse) ); edgeFromState = executable.ruleStartStates[returnDesc.consumedRule]; } for (vint compRef = 0; compRef < edgeDesc.competitions.count; compRef++) { auto&& comp = executable.competitions[edgeDesc.competitions.start + compRef]; // attend a competition from a ReturnDesc edge // find out the rule id and the competition 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&& fromState = executable.states[edgeFromState]; auto&& toState = executable.states[edgeDesc.toState]; vint32_t competitionRule = toState.endingState ? fromState.rule : toState.rule; CHECK_ERROR(competitionRule != -1, ERROR_MESSAGE_PREFIX L"Illegal rule id."); CHECK_ERROR(comp.competitionId != -1, ERROR_MESSAGE_PREFIX L"Illegal competition id."); AttendCompetition(trace, newAttendingCompetitions, newCarriedCompetitions, newReturnStack, competitionRule, comp); } #undef ERROR_MESSAGE_PREFIX } /*********************************************************************** CheckAttendingCompetitionsOnEndingEdge ***********************************************************************/ void TraceManager::CheckAttendingCompetitionsOnEndingEdge( Trace* trace, EdgeDesc& edgeDesc, Ref acId, Ref returnStack ) { while (acId != nullref) { // when executing an EndingInput transition, we announce high priority win a competition if // 1) such EndingInput transitions ends the rule, and the state of the trace holding competition belongs to the same rule // we ensure this by comparing rule 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 rule auto&& stateDesc = executable.states[edgeDesc.fromState]; if (cpt->ruleId == stateDesc.rule) { // check if it is a high bet if (ac->forHighPriority && cpt->status == CompetitionStatus::Holding) { cpt->status = CompetitionStatus::HighPriorityWin; } } } acId = ac->nextActiveAC; } } /*********************************************************************** CheckBackupTracesBeforeSwapping ***********************************************************************/ bool TraceManager::CheckBackupTracesBeforeSwapping(vint32_t currentTokenIndex) { bool closedCompetitions = false; // 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 != nullref) { 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 = EnsureTraceWithValidStates(backupTraces->Get(i)); auto acId = trace->competitionRouting.attendingCompetitions; while (acId != nullref) { 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 != nullref) { 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 =EnsureTraceWithValidStates(backupTraces->Get(i)); auto acId = trace->competitionRouting.attendingCompetitions; while (acId != nullref) { 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 { auto pnext = &activeCompetitions; while (*pnext != nullref) { 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 = EnsureTraceWithValidStates(backupTraces->Get(i)); auto attendingCompetitions = trace->competitionRouting.attendingCompetitions; auto* pnext = &trace->competitionRouting.attendingCompetitions; while (*pnext != nullref) { auto ac = GetAttendingCompetitions(*pnext); if (ac->closed) { *pnext = ac->nextActiveAC; } else { pnext = &ac->nextActiveAC; } } if (trace->competitionRouting.attendingCompetitions != attendingCompetitions) { // only check the head node since this could trigger merging closedCompetitions = true; } } return closedCompetitions; } } } } /*********************************************************************** .\TRACEMANAGER\TMINPUT_RETURNSTACK.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** GetCurrentSuccessorInReturnStack ***********************************************************************/ ReturnStackSuccessors* TraceManager::GetCurrentSuccessorInReturnStack(Ref base, vint32_t currentTokenIndex) { #define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::GetCurrentSuccessorInReturnStack(vint32_t, vint32_t)#" auto& cache = base == nullref ? initialReturnStackCache : GetReturnStack(base)->cache; if (cache.successors.tokenIndex == currentTokenIndex) { return &cache.successors; } if (cache.lastSuccessors.tokenIndex == currentTokenIndex) { return &cache.lastSuccessors; } CHECK_ERROR(currentTokenIndex > cache.successors.tokenIndex, ERROR_MESSAGE_PREFIX L"ReturnStackSuccessors::tokenIndex corrupted."); cache.lastSuccessors = cache.successors; cache.successors = {}; cache.successors.tokenIndex = currentTokenIndex; return &cache.successors; #undef ERROR_MESSAGE_PREFIX } /*********************************************************************** PushReturnStack ***********************************************************************/ ReturnStack* TraceManager::PushReturnStack(Ref base, vint32_t returnIndex, Ref fromTrace, vint32_t currentTokenIndex, bool allowReuse) { auto siblings = allowReuse ? GetCurrentSuccessorInReturnStack(base, currentTokenIndex) : nullptr; if (siblings) { auto successorId = siblings->first; while (successorId != nullref) { auto successor = GetReturnStack(successorId); successorId = successor->cache.next; if (successor->returnIndex == returnIndex && successor->fromTrace == fromTrace) { return successor; } } } auto returnStack = AllocateReturnStack(); returnStack->previous = base; returnStack->returnIndex = returnIndex; returnStack->fromTrace = fromTrace; returnStack->cache.tokenIndex = currentTokenIndex; if (siblings) { if (siblings->first == nullref) { siblings->first = returnStack; siblings->last = returnStack; } else { GetReturnStack(siblings->last)->cache.next = returnStack; returnStack->cache.prev = siblings->last; siblings->last = returnStack; } } return returnStack; } } } } /*********************************************************************** .\TRACEMANAGER\TMINPUT_WALK.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** TraceManager::IsQualifiedTokenForCondition ***********************************************************************/ bool TraceManager::IsQualifiedTokenForCondition(regex::RegexToken* token, StringLiteral condition) { if (condition.start == -1) return true; if (token->length != condition.count) return false; auto reading = executable.stringLiteralBuffer.Buffer(); if (memcmp(token->reading, reading + condition.start, sizeof(wchar_t) * condition.count) != 0) return false; return true; } /*********************************************************************** TraceManager::IsQualifiedTokenForEdgeArray ***********************************************************************/ bool TraceManager::IsQualifiedTokenForEdgeArray(regex::RegexToken* token, EdgeArray& edgeArray) { for (vint32_t edgeRef = 0; edgeRef < edgeArray.count; edgeRef++) { vint32_t byEdge = edgeArray.start + edgeRef; auto& edgeDesc = executable.edges[byEdge]; if (IsQualifiedTokenForCondition(token, edgeDesc.condition)) return true; } return false; } /*********************************************************************** TraceManager::TestLeftrecEdgeQualification ***********************************************************************/ void TraceManager::TestLeftrecEdgeQualification(EdgeDesc& edgeDesc, regex::RegexToken* lookAhead, bool& acceptLookAhead, bool& acceptEndingInput) { if (lookAhead) { vint32_t lookAheadTransitionIndex = executable.GetTransitionIndex(edgeDesc.toState, Executable::TokenBegin + (vint32_t)lookAhead->token); auto& lookAheadEdgeArray = executable.transitions[lookAheadTransitionIndex]; // mark this EndingInput if any LeftrecInput + lookAhead transition exists if (IsQualifiedTokenForEdgeArray(lookAhead, lookAheadEdgeArray)) { acceptLookAhead = true; } } { vint32_t endingInputTransitionIndex = executable.GetTransitionIndex(edgeDesc.toState, Executable::EndingInput); auto& endingInputEdgeArray = executable.transitions[endingInputTransitionIndex]; if (endingInputEdgeArray.count > 0) { acceptEndingInput = true; } } } /*********************************************************************** TraceManager::WalkAlongSingleEdge ***********************************************************************/ WalkingTrace TraceManager::WalkAlongSingleEdge( vint32_t currentTokenIndex, vint32_t input, WalkingTrace 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; Ref returnStack; Ref attendingCompetitions; Ref carriedCompetitions; Ref executedReturnStack; Trace* ambiguityTraceToMerge = nullptr; // attend a competition hold by the current trace if the priority is set for this output transition AttendCompetitionIfNecessary(trace.stateTrace, 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 != nullref) { 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.stateTrace, edgeDesc, attendingCompetitions, trace.stateTrace->returnStack); } // create a new trace for this current move auto newTrace = AllocateTrace(); AddTraceToCollection(newTrace, trace.currentTrace, &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; if (input == Executable::EndingInput) { // see if the target trace has the same state to any other surviving trace for (vint i = 0; i < concurrentCount; i++) { auto& candidate = backupTraces->operator[](i); if (candidate->byInput == Executable::EndingInput || candidate->state == -1) { if (AreTwoEndingInputTraceEqual(newTrace, candidate)) { // create a merging MergeTwoEndingInputTrace(newTrace, candidate); return { nullptr,nullptr }; } } } } // add to the current trace list only if it is not involved in ambiguity resolving AddTrace(newTrace); return { newTrace,newTrace }; #undef ERROR_MESSAGE_PREFIX } /*********************************************************************** TraceManager::WalkAlongEpsilonEdges ***********************************************************************/ void TraceManager::WalkAlongLeftrecEdges( vint32_t currentTokenIndex, regex::RegexToken* lookAhead, WalkingTrace trace, EdgeArray& edgeArray ) { 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 bool acceptLookAhead = false; bool acceptEndingInput = false; TestLeftrecEdgeQualification(edgeDesc, lookAhead, acceptLookAhead, acceptEndingInput); if (acceptLookAhead || acceptEndingInput) { // proceed only if it can auto nextTrace = WalkAlongSingleEdge(currentTokenIndex, Executable::LeftrecInput, trace, byEdge, edgeDesc); if (acceptEndingInput && nextTrace) { // A LeftrecInput will be generated because of // A real left-recursive rule // Merging prefix inside a rule // Merging prefix crossed-reference // The last two cases could connect LeftrecInput transitions to an ending state WalkAlongEpsilonEdges(currentTokenIndex, lookAhead, nextTrace); } } } } void TraceManager::WalkAlongEpsilonEdges( vint32_t currentTokenIndex, regex::RegexToken* lookAhead, WalkingTrace 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 there is no more tokens // then we have to go all the way to the end anyway // otherwise we see how many EndingInput transition we need to walk along vint32_t currentCount = 0; vint32_t currentState = trace.stateTrace->state; auto currentReturnStack = trace.stateTrace->returnStack; #define MARK_AT_LEAST_EXECUTE_TO_THIS_LEVEL endingCount = currentCount while (currentState != -1) { currentCount++; // try LeftrecInput + (lookAhead or EndingInput) { 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]; bool acceptLookAhead = false; bool acceptEndingInput = false; TestLeftrecEdgeQualification(edgeDesc, lookAhead, acceptLookAhead, acceptEndingInput); // mark this EndingInput if any LeftrecInput + (lookAhead or EndingInput) transition exists if (acceptLookAhead || acceptEndingInput) { MARK_AT_LEAST_EXECUTE_TO_THIS_LEVEL; goto TRY_ENDING_INPUT; } } } // try lookAhead if (lookAhead) { vint32_t transitionIndex = executable.GetTransitionIndex(currentState, Executable::TokenBegin + (vint32_t)lookAhead->token); auto&& edgeArray = executable.transitions[transitionIndex]; // mark this EndingInput if lookAhead transition exists if (IsQualifiedTokenForEdgeArray(lookAhead, edgeArray)) { MARK_AT_LEAST_EXECUTE_TO_THIS_LEVEL; } } // try EndingInput TRY_ENDING_INPUT: { vint32_t transitionIndex = executable.GetTransitionIndex(currentState, Executable::EndingInput); auto&& edgeArray = executable.transitions[transitionIndex]; if (edgeArray.count > 1) { // if there are multiple EndingInput transitions // assume they would all succeed, and do recursive calls later MARK_AT_LEAST_EXECUTE_TO_THIS_LEVEL; break; } else if (edgeArray.count == 1 && currentReturnStack != nullref) { auto rs = GetReturnStack(currentReturnStack); currentReturnStack = rs->previous; currentState = executable.returns[rs->returnIndex].returnState; } else if (lookAhead) { // lookAhead && (edgeArray.count == 0 || currentReturnStack == nullref) // if edgeArray.count == 0 // no further EndingInput transition could be walked // if currentReturnStack == nullref // it 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 break; } else if (edgeArray.count == 0) { // !lookAhead && 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 // it is possible that a LeftrecInput transition is available auto&& stateDesc = executable.states[currentState]; if (stateDesc.endingState) { MARK_AT_LEAST_EXECUTE_TO_THIS_LEVEL; } break; } else { // !lookAhead && edgeArray.count == 1 && currentReturnStack == nullref vint32_t byEdge = edgeArray.start; auto& edgeDesc = executable.edges[byEdge]; currentState = edgeDesc.toState; } } } } #undef MARK_AT_LEAST_EXECUTE_TO_THIS_LEVEL for (vint32_t i = 0; trace && (i < endingCount || endingCount == -1); i++) { { // LeftrecInput transition is an epsilon transition vint32_t transitionIndex = executable.GetTransitionIndex(trace.stateTrace->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.stateTrace->state, Executable::EndingInput); auto&& edgeArray = executable.transitions[transitionIndex]; // it has been ensured that edgeArray.count < 2 if (edgeArray.count == 0) { trace = { nullptr,nullptr }; } else { for (vint32_t edgeRef = 0; edgeRef < edgeArray.count; edgeRef++) { vint32_t byEdge = edgeArray.start + edgeRef; auto& edgeDesc = executable.edges[byEdge]; auto nextTrace = WalkAlongSingleEdge(currentTokenIndex, Executable::EndingInput, trace, byEdge, edgeDesc); if (edgeArray.count > 1) { // if the current trace has multiple EndingInput // we don't know if the current trace will survive or not // a following recursive call is necessary if (nextTrace) { WalkAlongEpsilonEdges(currentTokenIndex, lookAhead, nextTrace); } } else { trace = nextTrace; } } if (edgeArray.count > 1) { // when this for-loop ends, the outer for-loop also ends trace = { nullptr,nullptr }; } // EndingInput could be followed by EndingInput or LeftrecInput } } } /*********************************************************************** TraceManager::WalkAlongTokenEdges ***********************************************************************/ void TraceManager::WalkAlongTokenEdges( vint32_t currentTokenIndex, vint32_t input, regex::RegexToken* token, regex::RegexToken* lookAhead, WalkingTrace 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[byEdge]; if (IsQualifiedTokenForCondition(token, edgeDesc.condition)) { 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\TMPTR.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** PrepareTraceRoute ***********************************************************************/ void TraceManager::PrepareTraceRoute() { CHECK_ERROR(state == TraceManagerState::Finished, L"vl::glr::automaton::TraceManager::PrepareTraceRoute()#Wrong timing to call this function."); state = TraceManagerState::PreparedTraceRoute; AllocateExecutionData(); BuildAmbiguityStructures(); PartialExecuteTraces(); SummarizeInstructionRange(); } } } } /*********************************************************************** .\TRACEMANAGER\TMPTR_ALLOCATEEXECUTIONDATA.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** AllocateExecutionData ***********************************************************************/ void TraceManager::AllocateExecutionData() { #define TRACE_MAMAGER_PHRASE L"PrepareTraceRoute/AllocateExecutionData" vint32_t insExecCount = 0; auto nextBranchTrace = &firstBranchTrace; auto nextMergeTrace = &firstMergeTrace; IterateSurvivedTraces([&](Trace* trace, Trace* predecessor, vint32_t visitCount, vint32_t predecessorCount) { // ensure traceExecRef reflects the partial order of the execution order of traces if (predecessorCount > 1 && visitCount != predecessorCount) return; if (trace->traceExecRef != nullref) { throw TraceException(*this, trace, nullptr, TRACE_MAMAGER_PHRASE, L"IterateSurvivedTraces unexpectedly revisit a trace."); } trace->traceExecRef = traceExecs.Allocate(); auto traceExec = GetTraceExec(trace->traceExecRef); traceExec->traceId = trace; ReadInstructionList(trace, traceExec->insLists); if (traceExec->insLists.countAll > 0) { traceExec->insExecRefs.start = insExecCount; traceExec->insExecRefs.count = traceExec->insLists.countAll; insExecCount += traceExec->insLists.countAll; } // fill branch trace linked list if (trace->successors.first != trace->successors.last) { *nextBranchTrace = trace; nextBranchTrace = &traceExec->nextBranchTrace; } // fill merge branch linked list if (trace->predecessors.first != trace->predecessors.last) { *nextMergeTrace = trace; nextMergeTrace = &traceExec->nextMergeTrace; } }); insExecs.Resize(insExecCount); #undef TRACE_MAMAGER_PHRASE } } } } /*********************************************************************** .\TRACEMANAGER\TMPTR_BUILDAMBIGUITYSTRUCTURES.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { #define NEW_MERGE_STACK_MAGIC_COUNTER (void)(MergeStack_MagicCounter++) /*********************************************************************** BuildAmbiguityStructures ***********************************************************************/ Trace* TraceManager::StepForward(Trace* trace) { auto traceExec = GetTraceExec(trace->traceExecRef); // for ordinary trace, go to its forwardTrace if (traceExec->branchData.forwardTrace != trace) { return GetTrace(traceExec->branchData.forwardTrace); } // for initialTrace, stop if (trace->predecessors.first == nullref) { return nullptr; } // for merge trace, go to the forwardTrace of its commonForwardTrace if (trace->predecessors.first != trace->predecessors.last) { return GetTrace(GetTraceExec(GetTrace(traceExec->branchData.commonForwardBranch)->traceExecRef)->branchData.forwardTrace); } // otherwise, it is a successor of a branch trace // go to its predecessor's forwardTrace return GetTrace(GetTraceExec(GetTrace(trace->predecessors.first)->traceExecRef)->branchData.forwardTrace); } void TraceManager::BuildAmbiguityStructures() { #define TRACE_MAMAGER_PHRASE L"PrepareTraceRoute/BuildAmbiguityStructures" IterateSurvivedTraces( [this](Trace* trace, Trace* predecessor, vint32_t visitCount, vint32_t predecessorCount) { auto traceExec = GetTraceExec(trace->traceExecRef); if (predecessorCount == 0) { // for initialTrace, forwardTrace is itself traceExec->branchData.forwardTrace = trace; } else if (predecessorCount == 1) { if (predecessor->successors.first != predecessor->successors.last) { // for any successors of a branch trace, forwardTrace is itself traceExec->branchData.forwardTrace = trace; } else { // if any ordinary trace, use the data from its predecessor traceExec->branchData.forwardTrace = GetTraceExec(predecessor->traceExecRef)->branchData.forwardTrace ; } } else { if (predecessor->state == -1) { throw TraceException(*this, trace, predecessor, TRACE_MAMAGER_PHRASE, L"Predecessor trace of a merge trace cannot be a merge trace."); } if (visitCount == 1) { // for any merge trace, forwardTrace is itself traceExec->branchData.forwardTrace = trace; // for the first visiting, set commonForwardBranch to the forwardTrace of its first predecessor traceExec->branchData.commonForwardBranch = GetTrace(GetTraceExec(predecessor->traceExecRef)->branchData.forwardTrace); } else { // find the latest forwardTrace of its commonForwardBranch and the forwardTrace of the predecessor NEW_MERGE_STACK_MAGIC_COUNTER; auto magicCommonForward = MergeStack_MagicCounter; auto currentTrace = GetTrace(traceExec->branchData.commonForwardBranch); while (currentTrace) { GetTraceExec(currentTrace->traceExecRef)->branchData.mergeCounter = magicCommonForward; currentTrace = StepForward(currentTrace); } currentTrace = GetTrace(GetTraceExec(predecessor->traceExecRef)->branchData.forwardTrace); while (currentTrace) { if (GetTraceExec(currentTrace->traceExecRef)->branchData.mergeCounter == magicCommonForward) { break; } currentTrace = StepForward(currentTrace); } if (currentTrace == nullptr) { throw TraceException(*this, currentTrace, nullptr, TRACE_MAMAGER_PHRASE, L"Cannot determine commonForwardBranch of a merge trace."); } traceExec->branchData.commonForwardBranch = currentTrace; } } } ); #undef TRACE_MAMAGER_PHRASE } #undef NEW_MERGE_STACK_MAGIC_COUNTER } } } /*********************************************************************** .\TRACEMANAGER\TMPTR_PARTIALEXECUTETRACES.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** PartialExecuteTraces ***********************************************************************/ void TraceManager::PartialExecuteTraces() { #define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::PartialExecuteTraces()#" IterateSurvivedTraces( [this](Trace* trace, Trace* predecessor, vint32_t visitCount, vint32_t predecessorCount) { if (predecessorCount <= 1) { PartialExecuteOrdinaryTrace(trace); } else { if (visitCount > 1) { EnsureInsExecContextCompatible(predecessor, GetTrace(trace->predecessors.first)); } if (visitCount == predecessorCount) { MergeInsExecContext(trace); } } } ); #undef ERROR_MESSAGE_PREFIX } } } } /*********************************************************************** .\TRACEMANAGER\TMPTR_PARTIALEXECUTETRACES_ENSUREINSEXECCONTEXTCOMPATIBLE.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** EnsureInsExecContextCompatible ***********************************************************************/ void TraceManager::EnsureInsExecContextCompatible(Trace* baselineTrace, Trace* commingTrace) { #define TRACE_MAMAGER_PHRASE L"PrepareTraceRoute/EnsureInsExecContextCompatible" auto&& contextComming = GetTraceExec(baselineTrace->traceExecRef)->context; auto&& contextBaseline = GetTraceExec(commingTrace->traceExecRef)->context; // check if the two objectStack have the same depth if ((contextBaseline.objectStack == nullref) != (contextComming.objectStack == nullref)) { throw TraceException(*this, baselineTrace, commingTrace, TRACE_MAMAGER_PHRASE, L"Execution results of traces to merge do not have the same depth of objectStack."); } if (contextBaseline.objectStack != nullref) { auto objectStackBaseline = GetInsExec_StackArrayRefLink(contextBaseline.objectStack); auto objectStackComming = GetInsExec_StackArrayRefLink(contextComming.objectStack); if (objectStackBaseline->currentDepth != objectStackComming->currentDepth) { throw TraceException(*this, baselineTrace, commingTrace, TRACE_MAMAGER_PHRASE, L"Execution results of traces to merge do not have the same depth of objectStack."); } } // check if the two createStack have the same depth // check each corresponding createStack have the same stackBase auto stackBaseline = contextBaseline.createStack; auto stackComming = contextComming.createStack; while (stackBaseline != stackComming) { if (stackBaseline == nullref || stackComming == nullref) { throw TraceException(*this, baselineTrace, commingTrace, TRACE_MAMAGER_PHRASE, L"Execution results of traces to merge do not have the same depth of createStack."); } auto stackObjBaseline = GetInsExec_StackArrayRefLink(stackBaseline); auto stackObjComming = GetInsExec_StackArrayRefLink(stackComming); if (stackObjBaseline->objectStackDepthForCreateStack != stackObjComming->objectStackDepthForCreateStack) { throw TraceException(*this, baselineTrace, commingTrace, TRACE_MAMAGER_PHRASE, L"Execution results of traces to merge do not have the same depth of objectStack between one slice of both createStack."); } stackBaseline = stackObjBaseline->previous; stackComming = stackObjComming->previous; } #undef TRACE_MAMAGER_PHRASE } } } } /*********************************************************************** .\TRACEMANAGER\TMPTR_PARTIALEXECUTETRACES_MERGEINSEXECCONTEXT.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { using namespace collections; #define NEW_MERGE_STACK_MAGIC_COUNTER (void)(MergeStack_MagicCounter++) /*********************************************************************** MergeInsExecContext ***********************************************************************/ template (InsExec_Context::* stack), typename TMerge> Ref TraceManager::MergeStack(Trace* mergeTrace, TMerge&& merge) { Array stacks(mergeTrace->predecessorCount); // fill the first level of stacks objects { vint index = 0; auto predecessorId = mergeTrace->predecessors.first; while (predecessorId != nullref) { auto predecessor = GetTrace(predecessorId); auto traceExec = GetTraceExec(predecessor->traceExecRef); auto stackId = traceExec->context.*stack; stacks[index++] = stackId == nullref ? nullptr : GetInsExec_StackArrayRefLink(stackId); predecessorId = predecessor->predecessors.siblingNext; } } Ref stackTop; auto pStackPrevious = &stackTop; while (stacks[0]) { // check if all stack objects are the same bool sameStackObject = true; // TODO: (enumerable) Linq:Skip for (vint index = 1; index < stacks.Count(); index++) { if (stacks[0] != stacks[index]) { sameStackObject = false; break; } } if (sameStackObject) { // if yes, reuse this stack object *pStackPrevious = stacks[0]; break; } // otherwise, create a new stack object to merge all auto newStack = GetInsExec_StackArrayRefLink(insExec_StackArrayRefLinks.Allocate()); *pStackPrevious = newStack; pStackPrevious = &(newStack->previous); { // call this macro to create a one-time set for InsExec* NEW_MERGE_STACK_MAGIC_COUNTER; auto magicPush = MergeStack_MagicCounter; // TODO: (enumerable) foreach for (vint index = 0; index < stacks.Count(); index++) { // do not visit the same stack object repeatly if (stacks[index]->mergeCounter == magicPush) continue; stacks[index]->mergeCounter = magicPush; merge(newStack, stacks[index]); // do not visit the same object repeatly auto currentLinkRef = stacks[index]->ids; while (currentLinkRef != nullref) { auto currentLink = GetInsExec_StackRefLink(currentLinkRef); currentLinkRef = currentLink->previous; auto currentStack = GetInsExec_Stack(currentLink->id); if (currentStack->mergeCounter == magicPush) continue; currentStack->mergeCounter = magicPush; PushStackRefLink(newStack->ids, currentStack); } } } // move to next level of stack objects for (vint index = 0; index < stacks.Count(); index++) { auto stackId = stacks[index]->previous; stacks[index] = stackId == nullref ? nullptr : GetInsExec_StackArrayRefLink(stackId); } } return stackTop; } void TraceManager::MergeInsExecContext(Trace* mergeTrace) { // merge stacks so that objects created in all branches are accessible auto traceExec = GetTraceExec(mergeTrace->traceExecRef); traceExec->context.objectStack = MergeStack< &InsExec_Context::objectStack >( mergeTrace, [this](InsExec_StackArrayRefLink* newStack, InsExec_StackArrayRefLink* commingStack) { newStack->currentDepth = commingStack->currentDepth; }); traceExec->context.createStack = MergeStack< &InsExec_Context::createStack >( mergeTrace, [this](InsExec_StackArrayRefLink* newStack, InsExec_StackArrayRefLink* commingStack) { newStack->currentDepth = commingStack->currentDepth; newStack->objectStackDepthForCreateStack = commingStack->objectStackDepthForCreateStack; }); NEW_MERGE_STACK_MAGIC_COUNTER; auto predecessorId = mergeTrace->predecessors.first; while (predecessorId != nullref) { auto predecessor = GetTrace(predecessorId); predecessorId = predecessor->predecessors.siblingNext; auto predecessorTraceExec = GetTraceExec(predecessor->traceExecRef); } } #undef NEW_MERGE_STACK_MAGIC_COUNTER } } } /*********************************************************************** .\TRACEMANAGER\TMPTR_PARTIALEXECUTETRACES_PARTIALEXECUTEORDINARYTRACE.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { #define NEW_MERGE_STACK_MAGIC_COUNTER (void)(MergeStack_MagicCounter++) /*********************************************************************** PartialExecuteOrdinaryTrace ***********************************************************************/ InsExec_Stack* TraceManager::NewStack() { auto ieStack = GetInsExec_Stack(insExec_Stacks.Allocate()); ieStack->previous = firstStack; firstStack = ieStack; return ieStack; } void TraceManager::PushInsRefLink(Ref& link, InsRef insRef) { auto newLink = GetInsExec_InsRefLink(insExec_InsRefLinks.Allocate()); newLink->previous = link; newLink->insRef = insRef; link = newLink; } void TraceManager::PushStackRefLink(Ref& link, Ref id) { auto newLink = GetInsExec_StackRefLink(insExec_StackRefLinks.Allocate()); newLink->previous = link; newLink->id = id; link = newLink; } void TraceManager::PushStackArrayRefLink(Ref& arrayLink, Ref id) { Ref link; PushStackRefLink(link, id); PushStackArrayRefLink(arrayLink, link); } void TraceManager::PushStackArrayRefLink(Ref& arrayLink, Ref link) { auto newArrayLink = GetInsExec_StackArrayRefLink(insExec_StackArrayRefLinks.Allocate()); newArrayLink->previous = arrayLink; newArrayLink->ids = link; if (arrayLink == nullref) { newArrayLink->currentDepth = 0; } else { newArrayLink->currentDepth = GetInsExec_StackArrayRefLink(arrayLink)->currentDepth + 1; } arrayLink = newArrayLink; } Ref TraceManager::JoinInsRefLink(Ref first, Ref second) { if (first == nullref) return second; if (second == nullref) return first; Ref newInsRef; while (first != nullref) { auto insRef = GetInsExec_InsRefLink(first); first = insRef->previous; PushInsRefLink(newInsRef, insRef->insRef); } while (second != nullref) { auto insRef = GetInsExec_InsRefLink(second); second = insRef->previous; PushInsRefLink(newInsRef, insRef->insRef); } return newInsRef; } Ref TraceManager::JoinStackRefLink(Ref first, Ref second) { if (first == nullref) return second; if (second == nullref) return first; Ref newStack; while (first != nullref) { auto stack = GetInsExec_StackRefLink(first); first = stack->previous; PushStackRefLink(newStack, stack->id); } while (second != nullref) { auto stack = GetInsExec_StackRefLink(second); second = stack->previous; PushStackRefLink(newStack, stack->id); } return newStack; } void TraceManager::PartialExecuteOrdinaryTrace(Trace* trace) { #define TRACE_MAMAGER_PHRASE L"PrepareTraceRoute/PartialExecuteOrdinaryTrace" InsExec_Context context; if (trace->predecessors.first != nullref) { auto predecessor = GetTrace(trace->predecessors.first); auto traceExec = GetTraceExec(predecessor->traceExecRef); context = traceExec->context; } auto ForEachStack = [this](Ref targetStack, auto&& callback) { auto topStackArray = GetInsExec_StackArrayRefLink(targetStack); auto topStackLinkRef = topStackArray->ids; while (topStackLinkRef != nullref) { auto topStackLink = GetInsExec_StackRefLink(topStackLinkRef); topStackLinkRef = topStackLink->previous; auto topStack = GetInsExec_Stack(topStackLink->id); callback(topStack); } }; auto traceExec = GetTraceExec(trace->traceExecRef); for (vint32_t insRef = 0; insRef < traceExec->insLists.countAll; insRef++) { auto&& ins = ReadInstruction(insRef, traceExec->insLists); auto insExec = GetInsExec(traceExec->insExecRefs.start + insRef); insExec->contextBeforeExecution = context; switch (ins.type) { case AstInsType::CreateObject: { if (context.createStack == nullref) { throw TraceException(*this, { trace, insRef }, TRACE_MAMAGER_PHRASE, L"[CreateObject] context.createStack is empty."); } ForEachStack(context.createStack, [=, this](InsExec_Stack* topStack) { PushInsRefLink(topStack->createObjectInsRefs, { trace, insRef }); PushStackRefLink(insExec->operatingStacks, topStack); }); } break; case AstInsType::StackBegin: { auto newTopStack = NewStack(); PushStackArrayRefLink(context.createStack, newTopStack); newTopStack->beginInsRef = { trace, insRef }; PushStackRefLink(insExec->operatingStacks, newTopStack); auto newStackTop = GetInsExec_StackArrayRefLink(context.createStack); if (context.objectStack == nullref) { newStackTop->objectStackDepthForCreateStack = 0; } else { newStackTop->objectStackDepthForCreateStack = GetInsExec_StackArrayRefLink(context.objectStack)->currentDepth; } } break; case AstInsType::StackEnd: { if (context.createStack == nullref) { throw TraceException(*this, { trace, insRef }, TRACE_MAMAGER_PHRASE, L"[StackEnd] context.createStack is empty."); } bool endWithCreate = false; bool endWithReuse = false; ForEachStack(context.createStack, [&](InsExec_Stack* topStack) { bool executedCreateObject = false; if (topStack->createObjectInsRefs != nullref) { auto lastCreateObjectInsRefLink = GetInsExec_InsRefLink(topStack->createObjectInsRefs); executedCreateObject = lastCreateObjectInsRefLink->insRef.trace == trace; } if(executedCreateObject) { endWithCreate = true; PushInsRefLink(topStack->endWithCreateInsRefs, { trace, insRef }); } else { endWithReuse = true; PushInsRefLink(topStack->endWithReuseInsRefs, { trace, insRef }); } PushStackRefLink(insExec->operatingStacks, topStack); }); if (endWithCreate == endWithReuse) { throw TraceException(*this, { trace, insRef }, TRACE_MAMAGER_PHRASE, L"[StackEnd] Connected CreateObject and StackEnd should always be in the same trace."); } if (endWithReuse) { if (context.objectStack == nullref) { throw TraceException(*this, { trace, insRef }, TRACE_MAMAGER_PHRASE, L"[StackEnd] context.objectStack is empty."); } auto topObjects = GetInsExec_StackArrayRefLink(context.objectStack); context.objectStack = topObjects->previous; ForEachStack(context.createStack, [&](InsExec_Stack* topStack) { topStack->useFromStacks = JoinStackRefLink(topStack->useFromStacks, topObjects->ids); }); } auto topStacks = GetInsExec_StackArrayRefLink(context.createStack); context.createStack = topStacks->previous; PushStackArrayRefLink(context.objectStack, topStacks->ids); } break; case AstInsType::StackSlot: { if (context.createStack == nullref) { throw TraceException(*this, { trace, insRef }, TRACE_MAMAGER_PHRASE, L"[StackSlot] context.createStack is empty."); } if (context.objectStack == nullref) { throw TraceException(*this, { trace, insRef }, TRACE_MAMAGER_PHRASE, L"[StackSlot] context.objectStack is empty."); } auto topObjects = GetInsExec_StackArrayRefLink(context.objectStack); context.objectStack = topObjects->previous; ForEachStack(context.createStack, [&](InsExec_Stack* topStack) { topStack->fieldStacks = JoinStackRefLink(topStack->fieldStacks, topObjects->ids); }); } break; case AstInsType::Field: case AstInsType::FieldIfUnassigned: case AstInsType::Token: case AstInsType::EnumItem: break; case AstInsType::ResolveAmbiguity: throw TraceException(*this, { trace, insRef }, TRACE_MAMAGER_PHRASE, L"[ResolveAmbiguity] should not appear in traces."); default:; throw TraceException(*this, { trace, insRef }, TRACE_MAMAGER_PHRASE, L"Unrecognizabled instruction."); } } traceExec->context = context; #undef TRACE_MAMAGER_PHRASE } #undef NEW_MERGE_STACK_MAGIC_COUNTER } } } /*********************************************************************** .\TRACEMANAGER\TMPTR_PARTIALEXECUTETRACES_SUMMARIZEINSTRUCTIONRANGE.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { using namespace collections; #define NEW_MERGE_STACK_MAGIC_COUNTER (void)(MergeStack_MagicCounter++) /*********************************************************************** IterateStackWithDependency ***********************************************************************/ template void TraceManager::IterateStackWithDependency(Ref(InsExec_Stack::* dependencies), TCallback&& callback) { NEW_MERGE_STACK_MAGIC_COUNTER; auto stackMagicCounter = MergeStack_MagicCounter; // traverse through all stacks auto currentStackRef = firstStack; while (currentStackRef != nullref) { auto currentStack = GetInsExec_Stack(currentStackRef); currentStackRef = currentStack->previous; if (currentStack->mergeCounter == stackMagicCounter) continue; currentStack->mergeCounter = stackMagicCounter; List indirectStacks; indirectStacks.Add(currentStack); // list all untouched dependencies in order, skipped processed ones for (vint i = 0; i < indirectStacks.Count(); i++) { auto stack = indirectStacks[i]; auto currentInsRefLink = stack->*dependencies; while (currentInsRefLink != nullref) { auto insRefLink = GetInsExec_StackRefLink(currentInsRefLink); currentInsRefLink = insRefLink->previous; auto useFromStack = GetInsExec_Stack(insRefLink->id); if (useFromStack->mergeCounter == stackMagicCounter) continue; useFromStack->mergeCounter = stackMagicCounter; indirectStacks.Add(useFromStack); } } // process all listed stacks for (vint i = indirectStacks.Count() - 1; i >= 0; i--) { auto stack = indirectStacks[i]; callback(stack); } } } /*********************************************************************** SummarizeEarilestLocalInsRefs ***********************************************************************/ void TraceManager::SummarizeEarilestLocalInsRefs() { IterateStackWithDependency(&InsExec_Stack::useFromStacks, [this](InsExec_Stack* stack) { SortedList insRefs; auto currentStackRefLink = stack->useFromStacks; while (currentStackRefLink != nullref) { auto stackRefLink = GetInsExec_StackRefLink(currentStackRefLink); currentStackRefLink = stackRefLink->previous; auto useFromStack = GetInsExec_Stack(stackRefLink->id); UpdateTopTrace(stack->summarizing.earliestLocalInsRef, useFromStack->summarizing.earliestLocalInsRef); CollectInsRefs(insRefs, useFromStack->summarizing.indirectCreateObjectInsRefs); } UpdateTopTrace(stack->summarizing.earliestLocalInsRef, stack->beginInsRef); CollectInsRefs(insRefs, stack->createObjectInsRefs); for (auto insRef : insRefs) { PushInsRefLink(stack->summarizing.indirectCreateObjectInsRefs, insRef); } }); } /*********************************************************************** SummarizeEarilestStackInsRefs ***********************************************************************/ void TraceManager::SummarizeEarilestStackInsRefs() { { auto currentStackRef = firstStack; while (currentStackRef != nullref) { auto currentStack = GetInsExec_Stack(currentStackRef); currentStackRef = currentStack->previous; currentStack->allDependentStacks = JoinStackRefLink(currentStack->fieldStacks, currentStack->useFromStacks); } } IterateStackWithDependency(&InsExec_Stack::allDependentStacks, [this](InsExec_Stack* stack) { auto currentStackRefLink = stack->allDependentStacks; while (currentStackRefLink != nullref) { auto stackRefLink = GetInsExec_StackRefLink(currentStackRefLink); currentStackRefLink = stackRefLink->previous; auto fieldStack = GetInsExec_Stack(stackRefLink->id); UpdateTopTrace(stack->summarizing.earliestStackInsRef, fieldStack->summarizing.earliestStackInsRef); } UpdateTopTrace(stack->summarizing.earliestStackInsRef, stack->summarizing.earliestLocalInsRef); }); } /*********************************************************************** SummarizeEarilestInsRefs ***********************************************************************/ void TraceManager::SummarizeEarilestInsRefs() { List indirectStacks; // traverse through all stacks auto currentStackRef = firstStack; while (currentStackRef != nullref) { auto currentStack = GetInsExec_Stack(currentStackRef); currentStackRef = currentStack->previous; indirectStacks.Clear(); indirectStacks.Add(currentStack); // traverse through all useFromStacks recursively for (vint i = 0; i < indirectStacks.Count(); i++) { auto stack = indirectStacks[i]; // if earliestInsRef could be refreshed, propogate it into useFromStacks if (!UpdateTopTrace(stack->summarizing.earliestInsRef, currentStack->summarizing.earliestStackInsRef)) { continue; } if (stack == currentStack) { stack->summarizing.bottomInsRefs = JoinInsRefLink(stack->endWithCreateInsRefs, stack->endWithReuseInsRefs); } else { stack->summarizing.bottomInsRefs = currentStack->summarizing.bottomInsRefs; } auto currentInsRefLink = stack->useFromStacks; while (currentInsRefLink != nullref) { auto insRefLink = GetInsExec_StackRefLink(currentInsRefLink); currentInsRefLink = insRefLink->previous; auto useFromStack = GetInsExec_Stack(insRefLink->id); indirectStacks.Add(useFromStack); } } } } /*********************************************************************** SummarizeInstructionRange ***********************************************************************/ bool TraceManager::UpdateTopTrace(InsRef& topInsRef, InsRef newInsRef) { if ( topInsRef.trace == nullref || topInsRef.trace > newInsRef.trace || (topInsRef.trace == newInsRef.trace && topInsRef.ins > newInsRef.ins) ) { topInsRef = newInsRef; return true; } else { return false; } } void TraceManager::CollectInsRefs(collections::SortedList& insRefs, Ref link) { auto currentInsRefLink = link; while (currentInsRefLink != nullref) { auto insRefLink = GetInsExec_InsRefLink(currentInsRefLink); currentInsRefLink = insRefLink->previous; if (!insRefs.Contains(insRefLink->insRef)) { insRefs.Add(insRefLink->insRef); } } } void TraceManager::SummarizeInstructionRange() { SummarizeEarilestLocalInsRefs(); SummarizeEarilestStackInsRefs(); SummarizeEarilestInsRefs(); } #undef NEW_MERGE_STACK_MAGIC_COUNTER } } } /*********************************************************************** .\TRACEMANAGER\TMRA.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** ResolveAmbiguity ***********************************************************************/ void TraceManager::ResolveAmbiguity() { CHECK_ERROR(state == TraceManagerState::PreparedTraceRoute, L"vl::glr::automaton::TraceManager::ResolveAmbiguity()#Wrong timing to call this function."); state = TraceManagerState::ResolvedAmbiguity; CheckMergeTraces(); BuildExecutionOrder(); } #undef NEW_MERGE_STACK_MAGIC_COUNTER } } } /*********************************************************************** .\TRACEMANAGER\TMRA_BUILDEXECUTIONORDER.CPP ***********************************************************************/ #define DEFINE_EXECUTION_STEP_CONTEXT ExecutionStep*& root, ExecutionStep*& firstLeaf, ExecutionStep*& currentStep, ExecutionStep*& currentLeaf #define PASS_EXECUTION_STEP_CONTEXT root, firstLeaf, currentStep, currentLeaf namespace vl { namespace glr { namespace automaton { using namespace collections; #define TRACE_MAMAGER_PHRASE L"ResolveAmbiguity/BuildExecutionOrder" /*********************************************************************** ExecutionStep Operations ***********************************************************************/ void TraceManager::AppendStepsAfterList(ExecutionStepLinkedList steps, ExecutionStepLinkedList& current) { if (!steps.first) { return; } if (!current.first) { current = steps; } else { steps.first->parent = current.last; current.last = steps.last; } } void TraceManager::AppendLeafToTree(ExecutionStep* leaf, ExecutionStepTree& tree) { if (!tree.firstLeaf) { tree.firstLeaf = leaf; tree.lastLeaf = leaf; } else { tree.lastLeaf->leafNext = leaf; tree.lastLeaf = leaf; } } ExecutionStepLinkedList TraceManager::ConvertStepTreeToList(ExecutionStepTree tree) { ExecutionStepLinkedList result; // initialize visitCount and copyCount { Ref currentLeafRef = tree.firstLeaf; while (currentLeafRef != nullref) { auto currentLeaf = GetExecutionStep(currentLeafRef); currentLeafRef = currentLeaf->leafNext; Ref currentStepRef = currentLeaf; while (currentStepRef != nullref) { auto currentStep = GetExecutionStep(currentStepRef); currentStepRef = currentStep->parent; currentStep->visitCount = 0; currentStep->copyCount = 0; } } } { Ref currentLeafRef = tree.firstLeaf; while (currentLeafRef != nullref) { auto currentLeaf = GetExecutionStep(currentLeafRef); currentLeafRef = currentLeaf->leafNext; Ref currentStepRef = currentLeaf; while (currentStepRef != nullref) { auto currentStep = GetExecutionStep(currentStepRef); currentStepRef = currentStep->parent; currentStep->copyCount++; } } } // traverse through each leaf // make a list from root to leaf // join them { Ref currentLeafRef = tree.firstLeaf; while (currentLeafRef != nullref) { auto currentLeaf = GetExecutionStep(currentLeafRef); currentLeafRef = currentLeaf->leafNext; ExecutionStepLinkedList leafList{ currentLeaf,currentLeaf }; auto walkingStep = currentLeaf; while (walkingStep->parent != nullref) { walkingStep = GetExecutionStep(walkingStep->parent); if (walkingStep->visitCount++ == walkingStep->copyCount) { leafList.first = walkingStep; } else { auto stepCopy = GetExecutionStep(executionSteps.Allocate()); static_assert(sizeof(stepCopy->et_i) >= sizeof(stepCopy->et_ra)); stepCopy->type = walkingStep->type; stepCopy->et_i = walkingStep->et_i; leafList.first->parent = stepCopy; leafList.first = stepCopy; } } AppendStepsAfterList(leafList, result); } } // clean leafPrev and leafNext { Ref currentLeafRef = tree.firstLeaf; while (currentLeafRef != nullref) { auto currentLeaf = GetExecutionStep(currentLeafRef); currentLeafRef = currentLeaf->leafNext; currentLeaf->leafNext = nullref; } } return result; } /*********************************************************************** CreateResolveAmbiguityStep ***********************************************************************/ ExecutionStep* TraceManager::CreateResolveAmbiguityStep(TraceAmbiguity* ta) { auto taFirst = GetTrace(ta->firstTrace); auto taLast = GetTrace(ta->lastTrace); auto step = GetExecutionStep(executionSteps.Allocate()); step->type = ExecutionType::RA_End; step->et_ra.type = -1; step->et_ra.trace = taLast->allocatedIndex; { if (typeCallback == nullptr) { throw TraceException(*this, TRACE_MAMAGER_PHRASE, L"Missing ITypeCallback to resolve the type from multiple objects."); } auto currentStackLinkRef = ta->bottomCreateObjectStacks; while (currentStackLinkRef != nullref) { auto currentStackLink = GetInsExec_StackRefLink(currentStackLinkRef); currentStackLinkRef = currentStackLink->previous; auto ieObject = GetInsExec_Stack(currentStackLink->id); // find all CreateObject instructions in that stack if (ieObject->summarizing.indirectCreateObjectInsRefs == nullref) { throw TraceException(*this, ieObject, TRACE_MAMAGER_PHRASE, L"indirectCreateObjectInsRefs should not be null."); } auto coInsRefLink = ieObject->summarizing.indirectCreateObjectInsRefs; while (coInsRefLink != nullref) { auto coInsRef = GetInsExec_InsRefLink(coInsRefLink); coInsRefLink = coInsRef->previous; auto coTrace = GetTrace(coInsRef->insRef.trace); auto coTraceExec = GetTraceExec(coTrace->traceExecRef); auto&& coIns = ReadInstruction(coInsRef->insRef.ins, coTraceExec->insLists); if (coIns.type != AstInsType::CreateObject || coIns.param == -1) { throw TraceException(*this, ieObject, TRACE_MAMAGER_PHRASE, L"indirectCreateObjectInsRefs points to an unexpected instruction."); } if (step->et_ra.type == -1) { step->et_ra.type = coIns.param; } else if (step->et_ra.type != coIns.param) { vint32_t baseClass = typeCallback->FindCommonBaseClass(step->et_ra.type, coIns.param); if (baseClass == -1) { throw UnableToResolveAmbiguityException( WString::Unmanaged(L"Unable to resolve ambiguity type from ") + typeCallback->GetClassName(step->et_ra.type) + WString::Unmanaged(L" and ") + typeCallback->GetClassName(coIns.param) + WString::Unmanaged(L"."), step->et_ra.type, coIns.param, EnsureTraceWithValidStates(taFirst)->currentTokenIndex, EnsureTraceWithValidStates(taLast)->currentTokenIndex ); } step->et_ra.type = baseClass; } } } } return step; } /*********************************************************************** CollectNestedAmbiguities ***********************************************************************/ Ptr TraceManager::CollectNestedAmbiguities(TraceAmbiguity* ta) { auto taFirst = GetTrace(ta->firstTrace); auto taBranch = GetTrace(ta->branchTrace); Ptr nestedTas; { auto criticalTrace = taFirst; while (criticalTrace && criticalTrace->traceExecRef <= taBranch->traceExecRef) { auto criticalTraceExec = GetTraceExec(criticalTrace->traceExecRef); if (criticalTraceExec->ambiguityBegins != nullref) { auto taLink = GetTraceAmbiguityLink(criticalTraceExec->ambiguityBegins); auto nestedTa = GetTraceAmbiguity(taLink->ambiguity); if (nestedTa != ta) { auto nestedTaLast = GetTrace(nestedTa->lastTrace); if (nestedTaLast->traceExecRef > taBranch->traceExecRef) { if (!nestedTas) nestedTas = Ptr(new NestedAmbiguityInfo); nestedTas->nestedAmbiguities.Add(nestedTa); } else { criticalTrace = GetTrace(nestedTa->mergeTrace); continue; } } } auto criticalRef = criticalTraceExec->nextAmbiguityCriticalTrace; criticalTrace = criticalRef == nullref ? nullptr : GetTrace(criticalRef); } } if (nestedTas) { nestedTas->branchTraces.Add(GetTrace(ta->branchTrace), ta); for (auto nestedTa : nestedTas->nestedAmbiguities) { auto branchTrace = GetTrace(nestedTa->branchTrace); nestedTas->branchTraces.Add(branchTrace, nestedTa); } for (auto nestedTa : nestedTas->nestedAmbiguities) { auto currentTraceRef = nestedTa->branchTrace; while (currentTraceRef != nullref) { auto currentTrace = GetTrace(currentTraceRef); if (currentTrace->traceExecRef < taFirst->traceExecRef) { break; } if (currentTrace->successors.siblingNext != currentTrace->successors.siblingPrev) { auto predecessor = GetTrace(currentTrace->predecessors.first); if (nestedTas->branchTraces.Keys().Contains(predecessor)) { nestedTas->branchSelections.Add(nestedTa, currentTrace); } } auto currentTraceExec = GetTraceExec(currentTrace->traceExecRef); if (currentTraceExec->branchData.forwardTrace == currentTrace) { currentTraceRef = currentTrace->predecessors.first; } else { currentTraceRef = currentTraceExec->branchData.forwardTrace; } } } } return nestedTas; } /*********************************************************************** BuildStepLeafsForAmbiguityBranch ***********************************************************************/ void TraceManager::BuildStepLeafsForAmbiguityBranch( TraceAmbiguity* ta, ExecutionStep* lastSharedStep, Trace* ambiguityBranchStartTrace, vint32_t* ambiguityBranchStartIns, ExecutionStepTree& ambiguityStepTree) { auto taFirst = GetTrace(ta->firstTrace); auto taLast = GetTrace(ta->lastTrace); auto taMerge = GetTrace(ta->mergeTrace); auto taFirstExec = GetTraceExec(taFirst->traceExecRef); auto taLastExec = GetTraceExec(taLast->traceExecRef); auto taMergeExec = GetTraceExec(taMerge->traceExecRef); vint32_t prefixExtra = ta->prefix - taFirstExec->insLists.countAll; vint32_t postfixExtra = ta->postfix - taLastExec->insLists.countAll; ExecutionStepLinkedList branchList; // Execute the branch { Trace* rawBranchTrace = nullptr; auto steps = BuildStepListUntilFirstRawBranchTrace( ambiguityBranchStartTrace, ambiguityBranchStartIns ? *ambiguityBranchStartIns : (prefixExtra <= 0 ? 0 : prefixExtra), taMerge, (taMergeExec->insLists.countAll - 1 - (postfixExtra <= 0 ? 0 : postfixExtra)), nullptr, &rawBranchTrace ); if (rawBranchTrace) { if (steps.first) { steps.first->parent = lastSharedStep; } auto successorId = rawBranchTrace->successors.first; while (successorId != nullref) { auto successor = GetTrace(successorId); successorId = successor->successors.siblingNext; BuildStepLeafsForAmbiguityBranch(ta, (steps.first ? steps.last : lastSharedStep), successor, nullptr, ambiguityStepTree); } return; } AppendStepsAfterList(steps, branchList); } // Execute from taMerge to taLast if (postfixExtra < 0) { auto steps = BuildStepList( taMerge, 0, taLast, -postfixExtra - 1, nullptr ); AppendStepsAfterList(steps, branchList); } // Append RA_BRANCH { auto step = GetExecutionStep(executionSteps.Allocate()); step->type = ExecutionType::RA_Branch; step->et_ra.trace = taLast->allocatedIndex; step->et_ra.type = -1; AppendStepsAfterList({ step,step }, branchList); } branchList.first->parent = lastSharedStep; AppendLeafToTree(branchList.last, ambiguityStepTree); } /*********************************************************************** BuildStepLeafsForNestedAmbiguityBranch ***********************************************************************/ void TraceManager::BuildStepLeafsForNestedAmbiguityBranch( TraceAmbiguity* ta, ExecutionStep* lastSharedStep, BSLA_Guidance* guidance, ExecutionStepTree& ambiguityStepTree) { ExecutionStepLinkedList stepsBeforeBranch; auto nta = guidance->nestedTas->nestedAmbiguities[guidance->nextAmbiguityIndex]; auto taFirst = GetTrace(ta->firstTrace); auto ntaFirst = GetTrace(nta->firstTrace); // Execute from taFirst until the nested TraceAmbiguity { auto ntaFirst = GetTrace(nta->firstTrace); auto steps = BuildStepList( taFirst, ta->prefix, ntaFirst, -1, nullptr ); AppendStepsAfterList(steps, stepsBeforeBranch); } // Execute the nested TraceAmbiguity Trace* currentTrace = ntaFirst; vint32_t currentIns = 0; { auto steps = BuildStepListThroughAmbiguity( currentTrace, currentIns, nta, guidance ); AppendStepsAfterList(steps, stepsBeforeBranch); } // Execute the rest stepsBeforeBranch.first->parent = lastSharedStep; lastSharedStep = stepsBeforeBranch.last; BuildStepLeafsForAmbiguityBranch( ta, lastSharedStep, currentTrace, ¤tIns, ambiguityStepTree ); } /*********************************************************************** BuildStepListForAmbiguity ***********************************************************************/ ExecutionStepLinkedList TraceManager::BuildStepListForAmbiguity( TraceAmbiguity* ta, BSLA_Guidance* guidance) { BSLA_Guidance DoNotUse_BSLA_Guidance; BSL_Guidance DoNotUse_BSL_Guidance; ExecutionStepLinkedList result; auto taFirst = GetTrace(ta->firstTrace); auto taBranch = GetTrace(ta->branchTrace); auto taFirstExec = GetTraceExec(taFirst->traceExecRef); auto taBranchExec = GetTraceExec(taBranch->traceExecRef); vint32_t prefixExtra = ta->prefix - taFirstExec->insLists.countAll; // Find the first nested TraceAmbiguity between taFirst and taBranch bool currentAmbiguityIsNested = guidance != nullptr; if (!guidance && (DoNotUse_BSLA_Guidance.nestedTas = CollectNestedAmbiguities(ta))) { guidance = &DoNotUse_BSLA_Guidance; } if (currentAmbiguityIsNested) { guidance->nextAmbiguityIndex++; } bool nestedAmbiguityAvailable = guidance && guidance->nextAmbiguityIndex < guidance->nestedTas->nestedAmbiguities.Count(); // Append RA_BEGIN { auto step = GetExecutionStep(executionSteps.Allocate()); step->type = ExecutionType::RA_Begin; step->et_ra.trace = taFirst->allocatedIndex; step->et_ra.type = -1; AppendStepsAfterList({ step,step }, result); } { ExecutionStepTree branchSteps; // If there is a nested TraceAmbiguity, Execute it first if (nestedAmbiguityAvailable) { BuildStepLeafsForNestedAmbiguityBranch(ta, nullptr, guidance, branchSteps); } ExecutionStepLinkedList sharedSteps; // Execute from taFirst to taBranch if (prefixExtra < 0) { if (guidance) { DoNotUse_BSL_Guidance = { (currentAmbiguityIsNested ? &guidance->nestedTas->branchSelections[ta] : nullptr), &guidance->nestedTas->nestedAmbiguities, }; } sharedSteps = BuildStepList( taFirst, ta->prefix, taBranch, taBranchExec->insLists.countAll - 1, (guidance ? &DoNotUse_BSL_Guidance : nullptr) ); } // Nested TraceAmbiguity is not implemented, so all successors of taBranch are needed auto successorId = taBranch->successors.first; while (successorId != nullref) { auto successor = GetTrace(successorId); successorId = successor->successors.siblingNext; if (guidance) { // Skip visited branches for (vint i = guidance->nextAmbiguityIndex; i < guidance->nestedTas->nestedAmbiguities.Count(); i++) { auto nta = guidance->nestedTas->nestedAmbiguities[i]; for (auto selection : guidance->nestedTas->branchSelections[nta]) { if (selection == successor) { goto SKIP_CURRENT_SUCCESSOR; } } } } BuildStepLeafsForAmbiguityBranch(ta, sharedSteps.last, successor, nullptr, branchSteps); SKIP_CURRENT_SUCCESSOR:; } AppendStepsAfterList(ConvertStepTreeToList(branchSteps), result); } if (currentAmbiguityIsNested) { guidance->nextAmbiguityIndex--; } // Append RA_END { auto step = CreateResolveAmbiguityStep(ta); AppendStepsAfterList({ step,step }, result); } return result; } /*********************************************************************** BuildStepListThroughAmbiguity ***********************************************************************/ ExecutionStepLinkedList TraceManager::BuildStepListThroughAmbiguity( Trace*& currentTrace, vint32_t& currentIns, TraceAmbiguity* ta, BSLA_Guidance* guidance ) { ExecutionStepLinkedList result; auto taFirst = GetTrace(ta->firstTrace); auto taLast = GetTrace(ta->lastTrace); auto taFirstExec = GetTraceExec(taFirst->traceExecRef); auto taLastExec = GetTraceExec(taLast->traceExecRef); vint32_t prefixExtra = ta->prefix - taFirstExec->insLists.countAll; vint32_t postfixExtra = ta->postfix - taLastExec->insLists.countAll; if (currentTrace->traceExecRef < taFirst->traceExecRef || currentIns < ta->prefix) { auto step = GetExecutionStep(executionSteps.Allocate()); step->et_i.startTrace = currentTrace->allocatedIndex; step->et_i.startIns = currentIns; if (ta->prefix == 0) { if (taFirst->predecessors.first != taFirst->predecessors.last) { throw TraceException(*this, ta, nullptr, TRACE_MAMAGER_PHRASE, L"The prefix of the TraceAmbiguity is 0, but its firstTrace is a merge trace."); } auto taFirstPrev = GetTrace(taFirst->predecessors.first); auto taFirstPrevExec = GetTraceExec(taFirstPrev->traceExecRef); step->et_i.endTrace = taFirstPrev->allocatedIndex; step->et_i.endIns = taFirstPrevExec->insLists.countAll - 1; } else if (prefixExtra <= 0) { step->et_i.endTrace = taFirst->allocatedIndex; step->et_i.endIns = ta->prefix - 1; } else { step->et_i.endTrace = taFirst->allocatedIndex; step->et_i.endIns = taFirstExec->insLists.countAll - 1; } AppendStepsAfterList({ step, step }, result); } if (prefixExtra > 0) { // at the moment taFirst should be taBranch // TraceAmbiguity begins at each successors of taBranch, instead of before taBranch auto taFirstSuccessor = GetTrace(taFirst->successors.first); auto step = GetExecutionStep(executionSteps.Allocate()); step->et_i.startTrace = taFirstSuccessor->allocatedIndex; step->et_i.startIns = 0; step->et_i.endTrace = taFirstSuccessor->allocatedIndex; step->et_i.endIns = prefixExtra - 1; AppendStepsAfterList({ step, step }, result); } // Execute the next TraceAmbiguity auto taSteps = BuildStepListForAmbiguity(ta, guidance); AppendStepsAfterList(taSteps, result); // Step (currentTrace, currentIns) forward to right after TraceAmbiguity if (postfixExtra > 0) { // at the moment taLast should be taMerge // TraceAmbiguity ends at each predecessor of taMerge, instead of after taMerge auto taLastPredecessor = GetTrace(taLast->predecessors.first); auto taLastPredecessorExec = GetTraceExec(taLastPredecessor->traceExecRef); auto step = GetExecutionStep(executionSteps.Allocate()); step->et_i.startTrace = taLastPredecessor->allocatedIndex; step->et_i.startIns = taLastPredecessorExec->insLists.countAll - postfixExtra; step->et_i.endTrace = taLastPredecessor->allocatedIndex; step->et_i.endIns = taLastPredecessorExec->insLists.countAll - 1; AppendStepsAfterList({ step, step }, result); } if (ta->postfix == 0) { if (taLast->successors.first == nullref) { currentTrace = nullptr; } else if (taLast->successors.first != taLast->successors.last) { throw TraceException(*this, ta, nullptr, TRACE_MAMAGER_PHRASE, L"The postfix of the TraceAmbiguity is 0, but its lastTrace is a branch trace."); } else { currentTrace = GetTrace(taLast->successors.first); currentIns = 0; } } else { currentTrace = taLast; currentIns = -(postfixExtra <= 0 ? postfixExtra : 0); } return result; } /*********************************************************************** BuildStepList ***********************************************************************/ ExecutionStepLinkedList TraceManager::BuildStepListUntilFirstRawBranchTrace( Trace* startTrace, vint32_t startIns, Trace* endTrace, vint32_t endIns, BSL_Guidance* guidance, Trace** rawBranchTrace) { ExecutionStepLinkedList result; Trace* currentTrace = startTrace; vint32_t currentIns = startIns; while (currentTrace) { auto currentTraceExec = GetTraceExec(currentTrace->traceExecRef); // Find the next critical trace Trace* criticalTrace = nullptr; if (currentTraceExec->nextAmbiguityCriticalTrace != nullref) { criticalTrace = currentTrace; } else { criticalTrace = GetTrace(currentTraceExec->branchData.forwardTrace); } while (criticalTrace && criticalTrace->traceExecRef <= currentTrace->traceExecRef) { auto nextRef = GetTraceExec(criticalTrace->traceExecRef)->nextAmbiguityCriticalTrace; if (nextRef == nullref) { if (criticalTrace->successors.first != criticalTrace->successors.last) { // When there is no more next critical trace before a branch trace auto criticalTraceExec = GetTraceExec(criticalTrace->traceExecRef); if (criticalTraceExec->ambiguityBegins != nullref) { // If it is associated with a TraceAmbiguity, it is a critical trace we are looking for break; } throw TraceException(*this, currentTrace, nullptr, TRACE_MAMAGER_PHRASE, L"Failed to find a TraceAmbiguity between this trace and the next branch trace."); } else { // When there is no more next critical trace, we are about to reach the end // Ignore the current critical trace, stop searching, just run through the end goto NO_CRITICAL_TRACE; } } // When it runs past (endTrace, endIns) // Ignore the current critical trace, stop searching, just run through the end criticalTrace = nextRef == nullref ? nullptr : GetTrace(nextRef); if (criticalTrace->traceExecRef >= endTrace->traceExecRef) { goto NO_CRITICAL_TRACE; } else if (endIns < 0 && criticalTrace->successors.first == endTrace) { goto NO_CRITICAL_TRACE; } } // If the current critical trace is associated with a TraceAmbiguity // and the TraceAmbiguity is what configured to skip // treat it as an ordinary trace auto criticalTraceExec = GetTraceExec(criticalTrace->traceExecRef); bool ignoreCriticalAmgiguity = false; if (guidance && guidance->ambiguitiesToSkip && criticalTraceExec->ambiguityBegins != nullref) { auto ta = GetTraceAmbiguity(GetTraceAmbiguityLink(criticalTraceExec->ambiguityBegins)->ambiguity); for (auto nestedTa : *guidance->ambiguitiesToSkip) { if (nestedTa == ta) { ignoreCriticalAmgiguity = true; break; } } } if (ignoreCriticalAmgiguity || criticalTraceExec->ambiguityBegins == nullref) { // If the current critical trace is a branch trace // and there is a specified successor to execute // treat it as an ordinary trace // otherwise, exit properly Trace* specifieidBranchSelection = nullptr; if (criticalTrace->successors.first != criticalTrace->successors.last) { if (guidance && guidance->branchSelections) { for (auto selection : *guidance->branchSelections) { if (criticalTrace == selection->predecessors.first) { specifieidBranchSelection = selection; break; } } } if (!specifieidBranchSelection) { if (rawBranchTrace) { *rawBranchTrace = criticalTrace; endTrace = criticalTrace; endIns = GetTraceExec(endTrace->traceExecRef)->insLists.countAll - 1; goto NO_CRITICAL_TRACE; } else { throw TraceException(*this, currentTrace, criticalTrace, TRACE_MAMAGER_PHRASE, L"The next critical trace after the current trace is not associated with a TraceAmbiguity."); } } } // A critical trace could be a predecessor of a merge trace // Execute until here and continue auto step = GetExecutionStep(executionSteps.Allocate()); step->et_i.startTrace = currentTrace->allocatedIndex; step->et_i.startIns = currentIns; step->et_i.endTrace = criticalTrace->allocatedIndex; step->et_i.endIns = criticalTraceExec->insLists.countAll - 1; AppendStepsAfterList({ step, step }, result); if(specifieidBranchSelection) { currentTrace = specifieidBranchSelection; } else if (criticalTrace->successors.first == nullref) { currentTrace = nullptr; } else { currentTrace = GetTrace(criticalTrace->successors.first); currentIns = 0; } continue; } // Execute from (currentTrace, currentIns) until the next TraceAmbiguity auto ta = GetTraceAmbiguity(GetTraceAmbiguityLink(criticalTraceExec->ambiguityBegins)->ambiguity); auto steps = BuildStepListThroughAmbiguity(currentTrace, currentIns, ta, nullptr); AppendStepsAfterList(steps, result); } NO_CRITICAL_TRACE: if (endIns < 0 && endIns != GetTraceExec(endTrace->traceExecRef)->insLists.countAll - 1) { // The real endTrace is a predecessor of endTrace, but we need to find out which auto realEndTrace = currentTrace; while (realEndTrace->successors.first != endTrace) { realEndTrace = GetTrace(realEndTrace->successors.first); } auto realEndTraceExec = GetTraceExec(realEndTrace->traceExecRef); endTrace = realEndTrace; endIns = realEndTraceExec->insLists.countAll + endIns; } if (currentTrace) { if ( currentTrace->traceExecRef < endTrace->traceExecRef || (currentTrace->traceExecRef == endTrace->traceExecRef && currentIns <= endIns) ) { // Execute from (currentTrace, currentIns) to (endTrace, endIns) auto step = GetExecutionStep(executionSteps.Allocate()); step->et_i.startTrace = currentTrace->allocatedIndex; step->et_i.startIns = currentIns; step->et_i.endTrace = endTrace->allocatedIndex; step->et_i.endIns = endIns; AppendStepsAfterList({ step, step }, result); } else { throw TraceException(*this, currentTrace, endTrace, TRACE_MAMAGER_PHRASE, L"BuildStepList corrupted with a currentTrace after startIns."); } } return result; } ExecutionStepLinkedList TraceManager::BuildStepList( Trace* startTrace, vint32_t startIns, Trace* endTrace, vint32_t endIns, BSL_Guidance* guidance) { return BuildStepListUntilFirstRawBranchTrace(startTrace, startIns, endTrace, endIns, guidance, nullptr); } /*********************************************************************** BuildExecutionOrder ***********************************************************************/ void TraceManager::BuildExecutionOrder() { // get the instruction range auto startTrace = initialTrace; vint32_t startIns = 0; auto endTrace = concurrentTraces->Get(0); vint32_t endIns = GetTraceExec(endTrace->traceExecRef)->insLists.countAll - 1; auto steps = BuildStepList(startTrace, startIns, endTrace, endIns, nullptr); { auto current = steps.last; while (current != steps.first) { auto parent = GetExecutionStep(current->parent); parent->next = current; current = parent; } } firstStep = steps.first; } #undef TRACE_MAMAGER_PHRASE } } } #undef PASS_EXECUTION_STEP_CONTEXT #undef DEFINE_EXECUTION_STEP_CONTEXT /*********************************************************************** .\TRACEMANAGER\TMRA_CHECKMERGETRACES.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { using namespace collections; #define NEW_MERGE_STACK_MAGIC_COUNTER (void)(MergeStack_MagicCounter++) /*********************************************************************** CheckAmbiguityResolution ***********************************************************************/ template bool TraceManager::EnumerateObjects(Ref stackRefLinkStartSet, bool withCounter, TCallback&& callback) { // check every object in the link auto magicIterating = MergeStack_MagicCounter; auto linkId = stackRefLinkStartSet; while (linkId != nullref) { auto stackRefLink = GetInsExec_StackRefLink(linkId); linkId = stackRefLink->previous; auto ieObject = GetInsExec_Stack(stackRefLink->id); if (withCounter) { // skip if it has been searched if (ieObject->mergeCounter == magicIterating) goto CHECK_NEXT_OBJECT; ieObject->mergeCounter = magicIterating; } if (!callback(ieObject)) return false; CHECK_NEXT_OBJECT:; } return true; } template bool TraceManager::EnumerateBottomInstructions(InsExec_Stack* ieObject, TCallback&& callback) { auto insRefLinkId = ieObject->summarizing.bottomInsRefs; while (insRefLinkId != nullref) { auto insRefLink = GetInsExec_InsRefLink(insRefLinkId); insRefLinkId = insRefLink->previous; if (!callback(GetTrace(insRefLink->insRef.trace), insRefLink->insRef.ins)) return false; } return true; } bool TraceManager::ComparePrefix(TraceExec* baselineTraceExec, TraceExec* commingTraceExec, vint32_t prefix) { if (commingTraceExec->insLists.countAll < prefix) return false; for (vint32_t i = 0; i < prefix; i++) { auto&& insBaseline = ReadInstruction(i, baselineTraceExec->insLists); auto&& insComming = ReadInstruction(i, baselineTraceExec->insLists); if (insBaseline != insComming) return false; } return true; } bool TraceManager::ComparePostfix(TraceExec* baselineTraceExec, TraceExec* commingTraceExec, vint32_t postfix) { if (commingTraceExec->insLists.countAll < postfix) return false; for (vint32_t i = 0; i < postfix; i++) { auto&& insBaseline = ReadInstruction(baselineTraceExec->insLists.countAll - i - 1, baselineTraceExec->insLists); auto&& insComming = ReadInstruction(baselineTraceExec->insLists.countAll - i - 1, baselineTraceExec->insLists); if (insBaseline != insComming) return false; } return true; } template bool TraceManager::CheckAmbiguityResolution(TraceAmbiguity* ta, collections::List>& visitingIds, collections::List* failureReasons, TCallback&& callback) { // following conditions need to be satisfies if multiple objects could be the result of ambiguity // // StackBegin that create objects must be // the same instruction in the same trace // in different trace // these traces share the same predecessor // prefix in these traces are the same // // StackEnd that end objects must be // the same instruction in the same trace // in different trace // these traces share the same successor // postfix in these traces are the same // initialize TraceAmbiguity Trace* first = nullptr; Trace* last = nullptr; TraceExec* firstTraceExec = nullptr; TraceExec* lastTraceExec = nullptr; vint firstTraceCount = 0; vint firstSameTraceCount = 0; vint firstSamePredecessorCount = 0; bool foundEndSame = false; bool foundEndPostfix = false; bool succeeded = false; // iterate all top objects if (failureReasons) { failureReasons->Add(L"[InsExec_Stack->summarizing.earliestInsRef]"); } succeeded = callback([&](Ref objRefLink) { return EnumerateObjects(objRefLink, false, [&](InsExec_Stack* ieObject) { auto createTrace = GetTrace(ieObject->summarizing.earliestInsRef.trace); if (failureReasons) { failureReasons->Add(L" Verifying object " + itow(ieObject->allocatedIndex) + L", its earliestInsRef is " + itow(ieObject->summarizing.earliestInsRef.trace.handle) + L"@" + itow(ieObject->summarizing.earliestInsRef.ins) + L"."); } if (!first) { first = createTrace; firstTraceExec = GetTraceExec(first->traceExecRef); ta->firstTrace = createTrace; ta->prefix = ieObject->summarizing.earliestInsRef.ins; if (failureReasons) { failureReasons->Add(L" This is the first object in the list."); } } else { firstTraceCount++; if (first == createTrace) { // check if two instruction is the same if (ta->prefix != ieObject->summarizing.earliestInsRef.ins) { if (failureReasons) { failureReasons->Add(L" It has a different prefix, stopped."); } return false; } firstSameTraceCount++; } if (first->predecessors.first == createTrace->predecessors.first) { // check if two instruction shares the same prefix if (first->predecessors.first != createTrace->predecessors.first) { } auto createTraceExec = GetTraceExec(createTrace->traceExecRef); if (!ComparePrefix(firstTraceExec, createTraceExec, ta->prefix)) { if (failureReasons) { failureReasons->Add(L" They has a different postfix, stopped"); } return false; } firstSamePredecessorCount++; } if (first != createTrace && first->predecessors.first != createTrace->predecessors.first) { if (failureReasons) { failureReasons->Add(L" The predecessor of the trace where the earliestInsRef of the first object is " + itow(first->predecessors.first.handle) + L", meanwhile the one for the current object is " + itow(createTrace->predecessors.first.handle) + L", they are different, stopped."); } return false; } } return true; }); }); if (!succeeded) return false; // iterate all bottom instructions { if (failureReasons) { failureReasons->Add(L"[InsExec_Stack->endWithCreateInsRefs/endWithReuseInsRefs]"); } // endWith(Create|Reuse)InsRefs need to be filtered again // because the object from the first branch could be a field in the object from the second branch // in this case, that object could have multiple incompatible endWith(Create|Reuse)InsRefs // so we try eoTrace and the unique and existing eoTrace->successors.first // see which wins Group postfixesAtSelf, postfixesAtSuccessor; NEW_MERGE_STACK_MAGIC_COUNTER; callback([&](Ref objRefLink) { return EnumerateObjects(objRefLink, true, [&](InsExec_Stack* ieObject) { if (failureReasons) { failureReasons->Add(L" Verifying object " + itow(ieObject->allocatedIndex) + L" which has StackEnd instructions:"); } PushStackRefLink(ta->bottomCreateObjectStacks, ieObject); // check if EO satisfies the condition return EnumerateBottomInstructions(ieObject, [&](Trace* eoTrace, vint32_t eoIns) { if (failureReasons) { failureReasons->Add(L" " + itow(eoTrace->allocatedIndex) + L"@" + itow(eoIns) + L"."); } auto eoTraceExec = GetTraceExec(eoTrace->traceExecRef); InsRef insRef{ eoTrace,eoTraceExec->insLists.countAll - eoIns - 1 }; postfixesAtSelf.Add(eoTrace, insRef); Trace* successorTrace = nullptr; if (eoTrace->successorCount == 1) { successorTrace = GetTrace(eoTrace->successors.first); } postfixesAtSuccessor.Add(successorTrace, insRef); return true; }); }); }); if (failureReasons) { failureReasons->Add(L" [postfixesAtSelf]"); for (vint i = 0; i < postfixesAtSelf.Count(); i++) { auto key = postfixesAtSelf.Keys()[i]; WString message = L" " + itow(key ? key->allocatedIndex : -1) + L" ->"; for (auto&& value : postfixesAtSelf.GetByIndex(i)) { message += L" " + itow(value.trace.handle) + L"@-" + itow(value.ins); } failureReasons->Add(message); } failureReasons->Add(L" [postfixesAtSuccessor]"); for (vint i = 0; i < postfixesAtSuccessor.Count(); i++) { auto key = postfixesAtSuccessor.Keys()[i]; WString message = L" " + itow(key ? key->allocatedIndex : -1) + L" ->"; for (auto&& value : postfixesAtSuccessor.GetByIndex(i)) { message += L" " + itow(value.trace.handle) + L"@-" + itow(value.ins); } failureReasons->Add(message); } } // find the most possible answer from postfixesAtSelf and postfixesAtSuccessor // bottom bottomInsRefs are splitted into multiple group // find the unique one that has the maximum capacity vint maxOccurences = -1; for (vint i = 0; i < postfixesAtSelf.Count(); i++) { vint count = postfixesAtSelf.GetByIndex(i).Count(); if (count > maxOccurences) { maxOccurences = count; } } for (vint i = 0; i < postfixesAtSuccessor.Count(); i++) { vint count = postfixesAtSuccessor.GetByIndex(i).Count(); if (count > maxOccurences) { maxOccurences = count; } } vint uniqueAtSelf = -1; for (vint i = 0; i < postfixesAtSelf.Count(); i++) { vint count = postfixesAtSelf.GetByIndex(i).Count(); if (count == maxOccurences) { if (uniqueAtSelf == -1) { uniqueAtSelf = i; } else { uniqueAtSelf = -2; break; } } } vint uniqueAtSuccessor = -1; for (vint i = 0; i < postfixesAtSuccessor.Count(); i++) { vint count = postfixesAtSuccessor.GetByIndex(i).Count(); if (count == maxOccurences) { if (uniqueAtSuccessor == -1) { uniqueAtSuccessor = i; } else { uniqueAtSuccessor = -2; break; } } } InsRef lastPostfix; if (uniqueAtSelf >= 0) { // if all bottom traces are the same, their first successors are also the same lastPostfix = postfixesAtSelf.GetByIndex(uniqueAtSelf)[0]; } else if (uniqueAtSuccessor >= 0) { lastPostfix = postfixesAtSuccessor.GetByIndex(uniqueAtSuccessor)[0]; foundEndPostfix = true; } if (failureReasons) { failureReasons->Add(L" [unique possible largest group]"); failureReasons->Add(L" postfixesAtSelf -> " + itow(uniqueAtSelf)); failureReasons->Add(L" postfixesAtSuccessor -> " + itow(uniqueAtSuccessor)); failureReasons->Add(L" lastPostfix -> " + itow(lastPostfix.trace.handle) + L"@" + itow(lastPostfix.ins)); } if (lastPostfix.trace == nullref) { if (failureReasons) { failureReasons->Add(L" lastPostfix has an empty trace, stopped."); } succeeded = false; } else { // TODO: check if last is in the same thread and is or after the merge trace last = GetTrace(lastPostfix.trace); ta->lastTrace = last; ta->postfix = lastPostfix.ins; succeeded = true; } } if (!succeeded) return false; if (failureReasons) { failureReasons->Add(L"[TraceAmbiguity]"); } // ensure the statistics result is compatible if (last && !foundEndSame && !foundEndPostfix) foundEndSame = true; if (firstTraceCount != firstSameTraceCount && firstTraceCount != firstSamePredecessorCount) { if (failureReasons) { failureReasons->Add(L"Some StackBegin instructions share the same trace while some share the same predecessor, stopped."); } return false; } if (foundEndSame == foundEndPostfix) { if (failureReasons) { failureReasons->Add(L"Some StackEnd instructions share the same trace while some share the same successor, stopped."); } return false; } // fix prefix if necessary if (firstTraceCount != firstSameTraceCount) { auto first = GetTrace(GetTrace(ta->firstTrace)->predecessors.first); auto traceExec = GetTraceExec(first->traceExecRef); ta->firstTrace = first; ta->prefix += traceExec->insLists.countAll; } // fix postfix if necessary if (foundEndPostfix) { // last will be a merge trace // so ta->postfix doesn't need to change auto last = GetTrace(GetTrace(ta->lastTrace)->successors.first); auto traceExec = GetTraceExec(last->traceExecRef); ta->lastTrace = last; } // ensure firstTrace and lastTrace are in the same branch auto firstForward = GetTrace(GetTraceExec(GetTrace(ta->firstTrace)->traceExecRef)->branchData.forwardTrace); auto lastForward = GetTrace(GetTraceExec(GetTrace(ta->lastTrace)->traceExecRef)->branchData.forwardTrace); if (failureReasons) { failureReasons->Add(L"firstTrace: " + itow(ta->firstTrace.handle)); failureReasons->Add(L"prefix: " + itow(ta->prefix)); failureReasons->Add(L"lastTrace: " + itow(ta->lastTrace.handle)); failureReasons->Add(L"postfix: " + itow(ta->postfix)); failureReasons->Add(L"firstForward: " + itow(firstForward->allocatedIndex)); failureReasons->Add(L"lastForward (currentForward): " + itow(lastForward->allocatedIndex)); } auto currentForward = lastForward; while (true) { if (currentForward->traceExecRef < firstForward->traceExecRef) { if (failureReasons) { failureReasons->Add(L"currentForward is before firstForward, stopped."); } return false; } if (currentForward == firstForward) { return true; } auto currentExec = GetTraceExec(currentForward->traceExecRef); auto nextForwardRef = currentExec->branchData.commonForwardBranch; if (nextForwardRef == nullptr) { nextForwardRef = currentExec->branchData.forwardTrace; } auto nextForward = GetTrace(currentExec->branchData.forwardTrace); if (currentForward != nextForward) { currentForward = nextForward; if (failureReasons) { failureReasons->Add(L"currentForward steps forward to: " + itow(currentForward->allocatedIndex) + L"."); } } else if (currentForward->predecessorCount > 0) { currentForward = GetTrace(GetTraceExec(GetTrace(currentForward->predecessors.first)->traceExecRef)->branchData.forwardTrace); if (failureReasons) { failureReasons->Add(L"currentForward steps forward passing a branch to: " + itow(currentForward->allocatedIndex) + L"."); } } else { if (failureReasons) { failureReasons->Add(L"currentForward reaches the beginning of the trace, stopped."); } break; } } return false; } /*********************************************************************** CheckSingleMergeTrace ***********************************************************************/ bool TraceManager::CheckSingleMergeTrace(TraceAmbiguity* ta, Trace* trace, TraceExec* traceExec, collections::List>& visitingIds, collections::List* failureReasons) { if (failureReasons) { failureReasons->Add(L"Trying to merge trace " + itow(trace->allocatedIndex) + L"."); } // when a merge trace is the last trace // objects in the top object stack are the result of ambiguity if (trace->successorCount == 0) { if (failureReasons) { failureReasons->Add(L"This is the last trace, compare all concurrent objects in the objectStack top."); } auto ieOSTop = GetInsExec_StackArrayRefLink(traceExec->context.objectStack); return CheckAmbiguityResolution(ta, visitingIds, failureReasons, [=](auto&& callback) { return callback(ieOSTop->ids); }); } // otherwise // objects in the top create stack are the result of ambiguity // even when there is only one object in the stack // but in some cases // objects in the top object stack are the result of ambiguity // when these objects are the only difference in branches // here we need to test if the condition satisfied { // [CONDITION] // the first predecessor must has a StackEnd instruction // count the number of instructions after StackEnd // these instructions are the postfix vint32_t postfix = -1; auto firstTrace = GetTrace(trace->predecessors.first); auto firstTraceExec = GetTraceExec(firstTrace->traceExecRef); for (vint32_t i = firstTraceExec->insLists.countAll - 1; i >= 0; i--) { auto&& ins = ReadInstruction(i, firstTraceExec->insLists); if (ins.type == AstInsType::StackEnd) { postfix = firstTraceExec->insLists.countAll - i - 1; break; } } if (postfix == -1) { if (failureReasons) { failureReasons->Add(L"The first predecessor " + itow(firstTrace->allocatedIndex) + L" has no StackEnd."); } goto CHECK_OBJECTS_IN_TOP_CREATE_STACK; } if (failureReasons) { failureReasons->Add(L"The first predecessor " + itow(firstTrace->allocatedIndex) + L" has StackEnd, its postfix is " + itow(postfix) + L"."); } // [CONDITION] // all predecessor must have a StackEnd instruction // posftix of all predecessors must be the same { auto predecessorId = trace->predecessors.last; while (predecessorId != firstTrace) { auto predecessor = GetTrace(predecessorId); predecessorId = predecessor->predecessors.siblingPrev; if (!ComparePostfix(firstTraceExec, GetTraceExec(predecessor->traceExecRef), postfix + 1)) { if (failureReasons) { failureReasons->Add(L"Another predecessor " + itow(predecessor->allocatedIndex) + L" has no StackEnd or has a different postfix."); } goto CHECK_OBJECTS_IN_TOP_CREATE_STACK; } } } // check if all StackEnd ended objects are the result of ambiguity if (postfix == 0) { // if StackEnd is the last instruction of predecessors // then their objRefs has been written to the top object stack if (failureReasons) { failureReasons->Add(L"The postfix is 0, compare all concurrent objects in the objectStack top."); } auto ieOSTop = GetInsExec_StackArrayRefLink(traceExec->context.objectStack); auto succeeded = CheckAmbiguityResolution(ta, visitingIds, failureReasons, [=](auto&& callback) { return callback(ieOSTop->ids); }); if (succeeded) return true; } else { // otherwise find all objRefs of StackEnd if (failureReasons) { failureReasons->Add(L"The postfix > 0, compare all concurrent objects in all StackEnd instructions."); } auto succeeded = CheckAmbiguityResolution(ta, visitingIds, failureReasons, [=, this, &visitingIds](auto&& callback) { auto predecessorId = trace->predecessors.first; while (predecessorId != nullref) { auto predecessor = GetTrace(predecessorId); predecessorId = predecessor->predecessors.siblingNext; // search for the object it ends if (failureReasons) { failureReasons->Add(L"Verifying predecessor " + itow(predecessor->allocatedIndex) + L"."); } auto predecessorTraceExec = GetTraceExec(predecessor->traceExecRef); auto indexEO = predecessorTraceExec->insLists.countAll - postfix - 1; auto insExecEO = GetInsExec(predecessorTraceExec->insExecRefs.start + indexEO); if (!callback(insExecEO->operatingStacks)) return false; } return true; }); if (succeeded) return true; } } CHECK_OBJECTS_IN_TOP_CREATE_STACK: if (failureReasons) { failureReasons->Add(L"All condition dissatisfied, compare all concurrent objects in the createStack top."); } auto ieCSTop = GetInsExec_StackArrayRefLink(traceExec->context.createStack); return CheckAmbiguityResolution(ta, visitingIds, failureReasons, [=](auto&& callback) { return callback(ieCSTop->ids); }); } /*********************************************************************** LinkAmbiguityCriticalTrace ***********************************************************************/ void TraceManager::LinkAmbiguityCriticalTrace(Ref traceId) { auto trace = GetTrace(traceId); auto forward = GetTrace(GetTraceExec(trace->traceExecRef)->branchData.forwardTrace); if (trace == forward) return; auto nextAct = &GetTraceExec(forward->traceExecRef)->nextAmbiguityCriticalTrace; while (*nextAct != nullref) { if (*nextAct == traceId) return; if (*nextAct > traceId) break; nextAct = &GetTraceExec(GetTrace(*nextAct)->traceExecRef)->nextAmbiguityCriticalTrace; } auto traceExec = GetTraceExec(trace->traceExecRef); traceExec->nextAmbiguityCriticalTrace = *nextAct; *nextAct = traceId; } /*********************************************************************** CheckTraceAmbiguity ***********************************************************************/ void TraceManager::CheckTraceAmbiguity(TraceAmbiguity* ta) { #define TRACE_MAMAGER_PHRASE L"ResolveAmbiguity/CheckMergeTraces/CheckTraceAmbiguity" auto teFirst = GetTraceExec(GetTrace(ta->firstTrace)->traceExecRef); if (teFirst->ambiguityBegins == nullref) { LinkAmbiguityCriticalTrace(ta->firstTrace); } // search in all ambiguityBegins and try to find one has the same lastTrace TraceAmbiguityLink* taLinkToOverride = nullptr; auto taLinkRef = teFirst->ambiguityBegins; while (taLinkRef != nullref) { auto taLink = GetTraceAmbiguityLink(taLinkRef); taLinkRef = taLink->previous; auto ta2 = GetTraceAmbiguity(taLink->ambiguity); if (ta->lastTrace == ta2->lastTrace) { // if there is any, try to override this TraceAmbiguity taLinkToOverride = taLink; break; } } if (taLinkToOverride) { // if there is a TraceAmbiguity to override // ensure they are equivalent auto ta2 = GetTraceAmbiguity(taLinkToOverride->ambiguity); if (ta2->prefix != ta->prefix || ta2->postfix != ta->postfix) { throw TraceException(*this, ta, ta2, TRACE_MAMAGER_PHRASE, L"Incompatible TraceAmbiguity has been assigned at the same place"); } // override ambiguityBegins taLinkToOverride->ambiguity = ta; // override TraceAmbiguity ta->overridedAmbiguity = ta2; } else { // otherwise, append itself to the list auto taLink = GetTraceAmbiguityLink(traceAmbiguityLinks.Allocate()); taLink->ambiguity = ta; taLink->previous = teFirst->ambiguityBegins; teFirst->ambiguityBegins = taLink; } #undef TRACE_MAMAGER_PHRASE } /*********************************************************************** CategorizeTraceAmbiguities ***********************************************************************/ void TraceManager::MarkAmbiguityCoveredForward(Trace* currentTrace, TraceAmbiguity* ta, Trace* firstTrace, TraceExec* firstTraceExec) { #define TRACE_MAMAGER_PHRASE L"ResolveAmbiguity/CheckMergeTraces/MarkAmbiguityCoveredForward" while (true) { auto forward = GetTrace(GetTraceExec(currentTrace->traceExecRef)->branchData.forwardTrace); if (forward->traceExecRef <= firstTraceExec) { throw TraceException(*this, forward, nullptr, TRACE_MAMAGER_PHRASE, L"Unexpected ambiguity resolving structure found."); } auto forwardExec = GetTraceExec(forward->traceExecRef); if (forward->predecessors.first != forward->predecessors.last) { if (forwardExec->ambiguityDetected != nullref && forwardExec->ambiguityDetected != ta) { currentTrace = GetTrace(GetTraceAmbiguity(forwardExec->ambiguityDetected)->firstTrace); } else { auto predecessorId = forward->predecessors.first; while (predecessorId != nullref) { auto predecessor = GetTrace(predecessorId); predecessorId = predecessor->predecessors.siblingNext; MarkAmbiguityCoveredForward(predecessor, ta, firstTrace, firstTraceExec); } return; } } else if (forward->predecessors.first != firstTrace) { currentTrace = GetTrace(forward->predecessors.first); } else { return; } } #undef TRACE_MAMAGER_PHRASE } void TraceManager::CategorizeTraceAmbiguities(Trace* trace, TraceExec* traceExec) { // find all ambiguityBegins whose first ambiguity instruction is in successors auto taLinkRef = traceExec->ambiguityBegins; while (taLinkRef != nullref) { auto taLink = GetTraceAmbiguityLink(taLinkRef); taLinkRef = taLink->previous; auto ta = GetTraceAmbiguity(taLink->ambiguity); if (ta->prefix >= traceExec->insLists.countAll) { // mark ambiguityCoveredInForward MarkAmbiguityCoveredForward(GetTrace(ta->lastTrace), ta, trace, traceExec); } } } /*********************************************************************** CheckMergeTraces ***********************************************************************/ void TraceManager::CheckMergeTraces() { #define TRACE_MAMAGER_PHRASE L"ResolveAmbiguity/CheckMergeTraces" // mark all branch trace critical { auto traceId = firstBranchTrace; while (traceId != nullref) { LinkAmbiguityCriticalTrace(traceId); traceId = GetTraceExec(GetTrace(traceId)->traceExecRef)->nextBranchTrace; } } // mark all predecessor of merge trace critical { auto traceId = firstMergeTrace; while (traceId != nullref) { auto trace = GetTrace(traceId); auto predecessorId = trace->predecessors.first; while (predecessorId != nullref) { LinkAmbiguityCriticalTrace(predecessorId); predecessorId = GetTrace(predecessorId)->predecessors.siblingNext; } traceId = GetTraceExec(trace->traceExecRef)->nextMergeTrace; } } // iterating TraceMergeExec List> visitingIds; auto traceId = firstMergeTrace; while (traceId != nullref) { auto trace = GetTrace(traceId); auto traceExec = GetTraceExec(trace->traceExecRef); traceId = traceExec->nextMergeTrace; auto ta = GetTraceAmbiguity(traceAmbiguities.Allocate()); bool succeeded = CheckSingleMergeTrace(ta, trace, traceExec, visitingIds, nullptr); if (!succeeded) { List failureReasons; CheckSingleMergeTrace(ta, trace, traceExec, visitingIds, &failureReasons); throw TraceException(*this, trace, nullptr, TRACE_MAMAGER_PHRASE, stream::GenerateToStream([&](stream::TextWriter& writer) { writer.WriteLine(L"Failed to find ambiguous objects in a merge trace."); writer.WriteLine(L"[Details]"); for (auto&& reason : failureReasons) { writer.WriteLine(reason); } })); } traceExec->ambiguityDetected = ta; // record branch and merge trace ta->mergeTrace = trace; { auto currentBranchTrace = trace; auto predecessorRef = trace->predecessors.first; while (predecessorRef != nullref) { // when traces look like this // the first predecessor locates B while the correct one should be A // so all predecessors need to test // // A // | // +-+-+ // | | // B C // | | // +-+ | // | | | // D E F // | | | // +-+-+ // | // G auto predecessor = GetTrace(predecessorRef); predecessorRef = predecessor->predecessors.siblingNext; Trace* branchTrace = nullptr; auto predecessorForward = GetTrace(GetTraceExec(predecessor->traceExecRef)->branchData.forwardTrace); if (predecessorForward->predecessors.first == predecessorForward->predecessors.last) { branchTrace = predecessorForward; } else { branchTrace = GetTrace(GetTraceExec(predecessorForward->traceExecRef)->branchData.commonForwardBranch); } // when traces look like this // some branchTrace may be the root, ignores // // A // | // +-+-+ // | | | // B C D // | | | // +-+ | // | | // E F // | | // +---+ // | // G if (branchTrace->predecessors.first != nullref) { branchTrace = GetTrace(branchTrace->predecessors.first); if (currentBranchTrace->traceExecRef > branchTrace->traceExecRef) { currentBranchTrace = branchTrace; } } } ta->branchTrace = currentBranchTrace; } if (ta->firstTrace == ta->mergeTrace) { throw TraceException(*this, trace, nullptr, TRACE_MAMAGER_PHRASE, L"Failed to find TraceAmbiguity::branchTrace."); } // check if existing TraceAmbiguity in firstTrace are compatible CheckTraceAmbiguity(ta); } // find all branch trace with ambiguityBegins { auto traceId = firstBranchTrace; while (traceId != nullref) { auto trace = GetTrace(traceId); auto traceExec = GetTraceExec(trace->traceExecRef); traceId = traceExec->nextBranchTrace; if (traceExec->ambiguityBegins != nullref) { CategorizeTraceAmbiguities(trace, traceExec); } } } #undef TRACE_MAMAGER_PHRASE } #undef NEW_MERGE_STACK_MAGIC_COUNTER } } } /*********************************************************************** .\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 == nullref && elementCollection.siblingPrev == nullref) { auto&& ownerCollection = owner->*collection; if (ownerCollection.first == nullref) { ownerCollection.first = element; ownerCollection.last = element; } else { auto sibling = GetTrace(ownerCollection.last); auto&& siblingCollection = sibling->*collection; CHECK_ERROR(siblingCollection.siblingNext == nullref, errorMessage); siblingCollection.siblingNext = element; elementCollection.siblingPrev = sibling; ownerCollection.last = element; } } 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 = nullref; copiedElement->predecessors.siblingNext = nullref; // 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 EndOfInput // if Input and EndOfInput succeeded // there should not be any multiple to multiple relationship CHECK_FAIL(errorMessage); } } TraceManager::TraceManager(Executable& _executable, const ITypeCallback* _typeCallback, vint blockSize) : executable(_executable) , typeCallback(_typeCallback) , returnStacks(blockSize) , traces(blockSize) , competitions(blockSize) , attendingCompetitions(blockSize) , traceExecs(blockSize) , insExec_Stacks(blockSize) , insExec_InsRefLinks(blockSize) , insExec_StackRefLinks(blockSize) , insExec_StackArrayRefLinks(blockSize) , traceAmbiguities(blockSize) , traceAmbiguityLinks(blockSize) , executionSteps(blockSize) { } ReturnStack* TraceManager::GetReturnStack(Ref index) { return returnStacks.Get(index); } ReturnStack* TraceManager::AllocateReturnStack() { return returnStacks.Get(returnStacks.Allocate()); } Trace* TraceManager::GetTrace(Ref index) { return traces.Get(index); } Trace* TraceManager::AllocateTrace() { return traces.Get(traces.Allocate()); } Competition* TraceManager::GetCompetition(Ref index) { return competitions.Get(index); } Competition* TraceManager::AllocateCompetition() { return competitions.Get(competitions.Allocate()); } AttendingCompetitions* TraceManager::GetAttendingCompetitions(Ref index) { return attendingCompetitions.Get(index); } AttendingCompetitions* TraceManager::AllocateAttendingCompetitions() { return attendingCompetitions.Get(attendingCompetitions.Allocate()); } InsExec* TraceManager::GetInsExec(vint32_t index) { return &insExecs[index]; } InsExec_Stack* TraceManager::GetInsExec_Stack(Ref index) { return insExec_Stacks.Get(index); } InsExec_InsRefLink* TraceManager::GetInsExec_InsRefLink(Ref index) { return insExec_InsRefLinks.Get(index); } InsExec_StackRefLink* TraceManager::GetInsExec_StackRefLink(Ref index) { return insExec_StackRefLinks.Get(index); } InsExec_StackArrayRefLink* TraceManager::GetInsExec_StackArrayRefLink(Ref index) { return insExec_StackArrayRefLinks.Get(index); } TraceExec* TraceManager::GetTraceExec(Ref index) { return traceExecs.Get(index); } TraceAmbiguity* TraceManager::GetTraceAmbiguity(Ref index) { return traceAmbiguities.Get(index); } TraceAmbiguityLink* TraceManager::GetTraceAmbiguityLink(Ref index) { return traceAmbiguityLinks.Get(index); } ExecutionStep* TraceManager::GetExecutionStep(Ref index) { return executionSteps.Get(index); } /*********************************************************************** CreateExecutor ***********************************************************************/ Ptr CreateExecutor(Executable& executable, const IExecutor::ITypeCallback* typeCallback, vint blockSize) { return Ptr(new TraceManager(executable, typeCallback, blockSize)); } } } } /*********************************************************************** .\TRACEMANAGER\TRACEMANAGER_COMMON.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** ReadInstructionList ***********************************************************************/ void TraceManager::ReadInstructionList(Trace* trace, TraceInsLists& insLists) { // this function collects the following instructions in order: // 2) byEdge.insAfterInput // 3) executedReturnStack.returnIndex.insAfterInput in order if (trace->byEdge != -1) { auto& edgeDesc = executable.edges[trace->byEdge]; insLists.edgeInsAfterInput = edgeDesc.insAfterInput; } else { insLists.edgeInsAfterInput = {}; } if (trace->executedReturnStack != nullref) { auto returnStack = GetReturnStack(trace->executedReturnStack); auto& returnDesc = executable.returns[returnStack->returnIndex]; insLists.returnInsAfterInput = returnDesc.insAfterInput; } else { insLists.returnInsAfterInput = {}; } insLists.countAfterInput = (vint32_t)(insLists.edgeInsAfterInput.count); insLists.countAll = (vint32_t)(insLists.countAfterInput + 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.countAll, ERROR_MESSAGE_PREFIX L"Instruction index out of range."); vint32_t insRef = -1; if (instruction < insLists.countAfterInput) { insRef = insLists.edgeInsAfterInput.start + instruction; } else if (instruction < insLists.countAll) { insRef = insLists.returnInsAfterInput.start + (instruction - insLists.countAfterInput); } else { CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Instruction index out of range."); } return executable.astInstructions[insRef]; #undef ERROR_MESSAGE_PREFIX } } } } /*********************************************************************** .\TRACEMANAGER\TRACEMANAGER_EXECUTETRACE.CPP ***********************************************************************/ namespace vl { namespace glr { namespace automaton { /*********************************************************************** TraceManager::ExecuteTrace ***********************************************************************/ #define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::ExecuteTrace(Trace*, IAstInsReceiver&, List&)#" class AstInsOptimizer : public Object, public virtual IAstInsReceiver { protected: IAstInsReceiver& receiver; bool cachedStackBegin = false; const regex::RegexToken* cachedStackBeginToken = nullptr; vint32_t cachedStackBeginTokenIndex = -1; public: AstInsOptimizer(IAstInsReceiver& _receiver) :receiver(_receiver) { } void Execute(AstIns instruction, const regex::RegexToken& token, vint32_t tokenIndex) override { if (cachedStackBegin) { if (instruction.type == AstInsType::StackEnd) { cachedStackBegin = false; return; } receiver.Execute({ AstInsType::StackBegin }, *cachedStackBeginToken, cachedStackBeginTokenIndex); cachedStackBegin = false; } if (instruction.type == AstInsType::StackBegin) { cachedStackBegin = true; cachedStackBeginToken = &token; cachedStackBeginTokenIndex = tokenIndex; return; } receiver.Execute(instruction, token, tokenIndex); } Ptr Finished() override { if (cachedStackBegin) { receiver.Execute({ AstInsType::StackBegin }, *cachedStackBeginToken, cachedStackBeginTokenIndex); cachedStackBegin = false; } return receiver.Finished(); } }; void TraceManager::ExecuteSingleTrace(IAstInsReceiver& receiver, Trace* trace, vint32_t firstIns, vint32_t lastIns, TraceInsLists& insLists, collections::List& tokens) { for (vint32_t i = firstIns; i <= lastIns; i++) { auto& ins = ReadInstruction(i, insLists); auto& token = tokens[trace->currentTokenIndex]; receiver.Execute(ins, token, trace->currentTokenIndex); } } void TraceManager::ExecuteSingleStep(IAstInsReceiver& receiver, ExecutionStep* step, collections::List& tokens) { TraceInsLists temp; switch (step->type) { case ExecutionType::Instruction: { // execute from the start trace auto trace = GetTrace(Ref(step->et_i.startTrace)); while (trace) { vint32_t firstIns = -1; vint32_t lastIns = -1; auto insLists = &temp; if (trace->traceExecRef == nullref) { ReadInstructionList(trace, temp); } else { insLists = &GetTraceExec(trace->traceExecRef)->insLists; } // find instruction range to execute if (trace->allocatedIndex == step->et_i.startTrace) { firstIns = step->et_i.startIns; } else { firstIns = 0; } if (trace->allocatedIndex == step->et_i.endTrace) { lastIns = step->et_i.endIns; } else { lastIns = insLists->countAll - 1; } // execute instructions ExecuteSingleTrace(receiver, trace, firstIns, lastIns, *insLists, tokens); // find the next trace if (step->et_i.endTrace == trace->allocatedIndex) { break; } else if (trace->successors.first == nullref) { CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Successor trace missing!"); } else if (trace->successors.first == trace->successors.last) { trace = GetTrace(trace->successors.first); } else { CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Ambiguity should not happen inside one execution step!"); } } } break; default: { auto raTrace = GetTrace(Ref(step->et_ra.trace)); raTrace = EnsureTraceWithValidStates(raTrace); auto raToken = raTrace->currentTokenIndex; switch (step->type) { case ExecutionType::RA_Begin: { if (raToken == -1) raToken = 0; AstIns ins = { AstInsType::StackBegin }; receiver.Execute(ins, tokens[raToken], raToken); } break; case ExecutionType::RA_Branch: { AstIns ins = { AstInsType::StackSlot,-1,ResolveAmbiguitySlotIndex }; receiver.Execute(ins, tokens[raToken], raToken); } break; case ExecutionType::RA_End: { AstIns ins = { AstInsType::ResolveAmbiguity,step->et_ra.type,0 }; receiver.Execute(ins, tokens[raToken], raToken); } { AstIns ins = { AstInsType::StackEnd }; receiver.Execute(ins, tokens[raToken], raToken); } break; default:; } } } } Ptr TraceManager::ExecuteTrace(IAstInsReceiver& receiver, collections::List& tokens) { CHECK_ERROR(state == TraceManagerState::ResolvedAmbiguity, ERROR_MESSAGE_PREFIX L"Wrong timing to call this function."); // execute from the first step AstInsOptimizer optimizedReceiver(receiver); auto step = GetInitialExecutionStep(); CHECK_ERROR(step != nullptr, L"Internal error: execution steps not built!"); while (step) { // execute step ExecuteSingleStep(optimizedReceiver, step, tokens); // find the next step step = step->next == nullref ? nullptr : GetExecutionStep(step->next); } return optimizedReceiver.Finished(); } #undef ERROR_MESSAGE_PREFIX } } } /*********************************************************************** .\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& tokens; public: XmlUnescapeVisitor(List& _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()) { if (end == -1) end = i; } else { if (end != -1) begin = i + 1; } if (begin != -1 && end != -1) { vint beginTokenIndex = node->subNodes[begin].Cast()->content.index; vint endTokenIndex = node->subNodes[end].Cast()->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); auto xmlText = Ptr(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"name.value); writer.WriteChar(L'>'); } } void Visit(XmlInstruction* node) { writer.WriteString(L"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""; } WString XmlUnescapeCData(const WString& value) { return value.Sub(9, value.Length() - 12); } WString XmlEscapeComment(const WString& value) { return L""; } WString XmlUnescapeComment(const WString& value) { return value.Sub(4, value.Length() - 7); } /*********************************************************************** Parsing and Printing ***********************************************************************/ Ptr XmlParseDocument(const WString& input, const Parser& parser) { List tokens; parser.Tokenize(input, tokens); auto ast = parser.ParseXDocument(tokens); XmlUnescapeVisitor(tokens).InspectInto(ast.Obj()); return ast; } Ptr XmlParseElement(const WString& input, const Parser& parser) { List tokens; parser.Tokenize(input, tokens); auto ast = parser.ParseXElement(tokens); XmlUnescapeVisitor(tokens).InspectInto(ast.Obj()); return ast; } void XmlPrint(Ptr node, stream::TextWriter& writer) { XmlPrintVisitor visitor(writer); node->Accept(&visitor); } void XmlPrintContent(Ptr element, stream::TextWriter& writer) { XmlPrintVisitor visitor(writer); for (auto node : element->subNodes) { node->Accept(&visitor); } } WString XmlToString(Ptr node) { return GenerateToStream([&](StreamWriter& writer) { XmlPrint(node, writer); }); } /*********************************************************************** Utility ***********************************************************************/ Ptr XmlGetAttribute(Ptr element, const WString& name) { return XmlGetAttribute(element.Obj(), name); } Ptr XmlGetElement(Ptr element, const WString& name) { return XmlGetElement(element.Obj(), name); } collections::LazyList> XmlGetElements(Ptr element) { return XmlGetElements(element.Obj()); } collections::LazyList> XmlGetElements(Ptr element, const WString& name) { return XmlGetElements(element.Obj(), name); } WString XmlGetValue(Ptr element) { return XmlGetValue(element.Obj()); } Ptr XmlGetAttribute(XmlElement* element, const WString& name) { for (auto att : element->attributes) { if (att->name.value == name) { return att; } } return nullptr; } Ptr XmlGetElement(XmlElement* element, const WString& name) { for (auto node : element->subNodes) { Ptr subElement = node.Cast(); if (subElement && subElement->name.value == name) { return subElement; } } return nullptr; } collections::LazyList> XmlGetElements(XmlElement* element) { return From(element->subNodes).FindType(); } collections::LazyList> 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()) { result += text->content.value; } else if (auto text = node.Cast()) { result += text->content.value; } } return result; } /*********************************************************************** XmlElementWriter ***********************************************************************/ XmlElementWriter::XmlElementWriter(Ptr _element, const XmlElementWriter* _previousWriter) : element(_element) , previousWriter(_previousWriter) { } XmlElementWriter::~XmlElementWriter() { } const XmlElementWriter& XmlElementWriter::Attribute(const WString& name, const WString& value)const { auto node = Ptr(new XmlAttribute); node->name.value = name; node->value.value = value; element->attributes.Add(node); return *this; } XmlElementWriter XmlElementWriter::Element(const WString& name)const { auto node = Ptr(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 { auto node = Ptr(new XmlText); node->content.value = value; element->subNodes.Add(node); return *this; } const XmlElementWriter& XmlElementWriter::CData(const WString& value)const { auto node = Ptr(new XmlCData); node->content.value = value; element->subNodes.Add(node); return *this; } const XmlElementWriter& XmlElementWriter::Comment(const WString& value)const { auto node = Ptr(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::glr::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::reflection::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(), 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(), 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(), 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(), 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(), 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(), 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(), 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()) { auto loader = Ptr(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::glr::xml::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& value) { node->prologs.Add(value); return *this; } MakeDocument& MakeDocument::rootElement(const vl::Ptr& value) { node->rootElement = value; return *this; } /*********************************************************************** MakeElement ***********************************************************************/ MakeElement& MakeElement::attributes(const vl::Ptr& 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& value) { node->subNodes.Add(value); return *this; } /*********************************************************************** MakeInstruction ***********************************************************************/ MakeInstruction& MakeInstruction::attributes(const vl::Ptr& 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::glr::xml::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(from), static_cast(to)); to->content = from->content; } void AstVisitor::CopyFields(XmlComment* from, XmlComment* to) { CopyFields(static_cast(from), static_cast(to)); to->content = from->content; } void AstVisitor::CopyFields(XmlDocument* from, XmlDocument* to) { CopyFields(static_cast(from), static_cast(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(from), static_cast(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(from), static_cast(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(from), static_cast(to)); to->content = from->content; } void AstVisitor::Visit(XmlAttribute* node) { auto newNode = vl::Ptr(new XmlAttribute); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(XmlText* node) { auto newNode = vl::Ptr(new XmlText); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(XmlCData* node) { auto newNode = vl::Ptr(new XmlCData); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(XmlComment* node) { auto newNode = vl::Ptr(new XmlComment); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(XmlElement* node) { auto newNode = vl::Ptr(new XmlElement); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(XmlInstruction* node) { auto newNode = vl::Ptr(new XmlInstruction); CopyFields(node, newNode.Obj()); this->result = newNode; } void AstVisitor::Visit(XmlDocument* node) { auto newNode = vl::Ptr(new XmlDocument); CopyFields(node, newNode.Obj()); this->result = newNode; } vl::Ptr AstVisitor::CopyNode(XmlNode* node) { if (!node) return nullptr; node->Accept(static_cast(this)); this->result->codeRange = node->codeRange; return this->result.Cast(); } vl::Ptr AstVisitor::CopyNode(XmlAttribute* node) { if (!node) return nullptr; Visit(node); this->result->codeRange = node->codeRange; return this->result.Cast(); } vl::Ptr AstVisitor::CopyNode(XmlCData* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(XmlComment* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(XmlDocument* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(XmlElement* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(XmlInstruction* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } vl::Ptr AstVisitor::CopyNode(XmlText* node) { if (!node) return nullptr; return CopyNode(static_cast(node)).Cast(); } } /*********************************************************************** .\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::glr::xml::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::glr::xml::json_visitor { void AstVisitor::PrintFields(XmlAttribute* node) { BeginField(vl::WString::Unmanaged(L"name")); WriteToken(node->name); EndField(); BeginField(vl::WString::Unmanaged(L"value")); WriteToken(node->value); EndField(); } void AstVisitor::PrintFields(XmlCData* node) { BeginField(vl::WString::Unmanaged(L"content")); WriteToken(node->content); EndField(); } void AstVisitor::PrintFields(XmlComment* node) { BeginField(vl::WString::Unmanaged(L"content")); WriteToken(node->content); EndField(); } void AstVisitor::PrintFields(XmlDocument* node) { BeginField(vl::WString::Unmanaged(L"prologs")); BeginArray(); for (auto&& listItem : node->prologs) { BeginArrayItem(); Print(listItem.Obj()); EndArrayItem(); } EndArray(); EndField(); BeginField(vl::WString::Unmanaged(L"rootElement")); Print(node->rootElement.Obj()); EndField(); } void AstVisitor::PrintFields(XmlElement* node) { BeginField(vl::WString::Unmanaged(L"attributes")); BeginArray(); for (auto&& listItem : node->attributes) { BeginArrayItem(); Print(listItem.Obj()); EndArrayItem(); } EndArray(); EndField(); BeginField(vl::WString::Unmanaged(L"closingName")); WriteToken(node->closingName); EndField(); BeginField(vl::WString::Unmanaged(L"name")); WriteToken(node->name); EndField(); BeginField(vl::WString::Unmanaged(L"subNodes")); BeginArray(); for (auto&& listItem : node->subNodes) { BeginArrayItem(); Print(listItem.Obj()); EndArrayItem(); } EndArray(); EndField(); } void AstVisitor::PrintFields(XmlInstruction* node) { BeginField(vl::WString::Unmanaged(L"attributes")); BeginArray(); for (auto&& listItem : node->attributes) { BeginArrayItem(); Print(listItem.Obj()); EndArrayItem(); } EndArray(); EndField(); BeginField(vl::WString::Unmanaged(L"name")); WriteToken(node->name); EndField(); } void AstVisitor::PrintFields(XmlNode* node) { } void AstVisitor::PrintFields(XmlText* node) { BeginField(vl::WString::Unmanaged(L"content")); WriteToken(node->content); EndField(); } void AstVisitor::Visit(XmlText* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Text"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(XmlCData* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"CData"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(XmlComment* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Comment"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(XmlElement* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Element"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(XmlInstruction* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Instruction"), node); PrintFields(static_cast(node)); PrintFields(static_cast(node)); EndObject(); } void AstVisitor::Visit(XmlDocument* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Document"), node); PrintFields(static_cast(node)); PrintFields(static_cast(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(this)); } void AstVisitor::Print(XmlAttribute* node) { if (!node) { WriteNull(); return; } BeginObject(); WriteType(vl::WString::Unmanaged(L"Attribute"), node); PrintFields(static_cast(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::glr::xml::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(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(node->content); Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(XmlCData* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(node->content); Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(XmlComment* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(node->content); Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(XmlElement* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(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(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(XmlInstruction* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); for (auto&& listItem : node->attributes) { InspectInto(listItem.Obj()); } Traverse(node->name); Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::Visit(XmlDocument* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(static_cast(node)); for (auto&& listItem : node->prologs) { InspectInto(listItem.Obj()); } InspectInto(node->rootElement.Obj()); Finishing(static_cast(node)); Finishing(static_cast(node)); Finishing(static_cast(node)); } void AstVisitor::InspectInto(XmlNode* node) { if (!node) return; node->Accept(static_cast(this)); } void AstVisitor::InspectInto(XmlAttribute* node) { if (!node) return; Traverse(static_cast(node)); Traverse(static_cast(node)); Traverse(node->name); Traverse(node->value); Finishing(static_cast(node)); Finishing(static_cast(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::glr::xml { void XmlParserData(vl::stream::IStream& outputStream) { static const vl::vint dataLength = 2277; // 22621 bytes before compressing static const vl::vint dataBlock = 256; static const vl::vint dataRemain = 229; static const vl::vint dataSolidRows = 8; static const vl::vint dataRows = 9; static const char* compressed[] = { "\x5D\x58\x00\x00\xDD\x08\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\x69\x2A\x42\x7B\x7E\x5B\xCB\x63\xB5\xC3\x41\x72\x4D\x7E\x44\x7C\xEF\xEF\xBE\xC3\x41\x7A\x40\xB9\xC2\x4C\x73\x55\x51\x83\xF1\x41\xF1\xBA\x6B\xCC\xF1\x6F\xCE\xC5\x51\xF4\xF2\x28\xFB\xEB\x71\x51\xC1\xC2\x4D\x8B\xEF\xC6\xD2\xF9\x4A\xF5\x03\x47\xFD\xEE\x42\xDB\xDC\xF0\x02\xF8\xAE\x72\x40\xF9\xF7\x57\x59\xF1\x41\xF9\xDC\xE8\xF5\x6E\xFA\x0A\x72\xFA\x6E\xFB\x00\x30\xFF\xEE\xFD\xD0\xE9\x4F\xF2\x4C\x2B\x6B\x7D\x40\x4A\x7D\x36\xFC\x4F\x79\x24\xFC\x60\x82\xFF\x5E\x73\x66\x01\x80\x07\x7F\x29\x38\x7D\x6A\x66\x77\x7C\x06\xA3\x20\x82\x0A\x93\x5F\x63\x04\x8F\x31\x09\xA6\x7C\x7E\x7A\x36\x82\x06\xC5\x2E\x82\xEE\x60\x86\x20\x18\x99\x83\xCF\x0E\x8E\x80\x99\x38\x7F\x3B\xC2\x6A\x20\xFE\x47\x31\x85\xE1\x0A\x21\x3E\x36\x99\x87\xF5\x09\x2C\x7F\x04\xAA\x81", "\x47\x34\x88\x86\x08\xAF\x69\x84\x15\x8E\x4D\x88\x19\x87\x8B\x10\xBF\x68\x88\x05\x8A\x8C\x7A\x33\x6D\x88\x00\xCE\x4F\x31\x20\x83\x22\x8A\xD3\x76\x74\xCA\x58\x8B\x8B\x25\xA7\x6C\x8B\x51\x9E\x8B\x13\xDA\x83\x67\xC7\x3C\x7C\x85\xD8\x7E\x3A\x8B\x33\x84\x76\x19\xB7\x86\x8D\x3A\x81\x7D\xFD\x73\x80\x8A\x36\x70\x84\x78\x62\x87\x3C\x18\xCC\x6B\x8F\x79\x7D\x8C\x88\x79\x8F\x3F\x1F\xCC\x81\x90\xFB\x3E\x87\x87\xFF\x07\x93\x0F\x8A\x9A\x84\x46\x99\x83\x90\x67\x7B\x80\x05\xBD\x35\x84\x3C\xB5\x8B\x84\x57\x35\x93\xF2\x05\x94\x40\x07\xB8\x7E\x85\x0D\x2B\x8E\x42\x01\x45\x87\x1D\xA4\x8F\x82\x9C\x86\x48\x24\xE3\x89\x7D\x2E\x97\x90\x90\xAF\x84\x91\x2C\xE7\x6E\x80\x4D\x85\x82\x21\x0E\x81\x24\xFE\x0E\x84\x80\xFC\x46\x84\x8E\xA7\x9F\x23\x2A\xFA\x89\x94\x5B\x43\x9F\x3D\xB6\x92\x27\xF3\x49\x9B\x81\x84\x0C\x9E\x24\xBF\x93\x94\x24\xD3\x9E\x8B\x67\xA3\x22\x82\x45\x2B\x99\x36\xED\x83\x96\x6B\x9C\x30\x92\xDE\x9E\x23\xF3\x60\x95\x28\x02\xA1\x99\x36\xE7\x9F\x1E\x36\xD7\x26\x9D\xF3\x29\x9B\x9D\x7E\x24\x82\xC5\x14\x84\x80\x78\x97\x88\x97\xDC\x86", "\x22\x03\xCF\x7B\x9E\x38\x82\x89\x21\x56\x96\x92\x3E\xC0\x98\x34\x82\x82\x26\x81\x67\x86\xA1\x40\x08\xAE\x9E\x39\x80\xA2\xA1\xC0\x2A\x22\x2D\xE8\x89\x20\x4F\x86\x38\x9F\x09\x37\x8D\x40\x38\x86\x20\x52\x86\x21\x42\x06\x3A\x7F\x8F\x0F\x2A\x20\x33\x49\x26\x4E\x09\x2D\x52\x41\x16\x54\x83\x4C\x54\x85\x54\xEF\x21\x27\x24\x2E\x41\x24\x98\xB6\x39\x24\x94\x02\x95\x42\x31\x51\xA6\x85\x15\x16\x45\x0E\x96\x58\x32\x8A\x26\x12\x17\x44\x85\x59\x43\xA9\x23\x25\x2E\x46\x97\x68\x49\xAE\x20\x98\x0E\x47\xF3\x4F\x5F\xA9\x81\x19\x12\xA7\xB0\x47\x3D\x48\x1A\x14\xA6\x85\x23\x5D\xA7\x09\x3B\x11\x57\x89\x2F\xAB\x9B\x8A\x24\x13\x2E\x41\xA1\x40\x75\x50\xAC\x83\x1D\x11\x9F\xBA\x6A\x21\xC1\x6D\xA3\x21\x4F\x30\xAA\x20\xB6\x8E\x60\x5D\x82\x21\x15\xBB\x81\x22\xAD\x00\x0C\xAE\x59\x89\x23\x14\xA0\xB2\xAA\xAB\x0A\x24\x14\x53\x8A\x2A\xAF\xC1\x86\x25\x14\x69\xAA\x22\x60\x84\x41\x24\x53\x06\xB1\x21\x73\xAE\xB3\x40\x27\x1B\xB1\x84\x0D\xB4\xB2\x0A\x28\x16\x8B\x48\x03\x93\x16\xA8\x61\x24\x52\x88\xB6\x44\xFE\x6F\x80\x83\x76\x94\x80\x2B\x73\xA3\x79\x7D", "\x91\x72\xF6\x60\x3F\x3C\xF8\x6E\x93\xCF\x1A\xAD\xB5\xF7\x38\x7C\xA3\x96\x61\x22\x47\xF7\x9E\xB6\x35\xB5\xB7\x7D\x7E\xBB\x58\xFE\x43\xBA\x70\x83\x17\x4F\x9F\x86\x97\xA3\x71\x80\x08\xA4\x83\x29\x99\x24\xBC\xA0\xB3\xCA\x2E\xA6\xBB\xF3\x00\xBA\x20\xDA\xA8\x64\xAA\x4E\x97\x3C\xE6\xBF\xAC\xB5\xC0\x44\xBF\x7B\x20\xA3\x20\x20\x54\x72\x20\xC8\x50\xB8\x81\x6E\xB3\x20\x91\x8D\x69\x36\x48\xBD\xBB\x7B\x4F\xB3\x21\xEA\x81\xB8\x00\x42\xB2\xBE\x91\x7E\xB2\x20\x93\xAF\xB9\x20\xDD\x4A\xBE\x7D\x2A\xA3\x20\xEE\xBF\xBD\xAC\xC4\xB6\x3E\x83\x82\x2C\x53\xE9\xA7\x5F\xB6\xEF\x35\xC2\x41\x63\xB7\xC0\x00\x30\x58\x5D\xBF\x3A\xC3\x40\x2B\x53\xBB\xC9\x82\x20\xB6\x21\xD8\xA1\x87\x99\xB1\xC2\xEE\x44\x86\xA6\x03\x3C\xC3\x7F\x90\x60\xC4\xD1\x30\xC2\x20\x24\xDD\xC2\xC4\x35\xC4\x54\x15\xFF\xBC\x62\xA5\x91\x86\xB6\x32\xC2\x20\x96\x9D\xC0\x63\x0F\xAF\x3D\x8E\x83\x29\xBD\x0E\xCF\x6C\xC7\x9C\x2B\xCA\x40\x13\xCE\x70\x85\x23\x69\xC8\x02\xAD\xC4\x8E\x90\xAC\x6D\xE4\xB4\xB6\x20\x52\xDB\xA0\x6B\xF7\x68\xCB\xF3\xA5\xC8\x00\x61\xC4\x20\x6B\x85\x77\xCC\xDE", "\x8F\x79\xCD\x04\xD5\xCB\xE2\x49\xB6\xBD\xDE\xA0\xCA\x21\xF4\xAD\xBB\x40\x1B\x77\xCC\xFB\xAF\xCB\x94\xAC\xA1\x77\x99\xFC\xB9\xCA\x81\x3C\xA6\x20\x4D\xDF\xBD\xEB\x50\xC0\x35\x43\xCD\xC4\xB5\xB0\x67\xCD\x9C\xF6\xC3\x20\x47\xF6\xB7\xBF\x49\x09\xBA\x91\xDA\xC1\x20\x4B\xE2\xCB\xBA\x4B\x09\xBA\x88\x85\xDD\xD2\xE3\x9D\xC5\x09\xC9\xA4\xCB\x26\xBB\xAA\x21\x49\xEB\x67\x09\xC9\xBE\xD0\xA5\x86\xD8\xCE\xD6\x91\x09\xB9\xC3\x47\xCE\xAC\xF5\xCB\x65\x29\x09\xB9\xBE\x9C\xC0\x01\xA2\x82\x26\x59\xE9\x95\x0E\x60\xB9\xCB\xA4\x6B\xD6\x02\xBA\xFB\x05\xDE\x20\xC9\xDF\xBC\x17\x06\x60\xD9\x29\xEC\xB5\x0B\xC9\xB9\xBE\x90\x86\x25\xDB\x80\x3A\xB7\x6C\x5F\x09\xB8\x55\x98\xCC\xDB\x37\x93\xB9\x0C\xC9\xAE\xA8\xB9\x83\x2D\xDA\x35\xD3\xBB\x0C\xC9\xA1\xC3\xB6\xEC\xDD\xD4\xD6\xA5\x09\xB9\xD9\x4B\xDC\x7C\xB5\xD3\xBB\x33\x09\xB9\xC1\xFA\xC1\x21\xBB\xBC\xD8\x65\x34\x09\xBF\x5B\xDA\x5A\xDA\x40\x4B\x53\xBB\x35\x06\x63\xDC\x03\x2C\xE1\x87\xEC\x06\x60\x75\xD1\xE4\xB5\x6D\x06\x62\xBC\x8B\xEC\xB4\x37\x06\x61\xDF\x03\x28\xE1\x87\xEF\x09\xB8\xDE\x22\xE3\x20", "\xE1\x53\xB9\x1C\x06\x69\xE4\x83\x25\x5B\xBA\x72\x0C\xE6\x8F\xFA\xC2\x21\x39\x09\xBD\xE5\xF3\xC2\x20\x84\x82\x2F\xE5\x0E\xF5\x0E\x60\x3B\xEB\xA0\x6B\xF6\x09\xB9\xA0\xC0\x04\x80\x3D\xE3\x20\xC0\xFF\xB8\x0F\x99\xF6\x57\xC2\x21\xEC\xB4\x1F\x49\xB9\xE9\x13\xD7\x22\x21\x54\xD7\xBE\x6D\x7E\x09\xB8\xA8\xD6\xE9\x21\x5E\xE1\x22\xAB\xA8\x60\x11\xE4\x9F\xC1\xE0\x81\xAA\x23\xC9\xB4\xE1\x20\x41\x09\xBE\xC4\x03\x92\xB0\xD6\xAC\xB4\x11\xE4\xAC\xC7\xEB\x06\x30\xEC\x75\xAC\xB6\x11\xE4\x9F\xB0\xEF\x03\x37\xED\x40\x67\xEF\xBE\x44\x0D\xA6\x48\x7F\xE1\x23\xDA\xF2\xC6\x21\x46\x09\xBC\xC6\x68\xE9\xF0\x00\x59\xEB\x65\x47\x09\xBB\xC7\x91\xF5\xDF\x74\x91\x19\xB8\x20\xE8\xE8\xF2\x93\x9C\x21\xE8\xBF\x7C\x82\xD8\xA5\xF3\x2E\x34\xA7\x83\xFF\x07\x86\x96\x00\x09\x9D\xF5\xB9\x8D\x85\xEC\xA1\x23\xF6\xA7\xC2\xEE\xF6\x11\xB8\xF4\xFE\x00\x0F\x93\xDD\xFE\xF2\x97\x21\x20\xB0\x00\x5A\xB2\xF9\xE2\xC1\xF8\x81\xC8\xFC\x20\xFF\x15\x80\xA2\x9B\x00", }; 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 } \"\" ) >", L"[20][XElement]< \"<\" NAME @ { XAttribute } ( \"/>\" | \">\" { XSubNode } \"\" ) >", L"[21][XElement]< \"<\" NAME { XAttribute @ } ( \"/>\" | \">\" { XSubNode } \"\" ) >", L"[22][XElement]< \"<\" NAME { XAttribute } ( \"/>\" @ | \">\" { XSubNode } \"\" ) >", L"[23][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" @ { XSubNode } \"\" ) >", L"[24][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" { XSubNode @ } \"\" ) >", L"[25][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" { XSubNode } \"\" ) >", L"[26][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" { XSubNode } \"\" @ ) >", L"[27][XElement]< \"<\" NAME { XAttribute } ( \"/>\" | \">\" { XSubNode } \"\" ) >", L"[28][XSubNode] BEGIN ", L"[29][XSubNode] END [ENDING]", L"[30][XSubNode]", L"[31][XSubNode]", L"[32][XSubNode]", L"[33][XSubNode]", L"[34][XInstruction] BEGIN ", L"[35][XInstruction] END [ENDING]", L"[36][XInstruction]< \"\" >", L"[37][XInstruction]< \"\" >", L"[38][XInstruction]< \"\" >", L"[39][XInstruction]< \"\" @ >", 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(&XmlTokenDeleter, &XmlLexerData, &XmlParserData) { } vl::WString Parser::GetClassName(vl::vint32_t classIndex) const { return vl::WString::Unmanaged(XmlTypeName((XmlClasses)classIndex)); } vl::vint32_t Parser::FindCommonBaseClass(vl::vint32_t class1, vl::vint32_t class2) const { return -1; } vl::Ptr Parser::ParseXElement(const vl::WString& input, vl::vint codeIndex) const { return ParseWithString(input, this, codeIndex); } vl::Ptr Parser::ParseXElement(vl::collections::List& tokens, vl::vint codeIndex) const { return ParseWithTokens(tokens, this, codeIndex); } vl::Ptr Parser::ParseXDocument(const vl::WString& input, vl::vint codeIndex) const { return ParseWithString(input, this, codeIndex); } vl::Ptr Parser::ParseXDocument(vl::collections::List& tokens, vl::vint codeIndex) const { return ParseWithTokens(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::glr::xml { /*********************************************************************** XmlAstInsReceiver : public vl::glr::AstInsReceiverBase ***********************************************************************/ vl::Ptr XmlAstInsReceiver::CreateAstNode(vl::vint32_t type) { auto cppTypeName = XmlCppTypeName((XmlClasses)type); switch((XmlClasses)type) { case XmlClasses::Attribute: return vl::Ptr(new vl::glr::xml::XmlAttribute); case XmlClasses::CData: return vl::Ptr(new vl::glr::xml::XmlCData); case XmlClasses::Comment: return vl::Ptr(new vl::glr::xml::XmlComment); case XmlClasses::Document: return vl::Ptr(new vl::glr::xml::XmlDocument); case XmlClasses::Element: return vl::Ptr(new vl::glr::xml::XmlElement); case XmlClasses::Instruction: return vl::Ptr(new vl::glr::xml::XmlInstruction); case XmlClasses::Text: return vl::Ptr(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 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, bool weakAssignment) { 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 XmlAstInsReceiver::ResolveAmbiguity(vl::vint32_t type, vl::collections::Array>& 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::glr::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"=", 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"[a-zA-Z0-9:._/-]+", L"\"[^<>\"]*\"|\'[^<>\']*\'", L"/])*--/>", L"/])*/]/]+/>", 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 = 1105; // 7530 bytes before compressing static const vl::vint dataBlock = 256; static const vl::vint dataRemain = 81; static const vl::vint dataSolidRows = 4; static const vl::vint dataRows = 5; static const char* compressed[] = { "\x6A\x1D\x00\x00\x49\x04\x00\x00\x2D\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\x16\x04\x80\x81\x92\x90\x06\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\x37\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\x00\x26\x15\x90\x82\x06\x99\x8C\x82\x0A\x80\x02\x05\x1B\x9E\x82\x05\x82\x81\x84\x0B\xA6\x85\x84\x28\x9D\x83\x09\x93\x88\x82\x11\xA9\x86\x85\x2A\x8E\x80\x08\xB1\x8D\x83\xFA\x78\x7F\x86\xFA\x78\x85\xFF\x3A\x80\x81\x1C\xBE\x83", "\x7A\x3D\x84\x76\x10\x8A\x4E\x1F\x6F\x2B\x08\x00\x04\x10\x00\x4D\x05\x29\x35\x80\x0B\x38\x00\x4F\x87\x35\x68\x15\x32\x23\x2A\x8E\x8C\x22\x05\x2A\x34\x46\x24\x36\x8A\x00\x1F\x31\x20\x96\x21\x21\x70\x18\x3B\x8A\x32\x81\x26\x38\x00\x03\x8E\x1A\xE5\x8B\x8C\x31\xAC\x8F\x8D\xB8\x2D\x8D\x1A\xF0\x83\x8E\x37\xB6\x8D\x8E\x92\x24\x20", }; vl::glr::DecompressSerializedData(compressed, true, dataSolidRows, dataRows, dataBlock, dataRemain, outputStream); } }