/*=============================================================================
    Copyright (c) 2003 Giovanni Bajo
    Copyright (c) 2003 Joel de Guzman
    Copyright (c) 2003 Vaclav Vesely
    http://spirit.sourceforge.net/

    Use, modification and distribution is subject to the Boost Software
    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_assign_actor.hpp>

#include <boost/core/lightweight_test.hpp>

#ifdef _MSC_VER
// bogus https://developercommunity.visualstudio.com/t/buggy-warning-c4709/471956
# pragma warning(disable: 4709) // comma operator within array index expression
#endif

using namespace boost;
using namespace BOOST_SPIRIT_CLASSIC_NS;

///////////////////////////////////////////////////////////////////////////////
//
//  bug_001
//
//  access_node_d[] and access_match_d[] iterator bug
//  http://sf.net/mailarchive/forum.php?thread_id=1963157&forum_id=1595
//  http://sf.net/mailarchive/forum.php?thread_id=1966224&forum_id=1595
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/classic_ast.hpp>

struct my_action
{
    template <typename TreeT, typename IterT>
    void operator()(TreeT& /*t*/, IterT begin, IterT end) const
    {
        BOOST_TEST(*begin == '1');
        BOOST_TEST(*end == '2');
    }
};

void bug_001()
{
    const char* text = "123";

    ast_parse(text, text+3, access_node_d[chlit<>('1')][my_action()]);
    ast_parse(text, text+3, access_match_d[chlit<>('1')][my_action()]);
}

///////////////////////////////////////////////////////////////////////////////
//
//  bug_001
//
//  mismatch closure return type bug
//  http://article.gmane.org/gmane.comp.parsers.spirit.general/3678
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/classic_attribute.hpp>
#include <string>

typedef std::string member_type;

struct my_closure: closure<my_closure, member_type>
{
    member1 val;
};

void bug_002()
{
    rule<scanner<char const*>, my_closure::context_t> my_rule = real_p;
    BOOST_TEST(parse("1", my_rule).full);
}

///////////////////////////////////////////////////////////////////////////////
//
//  bug_003
//
//  impl::detach_clear bug
//  http://sourceforge.net/mailarchive/forum.php?thread_id=2008510&forum_id=25901
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/classic_chset.hpp>

void bug_003()
{
    chset<> set;
    set = 'a';
}

///////////////////////////////////////////////////////////////////////////////
//
//  bug_004
//
//  chset<>::operator~(range<>) bug
//  operator&(chset<>, range<>) bug
//  operator&(range<>, chset<>) bug
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/limits.hpp>
#include <boost/spirit/include/classic_chset.hpp>

void bug_004()
{
    const char min = (std::numeric_limits<char>::min)();
    const char max = (std::numeric_limits<char>::max)();

    {
        chset<> set(~range<>(min, max));
        BOOST_TEST(set.test(min) == false);
        BOOST_TEST(set.test(min) == false);
    }

    {
        chset<> set(chset<>(anychar_p) & range<>(min, max));
        BOOST_TEST(set.test(min) == true);
        BOOST_TEST(set.test(min) == true);
    }

    {
        chset<> set(range<>(min, max) & chset<>(anychar_p));
        BOOST_TEST(set.test(min) == true);
        BOOST_TEST(set.test(min) == true);
    }
}

///////////////////////////////////////////////////////////////////////////////
//
//  bug_005
//
//  Most trailing space bug
//  http://article.gmane.org/gmane.comp.parsers.spirit.general/4029
//  JDG: Oct 18, 2005. We shall revert to the previous behavior where
//                     Post skips are not allowed. The reason is that
//                     there is a valid use case where input is obtained
//                     from cin and multi_pass which results in an infinite
//                     loop while the post skipper waits for a whitespace.
//                     For examples like below, the grammar must explicitly
//                     include the post whitespace. One possible way is to
//                     place an end_p at the end of the grammar. The end_p
//                     will trigger the post-skip.
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/classic_core.hpp>

using namespace boost;
using namespace spirit;

void bug_005()
{
    BOOST_TEST(
        parse("   aaaaaaaaa     ", *ch_p('a') >> end_p, space_p).full
    );

    BOOST_TEST(
        parse("   aaaaaaaaa     ", lexeme_d[*ch_p('a')] >> end_p, space_p).full
    );

#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206))
    // not sure why Code Warrior 9.5 does not recognize ch_p(' ') as the 
    // same as space_p (see above) when the inputs are spaces. The
    // tests below are redundant anyway.
#else

    BOOST_TEST(
        parse("   aaaaaaaaa     ", *ch_p('a') >> end_p, ch_p(' ')).full
    );

    BOOST_TEST(
        parse("   aaaaaaaaa     ", lexeme_d[*ch_p('a')] >> end_p, ch_p(' ')).full
    );

#endif
}

///////////////////////////////////////////////////////////////////////////////
//
//  bug_006
//
//  confix bug
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/limits.hpp>
#include <boost/spirit/include/classic_confix.hpp>

