#ifndef GOOSE_EIR_MATCH_H
#define GOOSE_EIR_MATCH_H
namespace goose::eir
{
struct MatchScore
{
size_t m_complexity = 0;
size_t m_numVars = 0;
bool operator<( const MatchScore& rhs ) const
{
if( m_complexity != rhs.m_complexity )
return m_complexity < rhs.m_complexity;
return m_numVars > rhs.m_numVars;
}
bool operator>( const MatchScore& rhs ) const
{
if( m_complexity != rhs.m_complexity )
return m_complexity > rhs.m_complexity;
return m_numVars < rhs.m_numVars;
}
};
class MatchSolution
{
public:
size_t complexity() const { return m_complexity; }
size_t numVars() const;
MatchScore score() const { return MatchScore{ m_complexity, m_pVars ? m_pVars->size() : 0 }; }
template< typename T >
const T* getVar( const StringId& name ) const
{
if( name == "_"_sid )
return nullptr;
if( !m_pVars )
return nullptr;
auto it = m_pVars->find( name );
if( it == m_pVars->end() )
return nullptr;
return any_cast< T >( &it->second );
}
// Tries to set the variable. If it already exists but have a different
// value, returns false.
template< typename T >
bool setVar( const StringId& name, T&& val )
{
if( name == "_"_sid )
return true;
if( m_pVars )
{
auto it = m_pVars->find( name );
if( it != m_pVars->end() )
{
using TT = remove_cvref_t< T >;
if( const auto* pExistingVal = any_cast< TT >( &it->second ) )
return *pExistingVal == val;
return false;
}
}
setupVars();
m_pVars->emplace( name, forward< T >( val ) );
return true;
}
void addComplexity( uint32_t n ) { m_complexity += n; }
private:
void setupVars();
ptr< unordered_map< StringId, any > > m_pVars;
uint32_t m_complexity = 0; // Each matched structural element of the pattern (vector) adds 1,
// each matched literal element of the pattern adds 2
};
extern optional< MatchSolution > Match( const Term& expression, const Term& pattern );
template< typename U >
static Generator< pair< MatchSolution, const U& > > Match( const Term& expression, const Trie< U >& patterns );
}
#endif