<commit_before>/*
** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org).
**
** This Source Code Form is subject to the terms of the Mozilla Public License
** v.2.0. If a copy of the MPL was not distributed with this file, You can
** obtain one at http://mozilla.org/MPL/2.0/.
**
** github: https://github.com/libyuni/libyuni/
** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror)
*/
#include "grammar.h"
#include "../../io/file.h"



namespace Yuni
{
namespace Parser
{
namespace PEG
{

	namespace // anonymous
	{

		#include "yuni/private/parser/peg/__parser.include.cpp.hxx"



		class CPPConverter final
		{
		public:
			CPPConverter(const AnyString& root, const Node::Map& rules);
			bool initialize(const AnyString& name);
			void startHeaderheaderGuardID();
			void endHeaderheaderGuardID();
			void generateH();
			void generateHXX();
			void generateCPP();
			bool writeFiles() const;

		public:
			//! Original rules
			const Node::Map& rules;

			//! Code in the .h file
			Clob h;
			//! Code in the .hxx file
			Clob hxx;
			//! Code in the .cpp file
			Clob cpp;

			//! Header guard ID
			YString headerGuardID;
			//! Class name
			YString classname;
			//! Namespace
			YString::Vector namespaces;

			//! Root filename
			YString rootfilename;
			//! Local include
			YString localInclude;

		}; // class CPPConverter



		template<class YStringT>
		static inline void EnumIDToClassname(YStringT& out, const YString& enumID)
		{
			out = "Node";
			out << enumID;
			if (not enumID.empty())
				out[4] = (char) YString::ToUpper(out[4]);
		}


		inline CPPConverter::CPPConverter(const AnyString& root, const Node::Map& rules) :
			rules(rules),
			rootfilename(root)
		{
			IO::ExtractFileName(localInclude, root);
		}


		inline bool CPPConverter::initialize(const AnyString& name)
		{
			name.split(namespaces, "/\\:");
			return true;
		}


