Goose  Artifact [e2f16d7246]

Artifact e2f16d724613713dbb4348803735d11b8a6614aca57a26b010de6cdf99935f9f:

  • File bs/eir/match.h — part of check-in [a4f1ada98c] at 2021-09-15 21:24:51 on branch trunk —
    • VecOfLength() will now match vectors of compatible length, taking repetition terms into account
    • Vector unification and typechecking rules now handle vectors of variable lengths
    (user: achavasse size: 3562)

#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( 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( 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 ) )
                        {
                            if constexpr( is_same_v< TT, VecLength > )
                            {
                                if( !AreVecLengthsCompatible( *pExistingVal, val ) )
                                    return false;

                                it->second = VecLength(
                                    max( pExistingVal->minLength(), val.minLength() ),
                                    pExistingVal->isVariable() && val.isVariable()
                                );

                                return true;
                            }
                            else
                            {
                                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