Syntax tree - Visitors
Syntax trees can return a pre-configured visitor object that can be used to visit all the nodes. Also added a method to create a "root node" handle for the visitor, because I'm a lazy bastard.
This commit is contained in:
parent
a9762a901e
commit
b659f2f237
3 changed files with 159 additions and 1 deletions
|
@ -6,6 +6,7 @@
|
||||||
#define _H_EBCL_SYNTAXTREE
|
#define _H_EBCL_SYNTAXTREE
|
||||||
#include <ebcl/Types.hh>
|
#include <ebcl/Types.hh>
|
||||||
#include <ebcl/Arrays.hh>
|
#include <ebcl/Arrays.hh>
|
||||||
|
#include <ebcl/Algorithms.hh>
|
||||||
namespace ebcl {
|
namespace ebcl {
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,11 +30,29 @@ template<
|
||||||
public:
|
public:
|
||||||
using E_Node = NodeType;
|
using E_Node = NodeType;
|
||||||
using T_Self = T_SyntaxTree< NodeType , InPlaceSize >;
|
using T_Self = T_SyntaxTree< NodeType , InPlaceSize >;
|
||||||
|
|
||||||
static constexpr size_t StorageSize
|
static constexpr size_t StorageSize
|
||||||
= T_VariantExt< InPlaceSize >::StorageSize;
|
= T_VariantExt< InPlaceSize >::StorageSize;
|
||||||
|
|
||||||
private:
|
// A node, as seen from a visitor
|
||||||
|
struct T_Node
|
||||||
|
{
|
||||||
|
T_Self const& tree;
|
||||||
|
uint32_t node;
|
||||||
|
|
||||||
|
T_Node( ) = delete;
|
||||||
|
T_Node( T_Self const& tree , uint32_t node ) noexcept;
|
||||||
|
T_Node( T_Node const& other ) noexcept;
|
||||||
|
T_Node( T_Node&& other ) noexcept;
|
||||||
|
T_Node& operator =( T_Node const& other ) noexcept;
|
||||||
|
T_Node& operator =( T_Node&& other ) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Visitor type. "References" are actually values.
|
||||||
|
using T_Visitor = ::ebcl::T_Visitor< T_Node , T_Node >;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Internal storage for nodes
|
||||||
struct T_Node_
|
struct T_Node_
|
||||||
{
|
{
|
||||||
// Node type
|
// Node type
|
||||||
|
@ -108,6 +127,14 @@ template<
|
||||||
// Access the data stored inside a node
|
// Access the data stored inside a node
|
||||||
template< typename D >
|
template< typename D >
|
||||||
D& dataOf( uint32_t node );
|
D& dataOf( uint32_t node );
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Return a visitor suitable for this syntax tree
|
||||||
|
T_Visitor visitor( ) const noexcept;
|
||||||
|
|
||||||
|
// Return the root node in a format that can be fed to a visitor
|
||||||
|
T_Node root( ) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
template< typename T , size_t S >
|
template< typename T , size_t S >
|
||||||
|
|
|
@ -10,6 +10,51 @@ namespace ebcl {
|
||||||
|
|
||||||
/*= T_SyntaxTree =============================================================*/
|
/*= T_SyntaxTree =============================================================*/
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >::T_Node::T_Node(
|
||||||
|
T_Self const& tree ,
|
||||||
|
const uint32_t node ) noexcept
|
||||||
|
: tree{ tree } , node{ node }
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >::T_Node::T_Node(
|
||||||
|
T_Node const& other ) noexcept
|
||||||
|
: tree{ other.tree } , node{ other.node }
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >::T_Node::T_Node(
|
||||||
|
T_Node&& other ) noexcept
|
||||||
|
: T_Node( other )
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
typename T_SyntaxTree< T , S >::T_Node& T_SyntaxTree< T , S >::T_Node::operator =(
|
||||||
|
T_SyntaxTree< T , S >::T_Node const& other ) noexcept
|
||||||
|
{
|
||||||
|
assert( &other.tree == &tree );
|
||||||
|
node = other.node;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
typename T_SyntaxTree< T , S >::T_Node& T_SyntaxTree< T , S >::T_Node::operator =(
|
||||||
|
T_SyntaxTree< T , S >::T_Node&& other ) noexcept
|
||||||
|
{
|
||||||
|
assert( &other.tree == &tree );
|
||||||
|
node = other.node;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
template< typename T , size_t S >
|
template< typename T , size_t S >
|
||||||
T_SyntaxTree< T , S >::T_Node_::T_Node_(
|
T_SyntaxTree< T , S >::T_Node_::T_Node_(
|
||||||
const T nodeType ,
|
const T nodeType ,
|
||||||
|
@ -157,6 +202,28 @@ D& T_SyntaxTree< T , S >::dataOf(
|
||||||
return nodes_[ node ].data.template value< D >( );
|
return nodes_[ node ].data.template value< D >( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
typename T_SyntaxTree< T , S >::T_Visitor T_SyntaxTree< T , S >::visitor( ) const noexcept
|
||||||
|
{
|
||||||
|
return T_Visitor{
|
||||||
|
[this]( T_Node node , uint32_t child ) -> T_Optional< T_Node > {
|
||||||
|
auto const& n{ nodes_[ node.node ] };
|
||||||
|
if ( child >= n.children.size( ) ) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return T_Node{ node.tree , n.children[ child ] };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
typename T_SyntaxTree< T , S >::T_Node T_SyntaxTree< T , S >::root( ) const noexcept
|
||||||
|
{
|
||||||
|
return T_Node{ *this , 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
#endif // _H_EBCL_INLINE_SYNTAXTREE
|
#endif // _H_EBCL_INLINE_SYNTAXTREE
|
||||||
|
|
|
@ -9,6 +9,7 @@ class SyntaxTreeTest : public CppUnit::TestFixture
|
||||||
CPPUNIT_TEST( testSetData );
|
CPPUNIT_TEST( testSetData );
|
||||||
CPPUNIT_TEST( testUpdateData );
|
CPPUNIT_TEST( testUpdateData );
|
||||||
CPPUNIT_TEST( testAddChildren );
|
CPPUNIT_TEST( testAddChildren );
|
||||||
|
CPPUNIT_TEST( testVisit );
|
||||||
CPPUNIT_TEST_SUITE_END( );
|
CPPUNIT_TEST_SUITE_END( );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -16,6 +17,7 @@ public:
|
||||||
void testSetData( );
|
void testSetData( );
|
||||||
void testUpdateData( );
|
void testUpdateData( );
|
||||||
void testAddChildren( );
|
void testAddChildren( );
|
||||||
|
void testVisit( );
|
||||||
};
|
};
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION( SyntaxTreeTest );
|
CPPUNIT_TEST_SUITE_REGISTRATION( SyntaxTreeTest );
|
||||||
|
|
||||||
|
@ -75,3 +77,65 @@ void SyntaxTreeTest::testAddChildren( )
|
||||||
CPPUNIT_ASSERT_EQUAL( cc , st.childrenOf( rc )[ 0 ] );
|
CPPUNIT_ASSERT_EQUAL( cc , st.childrenOf( rc )[ 0 ] );
|
||||||
CPPUNIT_ASSERT( E_TestNode_::VALUE == st.typeOf( cc ) );
|
CPPUNIT_ASSERT( E_TestNode_::VALUE == st.typeOf( cc ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyntaxTreeTest::testVisit( )
|
||||||
|
{
|
||||||
|
T_Test_ st{ E_TestNode_::ROOT };
|
||||||
|
const uint32_t c0{ st.addChild( 0 , E_TestNode_::ADD ) };
|
||||||
|
const uint32_t c1{ st.addChild( c0 , E_TestNode_::VALUE ) };
|
||||||
|
const uint32_t c2{ st.addChild( c0 , E_TestNode_::VALUE ) };
|
||||||
|
st.newData< uint32_t >( c1 , 12u );
|
||||||
|
st.newData< uint32_t >( c2 , 42u );
|
||||||
|
|
||||||
|
using T_Result_ = std::tuple< bool , uint32_t , T_Optional< uint32_t > >;
|
||||||
|
T_Array< T_Result_ > visitData;
|
||||||
|
st.visitor( ).visit( st.root( ) ,
|
||||||
|
[&visitData]( T_Test_::T_Node node , bool after ) {
|
||||||
|
//fprintf( stderr , "NODE %d (%c)\n" , node.node , after ? 'O' : 'I' );
|
||||||
|
visitData.add( std::make_tuple( !after , node.node ,
|
||||||
|
node.tree.hasData( node.node )
|
||||||
|
? T_Optional< uint32_t >( node.tree.dataOf< uint32_t >( node.node ) )
|
||||||
|
: T_Optional< uint32_t >() ) );
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
|
||||||
|
// ROOT <-- ADD <-- VALUE{12}
|
||||||
|
// <-- VALUE{42}
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 8u , visitData.size( ) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT( std::get< 0 >( visitData[ 0 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 0u , std::get< 1 >( visitData[ 0 ] ) );
|
||||||
|
CPPUNIT_ASSERT( !std::get< 2 >( visitData[ 0 ] ) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT( std::get< 0 >( visitData[ 1 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( c0 , std::get< 1 >( visitData[ 1 ] ) );
|
||||||
|
CPPUNIT_ASSERT( !std::get< 2 >( visitData[ 1 ] ) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT( std::get< 0 >( visitData[ 2 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( c1 , std::get< 1 >( visitData[ 2 ] ) );
|
||||||
|
CPPUNIT_ASSERT( std::get< 2 >( visitData[ 2 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 12u , *std::get< 2 >( visitData[ 2 ] ) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT( !std::get< 0 >( visitData[ 3 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( c1 , std::get< 1 >( visitData[ 3 ] ) );
|
||||||
|
CPPUNIT_ASSERT( std::get< 2 >( visitData[ 3 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 12u , *std::get< 2 >( visitData[ 3 ] ) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT( std::get< 0 >( visitData[ 4 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( c2 , std::get< 1 >( visitData[ 4 ] ) );
|
||||||
|
CPPUNIT_ASSERT( std::get< 2 >( visitData[ 4 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 42u , *std::get< 2 >( visitData[ 4 ] ) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT( !std::get< 0 >( visitData[ 5 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( c2 , std::get< 1 >( visitData[ 5 ] ) );
|
||||||
|
CPPUNIT_ASSERT( std::get< 2 >( visitData[ 5 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 42u , *std::get< 2 >( visitData[ 5 ] ) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT( !std::get< 0 >( visitData[ 6 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( c0 , std::get< 1 >( visitData[ 6 ] ) );
|
||||||
|
CPPUNIT_ASSERT( !std::get< 2 >( visitData[ 6 ] ) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT( !std::get< 0 >( visitData[ 7 ] ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 0u , std::get< 1 >( visitData[ 7 ] ) );
|
||||||
|
CPPUNIT_ASSERT( !std::get< 2 >( visitData[ 6 ] ) );
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue