#ifndef GOOSE_BUILTINS_EXPRHELPERS_H
#define GOOSE_BUILTINS_EXPRHELPERS_H

#include "parse/parse.h"

namespace goose::builtins::exprhelpers
{
    template< typename V >
    Value Not( V&& val )
    {
        return BuildComputedValue( GetValueType< bool >(),
            cir::Not( forward< V >( val ) ) ).setLocationId( val.locationId() );
    }

    template< typename L, typename R >
    Value Or( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::Or( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value And( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::And( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value Eq( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::Eq( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value Neq( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::Neq( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value UGT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::UGT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value UGE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::UGE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value ULT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::ULT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value ULE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::ULE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SGT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::SGT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SGE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::SGE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SLT( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::SLT( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }

    template< typename L, typename R >
    Value SLE( L&& lhs, R&& rhs )
    {
        auto locId = max( lhs.locationId(), rhs.locationId() );
        return BuildComputedValue( GetValueType< bool >(),
            cir::SLE( forward< L >( lhs ), forward< R >( rhs ) ) ).setLocationId( locId );
    }
}

#endif
