mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-02-05 19:40:03 +08:00
3446 lines
117 KiB
C++
3446 lines
117 KiB
C++
/***********************************************************************
|
|
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
|
|
DEVELOPER: Zihan Chen(vczh)
|
|
***********************************************************************/
|
|
#include "VlppReflection.h"
|
|
#include "VlppOS.h"
|
|
#include "Vlpp.h"
|
|
#include "VlppRegex.h"
|
|
|
|
/***********************************************************************
|
|
.\ASTBASE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_ASTBASE
|
|
#define VCZH_PARSER2_ASTBASE
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
/***********************************************************************
|
|
ParsingTextPos
|
|
***********************************************************************/
|
|
|
|
/// <summary>A type representing text position.</summary>
|
|
struct ParsingTextPos
|
|
{
|
|
static const vint UnknownValue = -2;
|
|
/// <summary>Character index, begins at 0.</summary>
|
|
vint index;
|
|
/// <summary>Row number, begins at 0.</summary>
|
|
vint row;
|
|
/// <summary>Column number, begins at 0.</summary>
|
|
vint column;
|
|
|
|
ParsingTextPos()
|
|
:index(UnknownValue)
|
|
, row(UnknownValue)
|
|
, column(UnknownValue)
|
|
{
|
|
}
|
|
|
|
ParsingTextPos(vint _index)
|
|
:index(_index)
|
|
, row(UnknownValue)
|
|
, column(UnknownValue)
|
|
{
|
|
}
|
|
|
|
ParsingTextPos(vint _row, vint _column)
|
|
:index(UnknownValue)
|
|
, row(_row)
|
|
, column(_column)
|
|
{
|
|
}
|
|
|
|
ParsingTextPos(vint _index, vint _row, vint _column)
|
|
:index(_index)
|
|
, row(_row)
|
|
, column(_column)
|
|
{
|
|
}
|
|
|
|
/// <summary>Test if this position a valid position.</summary>
|
|
/// <returns>Returns true if this position is a valid position.</returns>
|
|
bool IsInvalid()const
|
|
{
|
|
return index < 0 && row < 0 && column < 0;
|
|
}
|
|
|
|
static ParsingTextPos Start(const regex::RegexToken* token)
|
|
{
|
|
return { token->start,token->rowStart,token->columnStart };
|
|
}
|
|
|
|
static ParsingTextPos End(const regex::RegexToken* token)
|
|
{
|
|
return { token->start + token->length - 1,token->rowEnd,token->columnEnd };
|
|
}
|
|
|
|
friend std::strong_ordering operator<=>(const ParsingTextPos& a, const ParsingTextPos& b)
|
|
{
|
|
if (a.IsInvalid() && b.IsInvalid())
|
|
{
|
|
return std::strong_ordering::equal;
|
|
}
|
|
else if (a.IsInvalid())
|
|
{
|
|
return std::strong_ordering::less;
|
|
}
|
|
else if (b.IsInvalid())
|
|
{
|
|
return std::strong_ordering::greater;
|
|
}
|
|
else if (a.index >= 0 && b.index >= 0)
|
|
{
|
|
return a.index <=> b.index;
|
|
}
|
|
else if (a.row >= 0 && a.column >= 0 && b.row >= 0 && b.column >= 0)
|
|
{
|
|
if (a.row == b.row)
|
|
{
|
|
return a.column <=> b.column;
|
|
}
|
|
else
|
|
{
|
|
return a.row <=> b.row;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return std::strong_ordering::equal;
|
|
}
|
|
}
|
|
|
|
friend bool operator==(const ParsingTextPos& a, const ParsingTextPos& b)
|
|
{
|
|
return(a <=> b) == 0;
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
ParsingTextRange
|
|
***********************************************************************/
|
|
|
|
/// <summary>A type representing text range.</summary>
|
|
struct ParsingTextRange
|
|
{
|
|
/// <summary>Text position for the first character.</summary>
|
|
ParsingTextPos start;
|
|
/// <summary>Text position for the last character.</summary>
|
|
ParsingTextPos end;
|
|
/// <summary>Code index, refer to [F:vl.regex.RegexToken.codeIndex]</summary>
|
|
vint codeIndex = -1;
|
|
|
|
ParsingTextRange() = default;
|
|
|
|
ParsingTextRange(const ParsingTextPos& _start, const ParsingTextPos& _end, vint _codeIndex = -1)
|
|
: start(_start)
|
|
, end(_end)
|
|
, codeIndex(_codeIndex)
|
|
{
|
|
}
|
|
|
|
ParsingTextRange(const regex::RegexToken* startToken, const regex::RegexToken* endToken)
|
|
: start(ParsingTextPos::Start(startToken))
|
|
, end(ParsingTextPos::End(endToken))
|
|
, codeIndex(startToken->codeIndex)
|
|
{
|
|
}
|
|
|
|
bool Contains(const ParsingTextPos& pos)const { return start <= pos && pos <= end; }
|
|
bool Contains(const ParsingTextRange& range)const { return start <= range.start && range.end <= end; }
|
|
|
|
friend std::strong_ordering operator<=>(const ParsingTextRange& a, const ParsingTextRange& b)
|
|
{
|
|
std::strong_ordering
|
|
result = a.start <=> b.start; if (result != 0) return result;
|
|
result = a.end <=> b.end; if (result != 0) return result;
|
|
return std::strong_ordering::equal;
|
|
}
|
|
|
|
friend bool operator==(const ParsingTextRange& a, const ParsingTextRange& b)
|
|
{
|
|
return (a <=> b) == 0;
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
ParsingError
|
|
***********************************************************************/
|
|
|
|
class ParsingAstBase;
|
|
|
|
struct ParsingError
|
|
{
|
|
ParsingAstBase* node = nullptr;
|
|
ParsingTextRange codeRange;
|
|
WString message;
|
|
};
|
|
|
|
/***********************************************************************
|
|
AST
|
|
***********************************************************************/
|
|
|
|
/// <summary>Base type of all strong typed syntax tree. Normally all strong typed syntax tree are generated from a grammar file using ParserGen.exe in Tools project.</summary>
|
|
class ParsingAstBase : public Object, public reflection::Description<ParsingAstBase>
|
|
{
|
|
public:
|
|
/// <summary>Range of all tokens that form this object.</summary>
|
|
ParsingTextRange codeRange;
|
|
};
|
|
|
|
/// <summary>Strong typed token syntax node, for all class fields of type "token" in the grammar file. See [T:vl.parsing.tabling.ParsingTable] for details.</summary>
|
|
struct ParsingToken
|
|
{
|
|
public:
|
|
/// <summary>Range of all tokens that form this object.</summary>
|
|
ParsingTextRange codeRange;
|
|
/// <summary>Index of the token in the token list provided to the parser.</summary>
|
|
vint index = -1;
|
|
/// <summary>Type of the token, representing the index of a regular expression that creates this token in the regular expression list in the grammar file.</summary>
|
|
vint token = -1;
|
|
/// <summary>Content of the token.</summary>
|
|
WString value;
|
|
|
|
operator bool() const { return value.Length() > 0; }
|
|
};
|
|
|
|
/***********************************************************************
|
|
AST (Builder)
|
|
***********************************************************************/
|
|
|
|
template<typename TAst>
|
|
class ParsingAstBuilder
|
|
{
|
|
protected:
|
|
Ptr<TAst> node{ new TAst };
|
|
ParsingAstBuilder() {}
|
|
public:
|
|
|
|
template<typename TExpected>
|
|
operator Ptr<TExpected>() const
|
|
{
|
|
return node;
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
AST (Visitor)
|
|
***********************************************************************/
|
|
|
|
class CopyVisitorBase : public Object
|
|
{
|
|
protected:
|
|
Ptr<ParsingAstBase> result;
|
|
};
|
|
|
|
class JsonVisitorBase : public Object
|
|
{
|
|
private:
|
|
stream::StreamWriter& writer;
|
|
vint indentation = 0;
|
|
collections::List<vint> indices;
|
|
|
|
protected:
|
|
|
|
void BeginObject();
|
|
void BeginField(const WString& field);
|
|
void EndField();
|
|
void EndObject();
|
|
void BeginArray();
|
|
void BeginArrayItem();
|
|
void EndArrayItem();
|
|
void EndArray();
|
|
void WriteIndent();
|
|
void WriteRange(const ParsingTextRange& range);
|
|
void WriteToken(const ParsingToken& token);
|
|
void WriteType(const WString& type, ParsingAstBase* node);
|
|
void WriteString(const WString& text);
|
|
void WriteNull();
|
|
public:
|
|
bool printTokenCodeRange = true;
|
|
bool printAstCodeRange = true;
|
|
bool printAstType = true;
|
|
|
|
JsonVisitorBase(stream::StreamWriter& _writer);
|
|
};
|
|
|
|
extern void JsonEscapeString(const WString& text, stream::TextWriter& writer);
|
|
extern void JsonUnescapeString(const WString& text, stream::TextWriter& writer);
|
|
|
|
/***********************************************************************
|
|
Instructions
|
|
***********************************************************************/
|
|
|
|
constexpr vint32_t ResolveAmbiguitySlotIndex = -2;
|
|
|
|
enum class AstInsType
|
|
{
|
|
Token, // Token(Count) : Put the current token in the Count-th slot.
|
|
EnumItem, // EnumItem(Value, Count) : Put an enum item in the Count-th slot.
|
|
StackBegin, // StackBegin() : Begin a new stack frame.
|
|
StackSlot, // StackSlot(Count) : Assign the just created object to the Count-th slot. Reset the creating object.
|
|
CreateObject, // CreateObject(Type) : Create an AST node, it becomes the creating object. Error if the previous creating object has not been reset.
|
|
Field, // Field(Field, Count) : Associate a field name of the creating object with the value in the Count-th slot. Ignored if the Count-th slot is empty.
|
|
FieldIfUnassigned, // FieldIfUnassigned(Field, Count) : Like Field(Field) but only take effect if such field has never been assigned.
|
|
StackEnd, // StackEnd() : End the current stack frame. Leave the creating object as is.
|
|
ResolveAmbiguity, // ResolveAmbiguity(Type) : Combine several values in the specified slot to one using an ambiguity node. Type is the type of each value.
|
|
};
|
|
|
|
struct AstIns
|
|
{
|
|
AstInsType type = AstInsType::Token;
|
|
vint32_t param = -1;
|
|
vint count = -1;
|
|
|
|
std::strong_ordering operator<=>(const AstIns& ins) const
|
|
{
|
|
std::strong_ordering
|
|
result = type <=> ins.type; if (result != 0) return result;
|
|
result = param <=> ins.param; if (result != 0) return result;
|
|
result = count <=> ins.count; if (result != 0) return result;
|
|
return result;
|
|
}
|
|
|
|
bool operator==(const AstIns& ins) const
|
|
{
|
|
return (*this <=> ins) == 0;
|
|
}
|
|
};
|
|
|
|
enum class AstInsErrorType
|
|
{
|
|
UnknownType, // UnknownType(Type) : The type id does not exist.
|
|
UnknownField, // UnknownField(Field) : The field id does not exist.
|
|
UnsupportedAbstractType, // UnsupportedAbstractType(Type) : Unable to create abstract class.
|
|
FieldNotExistsInType, // FieldNotExistsInType(Field) : The type doesn't have such field.
|
|
FieldReassigned, // FieldReassigned(Field) : An object is assigned to a field but this field has already been assigned.
|
|
FieldWeakAssignmentOnNonEnum, // FieldWeakAssignmentOnNonEnum(Field) : Weak assignment only available for field of enum type.
|
|
ObjectTypeMismatchedToField, // ObjectTypeMismatchedToField(Field) : Unable to assign an object to a field because the type does not match.
|
|
|
|
UnsupportedAmbiguityType, // UnsupportedAmbiguityType(Type) : The type is not configured to allow ambiguity.
|
|
UnexpectedAmbiguousCandidate, // UnexpectedAmbiguousCandidate(Type) : The type of the ambiguous candidate is not compatible to the required type.
|
|
MissingAmbiguityCandidate, // MissingAmbiguityCandidate() : There are less than two candidates to create an ambiguity node.
|
|
AmbiguityCandidateIsNotObject, // AmbiguityCandidateIsNotObject() : Tokens or enum items cannot be ambiguity candidates.
|
|
|
|
NoStackFrame, // NoStackFrame() : Stack operations are executed while no stack frame exists.
|
|
NoStackFrameForStackEnd, // NoStackFrameForStackEnd() : StackEnd when no stack frame exists.
|
|
NoCreatingObjectForField, // NoCreatingObjectForField() : Field when no creating object.
|
|
NoCreatingObjectForStackSlot, // NoCreatingObjectForStackSlot() : StackSlot when no creating object.
|
|
NoCreatingObjectForStackEnd, // NoCreatingObjectForStackEnd() : StackEnd when no creating object.
|
|
|
|
InstructionNotComplete, // InstructionNotComplete() : No more instruction but the root object has not been completed yet.
|
|
Corrupted, // Corrupted() : An exception has been thrown therefore this receiver cannot be used anymore.
|
|
Finished, // Finished() : The finished instruction has been executed therefore this receiver cannot be used anymore.
|
|
};
|
|
|
|
class AstInsException : public Exception
|
|
{
|
|
public:
|
|
AstInsErrorType error = AstInsErrorType::Corrupted;
|
|
vint32_t paramTypeOrField = -1;
|
|
|
|
AstInsException(const WString& message, AstInsErrorType _error, vint32_t _typeOrField = -1)
|
|
: Exception(message)
|
|
, error(_error)
|
|
, paramTypeOrField(_typeOrField)
|
|
{
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
IAstInsReceiver
|
|
***********************************************************************/
|
|
|
|
class IAstInsReceiver : public virtual Interface
|
|
{
|
|
public:
|
|
virtual void Execute(AstIns instruction, const regex::RegexToken& token, vint32_t tokenIndex) = 0;
|
|
virtual Ptr<ParsingAstBase> Finished() = 0;
|
|
};
|
|
|
|
namespace astins_slots
|
|
{
|
|
struct TokenSlot
|
|
{
|
|
regex::RegexToken token;
|
|
vint32_t index = -1;
|
|
|
|
auto operator<=>(const TokenSlot& slot) const
|
|
{
|
|
auto result = token.length <=> slot.token.length;
|
|
if (result != 0) return result;
|
|
result = token.token <=> slot.token.token;
|
|
if (result != 0) return result;
|
|
result = token.reading <=> slot.token.reading;
|
|
if (result != 0) return result;
|
|
return index <=> slot.index;
|
|
}
|
|
|
|
bool operator==(const TokenSlot& slot) const
|
|
{
|
|
return (*this <=> slot) == 0;
|
|
}
|
|
};
|
|
|
|
struct EnumItemSlot
|
|
{
|
|
vint32_t value = -1;
|
|
|
|
auto operator<=>(const EnumItemSlot&) const = default;
|
|
bool operator==(const EnumItemSlot& slot) const
|
|
{
|
|
return (*this <=> slot) == 0;
|
|
}
|
|
};
|
|
|
|
using SlotValue = Variant<TokenSlot, EnumItemSlot, Ptr<ParsingAstBase>>;
|
|
|
|
inline auto operator<=>(const SlotValue& a, const SlotValue& b)
|
|
{
|
|
auto result = a.Index() <=> b.Index();
|
|
if (result != 0) return result;
|
|
switch (a.Index())
|
|
{
|
|
case 0:
|
|
return a.Get<TokenSlot>() <=> b.Get<TokenSlot>();
|
|
case 1:
|
|
return a.Get<EnumItemSlot>() <=> b.Get<EnumItemSlot>();
|
|
case 2:
|
|
return a.Get<Ptr<ParsingAstBase>>() <=> b.Get<Ptr<ParsingAstBase>>();
|
|
default:
|
|
return std::strong_ordering::equal;
|
|
}
|
|
}
|
|
|
|
inline auto operator==(const SlotValue& a, const SlotValue& b)
|
|
{
|
|
return (a <=> b) == 0;
|
|
}
|
|
|
|
struct SlotStorage
|
|
{
|
|
SlotValue value;
|
|
Ptr<collections::List<SlotValue>> additionalValues;
|
|
|
|
auto operator<=>(const SlotStorage& slotStorage) const
|
|
{
|
|
auto result = value <=> slotStorage.value;
|
|
if (result != 0) return result;
|
|
result = static_cast<bool>(additionalValues) <=> static_cast<bool>(slotStorage.additionalValues);
|
|
if (result != 0) return result;
|
|
|
|
if (additionalValues)
|
|
{
|
|
result = collections::CompareEnumerable(*additionalValues.Obj(), *slotStorage.additionalValues.Obj());
|
|
if (result != 0) return result;
|
|
}
|
|
return std::strong_ordering::equal;
|
|
}
|
|
|
|
bool operator==(const SlotStorage& slotStorage) const
|
|
{
|
|
return (*this <=> slotStorage) == 0;
|
|
}
|
|
};
|
|
using SlotMap = collections::Dictionary<vint, SlotStorage>;
|
|
}
|
|
|
|
class AstInsReceiverBase : public Object, public virtual IAstInsReceiver
|
|
{
|
|
private:
|
|
|
|
struct StackFrame
|
|
{
|
|
astins_slots::SlotMap slots;
|
|
ParsingTextPos codeRangeStart;
|
|
};
|
|
using StackFrameList = collections::List<StackFrame>;
|
|
|
|
struct CreatingObject
|
|
{
|
|
Ptr<ParsingAstBase> object;
|
|
vint32_t type = -1;
|
|
};
|
|
using CreatingObjectList = collections::List<CreatingObject>;
|
|
|
|
CreatingObjectList creatingObjects;
|
|
StackFrameList stackFrames;
|
|
bool finished = false;
|
|
bool corrupted = false;
|
|
|
|
void EnsureContinuable();
|
|
void SetField(ParsingAstBase* object, vint32_t field, const astins_slots::SlotValue& value, bool weakAssignment);
|
|
|
|
protected:
|
|
virtual Ptr<ParsingAstBase> CreateAstNode(vint32_t type) = 0;
|
|
virtual void SetField(ParsingAstBase* object, vint32_t field, Ptr<ParsingAstBase> value) = 0;
|
|
virtual void SetField(ParsingAstBase* object, vint32_t field, const regex::RegexToken& token, vint32_t tokenIndex) = 0;
|
|
virtual void SetField(ParsingAstBase* object, vint32_t field, vint32_t enumValue, bool weakAssignment) = 0;
|
|
virtual Ptr<ParsingAstBase> ResolveAmbiguity(vint32_t type, collections::Array<Ptr<ParsingAstBase>>& candidates) = 0;
|
|
|
|
public:
|
|
AstInsReceiverBase() = default;
|
|
~AstInsReceiverBase() = default;
|
|
|
|
void Execute(AstIns instruction, const regex::RegexToken& token, vint32_t tokenIndex) override;
|
|
Ptr<ParsingAstBase> Finished() override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
IAstInsReceiver (Code Generation Templates)
|
|
***********************************************************************/
|
|
|
|
template<typename TClass, typename TField>
|
|
void AssemblerSetObjectField(Ptr<TField>(TClass::* member), ParsingAstBase* object, vint32_t field, Ptr<ParsingAstBase> value, const wchar_t* cppFieldName)
|
|
{
|
|
auto typedObject = dynamic_cast<TClass*>(object);
|
|
if (!typedObject)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" does not exist in the current object."),
|
|
AstInsErrorType::FieldNotExistsInType, field);
|
|
}
|
|
if ((typedObject->*member))
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" has already been assigned."),
|
|
AstInsErrorType::FieldReassigned, field);
|
|
}
|
|
|
|
auto typedValue = value.Cast<TField>();
|
|
if (!typedValue)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" cannot be assigned with an uncompatible value."),
|
|
AstInsErrorType::ObjectTypeMismatchedToField, field);
|
|
}
|
|
(typedObject->*member) = typedValue;
|
|
}
|
|
|
|
template<typename TClass, typename TField>
|
|
void AssemblerSetObjectField(collections::List<Ptr<TField>>(TClass::* member), ParsingAstBase* object, vint32_t field, Ptr<ParsingAstBase> value, const wchar_t* cppFieldName)
|
|
{
|
|
auto typedObject = dynamic_cast<TClass*>(object);
|
|
if (!typedObject)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" does not exist in the current object."),
|
|
AstInsErrorType::FieldNotExistsInType, field);
|
|
}
|
|
|
|
auto typedValue = value.Cast<TField>();
|
|
if (!typedValue)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" cannot be assigned with an uncompatible value."),
|
|
AstInsErrorType::ObjectTypeMismatchedToField, field);
|
|
}
|
|
(typedObject->*member).Add(typedValue);
|
|
}
|
|
|
|
template<typename TClass>
|
|
void AssemblerSetTokenField(ParsingToken(TClass::* member), ParsingAstBase* object, vint32_t field, const regex::RegexToken& token, vint32_t tokenIndex, const wchar_t* cppFieldName)
|
|
{
|
|
auto typedObject = dynamic_cast<TClass*>(object);
|
|
if (!typedObject)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" does not exist in the current object."),
|
|
AstInsErrorType::FieldNotExistsInType, field);
|
|
}
|
|
if ((typedObject->*member).value.Length() != 0)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" has already been assigned."),
|
|
AstInsErrorType::FieldReassigned, field);
|
|
}
|
|
|
|
ParsingToken& tokenField = typedObject->*member;
|
|
tokenField.codeRange = { &token,&token };
|
|
tokenField.index = tokenIndex;
|
|
tokenField.token = token.token;
|
|
tokenField.value = WString::CopyFrom(token.reading, token.length);
|
|
}
|
|
|
|
template<typename TClass, typename TField>
|
|
void AssemblerSetEnumField(TField(TClass::* member), ParsingAstBase* object, vint32_t field, vint32_t enumItem, bool weakAssignment, const wchar_t* cppFieldName)
|
|
{
|
|
auto typedObject = dynamic_cast<TClass*>(object);
|
|
if (!typedObject)
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" does not exist in the current object."),
|
|
AstInsErrorType::FieldNotExistsInType, field);
|
|
}
|
|
if ((typedObject->*member) != TField::UNDEFINED_ENUM_ITEM_VALUE)
|
|
{
|
|
if (weakAssignment) return;
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"Field \"") +
|
|
WString::Unmanaged(cppFieldName) +
|
|
WString::Unmanaged(L"\" has already been assigned."),
|
|
AstInsErrorType::FieldReassigned, field);
|
|
}
|
|
(typedObject->*member) = (TField)enumItem;
|
|
}
|
|
|
|
template<typename TElement, typename TAmbiguity>
|
|
Ptr<ParsingAstBase> AssemblerResolveAmbiguity(vint32_t type, collections::Array<Ptr<ParsingAstBase>>& candidates, const wchar_t* cppTypeName)
|
|
{
|
|
auto ast = Ptr(new TAmbiguity());
|
|
if (candidates.Count() > 0)
|
|
{
|
|
ast->codeRange = candidates[0]->codeRange;
|
|
}
|
|
for (auto candidate : candidates)
|
|
{
|
|
if (auto typedAst = candidate.Cast<TElement>())
|
|
{
|
|
ast->candidates.Add(typedAst);
|
|
}
|
|
else if (auto ambiguityAst = candidate.Cast<TAmbiguity>())
|
|
{
|
|
CopyFrom(ast->candidates, ambiguityAst->candidates, true);
|
|
}
|
|
else
|
|
{
|
|
throw AstInsException(
|
|
WString::Unmanaged(L"The type of the ambiguous candidate is not compatible to the required type \"") +
|
|
WString::Unmanaged(cppTypeName) +
|
|
WString::Unmanaged(L"\"."),
|
|
AstInsErrorType::UnexpectedAmbiguousCandidate, type);
|
|
}
|
|
}
|
|
return ast;
|
|
}
|
|
|
|
template<vint32_t Size>
|
|
vint32_t AssemblerFindCommonBaseClass(vint32_t class1, vint32_t class2, vint32_t(&matrix)[Size][Size])
|
|
{
|
|
if (class1 < 0 || class1 >= Size) throw glr::AstInsException(L"The type id does not exist.", glr::AstInsErrorType::UnknownType, class1);
|
|
if (class2 < 0 || class2 >= Size) throw glr::AstInsException(L"The type id does not exist.", glr::AstInsErrorType::UnknownType, class2);
|
|
return matrix[class1][class2];
|
|
}
|
|
|
|
/***********************************************************************
|
|
IAstInsReceiver (Code Generation Error Templates)
|
|
***********************************************************************/
|
|
|
|
extern Ptr<ParsingAstBase> AssemblyThrowCannotCreateAbstractType(vint32_t type, const wchar_t* cppTypeName);
|
|
extern void AssemblyThrowFieldNotObject(vint32_t field, const wchar_t* cppFieldName);
|
|
extern void AssemblyThrowFieldNotToken(vint32_t field, const wchar_t* cppFieldName);
|
|
extern void AssemblyThrowFieldNotEnum(vint32_t field, const wchar_t* cppFieldName);
|
|
extern Ptr<ParsingAstBase> AssemblyThrowTypeNotAllowAmbiguity(vint32_t type, const wchar_t* cppTypeName);
|
|
|
|
/***********************************************************************
|
|
Compression
|
|
***********************************************************************/
|
|
|
|
extern void DecompressSerializedData(const char** buffer, bool decompress, vint solidRows, vint rows, vint block, vint remain, stream::IStream& outputStream);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Reflection
|
|
***********************************************************************/
|
|
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
DECL_TYPE_INFO(vl::glr::ParsingTextPos)
|
|
DECL_TYPE_INFO(vl::glr::ParsingTextRange)
|
|
DECL_TYPE_INFO(vl::glr::ParsingToken)
|
|
DECL_TYPE_INFO(vl::glr::ParsingAstBase)
|
|
#endif
|
|
extern bool LoadParsing2Types();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\ASTPRINT.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_ASTPRINT
|
|
#define VCZH_PARSER2_ASTPRINT
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
/***********************************************************************
|
|
IParsingPrintNodeRecorder
|
|
***********************************************************************/
|
|
|
|
class IParsingPrintNodeRecorder : public virtual Interface
|
|
{
|
|
public:
|
|
virtual void Record(ParsingAstBase* node, const ParsingTextRange& range) = 0;
|
|
};
|
|
|
|
class ParsingEmptyPrintNodeRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
public:
|
|
ParsingEmptyPrintNodeRecorder();
|
|
~ParsingEmptyPrintNodeRecorder();
|
|
|
|
void Record(ParsingAstBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingMultiplePrintNodeRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
typedef collections::List<Ptr<IParsingPrintNodeRecorder>> RecorderList;
|
|
protected:
|
|
RecorderList recorders;
|
|
|
|
public:
|
|
ParsingMultiplePrintNodeRecorder();
|
|
~ParsingMultiplePrintNodeRecorder();
|
|
|
|
void AddRecorder(Ptr<IParsingPrintNodeRecorder> recorder);
|
|
void Record(ParsingAstBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingOriginalLocationRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
protected:
|
|
Ptr<IParsingPrintNodeRecorder> recorder;
|
|
|
|
public:
|
|
ParsingOriginalLocationRecorder(Ptr<IParsingPrintNodeRecorder> _recorder);
|
|
~ParsingOriginalLocationRecorder();
|
|
|
|
void Record(ParsingAstBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingGeneratedLocationRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
typedef collections::Dictionary<ParsingAstBase*, ParsingTextRange> RangeMap;
|
|
protected:
|
|
RangeMap& rangeMap;
|
|
|
|
public:
|
|
ParsingGeneratedLocationRecorder(RangeMap& _rangeMap);
|
|
~ParsingGeneratedLocationRecorder();
|
|
|
|
void Record(ParsingAstBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingUpdateLocationRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
public:
|
|
ParsingUpdateLocationRecorder();
|
|
~ParsingUpdateLocationRecorder();
|
|
|
|
void Record(ParsingAstBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
ParsingWriter
|
|
***********************************************************************/
|
|
|
|
class ParsingWriter : public stream::TextWriter
|
|
{
|
|
typedef collections::Pair<ParsingAstBase*, ParsingTextPos> NodePosPair;
|
|
typedef collections::List<NodePosPair> NodePosList;
|
|
protected:
|
|
stream::TextWriter& writer;
|
|
Ptr<IParsingPrintNodeRecorder> recorder;
|
|
vint codeIndex;
|
|
ParsingTextPos lastPos;
|
|
ParsingTextPos currentPos;
|
|
NodePosList nodePositions;
|
|
|
|
void HandleChar(wchar_t c);
|
|
public:
|
|
ParsingWriter(stream::TextWriter& _writer, Ptr<IParsingPrintNodeRecorder> _recorder = nullptr, vint _codeIndex = -1);
|
|
~ParsingWriter();
|
|
|
|
using stream::TextWriter::WriteString;
|
|
void WriteChar(wchar_t c)override;
|
|
void WriteString(const wchar_t* string, vint charCount)override;
|
|
void BeforePrint(ParsingAstBase* node);
|
|
void AfterPrint(ParsingAstBase* node);
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\EXECUTABLE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_EXECUTABLE
|
|
#define VCZH_PARSER2_EXECUTABLE
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
/***********************************************************************
|
|
Executable
|
|
***********************************************************************/
|
|
|
|
struct InstructionArray
|
|
{
|
|
vint32_t start = -1;
|
|
vint32_t count = 0;
|
|
};
|
|
|
|
struct StringLiteral
|
|
{
|
|
vint32_t start = -1;
|
|
vint32_t count = 0;
|
|
};
|
|
|
|
struct CompetitionArray
|
|
{
|
|
vint32_t start = -1;
|
|
vint32_t count = 0;
|
|
};
|
|
|
|
struct ReturnIndexArray
|
|
{
|
|
vint32_t start = -1;
|
|
vint32_t count = -1;
|
|
};
|
|
|
|
struct EdgeArray
|
|
{
|
|
vint32_t start = -1;
|
|
vint32_t count = 0;
|
|
};
|
|
|
|
struct CompetitionDesc
|
|
{
|
|
vint32_t competitionId = -1;
|
|
bool highPriority = false;
|
|
};
|
|
|
|
enum class ReturnRuleType
|
|
{
|
|
Field,
|
|
Partial,
|
|
Discard,
|
|
Reuse,
|
|
};
|
|
|
|
struct ReturnDesc
|
|
{
|
|
vint32_t consumedRule = -1;
|
|
vint32_t returnState = -1;
|
|
CompetitionArray competitions;
|
|
ReturnRuleType ruleType = ReturnRuleType::Field;
|
|
InstructionArray insAfterInput;
|
|
};
|
|
|
|
struct EdgeDesc
|
|
{
|
|
vint32_t fromState = -1;
|
|
vint32_t toState = -1;
|
|
StringLiteral condition;
|
|
CompetitionArray competitions;
|
|
InstructionArray insAfterInput;
|
|
ReturnIndexArray returnIndices;
|
|
};
|
|
|
|
struct StateDesc
|
|
{
|
|
vint32_t rule = -1;
|
|
bool endingState = false;
|
|
};
|
|
|
|
struct Executable
|
|
{
|
|
static constexpr vint32_t EndOfInputInput = -1;
|
|
static constexpr vint32_t EndingInput = 0;
|
|
static constexpr vint32_t LeftrecInput = 1;
|
|
static constexpr vint32_t TokenBegin = 2;
|
|
|
|
vint32_t tokenCount = 0;
|
|
vint32_t ruleCount = 0;
|
|
collections::Array<vint32_t> ruleStartStates; // ruleStartStates[rule] = the start state of this rule.
|
|
collections::Array<EdgeArray> transitions; // transitions[state * (TokenBegin + tokenCount) + input] = edges from state with specified input.
|
|
collections::Array<AstIns> astInstructions; // referenced by EdgeDesc::insBeforeInput and EdgeDesc::insAfterInput
|
|
collections::Array<vint32_t> returnIndices; // referenced by ReturnIndexArray
|
|
collections::Array<CompetitionDesc> competitions; // referenced by EdgeArray
|
|
collections::Array<ReturnDesc> returns; // referenced by Executable::returnIndices
|
|
collections::Array<EdgeDesc> edges; // referenced by EdgeArray
|
|
collections::Array<StateDesc> states; // referenced by returnState/fromState/toState
|
|
WString stringLiteralBuffer; // referenced by StringLiteral
|
|
|
|
Executable() = default;
|
|
Executable(stream::IStream& inputStream);
|
|
|
|
void Serialize(stream::IStream& outputStream);
|
|
|
|
vint32_t GetTransitionIndex(vint32_t state, vint32_t input)
|
|
{
|
|
return state * (TokenBegin + tokenCount) + input;
|
|
}
|
|
};
|
|
|
|
struct Metadata
|
|
{
|
|
collections::Array<WString> ruleNames;
|
|
collections::Array<WString> stateLabels;
|
|
};
|
|
|
|
/***********************************************************************
|
|
IExecutor
|
|
***********************************************************************/
|
|
|
|
class UnableToResolveAmbiguityException : public Exception
|
|
{
|
|
public:
|
|
vint32_t class1 = -1;
|
|
vint32_t class2 = -1;
|
|
vint32_t tokenIndex1 = -1;
|
|
vint32_t tokenIndex2 = -1;
|
|
|
|
UnableToResolveAmbiguityException(const WString& message, vint32_t _class1, vint32_t _class2, vint32_t _tokenIndex1, vint32_t _tokenIndex2)
|
|
: Exception(message)
|
|
, class1(_class1)
|
|
, class2(_class2)
|
|
, tokenIndex1(_tokenIndex1)
|
|
, tokenIndex2(_tokenIndex2)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct Trace;
|
|
|
|
class IExecutor : public virtual Interface
|
|
{
|
|
public:
|
|
class ITypeCallback : public virtual Interface
|
|
{
|
|
public:
|
|
virtual WString GetClassName(vint32_t classIndex) const = 0;
|
|
virtual vint32_t FindCommonBaseClass(vint32_t class1, vint32_t class2) const = 0;
|
|
};
|
|
|
|
virtual void Initialize(vint32_t startState) = 0;
|
|
virtual bool Input(vint32_t currentTokenIndex, regex::RegexToken* token, regex::RegexToken* lookAhead) = 0;
|
|
virtual bool EndOfInput(bool& ambiguityInvolved) = 0;
|
|
virtual void PrepareTraceRoute() = 0;
|
|
virtual void ResolveAmbiguity() = 0;
|
|
virtual Ptr<ParsingAstBase> ExecuteTrace(IAstInsReceiver& receiver, collections::List<regex::RegexToken>& tokens) = 0;
|
|
};
|
|
|
|
extern Ptr<IExecutor> CreateExecutor(Executable& executable, const IExecutor::ITypeCallback* typeCallback, vint _blockSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\SYNTAXBASE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_SYNTAXBASE
|
|
#define VCZH_PARSER2_SYNTAXBASE
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
/***********************************************************************
|
|
ParserBase<TTokens, TStates, TReceiver, TStateTypes>
|
|
***********************************************************************/
|
|
|
|
enum class ErrorType
|
|
{
|
|
UnrecognizedToken, // (token) the token is not recognizable to the tokenizer
|
|
InvalidToken, // (token, tokens, executable, traceManager) the token cause the parser to stop
|
|
InputIncomplete, // (tokens, executable, traceManager) all traces do not reach the end
|
|
UnexpectedAstType, // (tokens, executable, traceManager, ast) unexpected type of the created AST
|
|
};
|
|
|
|
enum class TraceProcessingPhase
|
|
{
|
|
EndOfInput,
|
|
PrepareTraceRoute,
|
|
ResolveAmbiguity,
|
|
};
|
|
|
|
struct TraceProcessingArgs
|
|
{
|
|
collections::List<regex::RegexToken>& tokens;
|
|
automaton::Executable& executable;
|
|
automaton::IExecutor* executor;
|
|
bool ambiguityInvolved;
|
|
TraceProcessingPhase phase;
|
|
};
|
|
|
|
struct ReadyToExecuteArgs
|
|
{
|
|
collections::List<regex::RegexToken>& tokens;
|
|
automaton::Executable& executable;
|
|
automaton::IExecutor* executor;
|
|
bool ambiguityInvolved;
|
|
};
|
|
|
|
struct ErrorArgs
|
|
{
|
|
bool throwError;
|
|
ErrorType error;
|
|
vint codeIndex;
|
|
regex::RegexToken& token;
|
|
collections::List<regex::RegexToken>& tokens;
|
|
automaton::Executable& executable;
|
|
automaton::IExecutor* executor;
|
|
Ptr<ParsingAstBase> ast;
|
|
|
|
static ErrorArgs UnrecognizedToken (const regex::RegexToken& token);
|
|
static ErrorArgs InvalidToken (regex::RegexToken& token, collections::List<regex::RegexToken>& tokens, automaton::Executable& executable, automaton::IExecutor* executor);
|
|
static ErrorArgs InputIncomplete (vint codeIndex, collections::List<regex::RegexToken>& tokens, automaton::Executable& executable, automaton::IExecutor* executor);
|
|
static ErrorArgs UnexpectedAstType (collections::List<regex::RegexToken>& tokens, automaton::Executable& executable, automaton::IExecutor* executor, Ptr<ParsingAstBase> ast);
|
|
|
|
ParsingError ToParsingError();
|
|
};
|
|
|
|
template<typename TParser>
|
|
Ptr<EventHandler> InstallDefaultErrorMessageGenerator(TParser& parser, collections::List<ParsingError>& errors)
|
|
{
|
|
return parser.OnError.Add([&errors](ErrorArgs& args)
|
|
{
|
|
args.throwError = false;
|
|
errors.Add(args.ToParsingError());
|
|
});
|
|
}
|
|
|
|
template<
|
|
typename TTokens,
|
|
typename TStates,
|
|
typename TReceiver
|
|
>
|
|
class ParserBase : public Object
|
|
{
|
|
static_assert(std::is_enum_v<TTokens>);
|
|
static_assert(std::is_enum_v<TStates>);
|
|
static_assert(std::is_convertible_v<TReceiver*, IAstInsReceiver*>);
|
|
|
|
using Deleter = bool(*)(vint);
|
|
using TokenList = collections::List<regex::RegexToken>;
|
|
using TraceProcessingCallback = void(TraceProcessingArgs&);
|
|
using ReadyToExecuteCallback = void(ReadyToExecuteArgs&);
|
|
using ErrorCallback = void(ErrorArgs&);
|
|
protected:
|
|
Deleter deleter;
|
|
Ptr<regex::RegexLexer> lexer;
|
|
Ptr<automaton::Executable> executable;
|
|
|
|
public:
|
|
Event<TraceProcessingCallback> OnTraceProcessing;
|
|
Event<ReadyToExecuteCallback> OnReadyToExecute;
|
|
Event<ErrorCallback> OnError;
|
|
|
|
ParserBase(
|
|
Deleter _deleter,
|
|
void(*_lexerData)(stream::IStream&),
|
|
void(*_parserData)(stream::IStream&)
|
|
) : deleter(_deleter)
|
|
{
|
|
{
|
|
stream::MemoryStream data;
|
|
_lexerData(data);
|
|
data.SeekFromBegin(0);
|
|
lexer = Ptr(new regex::RegexLexer(data));
|
|
}
|
|
{
|
|
stream::MemoryStream data;
|
|
_parserData(data);
|
|
data.SeekFromBegin(0);
|
|
executable = Ptr(new automaton::Executable(data));
|
|
}
|
|
}
|
|
|
|
regex::RegexLexer& Lexer() const
|
|
{
|
|
return *lexer.Obj();
|
|
}
|
|
|
|
Deleter LexerDeleter() const
|
|
{
|
|
return deleter;
|
|
}
|
|
|
|
void Tokenize(const WString& input, TokenList& tokens, vint codeIndex = -1) const
|
|
{
|
|
input.Buffer();
|
|
auto enumerable = lexer->Parse(input, {}, codeIndex);
|
|
auto enumerator = Ptr(enumerable.CreateEnumerator());
|
|
while (enumerator->Next())
|
|
{
|
|
auto&& token = enumerator->Current();
|
|
if (token.token == -1 || !token.completeToken)
|
|
{
|
|
auto args = ErrorArgs::UnrecognizedToken(token);
|
|
args.throwError = false;
|
|
OnError(args);
|
|
if (args.throwError)
|
|
{
|
|
CHECK_FAIL(L"vl::glr::ParserBase<...>::Tokenize(const WString&, List<RegexToken>&, vint)#Unrecognized token.");
|
|
}
|
|
}
|
|
else if (!deleter(token.token))
|
|
{
|
|
tokens.Add(token);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected:
|
|
Ptr<ParsingAstBase> ParseInternal(TokenList& tokens, vint32_t state, automaton::IExecutor* executor, const automaton::IExecutor::ITypeCallback* typeCallback, vint codeIndex) const
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::ParserBase<...>::ParseInternal(List<RegexToken>&, vint32_t TraceManager::ITypeCallback*)#"
|
|
if (codeIndex == -1 && tokens.Count() > 0)
|
|
{
|
|
codeIndex = tokens[0].codeIndex;
|
|
}
|
|
|
|
executor->Initialize(state);
|
|
for (vint32_t i = 0; i < tokens.Count(); i++)
|
|
{
|
|
auto token = &tokens[i];
|
|
auto lookAhead = i == tokens.Count() - 1 ? nullptr : &tokens[i + 1];
|
|
|
|
if (!executor->Input(i, token, lookAhead))
|
|
{
|
|
auto args = ErrorArgs::InvalidToken(*token, tokens, *executable.Obj(), executor);
|
|
OnError(args);
|
|
if (args.throwError) CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Error happens during parsing.");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
bool ambiguityInvolved = false;
|
|
if (!executor->EndOfInput(ambiguityInvolved))
|
|
{
|
|
auto args = ErrorArgs::InputIncomplete(codeIndex, tokens, *executable.Obj(), executor);
|
|
OnError(args);
|
|
if (args.throwError) CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Input is incomplete.");
|
|
return nullptr;
|
|
}
|
|
|
|
{
|
|
TraceProcessingArgs args = { tokens, *executable.Obj(), executor, ambiguityInvolved, TraceProcessingPhase::EndOfInput };
|
|
OnTraceProcessing(args);
|
|
}
|
|
if (ambiguityInvolved)
|
|
{
|
|
{
|
|
executor->PrepareTraceRoute();
|
|
TraceProcessingArgs args = { tokens, *executable.Obj(), executor, ambiguityInvolved, TraceProcessingPhase::PrepareTraceRoute };
|
|
OnTraceProcessing(args);
|
|
}
|
|
{
|
|
executor->ResolveAmbiguity();
|
|
TraceProcessingArgs args = { tokens, *executable.Obj(), executor, ambiguityInvolved, TraceProcessingPhase::ResolveAmbiguity };
|
|
OnTraceProcessing(args);
|
|
}
|
|
}
|
|
{
|
|
ReadyToExecuteArgs args = { tokens, *executable.Obj(), executor, ambiguityInvolved };
|
|
OnReadyToExecute(args);
|
|
}
|
|
|
|
TReceiver receiver;
|
|
return executor->ExecuteTrace(receiver, tokens);
|
|
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
template<typename TAst, TStates State>
|
|
Ptr<TAst> ParseWithTokens(TokenList& tokens, const automaton::IExecutor::ITypeCallback* typeCallback, vint codeIndex, vint blockSize = 1024) const
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::glr::ParserBase<...>::Parse<TAst, TStates>(List<RegexToken>& TraceManager::ITypeCallback*)#"
|
|
auto executor = automaton::CreateExecutor(*executable.Obj(), typeCallback, blockSize);
|
|
auto ast = ParseInternal(tokens, (vint32_t)State, executor.Obj(), typeCallback, codeIndex);
|
|
auto typedAst = ast.template Cast<TAst>();
|
|
|
|
if (ast && !typedAst)
|
|
{
|
|
auto args = ErrorArgs::UnexpectedAstType(tokens, *executable.Obj(), executor.Obj(), ast);
|
|
OnError(args);
|
|
if (args.throwError) CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unexpected type of the created AST.");
|
|
}
|
|
return typedAst;
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
template<typename TAst, TStates State>
|
|
Ptr<TAst> ParseWithString(const WString& input, const automaton::IExecutor::ITypeCallback* typeCallback, vint codeIndex, vint blockSize = 1024) const
|
|
{
|
|
TokenList tokens;
|
|
Tokenize(input, tokens, codeIndex);
|
|
return ParseWithTokens<TAst, State>(tokens, typeCallback, codeIndex, blockSize);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_AST_AST
|
|
#define VCZH_PARSER2_BUILTIN_JSON_AST_AST
|
|
|
|
|
|
namespace vl::glr::json
|
|
{
|
|
class JsonArray;
|
|
class JsonLiteral;
|
|
class JsonNode;
|
|
class JsonNumber;
|
|
class JsonObject;
|
|
class JsonObjectField;
|
|
class JsonString;
|
|
|
|
enum class JsonLiteralValue
|
|
{
|
|
UNDEFINED_ENUM_ITEM_VALUE = -1,
|
|
True = 0,
|
|
False = 1,
|
|
Null = 2,
|
|
};
|
|
|
|
class JsonNode abstract : public vl::glr::ParsingAstBase, vl::reflection::Description<JsonNode>
|
|
{
|
|
public:
|
|
class IVisitor : public virtual vl::reflection::IDescriptable, vl::reflection::Description<IVisitor>
|
|
{
|
|
public:
|
|
virtual void Visit(JsonLiteral* node) = 0;
|
|
virtual void Visit(JsonString* node) = 0;
|
|
virtual void Visit(JsonNumber* node) = 0;
|
|
virtual void Visit(JsonArray* node) = 0;
|
|
virtual void Visit(JsonObject* node) = 0;
|
|
};
|
|
|
|
virtual void Accept(JsonNode::IVisitor* visitor) = 0;
|
|
|
|
};
|
|
|
|
class JsonLiteral : public JsonNode, vl::reflection::Description<JsonLiteral>
|
|
{
|
|
public:
|
|
JsonLiteralValue value = JsonLiteralValue::UNDEFINED_ENUM_ITEM_VALUE;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class JsonString : public JsonNode, vl::reflection::Description<JsonString>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken content;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class JsonNumber : public JsonNode, vl::reflection::Description<JsonNumber>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken content;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class JsonArray : public JsonNode, vl::reflection::Description<JsonArray>
|
|
{
|
|
public:
|
|
vl::collections::List<vl::Ptr<JsonNode>> items;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class JsonObjectField : public vl::glr::ParsingAstBase, vl::reflection::Description<JsonObjectField>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken name;
|
|
vl::Ptr<JsonNode> value;
|
|
};
|
|
|
|
class JsonObject : public JsonNode, vl::reflection::Description<JsonObject>
|
|
{
|
|
public:
|
|
vl::collections::List<vl::Ptr<JsonObjectField>> fields;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor) override;
|
|
};
|
|
}
|
|
namespace vl::reflection::description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
DECL_TYPE_INFO(vl::glr::json::JsonNode)
|
|
DECL_TYPE_INFO(vl::glr::json::JsonNode::IVisitor)
|
|
DECL_TYPE_INFO(vl::glr::json::JsonLiteralValue)
|
|
DECL_TYPE_INFO(vl::glr::json::JsonLiteral)
|
|
DECL_TYPE_INFO(vl::glr::json::JsonString)
|
|
DECL_TYPE_INFO(vl::glr::json::JsonNumber)
|
|
DECL_TYPE_INFO(vl::glr::json::JsonArray)
|
|
DECL_TYPE_INFO(vl::glr::json::JsonObjectField)
|
|
DECL_TYPE_INFO(vl::glr::json::JsonObject)
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(vl::glr::json::JsonNode::IVisitor)
|
|
void Visit(vl::glr::json::JsonLiteral* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::json::JsonString* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::json::JsonNumber* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::json::JsonArray* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::json::JsonObject* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
END_INTERFACE_PROXY(vl::glr::json::JsonNode::IVisitor)
|
|
|
|
#endif
|
|
#endif
|
|
/// <summary>Load all reflectable AST types, only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is off.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
extern bool JsonAstLoadTypes();
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_BUILDER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_AST_AST_BUILDER
|
|
#define VCZH_PARSER2_BUILTIN_JSON_AST_AST_BUILDER
|
|
|
|
|
|
namespace vl::glr::json::builder
|
|
{
|
|
class MakeArray : public vl::glr::ParsingAstBuilder<JsonArray>
|
|
{
|
|
public:
|
|
MakeArray& items(const vl::Ptr<JsonNode>& value);
|
|
};
|
|
|
|
class MakeLiteral : public vl::glr::ParsingAstBuilder<JsonLiteral>
|
|
{
|
|
public:
|
|
MakeLiteral& value(JsonLiteralValue value);
|
|
};
|
|
|
|
class MakeNumber : public vl::glr::ParsingAstBuilder<JsonNumber>
|
|
{
|
|
public:
|
|
MakeNumber& content(const vl::WString& value);
|
|
};
|
|
|
|
class MakeObject : public vl::glr::ParsingAstBuilder<JsonObject>
|
|
{
|
|
public:
|
|
MakeObject& fields(const vl::Ptr<JsonObjectField>& value);
|
|
};
|
|
|
|
class MakeObjectField : public vl::glr::ParsingAstBuilder<JsonObjectField>
|
|
{
|
|
public:
|
|
MakeObjectField& name(const vl::WString& value);
|
|
MakeObjectField& value(const vl::Ptr<JsonNode>& value);
|
|
};
|
|
|
|
class MakeString : public vl::glr::ParsingAstBuilder<JsonString>
|
|
{
|
|
public:
|
|
MakeString& content(const vl::WString& value);
|
|
};
|
|
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_COPY.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_AST_AST_COPY_VISITOR
|
|
#define VCZH_PARSER2_BUILTIN_JSON_AST_AST_COPY_VISITOR
|
|
|
|
|
|
namespace vl::glr::json::copy_visitor
|
|
{
|
|
/// <summary>A copy visitor, overriding all abstract methods with AST copying code.</summary>
|
|
class AstVisitor
|
|
: public virtual vl::glr::CopyVisitorBase
|
|
, protected virtual JsonNode::IVisitor
|
|
{
|
|
protected:
|
|
void CopyFields(JsonArray* from, JsonArray* to);
|
|
void CopyFields(JsonLiteral* from, JsonLiteral* to);
|
|
void CopyFields(JsonNode* from, JsonNode* to);
|
|
void CopyFields(JsonNumber* from, JsonNumber* to);
|
|
void CopyFields(JsonObject* from, JsonObject* to);
|
|
void CopyFields(JsonObjectField* from, JsonObjectField* to);
|
|
void CopyFields(JsonString* from, JsonString* to);
|
|
|
|
protected:
|
|
virtual void Visit(JsonObjectField* node);
|
|
|
|
void Visit(JsonLiteral* node) override;
|
|
void Visit(JsonString* node) override;
|
|
void Visit(JsonNumber* node) override;
|
|
void Visit(JsonArray* node) override;
|
|
void Visit(JsonObject* node) override;
|
|
|
|
public:
|
|
virtual vl::Ptr<JsonNode> CopyNode(JsonNode* node);
|
|
virtual vl::Ptr<JsonObjectField> CopyNode(JsonObjectField* node);
|
|
|
|
vl::Ptr<JsonArray> CopyNode(JsonArray* node);
|
|
vl::Ptr<JsonLiteral> CopyNode(JsonLiteral* node);
|
|
vl::Ptr<JsonNumber> CopyNode(JsonNumber* node);
|
|
vl::Ptr<JsonObject> CopyNode(JsonObject* node);
|
|
vl::Ptr<JsonString> CopyNode(JsonString* node);
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_EMPTY.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_AST_AST_EMPTY_VISITOR
|
|
#define VCZH_PARSER2_BUILTIN_JSON_AST_AST_EMPTY_VISITOR
|
|
|
|
|
|
namespace vl::glr::json::empty_visitor
|
|
{
|
|
/// <summary>An empty visitor, overriding all abstract methods with empty implementations.</summary>
|
|
class NodeVisitor : public vl::Object, public JsonNode::IVisitor
|
|
{
|
|
protected:
|
|
// Dispatch (virtual) --------------------------------
|
|
|
|
public:
|
|
// Visitor Members -----------------------------------
|
|
void Visit(JsonLiteral* node) override;
|
|
void Visit(JsonString* node) override;
|
|
void Visit(JsonNumber* node) override;
|
|
void Visit(JsonArray* node) override;
|
|
void Visit(JsonObject* node) override;
|
|
};
|
|
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_JSON.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_AST_AST_JSON_VISITOR
|
|
#define VCZH_PARSER2_BUILTIN_JSON_AST_AST_JSON_VISITOR
|
|
|
|
|
|
namespace vl::glr::json::json_visitor
|
|
{
|
|
/// <summary>A JSON visitor, overriding all abstract methods with AST to JSON serialization code.</summary>
|
|
class AstVisitor
|
|
: public vl::glr::JsonVisitorBase
|
|
, protected virtual JsonNode::IVisitor
|
|
{
|
|
protected:
|
|
virtual void PrintFields(JsonArray* node);
|
|
virtual void PrintFields(JsonLiteral* node);
|
|
virtual void PrintFields(JsonNode* node);
|
|
virtual void PrintFields(JsonNumber* node);
|
|
virtual void PrintFields(JsonObject* node);
|
|
virtual void PrintFields(JsonObjectField* node);
|
|
virtual void PrintFields(JsonString* node);
|
|
|
|
protected:
|
|
void Visit(JsonLiteral* node) override;
|
|
void Visit(JsonString* node) override;
|
|
void Visit(JsonNumber* node) override;
|
|
void Visit(JsonArray* node) override;
|
|
void Visit(JsonObject* node) override;
|
|
|
|
public:
|
|
AstVisitor(vl::stream::StreamWriter& _writer);
|
|
|
|
void Print(JsonNode* node);
|
|
void Print(JsonObjectField* node);
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONAST_TRAVERSE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_AST_AST_TRAVERSE_VISITOR
|
|
#define VCZH_PARSER2_BUILTIN_JSON_AST_AST_TRAVERSE_VISITOR
|
|
|
|
|
|
namespace vl::glr::json::traverse_visitor
|
|
{
|
|
/// <summary>A traverse visitor, overriding all abstract methods with AST visiting code.</summary>
|
|
class AstVisitor
|
|
: public vl::Object
|
|
, protected virtual JsonNode::IVisitor
|
|
{
|
|
protected:
|
|
virtual void Traverse(vl::glr::ParsingToken& token);
|
|
virtual void Traverse(vl::glr::ParsingAstBase* node);
|
|
virtual void Traverse(JsonArray* node);
|
|
virtual void Traverse(JsonLiteral* node);
|
|
virtual void Traverse(JsonNode* node);
|
|
virtual void Traverse(JsonNumber* node);
|
|
virtual void Traverse(JsonObject* node);
|
|
virtual void Traverse(JsonObjectField* node);
|
|
virtual void Traverse(JsonString* node);
|
|
|
|
protected:
|
|
virtual void Finishing(vl::glr::ParsingAstBase* node);
|
|
virtual void Finishing(JsonArray* node);
|
|
virtual void Finishing(JsonLiteral* node);
|
|
virtual void Finishing(JsonNode* node);
|
|
virtual void Finishing(JsonNumber* node);
|
|
virtual void Finishing(JsonObject* node);
|
|
virtual void Finishing(JsonObjectField* node);
|
|
virtual void Finishing(JsonString* node);
|
|
|
|
protected:
|
|
void Visit(JsonLiteral* node) override;
|
|
void Visit(JsonString* node) override;
|
|
void Visit(JsonNumber* node) override;
|
|
void Visit(JsonArray* node) override;
|
|
void Visit(JsonObject* node) override;
|
|
|
|
public:
|
|
void InspectInto(JsonNode* node);
|
|
void InspectInto(JsonObjectField* node);
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSON_ASSEMBLER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Json
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_AST_ASSEMBLER
|
|
#define VCZH_PARSER2_BUILTIN_JSON_AST_ASSEMBLER
|
|
|
|
|
|
namespace vl::glr::json
|
|
{
|
|
enum class JsonClasses : vl::vint32_t
|
|
{
|
|
Array = 0,
|
|
Literal = 1,
|
|
Node = 2,
|
|
Number = 3,
|
|
Object = 4,
|
|
ObjectField = 5,
|
|
String = 6,
|
|
};
|
|
|
|
enum class JsonFields : vl::vint32_t
|
|
{
|
|
Array_items = 0,
|
|
Literal_value = 1,
|
|
Number_content = 2,
|
|
Object_fields = 3,
|
|
ObjectField_name = 4,
|
|
ObjectField_value = 5,
|
|
String_content = 6,
|
|
};
|
|
|
|
extern const wchar_t* JsonTypeName(JsonClasses type);
|
|
extern const wchar_t* JsonCppTypeName(JsonClasses type);
|
|
extern const wchar_t* JsonFieldName(JsonFields field);
|
|
extern const wchar_t* JsonCppFieldName(JsonFields field);
|
|
|
|
class JsonAstInsReceiver : public vl::glr::AstInsReceiverBase
|
|
{
|
|
protected:
|
|
vl::Ptr<vl::glr::ParsingAstBase> CreateAstNode(vl::vint32_t type) override;
|
|
void SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::Ptr<vl::glr::ParsingAstBase> value) override;
|
|
void SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, const vl::regex::RegexToken& token, vl::vint32_t tokenIndex) override;
|
|
void SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::vint32_t enumItem, bool weakAssignment) override;
|
|
vl::Ptr<vl::glr::ParsingAstBase> ResolveAmbiguity(vl::vint32_t type, vl::collections::Array<vl::Ptr<vl::glr::ParsingAstBase>>& candidates) override;
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSON_LEXER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Json
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_LEXER
|
|
#define VCZH_PARSER2_BUILTIN_JSON_LEXER
|
|
|
|
|
|
namespace vl::glr::json
|
|
{
|
|
enum class JsonTokens : vl::vint32_t
|
|
{
|
|
TRUE_VALUE = 0,
|
|
FALSE_VALUE = 1,
|
|
NULL_VALUE = 2,
|
|
OBJOPEN = 3,
|
|
OBJCLOSE = 4,
|
|
ARROPEN = 5,
|
|
ARRCLOSE = 6,
|
|
COMMA = 7,
|
|
COLON = 8,
|
|
NUMBER = 9,
|
|
STRING = 10,
|
|
SPACE = 11,
|
|
};
|
|
|
|
constexpr vl::vint JsonTokenCount = 12;
|
|
extern bool JsonTokenDeleter(vl::vint token);
|
|
extern const wchar_t* JsonTokenId(JsonTokens token);
|
|
extern const wchar_t* JsonTokenDisplayText(JsonTokens token);
|
|
extern const wchar_t* JsonTokenRegex(JsonTokens token);
|
|
extern void JsonLexerData(vl::stream::IStream& outputStream);
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GENERATED\JSONPARSER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Json
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON_PARSER_SYNTAX
|
|
#define VCZH_PARSER2_BUILTIN_JSON_PARSER_SYNTAX
|
|
|
|
|
|
namespace vl::glr::json
|
|
{
|
|
enum class ParserStates
|
|
{
|
|
JLiteral = 0,
|
|
JField = 7,
|
|
JObject = 12,
|
|
JArray = 18,
|
|
JValue = 24,
|
|
JRoot = 29,
|
|
};
|
|
|
|
const wchar_t* ParserRuleName(vl::vint index);
|
|
const wchar_t* ParserStateLabel(vl::vint index);
|
|
extern void JsonParserData(vl::stream::IStream& outputStream);
|
|
|
|
class Parser
|
|
: public vl::glr::ParserBase<JsonTokens, ParserStates, JsonAstInsReceiver>
|
|
, protected vl::glr::automaton::IExecutor::ITypeCallback
|
|
{
|
|
protected:
|
|
vl::WString GetClassName(vl::vint32_t classIndex) const override;
|
|
vl::vint32_t FindCommonBaseClass(vl::vint32_t class1, vl::vint32_t class2) const override;
|
|
public:
|
|
Parser();
|
|
|
|
vl::Ptr<vl::glr::json::JsonNode> ParseJRoot(const vl::WString& input, vl::vint codeIndex = -1) const;
|
|
vl::Ptr<vl::glr::json::JsonNode> ParseJRoot(vl::collections::List<vl::regex::RegexToken>& tokens, vl::vint codeIndex = -1) const;
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\GLRJSON.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Parser::ParsingJson_Parser
|
|
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_JSON
|
|
#define VCZH_PARSER2_BUILTIN_JSON
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace json
|
|
{
|
|
/// <summary>Deserialize JSON from string.</summary>
|
|
/// <returns>The deserialized JSON node.</returns>
|
|
/// <param name="input">The JSON code.</param>
|
|
/// <param name="parser">The generated parser.</param>
|
|
extern Ptr<JsonNode> JsonParse(const WString& input, const Parser& parser);
|
|
|
|
struct JsonFormatting
|
|
{
|
|
bool spaceAfterColon = false;
|
|
bool spaceAfterComma = false;
|
|
bool crlf = false;
|
|
bool compact = false; // available when crlf == true
|
|
const wchar_t* indentation = nullptr; // available when crlf == true;
|
|
|
|
JsonFormatting();
|
|
JsonFormatting(const JsonFormatting&) = default;
|
|
JsonFormatting(JsonFormatting&&) = default;
|
|
JsonFormatting& operator=(const JsonFormatting&) = default;
|
|
JsonFormatting& operator=(JsonFormatting&&) = default;
|
|
};
|
|
|
|
/// <summary>Serialize JSON to string.</summary>
|
|
/// <param name="node">The JSON node to serialize.</param>
|
|
/// <param name="writer">The text writer to receive the string.</param>
|
|
extern void JsonPrint(Ptr<JsonNode> node, stream::TextWriter& writer, JsonFormatting formatting = {});
|
|
|
|
/// <summary>Serialize JSON to string.</summary>
|
|
/// <returns>The serialized string.</returns>
|
|
/// <param name="node">The JSON node to serialize.</param>
|
|
extern WString JsonToString(Ptr<JsonNode> node, JsonFormatting formatting = {});
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_TRACEMANAGER_TRACEMANAGER
|
|
#define VCZH_PARSER2_TRACEMANAGER_TRACEMANAGER
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
/***********************************************************************
|
|
AllocateOnly<T>
|
|
***********************************************************************/
|
|
|
|
struct WithMagicCounter
|
|
{
|
|
vuint64_t mergeCounter = 0; // a temporary counter for internal use
|
|
};
|
|
|
|
struct NullRef {};
|
|
constexpr auto nullref = NullRef{};
|
|
|
|
template<typename T>
|
|
struct Ref
|
|
{
|
|
vint32_t handle = -1;
|
|
|
|
Ref() = default;
|
|
Ref(NullRef) :handle(-1) {}
|
|
Ref(T* obj) :handle(obj == nullptr ? -1 : obj->allocatedIndex) {}
|
|
Ref(const Ref<T>& ref) :handle(ref.handle) {}
|
|
explicit Ref(vint32_t _handle) :handle(_handle) {}
|
|
|
|
__forceinline bool operator==(NullRef) const { return handle == -1; }
|
|
__forceinline bool operator==(const Ref<T>& ref) const { return handle == ref.handle; }
|
|
__forceinline std::strong_ordering operator<=>(const Ref<T>& ref) const = default;
|
|
|
|
__forceinline Ref& operator=(const Ref<T>& ref) { handle = ref.handle; return *this; }
|
|
__forceinline Ref& operator=(T* obj) { handle = obj == nullptr ? -1 : obj->allocatedIndex; return *this; }
|
|
__forceinline Ref& operator=(NullRef) { handle = -1; return *this; }
|
|
|
|
__forceinline std::strong_ordering operator<=>(vint32_t) = delete;
|
|
__forceinline bool operator==(vint32_t) = delete;
|
|
__forceinline Ref& operator=(vint32_t) = delete;
|
|
};
|
|
|
|
template<typename T>
|
|
struct Allocatable
|
|
{
|
|
vint32_t allocatedIndex = -1;
|
|
};
|
|
|
|
template<typename T>
|
|
class AllocateOnly : public Object
|
|
{
|
|
static_assert(std::is_base_of_v<Allocatable<T>, T>, "T in AllocateOnly<T> does not inherit from Allocatable<T>.");
|
|
protected:
|
|
vint blockSize;
|
|
vint remains;
|
|
collections::List<Ptr<collections::Array<T>>> buffers;
|
|
|
|
public:
|
|
AllocateOnly(vint _blockSize)
|
|
: blockSize(_blockSize)
|
|
, remains(0)
|
|
{
|
|
}
|
|
|
|
T* Get(Ref<T> index)
|
|
{
|
|
vint row = index.handle / blockSize;
|
|
vint column = index.handle % blockSize;
|
|
CHECK_ERROR(0 <= row && row < buffers.Count(), L"vl::glr::automaton::AllocateOnly<T>::Get(vint)#Index out of range.");
|
|
if (row == buffers.Count() - 1)
|
|
{
|
|
CHECK_ERROR(0 <= column && column < (blockSize - remains), L"vl::glr::automaton::AllocateOnly<T>::Get(vint)#Index out of range.");
|
|
}
|
|
else
|
|
{
|
|
CHECK_ERROR(0 <= column && column < blockSize, L"vl::glr::automaton::AllocateOnly<T>::Get(vint)#Index out of range.");
|
|
}
|
|
return &buffers[row]->operator[](column);
|
|
}
|
|
|
|
Ref<T> Allocate()
|
|
{
|
|
if (remains == 0)
|
|
{
|
|
buffers.Add(Ptr(new collections::Array<T>(blockSize)));
|
|
remains = blockSize;
|
|
}
|
|
vint index = blockSize * (buffers.Count() - 1) + (blockSize - remains);
|
|
buffers[buffers.Count() - 1]->operator[](blockSize - remains).allocatedIndex = (vint32_t)index;
|
|
remains--;
|
|
return Ref<T>((vint32_t)index);
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
remains = 0;
|
|
buffers.Clear();
|
|
}
|
|
};
|
|
|
|
struct ReturnStack;
|
|
struct Trace;
|
|
struct TraceExec;
|
|
|
|
/***********************************************************************
|
|
TraceManager (Data Structures)
|
|
***********************************************************************/
|
|
|
|
struct ReturnStackSuccessors
|
|
{
|
|
vint32_t tokenIndex = -1; // index of the token when successors in this list are created
|
|
// the following members records all successors
|
|
// that is created at the token index
|
|
|
|
Ref<ReturnStack> first; // first successor
|
|
Ref<ReturnStack> last; // last successor
|
|
};
|
|
|
|
struct ReturnStackCache
|
|
{
|
|
ReturnStackSuccessors lastSuccessors; // the value of successors before the current one is changed
|
|
ReturnStackSuccessors successors; // successors of ReturnStack for a token
|
|
vint32_t tokenIndex = -1; // index of the token when this ReturnStack is created.
|
|
Ref<ReturnStack> prev; // previous successor of ReturnStack::previous
|
|
Ref<ReturnStack> next; // next successor of ReturnStack::previous
|
|
};
|
|
|
|
struct ReturnStack : Allocatable<ReturnStack>
|
|
{
|
|
Ref<ReturnStack> previous; // id of the previous ReturnStack
|
|
vint32_t returnIndex = -1; // index of the ReturnDesc
|
|
Ref<Trace> fromTrace; // id of the Trace which has a transition containing this ReturnStack
|
|
ReturnStackCache cache;
|
|
};
|
|
|
|
enum class CompetitionStatus
|
|
{
|
|
Holding,
|
|
HighPriorityWin,
|
|
LowPriorityWin,
|
|
};
|
|
|
|
struct Competition : Allocatable<Competition>
|
|
{
|
|
Ref<Competition> nextActiveCompetition; // next active Competition
|
|
Ref<Competition> nextHoldCompetition; // next Competition hold by this trace
|
|
|
|
CompetitionStatus status = CompetitionStatus::Holding; // if predecessors from this trace have different priority, the competition begins
|
|
// when the competition is over, it will be changed to HighPriorityWin or LowPriorityWin
|
|
// if all candidates fail, it could be Holding forever
|
|
|
|
vint32_t currentTokenIndex = -1; // currentTokenIndex from the trace that creates this competition
|
|
vint32_t ruleId = -1; // the rule id of state, when an edge starts this competition
|
|
vint32_t competitionId = -1; // the unique competition id in a rule, when an edge starts this competition
|
|
// an state must be picked up and ensure that, the syntax creating the priority and the state belong to the same clause
|
|
|
|
vint32_t highCounter = 0; // temporary counter for all existing high bets
|
|
// in the current step of input
|
|
vint32_t lowCounter = 0; // temporary counter for all existing low bets
|
|
// in the current step of input
|
|
};
|
|
|
|
struct AttendingCompetitions : Allocatable<AttendingCompetitions>
|
|
{
|
|
Ref<AttendingCompetitions> nextActiveAC; // the next AttendingCompetitions for RuntimeRouting::attendingCompetitions
|
|
Ref<AttendingCompetitions> nextCarriedAC; // the next AttendingCompetitions for RuntimeRouting::carriedCompetitions
|
|
Ref<Competition> competition; // the id of the Competition
|
|
bool forHighPriority = false; // bet of this competition
|
|
|
|
Ref<ReturnStack> returnStack; // the ReturnStack object for the competition
|
|
// if the competition is attended by a ReturnDesc
|
|
// then the ReturnStack object is the one before a ReturnDesc transition happens
|
|
|
|
bool closed = false; // true if the competition has been closed
|
|
// this flag is not always updated for discarded AttendingCompetitions objects
|
|
};
|
|
|
|
/***********************************************************************
|
|
TraceManager (Data Structures -- Input/EndOfInput)
|
|
|
|
For a trace like:
|
|
A
|
|
/ \
|
|
B C
|
|
\ /
|
|
D
|
|
|
|
A.successors.(first .. last) = {B,C}
|
|
B.successors.siblingNext = C
|
|
C.successors.siblingPrev = B
|
|
(B, C).successors.(first .. last) = {D}
|
|
|
|
predecessors are for reverse relationships.
|
|
Such data structure makes many-to-many relationships impossible to represent.
|
|
***********************************************************************/
|
|
|
|
struct TraceCollection
|
|
{
|
|
Ref<Trace> first; // first trace in the collection
|
|
Ref<Trace> last; // last trace in the collection
|
|
Ref<Trace> siblingPrev; // previous trace in the collection of the owned trace
|
|
Ref<Trace> siblingNext; // next trace in the collection of the owned trace
|
|
};
|
|
|
|
struct CompetitionRouting
|
|
{
|
|
Ref<Competition> holdingCompetitions; // the id of the active Competition
|
|
|
|
Ref<AttendingCompetitions> attendingCompetitions; // a linked list containing all AttendingCompetitions that this trace is attending
|
|
// predecessors could share and modify the same linked list
|
|
// if a competition is over, node could be removed from the linked list
|
|
// one competition only creates two AttendingCompetitions, traces with the same bet sharing the object
|
|
|
|
Ref<AttendingCompetitions> carriedCompetitions; // all attended competitions regardless of the status of the competition
|
|
};
|
|
|
|
struct Trace : Allocatable<Trace>
|
|
{
|
|
TraceCollection predecessors; // ids of predecessor Trace
|
|
|
|
// (filled by EndOfInput)
|
|
TraceCollection successors; // ids of successor Trace
|
|
vint32_t predecessorCount = 0;
|
|
vint32_t successorCount = 0;
|
|
|
|
// if state == -1
|
|
// it means this is an ambiguity resolving trace
|
|
// all merged traces are in predecessors
|
|
|
|
vint32_t state = -1; // id of the current StateDesc
|
|
Ref<ReturnStack> returnStack; // id of the current ReturnStack
|
|
Ref<ReturnStack> executedReturnStack; // id of the executed ReturnStack that contains the ReturnDesc being executed
|
|
vint32_t byEdge = -1; // id of the last EdgeDesc that make this trace
|
|
vint32_t byInput = -1; // the last input that make this trace
|
|
vint32_t currentTokenIndex = -1; // the index of the token that is byInput
|
|
CompetitionRouting competitionRouting; // a data structure carrying priority and competition information
|
|
|
|
// (filled by PrepareTraceRoute)
|
|
Ref<TraceExec> traceExecRef; // the allocated TraceExec
|
|
vint32_t iterateCounter = 0; // a temporary counter for IterateSurvivedTraces internal use
|
|
};
|
|
|
|
/***********************************************************************
|
|
TraceManager (Data Structures -- PrepareTraceRoute)
|
|
***********************************************************************/
|
|
|
|
struct InsExec_Stack;
|
|
|
|
struct InsRef
|
|
{
|
|
Ref<Trace> trace;
|
|
vint32_t ins = -1;
|
|
|
|
__forceinline std::strong_ordering operator<=>(const InsRef& ref) const = default;
|
|
};
|
|
|
|
struct InsExec_InsRefLink : Allocatable<InsExec_InsRefLink>
|
|
{
|
|
Ref<InsExec_InsRefLink> previous;
|
|
InsRef insRef;
|
|
};
|
|
|
|
struct InsExec_StackRefLink : Allocatable<InsExec_StackRefLink>
|
|
{
|
|
Ref<InsExec_StackRefLink> previous;
|
|
Ref<InsExec_Stack> id;
|
|
};
|
|
|
|
struct InsExec_StackArrayRefLink : Allocatable<InsExec_StackArrayRefLink>, WithMagicCounter
|
|
{
|
|
Ref<InsExec_StackArrayRefLink> previous;
|
|
Ref<InsExec_StackRefLink> ids;
|
|
|
|
// The current depth of the link. The first one is 0.
|
|
vint currentDepth = -1;
|
|
|
|
// Available when the link is in InsExec_Context::createStack
|
|
// It records the InsExec_Context::objectStack depth when the link is created.
|
|
vint objectStackDepthForCreateStack = -1;
|
|
};
|
|
|
|
struct InsExec_StackSummarizing
|
|
{
|
|
// The earliest StackBegin instructions including in useFromStacks
|
|
InsRef earliestLocalInsRef;
|
|
|
|
// The earliest StackBegin instructions including in useFromStacks and fieldStacks
|
|
InsRef earliestStackInsRef;
|
|
|
|
// earliestStackInsRef but propogated back into useFromStacks
|
|
InsRef earliestInsRef;
|
|
|
|
// StackEnd instructions mapping earliestInsRef.
|
|
// Such StackBegin and StackEnd may not belong to the same stack.
|
|
// But belong to the out-most stack.
|
|
Ref<InsExec_InsRefLink> bottomInsRefs;
|
|
|
|
// All CreateObject instructions including in useFromStacks
|
|
Ref<InsExec_InsRefLink> indirectCreateObjectInsRefs;
|
|
};
|
|
|
|
struct InsExec_Stack : Allocatable<InsExec_Stack>, WithMagicCounter
|
|
{
|
|
// previous allocated object
|
|
Ref<InsExec_Stack> previous;
|
|
|
|
// owner-field relationships
|
|
Ref<InsExec_StackRefLink> fieldStacks;
|
|
|
|
// useFrom-useBy relationships
|
|
Ref<InsExec_StackRefLink> useFromStacks;
|
|
|
|
// fieldStacks and useFromStacks
|
|
Ref<InsExec_StackRefLink> allDependentStacks;
|
|
|
|
// Key instructions in this stack
|
|
InsRef beginInsRef;
|
|
Ref<InsExec_InsRefLink> createObjectInsRefs;
|
|
Ref<InsExec_InsRefLink> endWithCreateInsRefs;
|
|
Ref<InsExec_InsRefLink> endWithReuseInsRefs;
|
|
|
|
InsExec_StackSummarizing summarizing;
|
|
};
|
|
|
|
struct InsExec_Context
|
|
{
|
|
Ref<InsExec_StackArrayRefLink> objectStack; // Stack of created objects
|
|
Ref<InsExec_StackArrayRefLink> createStack; // Stack of opening objects
|
|
};
|
|
|
|
struct InsExec : WithMagicCounter
|
|
{
|
|
// Stack operated by StackBegin/StackEnd/CreateObject
|
|
Ref<InsExec_StackRefLink> operatingStacks;
|
|
|
|
// Context before executing this instruction
|
|
InsExec_Context contextBeforeExecution;
|
|
};
|
|
|
|
/***********************************************************************
|
|
TraceManager (Data Structures -- ResolveAmbiguity)
|
|
|
|
A branch begins from:
|
|
The initial trace
|
|
Successors of a branch trace (a trace with multiple successors)
|
|
A merge trace (a trace with multiple predecessors)
|
|
branchData.forwardTrace points to the nearest beginning of a trace.
|
|
|
|
Here a demos of which traces are beginnings:
|
|
A*
|
|
|
|
|
B
|
|
/ \
|
|
C* D*
|
|
| |
|
|
E F
|
|
\ /
|
|
G*(cfb->B)
|
|
|
|
|
H
|
|
|
|
For any merge trace, its branchData.commonForwardBranch points to the latest forwardTrace that all comming branches share.
|
|
It does not necessary equal to branchData.forwardTrace of all predecessors as their values might be different.
|
|
|
|
All branch traces can be found beginning from TraceManager::firstBranchTrace following nextBranchTrace.
|
|
All merge traces can be found beginning from TraceManager::firstMergeTrace following nextMergeTrace.
|
|
Traversing through branchData.forwardTrace and branchData.commonForwardBranch will skip all branches going forward.
|
|
***********************************************************************/
|
|
|
|
// TraceAmbiguity describes where an ambiguity resolving begins and ends
|
|
struct TraceAmbiguity : Allocatable<TraceAmbiguity>
|
|
{
|
|
// all objects to merge, they all have valid createObjectInsRef
|
|
Ref<InsExec_StackRefLink> bottomCreateObjectStacks;
|
|
|
|
// if multiple TraceAmbiguity are assigned to the same place
|
|
// it records the one it overrides
|
|
Ref<TraceAmbiguity> overridedAmbiguity;
|
|
|
|
// the trace where ambiguity resolution begins
|
|
// prefix is the number of instructions before SB
|
|
// if prefix + 1 is larger than instructions in firstTrace
|
|
// then StackBegin is in all successors
|
|
// these instructions create topObjectIds
|
|
Ref<Trace> firstTrace;
|
|
vint32_t prefix = -1;
|
|
|
|
// the trace when ambiguity resolution ends
|
|
// postfix is the number of instructions after SE
|
|
// if lastTrace is a merge trace
|
|
// then StackEnd is in all predecessors
|
|
// these instructions end bottomObjectIds
|
|
Ref<Trace> lastTrace;
|
|
vint32_t postfix = -1;
|
|
|
|
// The merge trace that creates this TraceAmbiguity, and its associated branch trace
|
|
Ref<Trace> branchTrace;
|
|
Ref<Trace> mergeTrace;
|
|
};
|
|
|
|
struct TraceAmbiguityLink : Allocatable<TraceAmbiguityLink>
|
|
{
|
|
Ref<TraceAmbiguityLink> previous;
|
|
Ref<TraceAmbiguity> ambiguity;
|
|
};
|
|
|
|
struct TraceInsLists
|
|
{
|
|
InstructionArray edgeInsAfterInput;
|
|
InstructionArray returnInsAfterInput;
|
|
vint32_t countAfterInput;
|
|
vint32_t countAll;
|
|
};
|
|
|
|
struct TraceBranchData : WithMagicCounter
|
|
{
|
|
// it stores the first trace of non branching path that this trace is in
|
|
// such trace could be:
|
|
// the initial trace
|
|
// successors of a branch trace
|
|
// a merge trace
|
|
Ref<Trace> forwardTrace;
|
|
|
|
// for merge trace, it stores the latest forwardTrace that all comming branches share
|
|
Ref<Trace> commonForwardBranch;
|
|
};
|
|
|
|
// TraceExec stores all ambiguity awared data for a trace
|
|
struct TraceExec : Allocatable<TraceExec>
|
|
{
|
|
Ref<Trace> traceId;
|
|
TraceInsLists insLists; // instruction list of this trace
|
|
InstructionArray insExecRefs; // allocated InsExec for instructions
|
|
|
|
InsExec_Context context; // context after executing all instructions
|
|
TraceBranchData branchData; // branch shapes
|
|
|
|
// linked list of branch traces, in a global depth-first order, from TraceManager::firstBranchTrace
|
|
Ref<Trace> nextBranchTrace;
|
|
|
|
// linked list of merge traces, in a global depth-first order, from TraceManager::firstMergeTrace
|
|
Ref<Trace> nextMergeTrace;
|
|
|
|
// linked list of ambiguity critical trace
|
|
// it is stored in a trace whose forwardTrace is itself
|
|
// record all traces with the same forwardTrace value, order by trace id ascending
|
|
// a branch trace
|
|
// a predecessor of a merge trace
|
|
// a trace pointed by TraceAmbiguity::firstTrace
|
|
Ref<Trace> nextAmbiguityCriticalTrace;
|
|
|
|
// TraceAmbiguity associated to the trace
|
|
// it could be associated to
|
|
// TraceAmbiguity::firstTrace (order by prefix ascending)
|
|
// TraceAmbiguity::lastTrace (order by postfix ascending)
|
|
// the merge trace that create this TraceAmbiguity
|
|
// ambiguityBegins will contain multiple TraceAmbiguity when
|
|
// multiple ambiguity begins in different group of successors
|
|
// there is also a possibility when all ambiguities don't cover all successors
|
|
|
|
Ref<TraceAmbiguity> ambiguityDetected; // The TraceAmbiguity whose lastTrace is this trace
|
|
// Referring to the last StackEnd of all predecessors
|
|
// Or the opening object at the end of the trace
|
|
|
|
Ref<TraceAmbiguityLink> ambiguityBegins; // All TraceAmbiguity whose firstTrace is this trace
|
|
// All TraceAmbiguity in this list are grouped by lastTrace (using TraceAmbiguity::overridedAmbiguity)
|
|
// To traverse all of them, begins from each TraceAmbiguity in this list, and go through TraceAmbiguity::overridedAmbiguity
|
|
};
|
|
|
|
/***********************************************************************
|
|
TraceManager (Data Structures -- BuildExecutionOrder)
|
|
***********************************************************************/
|
|
|
|
enum class ExecutionType
|
|
{
|
|
Instruction,
|
|
RA_Begin,
|
|
RA_Branch,
|
|
RA_End,
|
|
};
|
|
|
|
struct ExecutionStep : Allocatable<ExecutionStep>
|
|
{
|
|
struct ETI
|
|
{
|
|
vint32_t startTrace;
|
|
vint32_t startIns;
|
|
vint32_t endTrace;
|
|
vint32_t endIns;
|
|
};
|
|
|
|
struct ETRA
|
|
{
|
|
vint32_t type;
|
|
vint32_t trace;
|
|
};
|
|
|
|
ExecutionType type = ExecutionType::Instruction;
|
|
|
|
union
|
|
{
|
|
ETI et_i;
|
|
ETRA et_ra;
|
|
};
|
|
|
|
// list (parent, next)
|
|
// tree (parent, leafPrev, leafNext)
|
|
Ref<ExecutionStep> next, parent, leafNext;
|
|
vint32_t visitCount = 0;
|
|
vint32_t copyCount = 0;
|
|
};
|
|
|
|
struct ExecutionStepLinkedList
|
|
{
|
|
ExecutionStep* first = nullptr;
|
|
ExecutionStep* last = nullptr;
|
|
};
|
|
|
|
struct ExecutionStepTree
|
|
{
|
|
ExecutionStep* firstLeaf = nullptr;
|
|
ExecutionStep* lastLeaf = nullptr;
|
|
};
|
|
|
|
/***********************************************************************
|
|
TraceManager
|
|
***********************************************************************/
|
|
|
|
enum class TraceManagerState
|
|
{
|
|
Uninitialized,
|
|
WaitingForInput,
|
|
Finished,
|
|
PreparedTraceRoute,
|
|
ResolvedAmbiguity,
|
|
};
|
|
|
|
struct WalkingTrace
|
|
{
|
|
Trace* currentTrace;
|
|
Trace* stateTrace;
|
|
|
|
operator bool() const
|
|
{
|
|
return currentTrace && stateTrace;
|
|
}
|
|
};
|
|
|
|
class TraceManager : public Object, public virtual IExecutor
|
|
{
|
|
protected:
|
|
Executable& executable;
|
|
const ITypeCallback* typeCallback = nullptr;
|
|
|
|
TraceManagerState state = TraceManagerState::Uninitialized;
|
|
AllocateOnly<ReturnStack> returnStacks;
|
|
AllocateOnly<Trace> traces;
|
|
AllocateOnly<Competition> competitions;
|
|
AllocateOnly<AttendingCompetitions> attendingCompetitions;
|
|
|
|
collections::List<Trace*> traces1;
|
|
collections::List<Trace*> traces2;
|
|
|
|
Trace* initialTrace = nullptr;
|
|
Ref<Competition> activeCompetitions;
|
|
ReturnStackCache initialReturnStackCache;
|
|
|
|
collections::List<bool> temporaryConditionStack;
|
|
vint32_t temporaryConditionStackSize = 0;
|
|
|
|
void BeginSwap();
|
|
void AddTrace(Trace* trace);
|
|
void EndSwap();
|
|
void AddTraceToCollection(Trace* owner, Trace* element, TraceCollection(Trace::* collection));
|
|
|
|
// Ambiguity
|
|
Trace* EnsureTraceWithValidStates(Trace* trace);
|
|
bool AreTwoEndingInputTraceEqual(Trace* newTrace, Trace* candidate);
|
|
Trace* MergeTwoEndingInputTrace(Trace* newTrace, Trace* candidate);
|
|
void TryMergeSurvivingTraces();
|
|
|
|
// Competition
|
|
void AttendCompetition(Trace* trace, Ref<AttendingCompetitions>& newAttendingCompetitions, Ref<AttendingCompetitions>& newCarriedCompetitions, Ref<ReturnStack> returnStack, vint32_t ruleId, CompetitionDesc comp);
|
|
void AttendCompetitionIfNecessary(Trace* trace, vint32_t currentTokenIndex, EdgeDesc& edgeDesc, Ref<AttendingCompetitions>& newAttendingCompetitions, Ref<AttendingCompetitions>& newCarriedCompetitions, Ref<ReturnStack>& newReturnStack);
|
|
void CheckAttendingCompetitionsOnEndingEdge(Trace* trace, EdgeDesc& edgeDesc, Ref<AttendingCompetitions> acId, Ref<ReturnStack> returnStack);
|
|
bool CheckBackupTracesBeforeSwapping(vint32_t currentTokenIndex);
|
|
|
|
// ReturnStack
|
|
ReturnStackSuccessors* GetCurrentSuccessorInReturnStack(Ref<ReturnStack> base, vint32_t currentTokenIndex);
|
|
ReturnStack* PushReturnStack(Ref<ReturnStack> base, vint32_t returnIndex, Ref<Trace> fromTrace, vint32_t currentTokenIndex, bool allowReuse);
|
|
|
|
// Walk
|
|
bool IsQualifiedTokenForCondition(regex::RegexToken* token, StringLiteral condition);
|
|
bool IsQualifiedTokenForEdgeArray(regex::RegexToken* token, EdgeArray& edgeArray);
|
|
void TestLeftrecEdgeQualification(EdgeDesc& edgeDesc, regex::RegexToken* lookAhead, bool& acceptLookAhead, bool& acceptEndingInput);
|
|
WalkingTrace WalkAlongSingleEdge(vint32_t currentTokenIndex, vint32_t input, WalkingTrace trace, vint32_t byEdge, EdgeDesc& edgeDesc);
|
|
void WalkAlongLeftrecEdges(vint32_t currentTokenIndex, regex::RegexToken* lookAhead, WalkingTrace trace, EdgeArray& edgeArray);
|
|
void WalkAlongEpsilonEdges(vint32_t currentTokenIndex, regex::RegexToken* lookAhead, WalkingTrace trace);
|
|
void WalkAlongTokenEdges(vint32_t currentTokenIndex, vint32_t input, regex::RegexToken* token, regex::RegexToken* lookAhead, WalkingTrace trace, EdgeArray& edgeArray);
|
|
|
|
// EndOfInput
|
|
void FillSuccessorsAfterEndOfInput(bool& ambiguityInvolved);
|
|
|
|
protected:
|
|
// Common
|
|
vuint64_t MergeStack_MagicCounter = 0;
|
|
|
|
template<typename TCallback>
|
|
void IterateSurvivedTraces(TCallback&& callback);
|
|
|
|
public:
|
|
void ReadInstructionList(Trace* trace, TraceInsLists& insLists);
|
|
AstIns& ReadInstruction(vint32_t instruction, TraceInsLists& insLists);
|
|
|
|
protected:
|
|
// PrepareTraceRoute
|
|
AllocateOnly<TraceExec> traceExecs;
|
|
collections::Array<InsExec> insExecs;
|
|
AllocateOnly<InsExec_Stack> insExec_Stacks;
|
|
AllocateOnly<InsExec_InsRefLink> insExec_InsRefLinks;
|
|
AllocateOnly<InsExec_StackRefLink> insExec_StackRefLinks;
|
|
AllocateOnly<InsExec_StackArrayRefLink> insExec_StackArrayRefLinks;
|
|
|
|
// phase: AllocateExecutionData
|
|
void AllocateExecutionData();
|
|
|
|
// phase: BuildAmbiguityStructures
|
|
Trace* StepForward(Trace* trace);
|
|
void BuildAmbiguityStructures();
|
|
|
|
// phase: PartialExecuteTraces - PartialExecuteOrdinaryTrace
|
|
InsExec_Stack* NewStack();
|
|
void PushInsRefLink(Ref<InsExec_InsRefLink>& link, InsRef insRef);
|
|
void PushStackRefLink(Ref<InsExec_StackRefLink>& link, Ref<InsExec_Stack> id);
|
|
void PushStackArrayRefLink(Ref<InsExec_StackArrayRefLink>& arrayLink, Ref<InsExec_Stack> id);
|
|
void PushStackArrayRefLink(Ref<InsExec_StackArrayRefLink>& arrayLink, Ref<InsExec_StackRefLink> link);
|
|
Ref<InsExec_InsRefLink> JoinInsRefLink(Ref<InsExec_InsRefLink> first, Ref<InsExec_InsRefLink> second);
|
|
Ref<InsExec_StackRefLink> JoinStackRefLink(Ref<InsExec_StackRefLink> first, Ref<InsExec_StackRefLink> second);
|
|
void PartialExecuteOrdinaryTrace(Trace* trace);
|
|
|
|
// phase: PartialExecuteTraces - EnsureInsExecContextCompatible
|
|
void EnsureInsExecContextCompatible(Trace* baselineTrace, Trace* commingTrace);
|
|
|
|
// phase: PartialExecuteTraces - MergeInsExecContext
|
|
template<Ref<InsExec_StackArrayRefLink> (InsExec_Context::*stack), typename TMerge>
|
|
Ref<InsExec_StackArrayRefLink> MergeStack(Trace* mergeTrace, TMerge&& merge);
|
|
void MergeInsExecContext(Trace* mergeTrace);
|
|
|
|
// phase: PartialExecuteTraces
|
|
void PartialExecuteTraces();
|
|
|
|
// phase: SummarizeInstructionRange
|
|
template<typename TCallback>
|
|
void IterateStackWithDependency(Ref<InsExec_StackRefLink>(InsExec_Stack::* dependencies), TCallback&& callback);
|
|
bool UpdateTopTrace(InsRef& topInsRef, InsRef newInsRef);
|
|
void CollectInsRefs(collections::SortedList<InsRef>& insRefs, Ref<InsExec_InsRefLink> link);
|
|
void SummarizeEarilestLocalInsRefs();
|
|
void SummarizeEarilestStackInsRefs();
|
|
void SummarizeEarilestInsRefs();
|
|
void SummarizeInstructionRange();
|
|
|
|
protected:
|
|
// ResolveAmbiguity
|
|
Ref<Trace> firstBranchTrace;
|
|
Ref<Trace> firstMergeTrace;
|
|
Ref<InsExec_Stack> firstStack;
|
|
Ref<ExecutionStep> firstStep;
|
|
AllocateOnly<TraceAmbiguity> traceAmbiguities;
|
|
AllocateOnly<TraceAmbiguityLink> traceAmbiguityLinks;
|
|
AllocateOnly<ExecutionStep> executionSteps;
|
|
|
|
// phase: CheckMergeTraces
|
|
template<typename TCallback>
|
|
bool EnumerateObjects(Ref<InsExec_StackRefLink> stackRefLinkStartSet, bool withCounter, TCallback&& callback);
|
|
template<typename TCallback>
|
|
bool EnumerateBottomInstructions(InsExec_Stack* ieObject, TCallback&& callback);
|
|
bool ComparePrefix(TraceExec* baselineTraceExec, TraceExec* commingTraceExec, vint32_t prefix);
|
|
bool ComparePostfix(TraceExec* baselineTraceExec, TraceExec* commingTraceExec, vint32_t postfix);
|
|
template<typename TCallback>
|
|
bool CheckAmbiguityResolution(TraceAmbiguity* ta, collections::List<Ref<InsExec_StackRefLink>>& visitingIds, collections::List<WString>* failureReasons, TCallback&& callback);
|
|
bool CheckSingleMergeTrace(TraceAmbiguity* ta, Trace* trace, TraceExec* traceExec, collections::List<Ref<InsExec_StackRefLink>>& visitingIds, collections::List<WString>* failureReasons);
|
|
void LinkAmbiguityCriticalTrace(Ref<Trace> traceId);
|
|
void CheckTraceAmbiguity(TraceAmbiguity* ta);
|
|
void MarkAmbiguityCoveredForward(Trace* currentTrace, TraceAmbiguity* ta, Trace* firstTrace, TraceExec* firstTraceExec);
|
|
void CategorizeTraceAmbiguities(Trace* trace, TraceExec* traceExec);
|
|
void CheckMergeTraces();
|
|
|
|
// phase: BuildExecutionOrder
|
|
|
|
|
|
struct NestedAmbiguityInfo
|
|
{
|
|
collections::List<TraceAmbiguity*> nestedAmbiguities; // all nested ambiguities in order from outer to inner
|
|
collections::Dictionary<Trace*, TraceAmbiguity*> branchTraces; // branchTrace to TraceAmbiguities
|
|
collections::Group<TraceAmbiguity*, Trace*> branchSelections; // critial successors of each TraceAmbiguities' branchTrace from inner to outer
|
|
};
|
|
|
|
struct BSL_Guidance
|
|
{
|
|
const collections::List<Trace*>* branchSelections = nullptr;
|
|
const collections::List<TraceAmbiguity*>* ambiguitiesToSkip = nullptr;
|
|
|
|
};
|
|
|
|
struct BSLA_Guidance
|
|
{
|
|
Ptr<NestedAmbiguityInfo> nestedTas;
|
|
vint nextAmbiguityIndex = 0;
|
|
};
|
|
|
|
void AppendStepsAfterList(ExecutionStepLinkedList steps, ExecutionStepLinkedList& current);
|
|
void AppendLeafToTree(ExecutionStep* leaf, ExecutionStepTree& tree);
|
|
ExecutionStepLinkedList ConvertStepTreeToList(ExecutionStepTree tree);
|
|
|
|
ExecutionStep* CreateResolveAmbiguityStep(TraceAmbiguity* ta);
|
|
Ptr<NestedAmbiguityInfo> CollectNestedAmbiguities(TraceAmbiguity* ta);
|
|
|
|
void BuildStepLeafsForAmbiguityBranch(
|
|
TraceAmbiguity* ta,
|
|
ExecutionStep* lastSharedStep,
|
|
Trace* ambiguityBranchStartTrace,
|
|
vint32_t* ambiguityBranchStartIns,
|
|
ExecutionStepTree& ambiguityStepTree);
|
|
void BuildStepLeafsForNestedAmbiguityBranch(
|
|
TraceAmbiguity* ta,
|
|
ExecutionStep* lastSharedStep,
|
|
BSLA_Guidance* guidance,
|
|
ExecutionStepTree& ambiguityStepTree);
|
|
ExecutionStepLinkedList BuildStepListForAmbiguity(
|
|
TraceAmbiguity* ta,
|
|
BSLA_Guidance* guidance);
|
|
ExecutionStepLinkedList BuildStepListThroughAmbiguity(
|
|
Trace*& currentTrace,
|
|
vint32_t& currentIns,
|
|
TraceAmbiguity* ta,
|
|
BSLA_Guidance* guidance
|
|
);
|
|
ExecutionStepLinkedList BuildStepListUntilFirstRawBranchTrace(
|
|
Trace* startTrace,
|
|
vint32_t startIns,
|
|
Trace* endTrace,
|
|
vint32_t endIns,
|
|
BSL_Guidance* guidance,
|
|
Trace** rawBranchTrace);
|
|
ExecutionStepLinkedList BuildStepList(
|
|
Trace* startTrace,
|
|
vint32_t startIns,
|
|
Trace* endTrace,
|
|
vint32_t endIns,
|
|
BSL_Guidance* guidance);
|
|
void BuildExecutionOrder();
|
|
|
|
public:
|
|
TraceManager(Executable& _executable, const ITypeCallback* _typeCallback, vint blockSize);
|
|
|
|
vint32_t concurrentCount = 0;
|
|
Nullable<vint32_t> concurrentCountBeforeError;
|
|
collections::List<Trace*>* concurrentTraces = nullptr;
|
|
collections::List<Trace*>* backupTraces = nullptr;
|
|
|
|
ReturnStack* GetReturnStack(Ref<ReturnStack> index);
|
|
ReturnStack* AllocateReturnStack();
|
|
Trace* GetTrace(Ref<Trace> index);
|
|
Trace* AllocateTrace();
|
|
Competition* GetCompetition(Ref<Competition> index);
|
|
Competition* AllocateCompetition();
|
|
AttendingCompetitions* GetAttendingCompetitions(Ref<AttendingCompetitions> index);
|
|
AttendingCompetitions* AllocateAttendingCompetitions();
|
|
|
|
InsExec* GetInsExec(vint32_t index);
|
|
InsExec_Stack* GetInsExec_Stack(Ref<InsExec_Stack> index);
|
|
InsExec_InsRefLink* GetInsExec_InsRefLink(Ref<InsExec_InsRefLink> index);
|
|
InsExec_StackRefLink* GetInsExec_StackRefLink(Ref<InsExec_StackRefLink> index);
|
|
InsExec_StackArrayRefLink* GetInsExec_StackArrayRefLink(Ref<InsExec_StackArrayRefLink> index);
|
|
TraceExec* GetTraceExec(Ref<TraceExec> index);
|
|
TraceAmbiguity* GetTraceAmbiguity(Ref<TraceAmbiguity> index);
|
|
TraceAmbiguityLink* GetTraceAmbiguityLink(Ref<TraceAmbiguityLink> index);
|
|
ExecutionStep* GetExecutionStep(Ref<ExecutionStep> index);
|
|
|
|
void Initialize(vint32_t startState) override;
|
|
Trace* GetInitialTrace();
|
|
ExecutionStep* GetInitialExecutionStep();
|
|
|
|
bool Input(vint32_t currentTokenIndex, regex::RegexToken* token, regex::RegexToken* lookAhead) override;
|
|
bool EndOfInput(bool& ambiguityInvolved) override;
|
|
|
|
void PrepareTraceRoute() override;
|
|
void ResolveAmbiguity() override;
|
|
|
|
protected:
|
|
void ExecuteSingleTrace(IAstInsReceiver& receiver, Trace* trace, vint32_t firstIns, vint32_t lastIns, TraceInsLists& insLists, collections::List<regex::RegexToken>& tokens);
|
|
void ExecuteSingleStep(IAstInsReceiver& receiver, ExecutionStep* step, collections::List<regex::RegexToken>& tokens);
|
|
public:
|
|
Ptr<ParsingAstBase> ExecuteTrace(IAstInsReceiver& receiver, collections::List<regex::RegexToken>& tokens) override;
|
|
};
|
|
|
|
class TraceException : public Exception
|
|
{
|
|
public:
|
|
TraceException(TraceManager& tm, InsRef insRef, const wchar_t* phrase, const wchar_t* message)
|
|
: Exception(
|
|
WString::Unmanaged(L"[") +
|
|
WString::Unmanaged(phrase) +
|
|
WString::Unmanaged(L"] at ") +
|
|
itow(insRef.trace.handle) + WString::Unmanaged(L"@") + itow(insRef.ins) +
|
|
WString::Unmanaged(L" : ") +
|
|
WString::Unmanaged(message)
|
|
)
|
|
{
|
|
}
|
|
|
|
TraceException(TraceManager& tm, Trace* trace1, Trace* trace2, const wchar_t* phrase, const WString& message)
|
|
: Exception(
|
|
WString::Unmanaged(L"[") +
|
|
WString::Unmanaged(phrase) +
|
|
WString::Unmanaged(L"] at trace ") +
|
|
itow(trace1->allocatedIndex) +
|
|
(trace2 == nullptr ? WString::Empty : WString::Unmanaged(L" and ") + itow(trace2->allocatedIndex)) +
|
|
WString::Unmanaged(L" : ") +
|
|
message
|
|
)
|
|
{
|
|
}
|
|
|
|
TraceException(TraceManager& tm, Trace* trace1, Trace* trace2, const wchar_t* phrase, const wchar_t* message)
|
|
: TraceException(tm, trace1, trace2, phrase, WString::Unmanaged(message))
|
|
{
|
|
}
|
|
|
|
TraceException(TraceManager& tm, TraceAmbiguity* ta1, TraceAmbiguity* ta2, const wchar_t* phrase, const wchar_t* message)
|
|
: Exception(
|
|
WString::Unmanaged(L"[") +
|
|
WString::Unmanaged(phrase) +
|
|
WString::Unmanaged(L"] at trace ambiguity ") +
|
|
itow(ta1->firstTrace.handle) + WString::Unmanaged(L"@") + itow(ta1->prefix) + WString::Unmanaged(L"..") +
|
|
itow(ta1->lastTrace.handle) + WString::Unmanaged(L"@-") + itow(ta1->postfix) +
|
|
(ta2 == nullptr ? WString::Empty :
|
|
WString::Unmanaged(L" and ") +
|
|
itow(ta2->firstTrace.handle) + WString::Unmanaged(L"@") + itow(ta2->prefix) + WString::Unmanaged(L"..") +
|
|
itow(ta2->lastTrace.handle) + WString::Unmanaged(L"@-") + itow(ta2->postfix)
|
|
) +
|
|
WString::Unmanaged(L" : ") +
|
|
WString::Unmanaged(message)
|
|
)
|
|
{
|
|
}
|
|
|
|
TraceException(TraceManager& tm, InsExec_Stack* stack, const wchar_t* phrase, const wchar_t* message)
|
|
: Exception(
|
|
WString::Unmanaged(L"[") +
|
|
WString::Unmanaged(phrase) +
|
|
WString::Unmanaged(L"] at trace ") +
|
|
itow(stack->allocatedIndex) +
|
|
WString::Unmanaged(L" : ") +
|
|
WString::Unmanaged(message)
|
|
)
|
|
{
|
|
}
|
|
|
|
TraceException(TraceManager& tm, const wchar_t* phrase, const wchar_t* message)
|
|
: Exception(
|
|
WString::Unmanaged(L"[") +
|
|
WString::Unmanaged(phrase) +
|
|
WString::Unmanaged(L"] : ") +
|
|
WString::Unmanaged(message)
|
|
)
|
|
{
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\TRACEMANAGER\TRACEMANAGER_COMMON.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_TRACEMANAGER_TRACEMANAGER_COMMON
|
|
#define VCZH_PARSER2_TRACEMANAGER_TRACEMANAGER_COMMON
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace automaton
|
|
{
|
|
/***********************************************************************
|
|
IterateSurvivedTraces
|
|
***********************************************************************/
|
|
|
|
template<typename TCallback>
|
|
void TraceManager::IterateSurvivedTraces(TCallback&& callback)
|
|
{
|
|
Trace* lastTrace = nullptr;
|
|
collections::List<Trace*> traces;
|
|
traces.Add(initialTrace);
|
|
|
|
while (traces.Count() > 0)
|
|
{
|
|
auto current = traces[traces.Count() - 1];
|
|
traces.RemoveAt(traces.Count() - 1);
|
|
|
|
if (current->iterateCounter == current->predecessorCount)
|
|
{
|
|
current->iterateCounter = 0;
|
|
}
|
|
|
|
current->iterateCounter++;
|
|
callback(
|
|
current,
|
|
(
|
|
current->predecessorCount == 0 ? nullptr :
|
|
current->predecessorCount == 1 ? GetTrace(current->predecessors.first) :
|
|
lastTrace
|
|
),
|
|
current->iterateCounter,
|
|
current->predecessorCount
|
|
);
|
|
lastTrace = current;
|
|
if (current->iterateCounter < current->predecessorCount) continue;
|
|
|
|
auto successorId = current->successors.last;
|
|
while (successorId != nullref)
|
|
{
|
|
auto successor = GetTrace(successorId);
|
|
successorId = successor->successors.siblingPrev;
|
|
traces.Add(successor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_AST_AST
|
|
#define VCZH_PARSER2_BUILTIN_XML_AST_AST
|
|
|
|
|
|
namespace vl::glr::xml
|
|
{
|
|
class XmlAttribute;
|
|
class XmlCData;
|
|
class XmlComment;
|
|
class XmlDocument;
|
|
class XmlElement;
|
|
class XmlInstruction;
|
|
class XmlNode;
|
|
class XmlText;
|
|
|
|
class XmlNode abstract : public vl::glr::ParsingAstBase, vl::reflection::Description<XmlNode>
|
|
{
|
|
public:
|
|
class IVisitor : public virtual vl::reflection::IDescriptable, vl::reflection::Description<IVisitor>
|
|
{
|
|
public:
|
|
virtual void Visit(XmlText* node) = 0;
|
|
virtual void Visit(XmlCData* node) = 0;
|
|
virtual void Visit(XmlComment* node) = 0;
|
|
virtual void Visit(XmlElement* node) = 0;
|
|
virtual void Visit(XmlInstruction* node) = 0;
|
|
virtual void Visit(XmlDocument* node) = 0;
|
|
};
|
|
|
|
virtual void Accept(XmlNode::IVisitor* visitor) = 0;
|
|
|
|
};
|
|
|
|
class XmlText : public XmlNode, vl::reflection::Description<XmlText>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken content;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class XmlCData : public XmlNode, vl::reflection::Description<XmlCData>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken content;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class XmlAttribute : public vl::glr::ParsingAstBase, vl::reflection::Description<XmlAttribute>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken name;
|
|
vl::glr::ParsingToken value;
|
|
};
|
|
|
|
class XmlComment : public XmlNode, vl::reflection::Description<XmlComment>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken content;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class XmlElement : public XmlNode, vl::reflection::Description<XmlElement>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken name;
|
|
vl::glr::ParsingToken closingName;
|
|
vl::collections::List<vl::Ptr<XmlAttribute>> attributes;
|
|
vl::collections::List<vl::Ptr<XmlNode>> subNodes;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class XmlInstruction : public XmlNode, vl::reflection::Description<XmlInstruction>
|
|
{
|
|
public:
|
|
vl::glr::ParsingToken name;
|
|
vl::collections::List<vl::Ptr<XmlAttribute>> attributes;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor) override;
|
|
};
|
|
|
|
class XmlDocument : public XmlNode, vl::reflection::Description<XmlDocument>
|
|
{
|
|
public:
|
|
vl::collections::List<vl::Ptr<XmlNode>> prologs;
|
|
vl::Ptr<XmlElement> rootElement;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor) override;
|
|
};
|
|
}
|
|
namespace vl::reflection::description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlNode)
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlNode::IVisitor)
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlText)
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlCData)
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlAttribute)
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlComment)
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlElement)
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlInstruction)
|
|
DECL_TYPE_INFO(vl::glr::xml::XmlDocument)
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(vl::glr::xml::XmlNode::IVisitor)
|
|
void Visit(vl::glr::xml::XmlText* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::xml::XmlCData* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::xml::XmlComment* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::xml::XmlElement* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::xml::XmlInstruction* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::glr::xml::XmlDocument* node) override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
END_INTERFACE_PROXY(vl::glr::xml::XmlNode::IVisitor)
|
|
|
|
#endif
|
|
#endif
|
|
/// <summary>Load all reflectable AST types, only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is off.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
extern bool XmlAstLoadTypes();
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_BUILDER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_AST_AST_BUILDER
|
|
#define VCZH_PARSER2_BUILTIN_XML_AST_AST_BUILDER
|
|
|
|
|
|
namespace vl::glr::xml::builder
|
|
{
|
|
class MakeAttribute : public vl::glr::ParsingAstBuilder<XmlAttribute>
|
|
{
|
|
public:
|
|
MakeAttribute& name(const vl::WString& value);
|
|
MakeAttribute& value(const vl::WString& value);
|
|
};
|
|
|
|
class MakeCData : public vl::glr::ParsingAstBuilder<XmlCData>
|
|
{
|
|
public:
|
|
MakeCData& content(const vl::WString& value);
|
|
};
|
|
|
|
class MakeComment : public vl::glr::ParsingAstBuilder<XmlComment>
|
|
{
|
|
public:
|
|
MakeComment& content(const vl::WString& value);
|
|
};
|
|
|
|
class MakeDocument : public vl::glr::ParsingAstBuilder<XmlDocument>
|
|
{
|
|
public:
|
|
MakeDocument& prologs(const vl::Ptr<XmlNode>& value);
|
|
MakeDocument& rootElement(const vl::Ptr<XmlElement>& value);
|
|
};
|
|
|
|
class MakeElement : public vl::glr::ParsingAstBuilder<XmlElement>
|
|
{
|
|
public:
|
|
MakeElement& attributes(const vl::Ptr<XmlAttribute>& value);
|
|
MakeElement& closingName(const vl::WString& value);
|
|
MakeElement& name(const vl::WString& value);
|
|
MakeElement& subNodes(const vl::Ptr<XmlNode>& value);
|
|
};
|
|
|
|
class MakeInstruction : public vl::glr::ParsingAstBuilder<XmlInstruction>
|
|
{
|
|
public:
|
|
MakeInstruction& attributes(const vl::Ptr<XmlAttribute>& value);
|
|
MakeInstruction& name(const vl::WString& value);
|
|
};
|
|
|
|
class MakeText : public vl::glr::ParsingAstBuilder<XmlText>
|
|
{
|
|
public:
|
|
MakeText& content(const vl::WString& value);
|
|
};
|
|
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_COPY.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_AST_AST_COPY_VISITOR
|
|
#define VCZH_PARSER2_BUILTIN_XML_AST_AST_COPY_VISITOR
|
|
|
|
|
|
namespace vl::glr::xml::copy_visitor
|
|
{
|
|
/// <summary>A copy visitor, overriding all abstract methods with AST copying code.</summary>
|
|
class AstVisitor
|
|
: public virtual vl::glr::CopyVisitorBase
|
|
, protected virtual XmlNode::IVisitor
|
|
{
|
|
protected:
|
|
void CopyFields(XmlAttribute* from, XmlAttribute* to);
|
|
void CopyFields(XmlCData* from, XmlCData* to);
|
|
void CopyFields(XmlComment* from, XmlComment* to);
|
|
void CopyFields(XmlDocument* from, XmlDocument* to);
|
|
void CopyFields(XmlElement* from, XmlElement* to);
|
|
void CopyFields(XmlInstruction* from, XmlInstruction* to);
|
|
void CopyFields(XmlNode* from, XmlNode* to);
|
|
void CopyFields(XmlText* from, XmlText* to);
|
|
|
|
protected:
|
|
virtual void Visit(XmlAttribute* node);
|
|
|
|
void Visit(XmlText* node) override;
|
|
void Visit(XmlCData* node) override;
|
|
void Visit(XmlComment* node) override;
|
|
void Visit(XmlElement* node) override;
|
|
void Visit(XmlInstruction* node) override;
|
|
void Visit(XmlDocument* node) override;
|
|
|
|
public:
|
|
virtual vl::Ptr<XmlNode> CopyNode(XmlNode* node);
|
|
virtual vl::Ptr<XmlAttribute> CopyNode(XmlAttribute* node);
|
|
|
|
vl::Ptr<XmlCData> CopyNode(XmlCData* node);
|
|
vl::Ptr<XmlComment> CopyNode(XmlComment* node);
|
|
vl::Ptr<XmlDocument> CopyNode(XmlDocument* node);
|
|
vl::Ptr<XmlElement> CopyNode(XmlElement* node);
|
|
vl::Ptr<XmlInstruction> CopyNode(XmlInstruction* node);
|
|
vl::Ptr<XmlText> CopyNode(XmlText* node);
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_EMPTY.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_AST_AST_EMPTY_VISITOR
|
|
#define VCZH_PARSER2_BUILTIN_XML_AST_AST_EMPTY_VISITOR
|
|
|
|
|
|
namespace vl::glr::xml::empty_visitor
|
|
{
|
|
/// <summary>An empty visitor, overriding all abstract methods with empty implementations.</summary>
|
|
class NodeVisitor : public vl::Object, public XmlNode::IVisitor
|
|
{
|
|
protected:
|
|
// Dispatch (virtual) --------------------------------
|
|
|
|
public:
|
|
// Visitor Members -----------------------------------
|
|
void Visit(XmlText* node) override;
|
|
void Visit(XmlCData* node) override;
|
|
void Visit(XmlComment* node) override;
|
|
void Visit(XmlElement* node) override;
|
|
void Visit(XmlInstruction* node) override;
|
|
void Visit(XmlDocument* node) override;
|
|
};
|
|
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_JSON.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_AST_AST_JSON_VISITOR
|
|
#define VCZH_PARSER2_BUILTIN_XML_AST_AST_JSON_VISITOR
|
|
|
|
|
|
namespace vl::glr::xml::json_visitor
|
|
{
|
|
/// <summary>A JSON visitor, overriding all abstract methods with AST to JSON serialization code.</summary>
|
|
class AstVisitor
|
|
: public vl::glr::JsonVisitorBase
|
|
, protected virtual XmlNode::IVisitor
|
|
{
|
|
protected:
|
|
virtual void PrintFields(XmlAttribute* node);
|
|
virtual void PrintFields(XmlCData* node);
|
|
virtual void PrintFields(XmlComment* node);
|
|
virtual void PrintFields(XmlDocument* node);
|
|
virtual void PrintFields(XmlElement* node);
|
|
virtual void PrintFields(XmlInstruction* node);
|
|
virtual void PrintFields(XmlNode* node);
|
|
virtual void PrintFields(XmlText* node);
|
|
|
|
protected:
|
|
void Visit(XmlText* node) override;
|
|
void Visit(XmlCData* node) override;
|
|
void Visit(XmlComment* node) override;
|
|
void Visit(XmlElement* node) override;
|
|
void Visit(XmlInstruction* node) override;
|
|
void Visit(XmlDocument* node) override;
|
|
|
|
public:
|
|
AstVisitor(vl::stream::StreamWriter& _writer);
|
|
|
|
void Print(XmlNode* node);
|
|
void Print(XmlAttribute* node);
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLAST_TRAVERSE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Ast
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_AST_AST_TRAVERSE_VISITOR
|
|
#define VCZH_PARSER2_BUILTIN_XML_AST_AST_TRAVERSE_VISITOR
|
|
|
|
|
|
namespace vl::glr::xml::traverse_visitor
|
|
{
|
|
/// <summary>A traverse visitor, overriding all abstract methods with AST visiting code.</summary>
|
|
class AstVisitor
|
|
: public vl::Object
|
|
, protected virtual XmlNode::IVisitor
|
|
{
|
|
protected:
|
|
virtual void Traverse(vl::glr::ParsingToken& token);
|
|
virtual void Traverse(vl::glr::ParsingAstBase* node);
|
|
virtual void Traverse(XmlAttribute* node);
|
|
virtual void Traverse(XmlCData* node);
|
|
virtual void Traverse(XmlComment* node);
|
|
virtual void Traverse(XmlDocument* node);
|
|
virtual void Traverse(XmlElement* node);
|
|
virtual void Traverse(XmlInstruction* node);
|
|
virtual void Traverse(XmlNode* node);
|
|
virtual void Traverse(XmlText* node);
|
|
|
|
protected:
|
|
virtual void Finishing(vl::glr::ParsingAstBase* node);
|
|
virtual void Finishing(XmlAttribute* node);
|
|
virtual void Finishing(XmlCData* node);
|
|
virtual void Finishing(XmlComment* node);
|
|
virtual void Finishing(XmlDocument* node);
|
|
virtual void Finishing(XmlElement* node);
|
|
virtual void Finishing(XmlInstruction* node);
|
|
virtual void Finishing(XmlNode* node);
|
|
virtual void Finishing(XmlText* node);
|
|
|
|
protected:
|
|
void Visit(XmlText* node) override;
|
|
void Visit(XmlCData* node) override;
|
|
void Visit(XmlComment* node) override;
|
|
void Visit(XmlElement* node) override;
|
|
void Visit(XmlInstruction* node) override;
|
|
void Visit(XmlDocument* node) override;
|
|
|
|
public:
|
|
void InspectInto(XmlNode* node);
|
|
void InspectInto(XmlAttribute* node);
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XML_ASSEMBLER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Xml
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_AST_ASSEMBLER
|
|
#define VCZH_PARSER2_BUILTIN_XML_AST_ASSEMBLER
|
|
|
|
|
|
namespace vl::glr::xml
|
|
{
|
|
enum class XmlClasses : vl::vint32_t
|
|
{
|
|
Attribute = 0,
|
|
CData = 1,
|
|
Comment = 2,
|
|
Document = 3,
|
|
Element = 4,
|
|
Instruction = 5,
|
|
Node = 6,
|
|
Text = 7,
|
|
};
|
|
|
|
enum class XmlFields : vl::vint32_t
|
|
{
|
|
Attribute_name = 0,
|
|
Attribute_value = 1,
|
|
CData_content = 2,
|
|
Comment_content = 3,
|
|
Document_prologs = 4,
|
|
Document_rootElement = 5,
|
|
Element_attributes = 6,
|
|
Element_closingName = 7,
|
|
Element_name = 8,
|
|
Element_subNodes = 9,
|
|
Instruction_attributes = 10,
|
|
Instruction_name = 11,
|
|
Text_content = 12,
|
|
};
|
|
|
|
extern const wchar_t* XmlTypeName(XmlClasses type);
|
|
extern const wchar_t* XmlCppTypeName(XmlClasses type);
|
|
extern const wchar_t* XmlFieldName(XmlFields field);
|
|
extern const wchar_t* XmlCppFieldName(XmlFields field);
|
|
|
|
class XmlAstInsReceiver : public vl::glr::AstInsReceiverBase
|
|
{
|
|
protected:
|
|
vl::Ptr<vl::glr::ParsingAstBase> CreateAstNode(vl::vint32_t type) override;
|
|
void SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::Ptr<vl::glr::ParsingAstBase> value) override;
|
|
void SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, const vl::regex::RegexToken& token, vl::vint32_t tokenIndex) override;
|
|
void SetField(vl::glr::ParsingAstBase* object, vl::vint32_t field, vl::vint32_t enumItem, bool weakAssignment) override;
|
|
vl::Ptr<vl::glr::ParsingAstBase> ResolveAmbiguity(vl::vint32_t type, vl::collections::Array<vl::Ptr<vl::glr::ParsingAstBase>>& candidates) override;
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XML_LEXER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Xml
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_LEXER
|
|
#define VCZH_PARSER2_BUILTIN_XML_LEXER
|
|
|
|
|
|
namespace vl::glr::xml
|
|
{
|
|
enum class XmlTokens : vl::vint32_t
|
|
{
|
|
INSTRUCTION_OPEN = 0,
|
|
INSTRUCTION_CLOSE = 1,
|
|
COMPLEX_ELEMENT_OPEN = 2,
|
|
SINGLE_ELEMENT_CLOSE = 3,
|
|
ELEMENT_OPEN = 4,
|
|
ELEMENT_CLOSE = 5,
|
|
EQUAL = 6,
|
|
NAME = 7,
|
|
ATTVALUE = 8,
|
|
COMMENT = 9,
|
|
CDATA = 10,
|
|
TEXT = 11,
|
|
SPACE = 12,
|
|
};
|
|
|
|
constexpr vl::vint XmlTokenCount = 13;
|
|
extern bool XmlTokenDeleter(vl::vint token);
|
|
extern const wchar_t* XmlTokenId(XmlTokens token);
|
|
extern const wchar_t* XmlTokenDisplayText(XmlTokens token);
|
|
extern const wchar_t* XmlTokenRegex(XmlTokens token);
|
|
extern void XmlLexerData(vl::stream::IStream& outputStream);
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GENERATED\XMLPARSER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:Xml
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML_PARSER_SYNTAX
|
|
#define VCZH_PARSER2_BUILTIN_XML_PARSER_SYNTAX
|
|
|
|
|
|
namespace vl::glr::xml
|
|
{
|
|
enum class ParserStates
|
|
{
|
|
XAttribute = 0,
|
|
XText = 5,
|
|
XCData = 11,
|
|
XComment = 14,
|
|
XElement = 17,
|
|
XSubNode = 28,
|
|
XInstruction = 34,
|
|
XDocument = 40,
|
|
};
|
|
|
|
const wchar_t* ParserRuleName(vl::vint index);
|
|
const wchar_t* ParserStateLabel(vl::vint index);
|
|
extern void XmlParserData(vl::stream::IStream& outputStream);
|
|
|
|
class Parser
|
|
: public vl::glr::ParserBase<XmlTokens, ParserStates, XmlAstInsReceiver>
|
|
, protected vl::glr::automaton::IExecutor::ITypeCallback
|
|
{
|
|
protected:
|
|
vl::WString GetClassName(vl::vint32_t classIndex) const override;
|
|
vl::vint32_t FindCommonBaseClass(vl::vint32_t class1, vl::vint32_t class2) const override;
|
|
public:
|
|
Parser();
|
|
|
|
vl::Ptr<vl::glr::xml::XmlElement> ParseXElement(const vl::WString& input, vl::vint codeIndex = -1) const;
|
|
vl::Ptr<vl::glr::xml::XmlElement> ParseXElement(vl::collections::List<vl::regex::RegexToken>& tokens, vl::vint codeIndex = -1) const;
|
|
vl::Ptr<vl::glr::xml::XmlDocument> ParseXDocument(const vl::WString& input, vl::vint codeIndex = -1) const;
|
|
vl::Ptr<vl::glr::xml::XmlDocument> ParseXDocument(vl::collections::List<vl::regex::RegexToken>& tokens, vl::vint codeIndex = -1) const;
|
|
};
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\GLRXML.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Parser::ParsingXml
|
|
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSER2_BUILTIN_XML
|
|
#define VCZH_PARSER2_BUILTIN_XML
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace glr
|
|
{
|
|
namespace xml
|
|
{
|
|
extern WString XmlEscapeValue(const WString& value);
|
|
extern WString XmlUnescapeValue(const WString& value);
|
|
extern WString XmlEscapeCData(const WString& value);
|
|
extern WString XmlUnescapeCData(const WString& value);
|
|
extern WString XmlEscapeComment(const WString& value);
|
|
extern WString XmlUnescapeComment(const WString& value);
|
|
|
|
/// <summary>Deserialize XML document from string.</summary>
|
|
/// <returns>The deserialized XML node.</returns>
|
|
/// <param name="input">The XML code.</param>
|
|
/// <param name="parser">The generated parser.</param>
|
|
extern Ptr<XmlDocument> XmlParseDocument(const WString& input, const Parser& parser);
|
|
|
|
/// <summary>Deserialize XML element from string.</summary>
|
|
/// <returns>The deserialized XML node.</returns>
|
|
/// <param name="input">The XML code.</param>
|
|
/// <param name="parser">The generated parser.</param>
|
|
extern Ptr<XmlElement> XmlParseElement(const WString& input, const Parser& parser);
|
|
|
|
/// <summary>Serialize XML to string.</summary>
|
|
/// <param name="node">The XML node to serialize.</param>
|
|
/// <param name="writer">The text writer to receive the string.</param>
|
|
extern void XmlPrint(Ptr<XmlNode> node, stream::TextWriter& writer);
|
|
|
|
/// <summary>Serialize sub nodes in an XML element to string.</summary>
|
|
/// <param name="element">The XML element in which sub nodes are to be serialized.</param>
|
|
/// <param name="writer">The text writer to receive the string.</param>
|
|
extern void XmlPrintContent(Ptr<XmlElement> element, stream::TextWriter& writer);
|
|
|
|
/// <summary>Serialize XML to string.</summary>
|
|
/// <returns>The serialized string.</returns>
|
|
/// <param name="node">The XML node to serialize.</param>
|
|
extern WString XmlToString(Ptr<XmlNode> node);
|
|
|
|
/// <summary>Try to read an attribute in an XML element.</summary>
|
|
/// <returns>The expected attribute. Returns null if it doesn't exist.</returns>
|
|
/// <param name="element">The element to find the attribute.</param>
|
|
/// <param name="name">The name of the attribute.</param>
|
|
extern Ptr<XmlAttribute> XmlGetAttribute(Ptr<XmlElement> element, const WString& name);
|
|
|
|
/// <summary>Try to read a sub element in an XML element.</summary>
|
|
/// <returns>The expected sub element. Returns null if it doesn't exist. If there are multiple elements of the expected name, returns the first one.</returns>
|
|
/// <param name="element">The element to find the sub element.</param>
|
|
/// <param name="name">The name of the sub element.</param>
|
|
extern Ptr<XmlElement> XmlGetElement(Ptr<XmlElement> element, const WString& name);
|
|
|
|
/// <summary>Get all sub elements in an XML element.</summary>
|
|
/// <returns>All sub elements in an XML element.</returns>
|
|
/// <param name="element">The container XML element.</param>
|
|
extern collections::LazyList<Ptr<XmlElement>> XmlGetElements(Ptr<XmlElement> element);
|
|
|
|
/// <summary>Try to read sub elements in an XML element.</summary>
|
|
/// <returns>Expected sub elements. All sub elements of the expected name will be returned.</returns>
|
|
/// <param name="element">The element to find sub elements.</param>
|
|
/// <param name="name">The name of sub elements.</param>
|
|
extern collections::LazyList<Ptr<XmlElement>> XmlGetElements(Ptr<XmlElement> element, const WString& name);
|
|
|
|
/// <summary>Serialize contents in an XML element.</summary>
|
|
/// <returns>The serialized contents in an XML element.</returns>
|
|
/// <param name="element">The XML element in which contents are to be serialized.</param>
|
|
extern WString XmlGetValue(Ptr<XmlElement> element);
|
|
|
|
extern Ptr<XmlAttribute> XmlGetAttribute(XmlElement* element, const WString& name);
|
|
extern Ptr<XmlElement> XmlGetElement(XmlElement* element, const WString& name);
|
|
extern collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element);
|
|
extern collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element, const WString& name);
|
|
extern WString XmlGetValue(XmlElement* element);
|
|
|
|
class XmlElementWriter : public Object
|
|
{
|
|
protected:
|
|
Ptr<XmlElement> element;
|
|
const XmlElementWriter* previousWriter;
|
|
|
|
public:
|
|
XmlElementWriter(Ptr<XmlElement> _element, const XmlElementWriter* _previousWriter=0);
|
|
~XmlElementWriter();
|
|
|
|
const XmlElementWriter& Attribute(const WString& name, const WString& value)const;
|
|
XmlElementWriter Element(const WString& name)const;
|
|
const XmlElementWriter& End()const;
|
|
const XmlElementWriter& Text(const WString& value)const;
|
|
const XmlElementWriter& CData(const WString& value)const;
|
|
const XmlElementWriter& Comment(const WString& value)const;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|