void bug_006()
{
    BOOST_TEST(parse("#some comment", comment_p('#')).full);
}

///////////////////////////////////////////////////////////////////////////////
//
//  bug_007
//
//  handling of trailing whitespace bug (ast_parse/pt_parse related)
//  JDG: Oct 18, 2005. We shall revert to the previous behavior where
//                     Post skips are not allowed. The reason is that
//                     there is a valid use case where input is obtained
//                     from cin and multi_pass which results in an infinite
//                     loop while the post skipper waits for a whitespace.
//                     For examples like below, the grammar must explicitly
//                     include the post whitespace. One possible way is to
//                     place an end_p at the end of the grammar. The end_p
//                     will trigger the post-skip.
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/classic_ast.hpp>
#include <boost/spirit/include/classic_parse_tree.hpp>

void bug_007()
{
    BOOST_TEST(parse("test ", str_p("test") >> end_p, space_p).full);
    BOOST_TEST(pt_parse("test ", str_p("test") >> end_p, space_p).full);
    BOOST_TEST(ast_parse("test ", str_p("test") >> end_p, space_p).full);
}

///////////////////////////////////////////////////////////////////////////////
//
//  sf_bug_718903
//
//  see https://sourceforge.net/tracker/index.php
//  ?func=detail&aid=718903&group_id=28447&atid=393386
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/cstdlib.hpp>
#include <boost/spirit/include/classic_chset.hpp>

void sf_bug_718903()
{
    empty_match_parser<chset<char> >
        e(epsilon_p(chset_p("abc")));
}

///////////////////////////////////////////////////////////////////////////////
//
//  sf_bug_719322
//  range_run bug
//
//  see http://sourceforge.net/tracker/index.php
//  ?func=detail&aid=719322&group_id=28447&atid=393386
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/classic_basic_chset.hpp>

void sf_bug_719322()
{
    basic_chset<int> s;
    s.set(3, 3);
    s.set(1, 5);
    BOOST_TEST(s.test(5));
}

///////////////////////////////////////////////////////////////////////////////
//
//  sf_bug_742038
//
//  see http://sf.net/tracker/
//  ?func=detail&atid=393386&aid=742038&group_id=28447
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/classic_position_iterator.hpp>
#include <boost/spirit/include/classic_file_iterator.hpp>
#include <string>
#include <fstream>
#include <iostream>
#include <boost/core/lightweight_test.hpp>
#include <stdio.h>

template <typename IterT>
void test_assign(IterT b, IterT e)
{
    typedef scanner<IterT> scanner_t;

#if     (defined(__GNUC__) && defined(__MINGW32__)) \
    ||  (defined(__GNUC__) && (__GNUC_MINOR__ < 20))

//  There's a bug in g++3.x on MinGW that makes basic_string assert
//  when assigning from IterT [f, l) where IterT is a position_iterator.
//  This issue is discussed here:
//
//  http://gcc.gnu.org/ml/libstdc++/2002-03/msg00196.html
//
//  Aparently, this bug is only present on MinGW. I'm clueless as
//  to why this is so. Regressions on linux seem to be OK! :(
//
//  With, g++3.1, assigning to basic_string from IterT [f, l) is a
//  compile error (a g++3.1 bug).
//
//  In both cases above, we use a vector instead of a string.

    typedef std::vector<char> store;
#else
    typedef std::string store;
#endif

    store dst;
    rule<scanner_t> r = (*alpha_p)[assign_a(dst)];

    parse(b, e, r);

    store::iterator d = dst.begin();

    while (b != e)
    {
        if (*d != *b)
        BOOST_TEST(*d == *b);
        ++b;
        ++d;
    }
}

void sf_bug_742038()
{
    std::string src = "abcdef";
    const char* tmpfilename = "sf_bug_742038.tmp";

    test_assign(src.begin(), src.end());

    position_iterator<std::string::iterator> b(src.begin(), src.end(), "");
    position_iterator<std::string::iterator> e;
    test_assign(b, e);

    {
        std::fstream f(tmpfilename, std::ios::out);
        f << src;
        f.close();

        file_iterator<> b1(tmpfilename);
        file_iterator<> e1(b1.make_end());
        test_assign(b1, e1);
    }

    std::remove(tmpfilename);
}

///////////////////////////////////////////////////////////////////////////////
//
//  bug_009
//
//  limit_d bug
//  http://article.gmane.org/gmane.comp.parsers.spirit.devel/1891/
//
///////////////////////////////////////////////////////////////////////////////
void
bug_009()
{
    parse(
        "test"
      , limit_d(1U, 10U)[uint_p] | str_p("test"));
}

int
main()
{
    bug_001();
    bug_002();
    bug_003();
    bug_004();
    bug_005();
    bug_006();
    bug_007();
    bug_009();

    sf_bug_718903();
    sf_bug_719322();
    sf_bug_742038();

    return boost::report_errors();
}
