Goose  Artifact [7725921ed0]

Artifact 7725921ed01da6752f5f0086bd8af9d0e5c24b6efcba694fc8b14d497a4133a5:

  • File bs/parse/parser.cpp — part of check-in [91eda406ef] at 2019-02-11 22:44:43 on branch trunk —
    • Resolver: implemented an utility function to gather blocks as lists of tokens without parsing them, for when we want to perform lazy parsing.
    • Parser: fixed some bugs with the current delimiter getting lost in nested parsers, which caused spurious misplaced end delimiter error messages.
    (user: achavasse size: 4837)


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

using namespace empathy;
using namespace empathy::parse;

Parser Parser::makeNestedParser()
{
    Parser p( m_resolver );
    p.m_introDelimiter = m_introDelimiter;
    return p;
}

optional< Value > Parser::parse( uint32_t precedence )
{
    auto next = m_resolver->lookAhead();
    if( !next )
        return nullopt;

    auto leftVal = parsePrefix( *next, precedence );
    if( !leftVal )
        return nullopt;

    push( leftVal );

    while( next = m_resolver->lookAhead() )
    {
        auto prec = getPrecedence( *next );
        if( !prec || precedence > *prec )
            return result();

        push( parseInfix( *next, *prec ) );
    }

    return result();
}

optional< Value > Parser::result() const
{
    if( !m_seq )
        return m_lastValue;

    if( m_seq && m_lastValue )
    {
        const auto& llr = m_lastValue->llr();
        m_seq->emplace_back( move( *llr ) );
        return Value( m_lastValue->type(), make_shared< llr::Element >( m_seq ) );
    }

    // If we don't have a pending value, we wrap it into a void type value
    // which is a sort of hackish way to encode a value that isn't really a value but have side effects.
    return Value( GetValueType< void >(), make_shared< llr::Element >( m_seq ) );
}

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

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

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

optional< Value > Parser::parsePrefix( uint64_t intlit, uint32_t )
{
    m_resolver->consume();
    return ToValue( intlit );
}

optional< Value > Parser::parsePrefix( const string& strlit, uint32_t )
{
    m_resolver->consume();
    return ToValue( strlit );
}

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

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

// 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 = lastValue();
    if( !leftVal )
        return nullopt;

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

    return nullopt;
}

optional< Value > Parser::parseInfix( const StringId& strid, uint32_t prec )
{
    const auto& leftVal = lastValue();
    if( !leftVal )
        return parsePrefix( strid, prec );

    if( leftVal->type() == TSID( type ) )
    {
        auto nameTerm = m_resolver->consume();
        const auto* name = get_if< StringId >( &nameTerm->content() );
        auto type = ValueToIRExpr( *pop() );

        return ToValue( builtins::Decl( move( type ), *name ) );
    }

    return parsePrefix( strid, prec );
}

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

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

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

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

optional< Value > Parser::parsePrefix( const pvec& vec, uint32_t prec )
{
    auto t = *m_resolver->consume();

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

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

    if( !rule->isPrefix() )
        return val;

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

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

    auto val = ValueFromIRExpr( t );
    if( !val )
        return makeNestedParser().parse( prec );

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

    m_resolver->consume();

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

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