Goose  Artifact [0b7478edb4]

Artifact 0b7478edb483be87b00866ad305ab377f39fcb927159772bb302d90cc466a4e5:

  • File bs/parse/resolver.cpp — 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: 5295)

#include "parse.h"

using namespace goose;
using namespace goose::parse;

bool Resolver::eos() const
{
    clearCacheIfNeeded();
    return m_tokProvider->eos() && m_lookAheadCache.empty();
}

optional< TermLoc > Resolver::consume()
{
    clearCacheIfNeeded();

    auto tok = m_tokProvider->consume();

    if( m_lookAheadCache.empty() )
    {
        if( !tok )
            return nullopt;
        return resolve( *tok );
    }

    auto t = move( m_lookAheadCache.front() );
    m_lookAheadCache.pop_front();
    return t;
}

optional< TermLoc > Resolver::consumeUnresolved()
{
    clearCacheIfNeeded();

    if( !m_lookAheadCache.empty() )
        m_lookAheadCache.pop_front();

    return m_tokProvider->consume();
}

optional< TermLoc > Resolver::lookAhead( size_t distance )
{
    clearCacheIfNeeded();
    size_t i = 0;

    while( m_lookAheadCache.size() < ( distance + 1 ) )
    {
        auto tok = m_tokProvider->lookAhead( i++ );
        if( !tok )
            return nullopt;

        m_lookAheadCache.emplace_back( resolve( *tok ) );
    }

    return m_lookAheadCache[distance];
}

optional< TermLoc > Resolver::lookAheadUnresolved( size_t distance )
{
    return m_tokProvider->lookAhead( distance );
}

void Resolver::clearLookAheadCache() const
{
    m_lookAheadCache.clear();
    m_valueStoreVersion = m_context.env()->valueStoreVersion();
}

TermLoc Resolver::resolve( const TermLoc& t ) const
{
    auto identifier = Decompose( t.first, Val< StringId >() );
    if( !identifier )
        return t;

    Term result;

    DiagnosticsContext dc( t.second, "Referenced here." );

    auto valId = AppendToVectorTerm( m_context.identity(), t.first );
    switch( m_context.env()->retrieveValue( valId, m_context.identity(), result ) )
    {
        case sema::Env::Status::NoMatch:
            return t;

        case sema::Env::Status::AmbiguousMatch:
            DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                t.second, "ambiguous match for symbol.", 0 );
            return t;

        default:
            break;
    }

    return TermLoc( result, t.second );
}

Generator< TermLoc > Resolver::consumeUnit()
{
    auto tok = consumeUnresolved();
    if( !tok )
        co_return;

    const auto* delim = get_if< Delimiter >( &tok->first );
    if( !delim )
    {
        co_yield move( *tok );
        co_return;
    }

    switch( *delim )
    {
        case Delimiter::OpenParen:
            co_yield move( *tok );
            co_yield consumeBlock( Delimiter::CloseParen );
            break;

        case Delimiter::OpenBrace:
            co_yield move( *tok );
            co_yield consumeBlock( Delimiter::CloseBrace );
            break;

        case Delimiter::OpenBracket:
            co_yield move( *tok );
            co_yield consumeBlock( Delimiter::CloseBracket );
            break;

        case Delimiter::CloseParen:
            DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                tok->second, "mismatched ')'.", 0 );
            break;

        case Delimiter::CloseBrace:
            DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                tok->second, "mismatched '}'.", 0 );
            break;

        case Delimiter::CloseBracket:
            DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                tok->second, "mismatched ']'.", 0 );
            break;

        default:
            co_yield move( *tok );
            break;
    }
}

Generator< TermLoc > Resolver::consumeBlock( Delimiter end )
{
    while( const auto& tok = lookAheadUnresolved() )
    {
        const auto* delim = get_if< Delimiter >( &tok->first );
        if( delim )
        {
            if( *delim == end )
            {
                co_yield *consumeUnresolved();
                co_return;
            }
            else
            {
                switch( *delim )
                {
                    case Delimiter::CloseParen:
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                            tok->second, "mismatched ')'.", 0 );
                        co_return;

                    case Delimiter::CloseBrace:
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                            tok->second, "mismatched '}'.", 0 );
                        co_return;

                    case Delimiter::CloseBracket:
                        DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                            tok->second, "mismatched ']'.", 0 );
                        co_return;

                    default:
                        break;
                }
            }
        }

        co_yield consumeUnit();
    }

    switch( end )
    {
        case Delimiter::CloseParen:
            DiagnosticsManager::GetInstance().emitLexerErrorMessage( currentLocation(), "missing ')'." );
            break;

        case Delimiter::CloseBrace:
            DiagnosticsManager::GetInstance().emitLexerErrorMessage( currentLocation(), "missing '}'." );
            break;

        case Delimiter::CloseBracket:
            DiagnosticsManager::GetInstance().emitLexerErrorMessage( currentLocation(), "missing ']'." );
            break;

        default:
            break;
    }
}