from ..extern.pyparsing import (Optional, Keyword, Literal, Combine, Word, OneOrMore,
        ZeroOrMore, QuotedString, delimitedList, ParseException, nums,
        alphas, alphanums, Group, Forward, Regex)
import re
from .. import log; log = log[__name__]


class CPPGrammar(object):

    ERROR_PATTERN = re.compile('\(line:\d+, col:(\d+)\)')

    QUOTED_STRING = (
        QuotedString('"', escChar='\\') | Literal('""') |
        QuotedString("'", escChar='\\') | Literal("''"))

    PTR = Combine(OneOrMore(Word("*") | Word("&")), adjacent=False)
    SIGN = Optional(Literal('+') | Literal('-'))
    CONST = Keyword("const")
    SIGNED = Optional(Keyword('signed') | Keyword('unsigned'))
    STATIC = Keyword('static')
    VOID = Combine(Literal('void') + Optional(PTR), adjacent=False)

    BASIC_TYPE = Group(
        Keyword('bool') |
        (SIGNED + Keyword('char')) |
        (SIGNED + Keyword('short')) |
        (SIGNED + Keyword('int')) |
        (SIGNED + Keyword('long') + Optional(Keyword('long'))) |
        Keyword('enum') |
        Keyword('float') |
        (Optional('long') + Keyword('double')))('type_name')

    IDENTIFIER = Word(alphas + "_", alphanums + "_").setName("identifier")

    hexnums = nums + "abcdefABCDEF" + "_?"
    base = Regex("'[bBoOdDhH]").setName("base")
    BASEDNUMBER = Combine(
        Optional(Word(nums + "_")) + base +
        Word(hexnums + "xXzZ"),
        joinString=" ", adjacent=False).setName("based number")
    NUMBER = (BASEDNUMBER |
        Regex(r"[-+]?([0-9]*\.[0-9]+|[0-9]+\.?)([Ee][-+]?[0-9]+)?")).setName("numeric")

    ARITH_OPERATOR = Word("*/+-").setName('arith op')
    BIT_OPERATOR = Word('&|').setName('bit op')
    BIT_EXPRESSION = (IDENTIFIER +
        OneOrMore(BIT_OPERATOR + IDENTIFIER)).setName('bit_expression')
    EXPRESSION = OneOrMore(
        NUMBER | ARITH_OPERATOR | IDENTIFIER).setName('expression')
    FULL_EXPRESSION = OneOrMore(
        NUMBER | ARITH_OPERATOR |
        Literal('(') | Literal(')')).setName('full_expression')

    NAMESPACED_NAME = delimitedList(IDENTIFIER, delim='::', combine=True)

    TYPE = Forward()

    TEMPLATE_PARAMS = (
        Literal("<").suppress() +
        Group(delimitedList(TYPE | FULL_EXPRESSION))("template_params") +
        Literal(">").suppress())

    CLASS_MEMBER = (Literal('::').suppress() + NAMESPACED_NAME)("template_member")

    COMPLEX_TYPE = Group(NAMESPACED_NAME)('type_name') + Optional(TEMPLATE_PARAMS +
        Optional(CLASS_MEMBER))

    TYPE << (
        Group(Optional(CONST))('type_prefix') +
        (BASIC_TYPE | COMPLEX_TYPE) +
        Group(Optional(PTR + Optional(CONST)))('type_suffix'))

    TYPE_EXPRESSION = (
        Optional(NUMBER + ARITH_OPERATOR) + TYPE)('type_expression')

    SIMPLE_ARG_DEFAULT = Forward()
    ARG_LIST = delimitedList(SIMPLE_ARG_DEFAULT)('arg_list')
    SIMPLE_ARG_DEFAULT << (
        QUOTED_STRING | BIT_EXPRESSION | (TYPE_EXPRESSION +
        Optional(
            Literal('(').suppress() +
            Optional(ARG_LIST) +
            Literal(')').suppress())) |
        EXPRESSION)

    FUNC_ARG_DEFAULT = (Literal('&') + TYPE_EXPRESSION +
        Optional(Literal('(').suppress() +
        Optional(ARG_LIST) +
        Literal(')').suppress()))

    METHOD_ARGS = Forward()

    SIMPLE_ARG = (Optional(Optional(IDENTIFIER('arg_name')) +
        Optional(Literal('=').suppress() +
            SIMPLE_ARG_DEFAULT('arg_default'))))

    FUNC_ARG = (Literal('(*)') +
        Literal("(").suppress() +
        Optional(METHOD_ARGS)('func_arg_signature') +
        Literal(")").suppress() +
        Optional(Optional(IDENTIFIER)('arg_name') +
            Optional(Literal('=').suppress() +
                FUNC_ARG_DEFAULT('arg_default'))))

    METHOD_ARG = Group((VOID('arg_type') | TYPE('arg_type')) +
        (FUNC_ARG | SIMPLE_ARG))('arg')

    METHOD_ARGS << (delimitedList(METHOD_ARG) | Literal('...'))

    METHOD_SIGNATURE = (
        Optional(STATIC) +
        ((VOID('return') + COMPLEX_TYPE('name')) |
         (TYPE('return') + COMPLEX_TYPE('name')) |
         COMPLEX_TYPE('name')) +
        Literal("(").suppress() +
        Optional(Group(METHOD_ARGS)('args')) +
        Literal(")").suppress())

    @classmethod
    def _parse(cls, grammar, string, raise_exception=False, silent=True):

        try:
            return grammar.parseString(string, parseAll=True)
        except ParseException as e:
            if not silent:
                log.warning(string)
                str_e = str(e)
                match = re.search(cls.ERROR_PATTERN, str_e)
                if match:
                    log.warning(" " * (int(match.group(1)) - 1) + '^')
            if raise_exception:
                raise
            if not silent:
                log.warning(e)
            return None

    @classmethod
    def parse_type(cls, string, raise_exception=False, silent=True):

        return cls._parse(cls.TYPE, string,
                raise_exception, silent)

    @classmethod
    def parse_method(cls, string, raise_exception=False, silent=True):

        return cls._parse(cls.METHOD_SIGNATURE,
                string, raise_exception, silent)

