#include "ir.h"
namespace empathy::ir
{
size_t MatchSolution::numVars() const
{
if( !m_pVars )
return 0;
return m_pVars->size();
}
void MatchSolution::setupVars()
{
if( !m_pVars )
m_pVars = make_shared< unordered_map< StringId, any > >();
else if( m_pVars.use_count() > 1 )
m_pVars = make_shared< unordered_map< StringId, any > >( *m_pVars );
}
Generator< MatchSolution > Match( const Term& expression, const Trie<>& patterns )
{
for( auto&& [s,p] : Match<>( expression, patterns ) )
co_yield move( s );
}
optional< MatchSolution > Match( MatchSolution&& currentSolution, const Term& expression, const Term& pattern );
//--------------------------------------------------------------------------------------------
// AnyTerm
//--------------------------------------------------------------------------------------------
optional< MatchSolution > MatchAnyTerm( MatchSolution&& currentSolution, const Term& expression, const AnyTerm& pattern )
{
if( currentSolution.setVar( pattern.varName(), expression ) )
return move( currentSolution );
return nullopt;
}
//--------------------------------------------------------------------------------------------
// VecOfLength
//--------------------------------------------------------------------------------------------
optional< MatchSolution > MatchVecOfLength( MatchSolution&& currentSolution, const Term& expression, const VecOfLength& pattern )
{
if( !holds_alternative< pvec >( expression.content() ) )
return nullopt;
// When a repetition appears in the expression vector, consider it to be an extra element at the end.
const auto& vec = *get< pvec >( expression.content() );
const auto exprLength = vec.length();
size_t exprSize = exprLength.minLength();
if( exprLength.isVariable() )
++exprSize;
if( currentSolution.setVar( pattern.varName(), exprSize ) )
{
currentSolution.incComplexity();
return move( currentSolution );
}
return nullopt;
}
//--------------------------------------------------------------------------------------------
// Vec
//--------------------------------------------------------------------------------------------
optional< MatchSolution > MatchVec( MatchSolution&& currentSolution, const Term& expression, const pvec& pattern )
{
if( !holds_alternative< pvec >( expression.content() ) )
return nullopt;
// When a repetition appears in the expression vector, consider it to be an extra element at the end.
const auto& vec = *get< pvec >( expression.content() );
const auto exprLength = vec.length();
const auto patLength = pattern->length();
size_t exprSize = exprLength.minLength();
if( exprLength.isVariable() )
++exprSize;
if( exprSize < patLength.minLength() )
return nullopt;
if( !patLength.isVariable() && patLength.minLength() < exprSize )
return nullopt;
auto gen = vec.ForEachTerm();
auto it = gen.begin();
auto curSolution = move( currentSolution );
for( auto&& pat : pattern->terms() )
{
assert( it != gen.end() );
auto sol = Match( move( curSolution ), *it, pat );
if( !sol )
return nullopt;
curSolution = move( *sol );
++it;
}
assert( it == gen.end() || pattern->repetitionTerm() );
while( it != gen.end() )
{
auto sol = Match( move( curSolution ), *it, *pattern->repetitionTerm() );
if( !sol )
return nullopt;
curSolution = move( *sol );
++it;
}
curSolution.incComplexity();
return move( curSolution );
}
//--------------------------------------------------------------------------------------------
// Value
//--------------------------------------------------------------------------------------------
template< typename T >
optional< MatchSolution > MatchValue( MatchSolution&& currentSolution, const Term& expression, const T& pattern )
{
using TT = remove_constref_t< decltype( pattern ) >;
const auto* pVal = get_if< TT >( &expression.content() );
if( pVal && *pVal == pattern )
return move( currentSolution );
return nullopt;
}
//--------------------------------------------------------------------------------------------
// Terms
//--------------------------------------------------------------------------------------------
optional< MatchSolution > Match( MatchSolution&& currentSolution, const Term& expression, const Term& pattern )
{
return visit( [&]( auto&& t )
{
using T = remove_constref_t< decltype( t ) >;
if constexpr( is_same_v< T, AnyTerm > )
return MatchAnyTerm( move( currentSolution ), expression, t );
else if constexpr( is_same_v< T, VecOfLength > )
return MatchVecOfLength( move( currentSolution ), expression, t );
else if constexpr( is_same_v< T, pvec > )
return MatchVec( move( currentSolution ), expression, t );
else
return MatchValue( move( currentSolution ), expression, t );
}, pattern.content() );
}
optional< MatchSolution > Match( const Term& expression, const Term& pattern )
{
return Match( MatchSolution(), expression, pattern );
}
}