
// Copyright {Jagger Software Limited} 2003

#include "grammar/multiplicity.hpp"

#include "contract/pre_condition.hpp"
#include "grammar/infinity.hpp"
#include "grammar/symbol_definition.hpp"
#include <iostream>

using namespace ::std;

namespace grammar // multiplicity - 'tors
{
    multiplicity::multiplicity(size_t fixed)
        : lower_bound(fixed)
        , upper_bound(fixed)
    {
        PRE_CONDITION(fixed != 0);
    }   

    multiplicity::multiplicity(size_t lo, size_t hi)
        : lower_bound(lo)
        , upper_bound(hi)
    {
        PRE_CONDITION(lo != 0 || hi != 0);
        PRE_CONDITION(lo <= hi);
    }   

    multiplicity::multiplicity(size_t lo, infinity_type infinity)
        : lower_bound(lo)
        , upper_bound(infinity)
    {
    }   
}

namespace grammar // multiplicity - named values
{
    const multiplicity & multiplicity::compulsory()
    {
        static const multiplicity named_value(1, 1);
        return named_value;
    }
    
    const multiplicity & multiplicity::optional()
    {
        static const multiplicity named_value(0, 1);
        return named_value;
    }
    
    const multiplicity & multiplicity::one_or_more()
    {
        static const multiplicity named_value(1, infinity());
        return named_value;        
    }
    
    const multiplicity & multiplicity::zero_or_more()
    {
        static const multiplicity named_value(0, infinity());
        return named_value;        
    }
}

namespace grammar // multiplicity - in/equality
{
    bool operator==(const multiplicity & lhs, const multiplicity & rhs)
    {
        return lhs.lower_bound == rhs.lower_bound && 
               lhs.upper_bound == rhs.upper_bound;
    }
    
    bool operator!=(const multiplicity & lhs, const multiplicity & rhs)
    {
        return lhs.lower_bound != rhs.lower_bound ||
               lhs.upper_bound != rhs.upper_bound;
    }
}

namespace grammar // multiplicity - streaming
{
    ostream & operator<<(ostream & out, const multiplicity & to_write)
    {
        if (to_write == multiplicity::compulsory())
            ; // nothing
        else if (to_write == multiplicity::optional())
           out << '?';
        else if (to_write == multiplicity::one_or_more())
           out << '+';
        else if (to_write == multiplicity::zero_or_more())
            out << '*';
        else if (to_write.lower_bound == to_write.upper_bound)
            out << '{' << to_write.lower_bound << '}';
        else
            out << '{' << to_write.lower_bound << ',' << to_write.upper_bound << '}';
    
        return out;
    }
}
    
