
// Copyright {Jagger Software Limited} 2003

#include "grammar/production_symbol_definition.hpp"

#include "contract/not_null_ptr.hpp"
#include "contract/post_condition.hpp"
#include "contract/pre_condition.hpp"
#include "grammar/non_terminal_symbol_definition.hpp"
#include "grammar/out_of_range_exception.hpp"
#include "grammar/visitor.hpp"
#include <cstring>
#include <iostream>
#include <stdexcept>

using namespace ::contract;
using namespace ::std;

namespace grammar // production_symbol_definition - 'tor
{
    production_symbol_definition::production_symbol_definition
    (
        const key_type & key,
        const non_terminal_symbol_definition & parent,
        const qualified_symbol_definition * begin,
        const qualified_symbol_definition * end
    )
        : symbol_definition(key, parent.name)
        , symbols(not_null_ptr(begin), not_null_ptr(end))
    {
        PRE_CONDITION(begin != end);
        POST_CONDITION(size() > 0);
    }
}

namespace grammar // production_symbol_definition - subscripting
{
    size_t production_symbol_definition::size() const
    {
        return symbols.size();
    }

    const qualified_symbol_definition & 
    production_symbol_definition::operator[](size_t at) const
    {
        range_check(at);
        return symbols[at];
    }
}

namespace grammar // production_symbol_definition - validating
{
    void production_symbol_definition::range_check(size_t at) const
    {
        if (at >= size())
        {
            throw out_of_range_exception(typeid(*this), name, at, size());
        }
    }
}

namespace grammar // production_symbol_definition - visiting
{
    bool production_symbol_definition::accept(::grammar::visitor & visitor) const
    { 
        return visitor.visit(*this);
    }
}

namespace grammar // production_symbol_definition - streaming
{
    void production_symbol_definition::write(ostream & out) const
    {       
        out << "    " << (*this)[0];
        
        for (size_t at = 1; at != size(); ++at)
        {
            out << ' ' << (*this)[at];
        }
    }
}

