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

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupBreakStmt( Env& e )
    {
        auto handleBreak = []( Parser& p, uint32_t locationId, uint32_t prec )
        {
            auto& dm = DiagnosticsManager::GetInstance();
            const auto& cb = p.context().codeBuilder();

            if( p.isInParenExpr() || !cb || !cb->breakableScopeLevels() )
            {
                dm.emitSyntaxErrorMessage( locationId, "the break statement is not allowed here.", 0 );
                return false;
            }

            const auto& cfg = cb->cfg();

            if( !cfg->currentBB() || cfg->currentBB()->terminator() )
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
                    locationId, "unreachable code.", 0 );
                cb->poison();
                return true;
            }

            // Emit cleanups for all live variables in the scopes that we are breaking through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->breakableScopeLevels() );

            cfg->currentBB()->setTerminator( cir::Break( cb->breakableScopeLevels() ) );
            return true;
        };

        Rule r( handleBreak );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( break ) ), ANYTERM( _ ), ruleTerm );
    }
}
