Goose  Artifact [65f703a037]

Artifact 65f703a03756b7f40fcbad48152595d786ff8b140f420c2b6debce26717cac4a:

  • File bs/parse/parser.cpp — part of check-in [5aab57179e] at 2019-01-22 22:46:29 on branch trunk — Builtins: implemented the comma operator. (user: achavasse size: 3957)


#include "parse.h"

using namespace empathy;
using namespace empathy::parse;

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

    auto leftVal = parsePrefix( *m_resolver->consume(), precedence );
    if( !leftVal )
        return nullopt;

    push( leftVal );

    while( next = m_resolver->lookAhead() )
    {
        auto prec = getPrecedence( *next );
        if( !prec || precedence > *prec )
        {
            // If we're at precedence = 0 (ie the top level),
            // and the parsing rules haven't consumed all of the input,
            // it means that someting unparseable was encountered.
            if( precedence == 0 )
            {
                // TODO proper error management, poisoning etc.
                cout << "parse error\n";
            }

            return result();
        }

        push( *parseInfix( *m_resolver->consume(), *prec ) );
    }

    return result();
}

optional< ir::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(), m_seq );
    }

    return nullopt;
}

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

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

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

optional< ir::Value > Parser::parsePrefix( const Term&, uint64_t intlit, uint32_t )
{
    static auto type = ValueToIRExpr( Value( TSID( type ), TSID( integer_literal ) ) );
    return ir::Value( type, TERM( intlit ) );
}

optional< ir::Value > Parser::parsePrefix( const Term&, const string& strlit, uint32_t )
{
    static auto type = ValueToIRExpr( Value( TSID( type ), TSID( string_literal ) ) );
    return ir::Value( type, TERM( strlit ) );
}

// Standalone (ie not part of a grammar construct that expects them such as a decl), unresolved identifiers
// end up here.
optional< ir::Value > Parser::parsePrefix( const Term&, const StringId& strid, uint32_t )
{
    // TODO location, poisoning
    cout << "undefined identifier '" << strid.c_str() << "'\n";
    return nullopt;
}

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 = RuleFromValue( *val );
    if( !rule )
        return nullopt;

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

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

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

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

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

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

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

    // If the term is an infix rule value, invoke its parseInfix() function.
    auto rule = RuleFromValue( *val );
    if( !rule )
        return nullopt;

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

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