		inline void CPPConverter::generateH()
		{
			const Node::Map::const_iterator end = rules.end();

			h << "#pragma once\n";
			h << "#include <yuni/yuni.h>\n";
			h << "#include <yuni/core/string.h>\n";
			h << "#include <yuni/core/bind.h>\n";
			h << "#include <yuni/core/dictionary.h>\n";
			h << "#include <yuni/core/smartptr/intrusive.h>\n";
			h << "#include <initializer_list>\n";
			h << "\n\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';

			for (uint32_t i = 0; i != namespaces.size(); ++i)
				h << "namespace " << namespaces[i] << "\n{\n";
			h << '\n';
			h << "	enum Rule\n";
			h << "	{\n";
			h << "		//! Unknown rule\n";
			h << "		rgUnknown = 0,\n";
			uint32_t enumIndex = 1;
			for (Node::Map::const_iterator i = rules.begin(); i != end; ++i, ++enumIndex)
			{
				h << "		//! enum for the rule `" << i->first << '`';
				if (i->second.attributes.inlined)
					h << " [inline]";
				h << '\n';
				h << "		" << i->second.enumID << ", // = " << enumIndex << '\n';
			}
			h << "		//! enum for the final rule\n";
			h << "		rgEOF // " << (enumIndex++) << '\n';
			h << "	};\n";

			// rule count
			h << '\n';
			h << '\n';
			h << "	//! The total number of rules\n";
			h << "	constexpr const uint32_t ruleCount = " << enumIndex << ";\n";
			h << "\n\n\n";

			h << "	//! Convert a rule id into its text representation\n";
			h << "	YUNI_DECL AnyString ruleToString(enum Rule);\n";
			h << '\n';
			h << "	//! Get if a rule is an error\n";
			h << "	YUNI_DECL bool ruleIsError(enum Rule ruleid);\n";
			h << '\n';
			h << "	//! Get if the rule should be ignored when duplucating an AST (starting from 'tk-' and some special rules)\n";
			h << "	YUNI_DECL bool shouldIgnoreForDuplication(enum Rule);\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << "	enum class Error\n";
			h << "	{\n";
			h << "		//! No error\n";
			h << "		none,\n";
			h << "		//! Parse error\n";
			h << "		parse,\n";
			h << "	};\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';
			h << "	class YUNI_DECL Notification final\n";
			h << "	{\n";
			h << "	public:\n";
			h << "		//! Most suitable martptr\n";
			h << "		typedef Yuni::SmartPtr<Notification> Ptr;\n";
			h << "		//! Vector of nodes\n";
			h << "		typedef std::vector<Ptr> Vector;\n";
			h << '\n';
			h << "	public:\n";
			h << "		//! Start offset\n";
			h << "		uint32_t offset = 0;\n";
			h << "		//! Line Index\n";
			h << "		uint32_t line = 0;\n";
			h << "		//! Filename\n";
			h << "		YString message;\n";
			h << "		//! Filename\n";
			h << "		YString filename;\n";
			h << '\n';
			h << "	}; // class Notification\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';
			h << "	class YUNI_DECL Node;\n";
			h << '\n';
			h << '\n';
			h << "	class YUNI_DECL NodeVector final\n";
			h << "	{\n";
			h << "	public:\n";
			h << "		using T = Node;\n";
			h << '\n';
			h << "		struct Iterator final: public std::iterator<std::input_iterator_tag, T>\n";
			h << "		{\n";
			h << "			Iterator(T** array, uint32_t index) noexcept :m_array(array), m_index{index} {}\n";
			h << "			Iterator(const Iterator&) noexcept = default;\n";
			h << "			Iterator& operator++() noexcept { ++m_index; return *this; }\n";
			h << "			Iterator operator++(int) noexcept {Iterator tmp(*this); operator++(); return tmp;}\n";
			h << "			bool operator==(const Iterator& rhs) const noexcept { return rhs.m_index == m_index; };\n";
			h << "			bool operator!=(const Iterator& rhs) const noexcept { return rhs.m_index != m_index; };\n";
			h << "			T& operator * () noexcept { return *(m_array[m_index]); }\n";
			h << '\n';
			h << "		private:\n";
			h << "			T** const m_array;\n";
			h << "			uint32_t m_index = 0;\n";
			h << "			friend class NodeVector;\n";
			h << "		};\n";
			h << '\n';
			h << "		struct ConstIterator final: public std::iterator<std::input_iterator_tag, T>\n";
			h << "		{\n";
			h << "			ConstIterator(T** array, uint32_t index) noexcept :m_array(array), m_index{index} {}\n";
			h << "			ConstIterator(const ConstIterator&) noexcept = default;\n";
			h << "			ConstIterator& operator++() noexcept { ++m_index; return *this; }\n";
			h << "			ConstIterator operator++(int) noexcept {ConstIterator tmp(*this); operator++(); return tmp;}\n";
			h << "			bool operator==(const ConstIterator& rhs) const noexcept { return rhs.m_index == m_index; };\n";
			h << "			bool operator!=(const ConstIterator& rhs) const noexcept { return rhs.m_index != m_index; };\n";
			h << "			const T& operator * () const noexcept { return *(m_array[m_index]); }\n";
			h << '\n';
			h << "		private:\n";
			h << "			T** const m_array;\n";
			h << "			uint32_t m_index = 0;\n";
			h << "			friend class NodeVector;\n";
			h << "		};\n";
			h << '\n';
			h << "	public:\n";
			h << "		NodeVector() = default;\n";
			h << "		NodeVector(const NodeVector&) = delete;\n";
			h << "		NodeVector(NodeVector&&) = default;\n";
			h << "		~NodeVector();\n";
			h << '\n';
			h << "		Iterator begin() noexcept;\n";
			h << "		Iterator end() noexcept;\n";
			h << '\n';
			h << "		ConstIterator begin() const noexcept;\n";
			h << "		ConstIterator end() const noexcept;\n";
			h << '\n';
			h << "		ConstIterator cbegin() const noexcept;\n";
			h << "		ConstIterator cend() const noexcept;\n";
			h << '\n';
			h << "		void push_back(T* const element);\n";
			h << '\n';
			h << "		template<class U> void push_back(U& element);\n";
			h << '\n';
			h << "		void push_front(T* const element);\n";
			h << '\n';
			h << "		template<class U> void push_front(U& element);\n";
			h << '\n';
			h << "		//! Remove the last element\n";
			h << "		void pop_back() noexcept;\n";
			h << '\n';
			h << "		//! Empty the container\n";
			h << "		void clear() noexcept;\n";
			h << '\n';
			h << "		//! remove an element\n";
			h << "		void erase(uint32_t index) noexcept;\n";
			h << '\n';
			h << "		void erase(const Iterator& it) noexcept;\n";
			h << '\n';
			h << "		void erase(const ConstIterator& it) noexcept;\n";
			h << '\n';
			h << "		//! Resize the container to N elements\n";
			h << "		void resize(uint32_t count);\n";
			h << '\n';
			h << "		//! Get if the container is empty\n";
			h << "		bool empty() const noexcept;\n";
			h << '\n';
			h << "		//! Get the number of elements\n";
			h << "		uint32_t size() const noexcept;\n";
			h << '\n';
			h << "		//! Get the maximum number of elements before resizing\n";
			h << "		uint32_t capacity() const noexcept;\n";
			h << '\n';
			h << "		void shrink_to_fit() noexcept;\n";
			h << '\n';
			h << "		//! Retrieve the last element\n";
			h << "		T& back();\n";
			h << "		//! Retrieve the last element (const)\n";
			h << "		const T& back() const;\n";
			h << '\n';
			h << "		//! Retrive the first element\n";
			h << "		T& front();\n";
			h << "		//! Retrive the first element (const)\n";
			h << "		const T& front() const;\n";
			h << '\n';
			h << "		//! Retrieve the Nth element\n";
			h << "		T& operator [] (uint32_t i) noexcept;\n";
			h << "		//! Retrieve the Nth element (const)\n";
			h << "		const T& operator [] (uint32_t i) const noexcept;\n";
			h << "		//! Move operator\n";
			h << "		NodeVector& operator = (NodeVector&&) = default;\n";
			h << "		//! Copy operator\n";
			h << "		NodeVector& operator = (const NodeVector&);\n";
			h << '\n';
			h << '\n';
			h << "	private:\n";
			h << "		static void deleteElement(T* const ptr) noexcept;\n";
			h << "		void grow();\n";
			h << '\n';
			h << "	private:\n";
			h << "		static constexpr uint32_t preAllocatedCount = 2;\n";
			h << "		uint32_t m_size = 0;\n";
			h << "		uint32_t m_capacity = preAllocatedCount;\n";
			h << "		T** m_pointer = &(m_innerstorage[0]);\n";
			h << "		T* m_innerstorage[preAllocatedCount];\n";
			h << '\n';
			h << "		friend class Iterator;\n";
			h << "	};\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';
			h << "	class YUNI_DECL Node final : public Yuni::IIntrusiveSmartPtr<Node, false, Yuni::Policy::SingleThreaded>\n";
			h << "	{\n";
			h << "	public:\n";
			h << "		//! Ancestor\n";
			h << "		typedef Yuni::IIntrusiveSmartPtr<Node, false, Yuni::Policy::SingleThreaded> inherited;\n";
			h << "		//! Threading policy\n";
			h << "		typedef inherited::ThreadingPolicy ThreadingPolicy;\n";
			h << "		//! The most suitable smart ptr for the class\n";
			h << "		typedef inherited::SmartPtrType<Node>::Ptr  Ptr;\n";
			h << "		//! Vector of nodes\n";
			h << "		typedef std::vector<Node::Ptr> Vector;\n";
			h << "		//! Set of symbols\n";
			h << "		typedef Yuni::Set<Ptr>::Unordered Set;\n";
			h << '\n';
			h << "		//! Callback definition for export a node\n";
			h << "		typedef void (* ExportCallback)(const Node& node, YString& tmp);\n";
			h << '\n';
			h << '\n';
			h << "	public:\n";
			h << "		//! Export the tree node\n";
			h << "		static void Export(Yuni::Clob& out, const Node& node);\n";
			h << "		//! Export the tree node (with color output)\n";
			h << "		static void Export(Yuni::Clob& out, const Node& node, bool color, ExportCallback callback = nullptr);\n";
			h << "		//! Export the tree node to HTML\n";
			h << "		static void ExportToHTML(Yuni::Clob& out, const Node& node);\n";
			h << '\n';<commit_msg>parser: fixed warning mix struct/class<commit_after>/*
** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org).
**
** This Source Code Form is subject to the terms of the Mozilla Public License
** v.2.0. If a copy of the MPL was not distributed with this file, You can
** obtain one at http://mozilla.org/MPL/2.0/.
**
** github: https://github.com/libyuni/libyuni/
** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror)
*/
#include "grammar.h"
#include "../../io/file.h"



namespace Yuni
{
namespace Parser
{
namespace PEG
{

	namespace // anonymous
	{

		#include "yuni/private/parser/peg/__parser.include.cpp.hxx"



		class CPPConverter final
		{
		public:
			CPPConverter(const AnyString& root, const Node::Map& rules);
			bool initialize(const AnyString& name);
			void startHeaderheaderGuardID();
			void endHeaderheaderGuardID();
			void generateH();
			void generateHXX();
			void generateCPP();
			bool writeFiles() const;

		public:
			//! Original rules
			const Node::Map& rules;

			//! Code in the .h file
			Clob h;
			//! Code in the .hxx file
			Clob hxx;
			//! Code in the .cpp file
			Clob cpp;

			//! Header guard ID
			YString headerGuardID;
			//! Class name
			YString classname;
			//! Namespace
			YString::Vector namespaces;

			//! Root filename
			YString rootfilename;
			//! Local include
			YString localInclude;

		}; // class CPPConverter



		template<class YStringT>
		static inline void EnumIDToClassname(YStringT& out, const YString& enumID)
		{
			out = "Node";
			out << enumID;
			if (not enumID.empty())
				out[4] = (char) YString::ToUpper(out[4]);
		}


		inline CPPConverter::CPPConverter(const AnyString& root, const Node::Map& rules) :
			rules(rules),
			rootfilename(root)
		{
			IO::ExtractFileName(localInclude, root);
		}


		inline bool CPPConverter::initialize(const AnyString& name)
		{
			name.split(namespaces, "/\\:");
			return true;
		}


		inline void CPPConverter::generateH()
		{
			const Node::Map::const_iterator end = rules.end();

			h << "#pragma once\n";
			h << "#include <yuni/yuni.h>\n";
			h << "#include <yuni/core/string.h>\n";
			h << "#include <yuni/core/bind.h>\n";
			h << "#include <yuni/core/dictionary.h>\n";
			h << "#include <yuni/core/smartptr/intrusive.h>\n";
			h << "#include <initializer_list>\n";
			h << "\n\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';

			for (uint32_t i = 0; i != namespaces.size(); ++i)
				h << "namespace " << namespaces[i] << "\n{\n";
			h << '\n';
			h << "	enum Rule\n";
			h << "	{\n";
			h << "		//! Unknown rule\n";
			h << "		rgUnknown = 0,\n";
			uint32_t enumIndex = 1;
			for (Node::Map::const_iterator i = rules.begin(); i != end; ++i, ++enumIndex)
			{
				h << "		//! enum for the rule `" << i->first << '`';
				if (i->second.attributes.inlined)
					h << " [inline]";
				h << '\n';
				h << "		" << i->second.enumID << ", // = " << enumIndex << '\n';
			}
			h << "		//! enum for the final rule\n";
			h << "		rgEOF // " << (enumIndex++) << '\n';
			h << "	};\n";

			// rule count
			h << '\n';
			h << '\n';
			h << "	//! The total number of rules\n";
			h << "	constexpr const uint32_t ruleCount = " << enumIndex << ";\n";
			h << "\n\n\n";

			h << "	//! Convert a rule id into its text representation\n";
			h << "	YUNI_DECL AnyString ruleToString(enum Rule);\n";
			h << '\n';
			h << "	//! Get if a rule is an error\n";
			h << "	YUNI_DECL bool ruleIsError(enum Rule ruleid);\n";
			h << '\n';
			h << "	//! Get if the rule should be ignored when duplucating an AST (starting from 'tk-' and some special rules)\n";
			h << "	YUNI_DECL bool shouldIgnoreForDuplication(enum Rule);\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << "	enum class Error\n";
			h << "	{\n";
			h << "		//! No error\n";
			h << "		none,\n";
			h << "		//! Parse error\n";
			h << "		parse,\n";
			h << "	};\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';
			h << "	class YUNI_DECL Notification final\n";
			h << "	{\n";
			h << "	public:\n";
			h << "		//! Most suitable martptr\n";
			h << "		typedef Yuni::SmartPtr<Notification> Ptr;\n";
			h << "		//! Vector of nodes\n";
			h << "		typedef std::vector<Ptr> Vector;\n";
			h << '\n';
			h << "	public:\n";
			h << "		//! Start offset\n";
			h << "		uint32_t offset = 0;\n";
			h << "		//! Line Index\n";
			h << "		uint32_t line = 0;\n";
			h << "		//! Filename\n";
			h << "		YString message;\n";
			h << "		//! Filename\n";
			h << "		YString filename;\n";
			h << '\n';
			h << "	}; // class Notification\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';
			h << "	class YUNI_DECL Node;\n";
			h << '\n';
			h << '\n';
			h << "	class YUNI_DECL NodeVector final\n";
			h << "	{\n";
			h << "	public:\n";
			h << "		using T = Node;\n";
			h << '\n';
			h << "		struct Iterator final: public std::iterator<std::input_iterator_tag, T>\n";
			h << "		{\n";
			h << "			Iterator(T** array, uint32_t index) noexcept :m_array(array), m_index{index} {}\n";
			h << "			Iterator(const Iterator&) noexcept = default;\n";
			h << "			Iterator& operator++() noexcept { ++m_index; return *this; }\n";
			h << "			Iterator operator++(int) noexcept {Iterator tmp(*this); operator++(); return tmp;}\n";
			h << "			bool operator==(const Iterator& rhs) const noexcept { return rhs.m_index == m_index; };\n";
			h << "			bool operator!=(const Iterator& rhs) const noexcept { return rhs.m_index != m_index; };\n";
			h << "			T& operator * () noexcept { return *(m_array[m_index]); }\n";
			h << '\n';
			h << "		private:\n";
			h << "			T** const m_array;\n";
			h << "			uint32_t m_index = 0;\n";
			h << "			friend class NodeVector;\n";
			h << "		};\n";
			h << '\n';
			h << "		struct ConstIterator final: public std::iterator<std::input_iterator_tag, T>\n";
			h << "		{\n";
			h << "			ConstIterator(T** array, uint32_t index) noexcept :m_array(array), m_index{index} {}\n";
			h << "			ConstIterator(const ConstIterator&) noexcept = default;\n";
			h << "			ConstIterator& operator++() noexcept { ++m_index; return *this; }\n";
			h << "			ConstIterator operator++(int) noexcept {ConstIterator tmp(*this); operator++(); return tmp;}\n";
			h << "			bool operator==(const ConstIterator& rhs) const noexcept { return rhs.m_index == m_index; };\n";
			h << "			bool operator!=(const ConstIterator& rhs) const noexcept { return rhs.m_index != m_index; };\n";
			h << "			const T& operator * () const noexcept { return *(m_array[m_index]); }\n";
			h << '\n';
			h << "		private:\n";
			h << "			T** const m_array;\n";
			h << "			uint32_t m_index = 0;\n";
			h << "			friend class NodeVector;\n";
			h << "		};\n";
			h << '\n';
			h << "	public:\n";
			h << "		NodeVector() = default;\n";
			h << "		NodeVector(const NodeVector&) = delete;\n";
			h << "		NodeVector(NodeVector&&) = default;\n";
			h << "		~NodeVector();\n";
			h << '\n';
			h << "		Iterator begin() noexcept;\n";
			h << "		Iterator end() noexcept;\n";
			h << '\n';
			h << "		ConstIterator begin() const noexcept;\n";
			h << "		ConstIterator end() const noexcept;\n";
			h << '\n';
			h << "		ConstIterator cbegin() const noexcept;\n";
			h << "		ConstIterator cend() const noexcept;\n";
			h << '\n';
			h << "		void push_back(T* const element);\n";
			h << '\n';
			h << "		template<class U> void push_back(U& element);\n";
			h << '\n';
			h << "		void push_front(T* const element);\n";
			h << '\n';
			h << "		template<class U> void push_front(U& element);\n";
			h << '\n';
			h << "		//! Remove the last element\n";
			h << "		void pop_back() noexcept;\n";
			h << '\n';
			h << "		//! Empty the container\n";
			h << "		void clear() noexcept;\n";
			h << '\n';
			h << "		//! remove an element\n";
			h << "		void erase(uint32_t index) noexcept;\n";
			h << '\n';
			h << "		void erase(const Iterator& it) noexcept;\n";
			h << '\n';
			h << "		void erase(const ConstIterator& it) noexcept;\n";
			h << '\n';
			h << "		//! Resize the container to N elements\n";
			h << "		void resize(uint32_t count);\n";
			h << '\n';
			h << "		//! Get if the container is empty\n";
			h << "		bool empty() const noexcept;\n";
			h << '\n';
			h << "		//! Get the number of elements\n";
			h << "		uint32_t size() const noexcept;\n";
			h << '\n';
			h << "		//! Get the maximum number of elements before resizing\n";
			h << "		uint32_t capacity() const noexcept;\n";
			h << '\n';
			h << "		void shrink_to_fit() noexcept;\n";
			h << '\n';
			h << "		//! Retrieve the last element\n";
			h << "		T& back();\n";
			h << "		//! Retrieve the last element (const)\n";
			h << "		const T& back() const;\n";
			h << '\n';
			h << "		//! Retrive the first element\n";
			h << "		T& front();\n";
			h << "		//! Retrive the first element (const)\n";
			h << "		const T& front() const;\n";
			h << '\n';
			h << "		//! Retrieve the Nth element\n";
			h << "		T& operator [] (uint32_t i) noexcept;\n";
			h << "		//! Retrieve the Nth element (const)\n";
			h << "		const T& operator [] (uint32_t i) const noexcept;\n";
			h << "		//! Move operator\n";
			h << "		NodeVector& operator = (NodeVector&&) = default;\n";
			h << "		//! Copy operator\n";
			h << "		NodeVector& operator = (const NodeVector&);\n";
			h << '\n';
			h << '\n';
			h << "	private:\n";
			h << "		static void deleteElement(T* const ptr) noexcept;\n";
			h << "		void grow();\n";
			h << '\n';
			h << "	private:\n";
			h << "		static constexpr uint32_t preAllocatedCount = 2;\n";
			h << "		uint32_t m_size = 0;\n";
			h << "		uint32_t m_capacity = preAllocatedCount;\n";
			h << "		T** m_pointer = &(m_innerstorage[0]);\n";
			h << "		T* m_innerstorage[preAllocatedCount];\n";
			h << '\n';
			h << "		friend struct Iterator;\n";
			h << "	};\n";
			h << '\n';
			h << '\n';
			h << '\n';
			h << '\n';
			h << "	class YUNI_DECL Node final : public Yuni::IIntrusiveSmartPtr<Node, false, Yuni::Policy::SingleThreaded>\n";
			h << "	{\n";
			h << "	public:\n";
			h << "		//! Ancestor\n";
			h << "		typedef Yuni::IIntrusiveSmartPtr<Node, false, Yuni::Policy::SingleThreaded> inherited;\n";
			h << "		//! Threading policy\n";
			h << "		typedef inherited::ThreadingPolicy ThreadingPolicy;\n";
			h << "		//! The most suitable smart ptr for the class\n";
			h << "		typedef inherited::SmartPtrType<Node>::Ptr  Ptr;\n";
			h << "		//! Vector of nodes\n";
			h << "		typedef std::vector<Node::Ptr> Vector;\n";
			h << "		//! Set of symbols\n";
			h << "		typedef Yuni::Set<Ptr>::Unordered Set;\n";
			h << '\n';
			h << "		//! Callback definition for export a node\n";
			h << "		typedef void (* ExportCallback)(const Node& node, YString& tmp);\n";
			h << '\n';
			h << '\n';
			h << "	public:\n";
			h << "		//! Export the tree node\n";
			h << "		static void Export(Yuni::Clob& out, const Node& node);\n";
			h << "		//! Export the tree node (with color output)\n";
			h << "		static void Export(Yuni::Clob& out, const Node& node, bool color, ExportCallback callback = nullptr);\n";
			h << "		//! Export the tree node to HTML\n";
			h << "		static void ExportToHTML(Yuni::Clob& out, const Node& node);\n";
			h << '\n';
{'fraction_non_alphanumeric': 0.2170773535517646, 'fraction_numerical': 0.004693564401119235, 'mean_word_length': 2.5579640333975595, 'pattern_counts': {'":': 0, '<': 1007, '<?xml version=': 0, '>': 45, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7229900', 'n_tokens_mistral': 9852, 'n_tokens_neox': 8355, 'n_words': 2245}