#!/usr/bin/python


"""
Make the whitespace_checker detect illegal tokens after a closing
parenthesis that has its opening parenthesis on a previous line (only
closing tokens are allowed there until the end of the line).
"""

import re

class EvalMatches(object):
    _closing_parens = re.compile(r'''(?x)
(\() | # Either an opening or
(\))[ ]*[)}\],;]*[ ]*([^\s(;]) # Or a closing with an illegal token
'''
)
    _error_msg = "Found '%s', but only closing tokens are allowed after closing " \
        "parenthesis with corresponding opening parenthesis "\
        "on an earlier line"
    def __call__(self,lines,fn):
        errors = []

        open_parens = 0
        for lineno,line in enumerate(lines):

            last_opening_parens = open_parens

            # Find all closing parens
            open_parens_on_line = 0
            for m in self._closing_parens.finditer(line):
                if m.group(1) == '(':
                    open_parens += 1
                    open_parens_on_line += 1
                else:
                    open_parens -= m.group(0).count(')')
                    open_parens_on_line -= m.group(0).count(')')
                    if last_opening_parens and open_parens_on_line < 0 and \
                       m.group(3) not in ')}],;':
                        g = m.group(3)
                        # pure virtual function?
                        if not line.strip().endswith("= 0;"):
                            errors.append((fn,lineno+1,self._error_msg % g))

            open_parens = last_opening_parens + line.count('(') - line.count(')')



        return errors

evaluate_matches = EvalMatches()


strip_macros = True
strip_comments_and_strings = True

forbidden = [
# Eriks tests
## illegal_character_after_closing_brace.cc
"""bool func(bool const a, bool const b) {
\treturn
\t\tfunc
\t\t\t(a,
\t\t\t func(b, a)) == func(b, func(b, a));
}""",

"""bool fund(bool const a, bool const b) {
\treturn
\t\tfunc
\t\t\t(func
\t\t\t \t(a,
\t\t\t \t func(b, a)), func(b, func(b, a)));
}""",

]

allowed = [
"""std::set<std::string> const & operator[] (size_t const i) const {
\t}
\tstd::set<std::string>       & operator[] (size_t const i)       {
\t}
""",

"""(dynamic_cast<Road const *>(pimm) &&
\t\t\t  fc.field->get_caps() & BUILDCAPS_FLAG));""",

"""snprintf
\t\t(buffer, sizeof(buffer),
\t\t _("%u%% built"), (get_built_per64k() * 100) >> 16);""",
"""blah
    (int a, int b,
    int c) = 0;
""",

]