@@ -67,16 +67,24 @@
 e, Word,
+%0A       
  OneOrMo
@@ -86,24 +86,16 @@
 eOrMore,
-%0A       
  ZeroOrM
@@ -147,22 +147,16 @@
 ion,
- nums,
 %0A       
  alp
@@ -151,16 +151,22 @@
 %0A       
+ nums,
  alphas,
@@ -204,18 +204,8 @@
 ex)%0A
-import re%0A
 from
@@ -240,16 +240,26 @@
 name__%5D%0A
+import re%0A
 %0A%0Aclass 
@@ -278,16 +278,98 @@
 bject):%0A
+    %22%22%22%0A    A grammar for parsing C++ method/function signatures and types%0A    %22%22%22
 %0A    ERR
@@ -1556,16 +1556,25 @@
 MBER = (
+%0A        
 BASEDNUM
@@ -1646,16 +1646,25 @@
 -9%5D+)?%22)
+%0A        
 ).setNam
@@ -2393,24 +2393,33 @@
 S_MEMBER = (
+%0A        
 Literal('::'
@@ -2432,16 +2432,24 @@
 ress() +
+%0A       
  NAMESPA
@@ -2492,24 +2492,34 @@
 MPLEX_TYPE =
+ (%0A       
  Group(NAMES
@@ -2540,24 +2540,32 @@
 ype_name') +
+%0A       
  Optional(TE
@@ -2579,24 +2579,16 @@
 PARAMS +
-%0A       
  Optiona
@@ -2603,16 +2603,17 @@
 MEMBER))
+)
 %0A%0A    TY

clean up cpp