
#include "parse.h"
#include "builtins/builtins.h"

using namespace empathy;
using namespace empathy::parse;
using namespace empathy::builtins;

Parser* Parser::ms_pCurrentParser = nullptr;

Parser Parser::makeNestedParser()
{
    Parser p( m_resolver );
    p.m_introDelimiter = m_introDelimiter;
    p.setCFG( cfg() );
    p.setCurrentBB( currentBB() );
    return p;
}

void Parser::parseSequence()
{
    while( parseExpression( 0 ) )
        m_resolver->consumeNewLines();

    flushValue();
}

bool Parser::parseExpression( uint32_t precedence )
{
    auto next = m_resolver->lookAhead();
    if( !next )
        return false;

    if( !parsePrefix( *next, precedence ) )
        return false;

    parsePostfixExpression( precedence );
    return true;
}

void Parser::parsePostfixExpression( uint32_t precedence )
{
    while( auto next = m_resolver->lookAhead() )
    {
        auto prec = getPrecedence( *next );
        if( !prec || precedence > *prec )
            break;

        if( !parseInfix( *next, *prec ) )
            break;
    }
}

void Parser::flushValue()
{
    // Flush the pending value's llr as a standalone instruction,
    // if any. If it is a constant, complain about discarding it.
    if( !m_lastValue )
        return;

    if( m_lastValue->isConstant() )
        return;

    assert( m_currentBB );

    auto llr = move( *m_lastValue->llr() );
    m_lastValue = nullopt;
    emitInstruction( move( llr ) );
}

optional< uint32_t > Parser::getPrecedence( const Term& t )
{
    return visit( [&]( auto&& content )
    {
        return getPrecedence( t, content );
    }, t );
}

bool Parser::parsePrefix( const Term& t, uint32_t precedence )
{
    return visit( [&]( auto&& content )
    {
        return parsePrefix( content, precedence );
    }, t );
}

bool Parser::parseInfix( const Term& t, uint32_t precedence )
{
    return visit( [&]( auto&& content )
    {
        return parseInfix( content, precedence );
    }, t );
}

bool Parser::parsePrefix( const BigInt& intlit, uint32_t )
{
    m_resolver->consume();
    pushValue( ToValue( intlit ) );
    return true;
}

bool Parser::parsePrefix( const string& strlit, uint32_t )
{
    m_resolver->consume();
    pushValue( ToValue( strlit ) );
    return true;
}

// Standalone (ie not part of a grammar construct that expects them such as a decl), unresolved identifiers
// end up here.
bool Parser::parsePrefix( const StringId& strid, uint32_t )
{
    m_resolver->consume();

    // TODO location, poisoning
    cout << "undefined identifier '" << strid.c_str() << "'\n";
    return false;
}

// Infix identifiers: if the left value is a type, then we have a decl.
optional< uint32_t > Parser::getPrecedence( const Term&, const StringId& strid )
{
    const auto& leftVal = peekLastValue();
    if( !leftVal )
        return nullopt;

    // If leftVal is a type, this is a decl, so set the precedence to Application.
    if( leftVal->isType() || IsTExpr( *leftVal ) )
        return precedence::Application;

    return nullopt;
}

bool Parser::parseInfix( const StringId& strid, uint32_t prec )
{
    const auto& leftVal = peekLastValue();
    if( !leftVal )
        return parsePrefix( strid, prec );

    auto nameTerm = m_resolver->consume();
    const auto* name = get_if< StringId >( &nameTerm.value() );

    if( IsTExpr( *leftVal ) )
    {
        auto texpr = ValueToIRExpr( *popValue() );
        pushValue( ToValue( TNamedDecl( move( texpr ), *name ) ) );
        return true;
    }
    else if( leftVal->isType() )
    {
        auto type = ValueToIRExpr( *popValue() );
        pushValue( ToValue( Decl( move( type ), *name ) ) );
        return true;
    }

    return parsePrefix( strid, prec );
}

bool Parser::parsePrefix( const pvec& vec, uint32_t prec )
{
    auto t = *m_resolver->lookAhead();

    auto val = ValueFromIRExpr( t );
    if( !val )
        return false;

    // If the term is a prefix rule value, invoke its parsePrefix() function.
    auto rule = FromValue< Rule >( *val );
    if( !rule )
    {
        m_resolver->consume();
        pushValue( *val );
        return true;
    }

    if( !( *rule )->isPrefix() )
        return false;

    m_resolver->consume();
    return ( *rule )->parsePrefix( *this, t, prec );
}

optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
    auto val = ValueFromIRExpr( t );
    if( !val )
        return nullopt;

    if( val->type() == GetValueType< ptr< OverloadSet > >() )
    {
        if( !peekLastValue() )
            return nullopt;

        if( !peekLastValue()->isType() && !IsTExpr( *peekLastValue() ) )
            return nullopt;

        return getInfixOverloadSetPrecedence();
    }

    // If the term is an infix rule value, invoke its getPrecedence() function.
    auto rule = FromValue< Rule >( *val );
    if( !rule )
        return nullopt;

    if( !( *rule )->isInfix() )
        return nullopt;

    return ( *rule )->getPrecedence( *this, t );
}

bool Parser::parseInfix( const pvec& vec, uint32_t prec )
{
    auto t = *m_resolver->lookAhead();

    auto val = ValueFromIRExpr( t );
    if( !val )
        return false;

    if( val->type() == GetValueType< ptr< OverloadSet > >() )
        return parseInfixOverloadSet( *FromValue< ptr< OverloadSet > >( *val ), prec );

    // If the term is an infix rule value, invoke its parseInfix() function.
    auto rule = FromValue< Rule >( *val );
    if( !rule )
        return false;

    m_resolver->consume();

    if( !( *rule )->isInfix() )
        return false;

    return ( *rule )->parseInfix( *this, t, prec );
}
