#include "parse.h"
#include "builtins/builtins.h"
using namespace goose;
using namespace goose::parse;
using namespace goose::builtins;
Parser Parser::makeNestedParser()
{
Parser p( m_resolver );
p.m_introDelimiter = m_introDelimiter;
return p;
}
Parser Parser::makeNestedParser( Delimiter introDelimiter )
{
Parser p( m_resolver, introDelimiter );
return p;
}
// Parse a sequence of expression. Each expression is
// a statement.
void Parser::parseSequence()
{
for(;;)
{
CodeBuilder::LifetimeScopeGuard lsg( context() );
{
// Each statement gets its own visibility scope,
// so that vars defined inside of the statement are only
// visible from within it.
// However, they also have a lifetime scope, which
// is separate because we need to flush the value
// generated by the statement before destroying any
// temporary that it may depend on.
// However, the visibility rule must end before that
// since local variable declarations (which must remain
// visible for following statements) are made visible
// when the decl or localvar is flushed.
VisibilityScope vs( *this );
if( !parseExpression( 0 ) )
break;
}
flushValue();
}
flushValue();
}
bool Parser::parseExpression( uint32_t precedence )
{
auto next = m_resolver->lookAhead();
if( !next )
return false;
if( !parsePrefix( next->first, precedence ) )
return false;
parsePostfixExpression( precedence );
return true;
}
void Parser::parsePostfixExpression( uint32_t precedence )
{
while( auto next = m_resolver->lookAhead() )
{
auto prec = getPrecedence( next->first );
if( !prec || precedence > *prec )
break;
if( !parseInfix( next->first, *prec ) )
break;
}
}
void Parser::flushValue()
{
const auto& cb = context().codeBuilder();
if( m_lastValue && cb && cb->cfg() && ( !cb->cfg()->currentBB() || cb->cfg()->currentBB()->terminator() ) )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
m_lastValue->locationId(), "unreachable code.", 0 );
}
// Flush the pending value, by invoking the DropValue
// extension point, where an overload will decide
// of the value's fate (or possibly emit an error
// if that value wasn't allowed to be discarded).
while( m_lastValue )
{
auto val = move( *m_lastValue );
m_lastValue = nullopt;
if( val.isPoison() )
return;
DiagnosticsContext dc( val.locationId(), "When invoking DropValue." );
InvokeOverloadSet( context(), context().env()->extDropValue(),
MakeTuple( val ) );
}
}
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 )
{
auto tok = m_resolver->consume();
pushValue( ToValue( intlit ).setLocationId( tok->second ) );
return true;
}
bool Parser::parsePrefix( uint32_t charlit, uint32_t )
{
auto tok = m_resolver->consume();
pushValue( ToValue( static_cast< char32_t >( charlit ) ).setLocationId( tok->second ) );
return true;
}
bool Parser::parsePrefix( const string& strlit, uint32_t )
{
auto tok = m_resolver->consume();
pushValue( ToValue( strlit ).setLocationId( tok->second ) );
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 )
{
auto tok = m_resolver->consume();
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( tok->second,
"undefined identifier.", 0 );
return true;
}
// 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( IsType( *leftVal ) || IsTExpr( *leftVal ) )
{
// If it is a regular decl (such a function parameters and variable declarations),
// it have the very high "Application" precedence.
// However, if the identifier is followed by a parent block,
// this is a function declaration, and it gets the "FuncDecl" precedence, which
// is set to be lower than the comma operator.
//
// The reason for this is that while we want to construct tuples of about anything just
// by separating things with commas (not only to build function parameters and function arguments
// but also for multiple return values and multiple variable declarations), we also
// want to be able to use a tuple of those things as the return type for a function,
// so the construction of the tuple (the comma oeprator) needs a higher precedence than
// the function declaration. In other words, we don't want the last type of a tuple of type to
// become the return type of a function subsequently added to the tuple.
auto next = m_resolver->lookAheadUnresolved( 1 );
if( !next )
return precedence::Application;
auto decomp = Decompose( next->first, Val< Delimiter >() );
if( !decomp || *decomp != Delimiter::OpenParen )
return precedence::Application;
return precedence::FuncDecl;
}
return nullopt;
}
// An unbound infix identifier
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->first );
// If the identifier is preceded by a TExpr or a Type,
// then this becomes a TDecl or a Decl, respectively.
if( IsTExpr( *leftVal ) )
{
auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );
auto texpr = ValueToIRExpr( *popType() );
pushValue( ToValue( TNamedDecl( move( texpr ), *name ) ).setLocationId( loc ) );
return true;
}
else if( IsType( *leftVal ) )
{
auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );
auto type = ValueToIRExpr( *popType() );
pushValue( ToValue( Decl( move( type ), *name ) ).setLocationId( loc ) );
return true;
}
return parsePrefix( strid, prec );
}
bool Parser::parsePrefix( const pvec& vec, uint32_t prec )
{
auto t = *m_resolver->lookAhead();
auto val = ValueFromIRExpr( t.first );
if( !val )
return false;
if( val->isPoison() )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
// If the term is a prefix rule value, invoke its parsePrefix() function.
auto rule = FromValue< Rule >( *val );
if( !rule )
{
m_resolver->consume();
pushValue( Value( move( *val ) ).setLocationId( t.second ) );
return true;
}
if( !( *rule )->isPrefix() )
return false;
m_resolver->consume();
return ( *rule )->parsePrefix( *this, t.second, 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( !IsType( *peekLastValue() ) && ( !IsTExpr( *peekLastValue() ) || IsTFunc( *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 );
}
bool Parser::parseInfix( const pvec& vec, uint32_t prec )
{
auto t = *m_resolver->lookAhead();
auto val = ValueFromIRExpr( t.first );
if( !val )
return false;
if( val->isPoison() )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );
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.second, prec );
}
optional< Value > Parser::popType()
{
if( !m_lastValue )
return nullopt;
auto typeVal = *popValue();
if( !typeVal.isConstant() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( typeVal.locationId(),
"this type expression can't be evaluated here.", 0 );
return PoisonType();
}
return typeVal;
}