Ejemplo n.º 1
0
def hwdb_grammar():
    ParserElement.setDefaultWhitespaceChars('')

    prefix = Or(category + ':' + Or(conn) + ':'
                for category, conn in TYPES.items())
    matchline = Combine(prefix + Word(printables + ' ' + '®')) + EOL
    propertyline = (
        White(' ', exact=1).suppress()
        + Combine(UDEV_TAG
                  - '='
                  - Word(alphanums + '_=:@*.! ')
                  - Optional(pythonStyleComment))
        + EOL
    )
    propertycomment = White(' ', exact=1) + pythonStyleComment + EOL

    group = (
        OneOrMore(matchline('MATCHES*') ^ COMMENTLINE.suppress())
        - OneOrMore(propertyline('PROPERTIES*') ^ propertycomment.suppress())
        - (EMPTYLINE ^ stringEnd()).suppress()
    )
    commentgroup = OneOrMore(COMMENTLINE).suppress() - EMPTYLINE.suppress()

    grammar = OneOrMore(group('GROUPS*') ^ commentgroup) + stringEnd()

    return grammar
Ejemplo n.º 2
0
def hwdb_grammar():
    ParserElement.setDefaultWhitespaceChars('')

    prefix = Or(category + ':' + Or(conn) + ':'
                for category, conn in TYPES.items())

    matchline_typed = Combine(prefix + Word(printables + ' ' + '®'))
    matchline_general = Combine(
        Or(GENERAL_MATCHES) + ':' + Word(printables + ' ' + '®'))
    matchline = (matchline_typed | matchline_general) + EOL

    propertyline = (
        White(' ', exact=1).suppress() +
        Combine(UDEV_TAG - '=' - Optional(Word(alphanums + '_=:@*.!-;, "/')) -
                Optional(pythonStyleComment)) + EOL)
    propertycomment = White(' ', exact=1) + pythonStyleComment + EOL

    group = (
        OneOrMore(matchline('MATCHES*') ^ COMMENTLINE.suppress()) -
        OneOrMore(propertyline('PROPERTIES*') ^ propertycomment.suppress()) -
        (EMPTYLINE ^ stringEnd()).suppress())
    commentgroup = OneOrMore(COMMENTLINE).suppress() - EMPTYLINE.suppress()

    grammar = OneOrMore(Group(group)('GROUPS*') ^ commentgroup) + stringEnd()

    return grammar
Ejemplo n.º 3
0
def oui_grammar(type):
    prefix_line = (
        Combine(NUM2 - Suppress('-') - NUM2 - Suppress('-') - NUM2)('prefix') -
        Literal('(hex)') - text_eol('text'))
    if type == 'small':
        vendor_line = (NUM3('start') - '000-' - NUM3('end') - 'FFF' -
                       Literal('(base 16)') - text_eol('text2'))
    elif type == 'medium':
        vendor_line = (NUM1('start') - '00000-' - NUM1('end') - 'FFFFF' -
                       Literal('(base 16)') - text_eol('text2'))
    else:
        assert type == 'large'
        vendor_line = (NUM6('start') - Literal('(base 16)') -
                       text_eol('text2'))

    extra_line = TAB - TAB - TAB - TAB - SkipTo(EOL)
    vendor = prefix_line + vendor_line + ZeroOrMore(extra_line) + Optional(
        EMPTYLINE)

    grammar = (Literal('OUI') + text_eol('header') + text_eol('header') +
               text_eol('header') + EMPTYLINE + OneOrMore(vendor('VENDORS*')) +
               stringEnd())

    grammar.parseWithTabs()
    return grammar
Ejemplo n.º 4
0
def usb_ids_grammar():
    vendor_line = NUM4('vendor') + text_eol('text')
    device_line = TAB + NUM4('device') + text_eol('text')
    interface_line = TAB + TAB + NUM4('interface') + NUM4(
        'interface2') + text_eol('text')
    device = (device_line +
              ZeroOrMore(Group(interface_line) ^ COMMENTLINE.suppress()))
    vendor = (
        vendor_line('VENDOR') +
        ZeroOrMore(Group(device)('VENDOR_DEV*') ^ COMMENTLINE.suppress()))

    klass = klass_grammar()

    other_line = (Literal('AT ') ^ Literal('HID ') ^ Literal('R ')
                  ^ Literal('PHY ') ^ Literal('BIAS ') ^ Literal('HUT ')
                  ^ Literal('L ') ^ Literal('VT ')
                  ^ Literal('HCC ')) + text_eol('text')
    other_group = (other_line - ZeroOrMore(TAB + text_eol('text')))

    commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
    grammar = OneOrMore(
        Group(vendor)('VENDORS*') ^ Group(klass)('CLASSES*')
        ^ other_group.suppress() ^ commentgroup) + stringEnd()

    grammar.parseWithTabs()
    return grammar
Ejemplo n.º 5
0
 def __init__(self):
     """
     Create a parser that parse arithmetic expressions. They can
     contains variable identifiers or raw numbers. The meaning
     for the identifiers is left to the
     """
     number = p.Regex(r'\d+(\.\d*)?([eE]\d+)?')
     identifier = p.Word(p.alphas)
     terminal = identifier | number
     self._expr = p.infixNotation(
         terminal, [(p.oneOf('* /'), 2, p.opAssoc.LEFT),
                    (p.oneOf('+ -'), 2, p.opAssoc.LEFT)]) + p.stringEnd()
Ejemplo n.º 6
0
 def __init__(self):
     """
     Create a parser that parse arithmetic expressions. They can
     contains variable identifiers or raw numbers. The meaning
     for the identifiers is left to the
     """
     number = p.Regex(r'\d+(\.\d*)?([eE]\d+)?')
     identifier = p.Word(p.alphas)
     terminal = identifier | number
     self._expr = p.infixNotation(terminal, [
         (p.oneOf('* /'), 2, p.opAssoc.LEFT),
         (p.oneOf('+ -'), 2, p.opAssoc.LEFT)
     ]) + p.stringEnd()
Ejemplo n.º 7
0
def sdio_ids_grammar():
    vendor_line = NUM4('vendor') + text_eol('text')
    device_line = TAB + NUM4('device') + text_eol('text')
    vendor = (vendor_line('VENDOR') +
              ZeroOrMore(device_line('DEVICES*') ^ COMMENTLINE.suppress()))

    klass = klass_grammar()

    commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
    grammar = OneOrMore(vendor('VENDORS*') ^ klass('CLASSES*') ^ commentgroup) + stringEnd()

    grammar.parseWithTabs()
    return grammar
Ejemplo n.º 8
0
def create_parser():
    """Creates the parser using PyParsing functions."""

    # Day details (day number, superscript and day name)
    daynum = Word(nums, max=2)
    superscript = oneOf("th rd st nd", caseless=True)
    day = oneOf(
        "Mon Monday Tue Tues Tuesday Wed Weds Wednesday "
        "Thu Thur Thurs Thursday Fri Friday Sat Saturday Sun Sunday",
        caseless=True)

    full_day_string = daynum + Optional(superscript).suppress()
    full_day_string.setParseAction(check_day)
    full_day_string.leaveWhitespace()

    # Month names, with abbreviations, with action to convert to equivalent month number
    month = oneOf(list(MONTHS.keys()), caseless=True) + \
        Optional(Literal(".").suppress())
    month.setParseAction(month_to_number)

    # Year
    year = Word(nums, exact=4)
    year.setParseAction(lambda tokens: int(tokens[0]))

    time_sep = oneOf(": .")
    am_pm = oneOf("am pm", caseless=True)
    hours = Word(nums, max=2)
    mins = Word(nums, max=2)

    time = hours("hour") + time_sep.suppress() + \
        mins("mins") + Optional(am_pm)("meridian")

    # date pattern
    date = (Optional(time).suppress() & Optional(full_day_string("day"))
            & Optional(day).suppress() & Optional(month("month"))
            & Optional(year("year")))

    # Possible separators
    separator = oneOf("- -- to until through till untill \u2013 \u2014 ->",
                      caseless=True)

    # Strings to completely ignore (whitespace ignored by default)
    ignoreable_chars = oneOf(", from starting beginning of", caseless=True)

    # Final putting together of everything
    daterange = (Optional(
        date("start") + Optional(time).suppress() + separator.suppress()) +
                 date("end") + Optional(time).suppress() + stringEnd())
    daterange.ignore(ignoreable_chars)

    return daterange
Ejemplo n.º 9
0
def create_parser():
    """Creates the parser using PyParsing functions."""

    # Day details (day number, superscript and day name)
    daynum = Word(nums, max=2)
    superscript = oneOf("th rd st nd", caseless=True)
    day = oneOf("Mon Monday Tue Tues Tuesday Wed Weds Wednesday "
                "Thu Thur Thurs Thursday Fri Friday Sat Saturday Sun Sunday", caseless=True)

    full_day_string = daynum + Optional(superscript).suppress()
    full_day_string.setParseAction(check_day)
    full_day_string.leaveWhitespace()

    # Month names, with abbreviations, with action to convert to equivalent month number
    month = oneOf(list(MONTHS.keys()), caseless=True) + \
        Optional(Literal(".").suppress())
    month.setParseAction(month_to_number)

    # Year
    year = Word(nums, exact=4)
    year.setParseAction(lambda tokens: int(tokens[0]))

    time_sep = oneOf(": .")
    am_pm = oneOf("am pm", caseless=True)
    hours = Word(nums, max=2)
    mins = Word(nums, max=2)

    time = hours("hour") + time_sep.suppress() + \
        mins("mins") + Optional(am_pm)("meridian")

    # date pattern
    date = (
        Optional(time).suppress() & Optional(full_day_string("day")) & Optional(day).suppress() &
        Optional(month("month")) & Optional(year("year"))
    )

    # Possible separators
    separator = oneOf("- -- to until through till untill \u2013 \u2014 ->", caseless=True)

    # Strings to completely ignore (whitespace ignored by default)
    ignoreable_chars = oneOf(", from starting beginning of", caseless=True)

    # Final putting together of everything
    daterange = (
        Optional(date("start") + Optional(time).suppress() + separator.suppress()) +
        date("end") + Optional(time).suppress() + stringEnd()
    )
    daterange.ignore(ignoreable_chars)

    return daterange
Ejemplo n.º 10
0
def sdio_ids_grammar():
    vendor_line = NUM4('vendor') + text_eol('text')
    device_line = TAB + NUM4('device') + text_eol('text')
    vendor = (vendor_line('VENDOR') +
              ZeroOrMore(device_line('DEVICES*') ^ COMMENTLINE.suppress()))

    klass = klass_grammar()

    commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
    grammar = OneOrMore(vendor('VENDORS*') ^ klass('CLASSES*')
                        ^ commentgroup) + stringEnd()

    grammar.parseWithTabs()
    return grammar
Ejemplo n.º 11
0
def pci_ids_grammar():
    vendor_line = NUM4('vendor') + text_eol('text')
    device_line = TAB + NUM4('device') + text_eol('text')
    subvendor_line = TAB + TAB + NUM4('a') + White(' ') + NUM4('b') + text_eol('name')

    device = (device_line('DEVICE') +
              ZeroOrMore(Group(subvendor_line)('SUBVENDORS*') ^ COMMENTLINE.suppress()))
    vendor = (vendor_line('VENDOR') +
              ZeroOrMore(Group(device)('DEVICES*') ^ COMMENTLINE.suppress()))

    klass = klass_grammar()

    commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
    grammar = OneOrMore(Group(vendor)('VENDORS*')
                        ^ Group(klass)('CLASSES*')
                        ^ commentgroup) + stringEnd()

    grammar.parseWithTabs()
    return grammar
Ejemplo n.º 12
0
def pci_ids_grammar():
    vendor_line = NUM4('vendor') + text_eol('text')
    device_line = TAB + NUM4('device') + text_eol('text')
    subvendor_line = TAB + TAB + NUM4('a') + White(' ') + NUM4('b') + text_eol('name')

    device = (device_line('DEVICE') +
              ZeroOrMore(Group(subvendor_line)('SUBVENDORS*') ^ COMMENTLINE.suppress()))
    vendor = (vendor_line('VENDOR') +
              ZeroOrMore(Group(device)('DEVICES*') ^ COMMENTLINE.suppress()))

    klass = klass_grammar()

    commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
    grammar = OneOrMore(Group(vendor)('VENDORS*')
                        ^ Group(klass)('CLASSES*')
                        ^ commentgroup) + stringEnd()

    grammar.parseWithTabs()
    return grammar
Ejemplo n.º 13
0
def usb_ids_grammar():
    vendor_line = NUM4('vendor') + text_eol('text')
    device_line = TAB + NUM4('device') + text_eol('text')
    vendor = (vendor_line('VENDOR') +
             ZeroOrMore(device_line('VENDOR_DEV*') ^ COMMENTLINE.suppress()))

    klass = klass_grammar()

    other_line = (Literal('AT ') ^ Literal('HID ') ^ Literal('R ')
                  ^ Literal('PHY ') ^ Literal('BIAS ') ^ Literal('HUT ')
                  ^ Literal('L ') ^ Literal('VT ') ^ Literal('HCC ')) + text_eol('text')
    other_group = (other_line - ZeroOrMore(TAB + text_eol('text')))

    commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
    grammar = OneOrMore(vendor('VENDORS*') ^ klass('CLASSES*')
                        ^ other_group.suppress() ^ commentgroup) + stringEnd()

    grammar.parseWithTabs()
    return grammar
Ejemplo n.º 14
0
def oui_grammar(type):
    prefix_line = (Combine(NUM2 - Suppress('-') - NUM2 - Suppress('-') - NUM2)('prefix')
                   - Literal('(hex)') -  text_eol('text'))
    if type == 'small':
        vendor_line = (NUM3('start') - '000-' - NUM3('end') - 'FFF'
                       - Literal('(base 16)') - text_eol('text2'))
    elif type == 'medium':
        vendor_line = (NUM1('start') - '00000-' - NUM1('end') - 'FFFFF'
                       - Literal('(base 16)') - text_eol('text2'))
    else:
        assert type == 'large'
        vendor_line = (NUM6('start')
                       - Literal('(base 16)') - text_eol('text2'))

    extra_line = TAB - TAB - TAB - TAB - SkipTo(EOL)
    vendor = prefix_line + vendor_line + ZeroOrMore(extra_line) + Optional(EMPTYLINE)

    grammar = (Literal('OUI') + text_eol('header')
               + text_eol('header') + text_eol('header') + EMPTYLINE
               + OneOrMore(vendor('VENDORS*')) + stringEnd())

    grammar.parseWithTabs()
    return grammar
    def dockerfile_instruction_grammar(self):
        """dockerfile_instruction_grammar"""

        #
        # Fail Action - Error template - Line / Col / Instruction
        #
        def error(s, loc, expr, error):
            """Main error template"""
            raise ParseFatalException(DOCKERFILE_ERROR[202].format(
                ligne=self.line_counter,
                colonne=error.loc,
                inst=self.currentInstructionName,
                erreur=error.msg))

        #
        # Parse Action (Basic verification)
        #

        def arg_validate(strng, loc, toks):
            """Do some verfications for the instruction arguments"""
            if not self.validator.validate_instruction(toks):
                raise ParseFatalException(self.validator.get_errors(), loc=loc)

        def instructions_parse(strng, loc, toks):
            """Check if the instruction exist in the config file"""

            self.currentInstructionName = toks[0]

            if toks[0] not in INSTRUCTION_CONFIG_LIST:
                raise ParseFatalException(DOCKERFILE_ERROR[211], loc=loc)

            self.currentInstruction = INSTRUCTION_CONFIG_LIST[toks[0]]

        def args_table_parse(strng, loc, toks):
            """Check if the table form is correct for the current instruction arguments"""

            if (self.currentInstruction[0] == 1):
                raise ParseFatalException(DOCKERFILE_ERROR[213], loc=loc)

        def args_list_parse(strng, loc, toks):
            """Check if the list form is correct for the current instruction arguments"""

            if (self.currentInstruction[0] == 2):
                raise ParseFatalException(DOCKERFILE_ERROR[214], loc=loc)

        def args_num_parse(strng, loc, toks):
            """Check if the number of arguments is correct"""

            minArg = self.currentInstruction[1]
            maxArg = self.currentInstruction[2]
            nbArgs = len(toks)
            if (not minArg <= nbArgs <= maxArg):
                raise ParseFatalException(DOCKERFILE_ERROR[215].format(
                    nombre=nbArgs, min=minArg, max=maxArg),
                                          loc=loc)

        def opt_parse(strng, loc, toks):
            """Check if the option exist and if she's correct for the current instruction"""

            if toks[0] not in OPTIONAL_OPTION_CONFIG:
                raise ParseFatalException(
                    DOCKERFILE_ERROR[216].format(opt=toks[0]), loc=loc)
            if self.currentInstructionName not in OPTIONAL_OPTION_CONFIG[
                    toks[0]]:
                raise ParseFatalException(
                    DOCKERFILE_ERROR[217].format(opt=toks[0]), loc=loc)

        #INIT
        ParserElement.setDefaultWhitespaceChars(" \t")

        #
        # TERMINALS
        #
        INST = Regex(r'([A-Z]+)(?<!\s)').setName('Instruction').setParseAction(
            instructions_parse)
        OPT = Regex(r'--[a-z]+=').setName('Option').setParseAction(opt_parse)

        STR = Regex(r'\"((.|\s)+?)\"').setName("chaîne de caractère")
        ARG = Regex(r'\S+').setName("argument")

        EOL = lineEnd().setName("fin de ligne").suppress()
        COM = Regex(r'#.*').suppress()

        OH = Literal('[').suppress()
        CH = Literal(']').suppress()
        CO = Literal(',').suppress()

        #
        # NO TERMINALS
        #
        #Arguments
        t_args_table = OH - STR - ZeroOrMore(CO - STR) - CH
        t_args_table.setName('["argument1", "argument2" …]')
        t_args_table.setParseAction(args_table_parse)

        t_args_list = ARG - ZeroOrMore(ARG)
        t_args_list.setName('argument1 argument2 …')
        t_args_list.setParseAction(args_list_parse)

        t_args = (t_args_table | t_args_list)
        t_args.setParseAction(args_num_parse)

        #Multiple lines separator
        continuation = '\\' - EOL

        #Optional elements
        t_opt = OneOrMore(OPT - Group(ARG))
        t_opt.setParseAction(opt_parse)

        #instruction
        instruction = (INST - Group(Optional(t_opt)) -
                       Group(t_args)).setParseAction(arg_validate)

        #line grammar
        line = (stringStart - (COM | Optional(instruction)) - EOL -
                stringEnd()).setFailAction(error)

        line.ignore(continuation)

        return line
    def __init__(self):

        # Bibtex keywords

        string_def_start = pp.CaselessKeyword("@string")
        preamble_start = pp.CaselessKeyword("@preamble")
        comment_line_start = pp.CaselessKeyword('@comment')

        # String names
        string_name = pp.Word(pp.alphanums + '_')('StringName')
        self.set_string_name_parse_action(lambda s, l, t: None)
        string_name.addParseAction(self._string_name_parse_action)

        # Values inside bibtex fields
        # Values can be integer or string expressions. The latter may use
        # quoted or braced values.

        # Integer values
        integer = pp.Word(pp.nums)('Integer')

        # Braced values: braced values can contain nested (but balanced) braces
        braced_value_content = pp.CharsNotIn('{}')
        braced_value = pp.Forward()  # Recursive definition for nested braces
        braced_value <<= pp.originalTextFor(
            '{' + pp.ZeroOrMore(braced_value | braced_value_content) + '}'
            )('BracedValue')
        braced_value.setParseAction(remove_braces)
        # TODO add ignore for "\}" and "\{" ?
        # TODO @ are not parsed by bibtex in braces

        # Quoted values: may contain braced content with balanced braces
        brace_in_quoted = pp.nestedExpr('{', '}')
        text_in_quoted = pp.CharsNotIn('"{}')
        # (quotes should be escaped in quoted value)
        quoted_value = pp.originalTextFor(
            '"' +
            pp.ZeroOrMore(text_in_quoted | brace_in_quoted) +
            '"')('QuotedValue')
        quoted_value.addParseAction(pp.removeQuotes)

        # String expressions
        string_expr = pp.delimitedList(
            (quoted_value | braced_value | string_name), delim='#'
            )('StringExpression')
        self.set_string_expression_parse_action(lambda s, l, t: None)
        string_expr.addParseAction(self._string_expr_parse_action)

        value = (integer | string_expr)('Value')

        # Entries

        # @EntryType { ...
        entry_type = (pp.Suppress('@') + pp.Word(pp.alphas))('EntryType')
        entry_type.setParseAction(first_token)

        # Entry key: any character up to a ',' without leading and trailing
        # spaces.
        key = pp.SkipTo(',')('Key')  # Exclude @',\#}{~%
        key.setParseAction(lambda s, l, t: first_token(s, l, t).strip())

        # Field name: word of letters and underscores
        field_name = pp.Word(pp.alphas + '_')('FieldName')
        field_name.setParseAction(first_token)

        # Field: field_name = value
        field = pp.Group(field_name + pp.Suppress('=') + value)('Field')
        field.setParseAction(field_to_pair)

        # List of fields: comma separeted fields
        field_list = (pp.delimitedList(field) + pp.Suppress(pp.Optional(','))
                      )('Fields')
        field_list.setParseAction(
            lambda s, l, t: {k: v for (k, v) in reversed(t.get('Fields'))})

        # Entry: type, key, and fields
        self.entry = (entry_type +
                      in_braces_or_pars(key + pp.Suppress(',') + field_list)
                      )('Entry')

        # Other stuff: comments, string definitions, and preamble declarations

        # Explicit comments: @comment + everything up to next valid declaration
        # starting on new line.
        not_an_implicit_comment = (pp.LineStart() + pp.Literal('@')
                                   ) | pp.stringEnd()
        self.explicit_comment = (
            pp.Suppress(comment_line_start) +
            pp.originalTextFor(pp.SkipTo(not_an_implicit_comment),
                               asString=True))('ExplicitComment')
        self.explicit_comment.addParseAction(remove_trailing_newlines)
        self.explicit_comment.addParseAction(remove_braces)
        # Previous implementation included comment until next '}'.
        # This is however not inline with bibtex behavior that is to only
        # ignore until EOL. Brace stipping is arbitrary here but avoids
        # duplication on bibtex write.

        # Empty implicit_comments lead to infinite loop of zeroOrMore
        def mustNotBeEmpty(t):
            if not t[0]:
                raise pp.ParseException("Match must not be empty.")

        # Implicit comments: not anything else
        self.implicit_comment = pp.originalTextFor(
            pp.SkipTo(not_an_implicit_comment).setParseAction(mustNotBeEmpty),
            asString=True)('ImplicitComment')
        self.implicit_comment.addParseAction(remove_trailing_newlines)

        # String definition
        self.string_def = (pp.Suppress(string_def_start) + in_braces_or_pars(
            string_name +
            pp.Suppress('=') +
            string_expr('StringValue')
            ))('StringDefinition')

        # Preamble declaration
        self.preamble_decl = (pp.Suppress(preamble_start) +
                              in_braces_or_pars(value))('PreambleDeclaration')

        # Main bibtex expression

        self.main_expression = pp.ZeroOrMore(
                self.string_def |
                self.preamble_decl |
                self.explicit_comment |
                self.entry |
                self.implicit_comment)
Ejemplo n.º 17
0
    pp.ZeroOrMore(pp.Literal(",").suppress() + value_or_property_name) +
    pp.Literal(")").suppress())

redirection << (live_calculation_property | stored_property
                ) + pp.Literal(".").suppress() + property_identifier

parameters = pp.Literal("(").suppress() + pp.Optional(
    value_or_property_name +
    pp.ZeroOrMore(pp.Literal(",").suppress() +
                  value_or_property_name)) + pp.Literal(")").suppress()
live_calculation_property << property_name + parameters

array_element << (
    (live_calculation_property | stored_property) + element_identifier)

property_complete = pp.stringStart() + value_or_property_name + pp.stringEnd()


def parse_property_name(name):
    with _parsing_lock:
        return property_complete.parseString(name)[0]


def parse_property_name_if_required(name):
    if isinstance(name, Calculation):
        return name
    else:
        return parse_property_name(name)


def parse_property_names(*names):
Ejemplo n.º 18
0
atom_vLevels = ("v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9")

integer = pp.Word(pp.nums)
atom_first_vLevel = pp.oneOf(atom_vLevels).setResultsName("firstVLevel")
atom_first_vLevel_int = integer.setResultsName("firstVLevelInt")
atom_second_vLevel = pp.oneOf(atom_vLevels).setResultsName("secondVLevel")
atom_second_vLevel_int = integer.setResultsName("secondVLevelInt")

atom_term = (
    pp.Optional(atom_first_vLevel_int)
    + atom_first_vLevel
    + "+"
    + pp.Optional(atom_second_vLevel_int)
    + atom_second_vLevel
    + pp.stringEnd()
)

atom_exc = integer.setResultsName("excLevel")
atom_term_exc = atom_exc + pp.StringEnd()


class VibrationalState(State):
    def parse_state(self, state_str):
        self.state_str = state_str.replace(" ", "")

        if "+" in state_str:
            try:
                components = atom_term.parseString(state_str)
            except pp.ParseException:
                raise StateParseError("Invalid atomic term symbol syntax: {0}".format(state_str))
Ejemplo n.º 19
0
    def __init__(self):

        # Bibtex keywords

        string_def_start = pp.CaselessKeyword("@string")
        preamble_start = pp.CaselessKeyword("@preamble")
        comment_line_start = pp.CaselessKeyword('@comment')

        # String names
        string_name = pp.Word(pp.alphanums + '_')('StringName')
        self.set_string_name_parse_action(lambda s, l, t: None)
        string_name.addParseAction(self._string_name_parse_action)

        # Values inside bibtex fields
        # Values can be integer or string expressions. The latter may use
        # quoted or braced values.

        # Integer values
        integer = pp.Word(pp.nums)('Integer')

        # Braced values: braced values can contain nested (but balanced) braces
        braced_value_content = pp.CharsNotIn('{}')
        braced_value = pp.Forward()  # Recursive definition for nested braces
        braced_value <<= pp.originalTextFor(
            '{' + pp.ZeroOrMore(braced_value | braced_value_content) + '}'
            )('BracedValue')
        braced_value.setParseAction(remove_braces)
        # TODO add ignore for "\}" and "\{" ?
        # TODO @ are not parsed by bibtex in braces

        # Quoted values: may contain braced content with balanced braces
        brace_in_quoted = pp.nestedExpr('{', '}', ignoreExpr=None)
        text_in_quoted = pp.CharsNotIn('"{}')
        # (quotes should be escaped by braces in quoted value)
        quoted_value = pp.originalTextFor(
            '"' + pp.ZeroOrMore(text_in_quoted | brace_in_quoted) + '"'
            )('QuotedValue')
        quoted_value.addParseAction(pp.removeQuotes)

        # String expressions
        string_expr = pp.delimitedList(
            (quoted_value | braced_value | string_name), delim='#'
            )('StringExpression')
        self.set_string_expression_parse_action(lambda s, l, t: None)
        string_expr.addParseAction(self._string_expr_parse_action)

        value = (integer | string_expr)('Value')

        # Entries

        # @EntryType { ...
        entry_type = (pp.Suppress('@') + pp.Word(pp.alphas))('EntryType')
        entry_type.setParseAction(first_token)

        # Entry key: any character up to a ',' without leading and trailing
        # spaces.
        key = pp.SkipTo(',')('Key')  # Exclude @',\#}{~%
        key.setParseAction(lambda s, l, t: first_token(s, l, t).strip())

        # Field name: word of letters, digits, dashes and underscores
        field_name = pp.Word(pp.alphanums + '_-()')('FieldName')
        field_name.setParseAction(first_token)

        # Field: field_name = value
        field = pp.Group(field_name + pp.Suppress('=') + value)('Field')
        field.setParseAction(field_to_pair)

        # List of fields: comma separeted fields
        field_list = (pp.delimitedList(field) + pp.Suppress(pp.Optional(','))
                      )('Fields')
        field_list.setParseAction(
            lambda s, l, t: {k: v for (k, v) in reversed(t.get('Fields'))})

        # Entry: type, key, and fields
        self.entry = (entry_type +
                      in_braces_or_pars(key + pp.Suppress(',') + field_list)
                      )('Entry')

        # Other stuff: comments, string definitions, and preamble declarations

        # Explicit comments: @comment + everything up to next valid declaration
        # starting on new line.
        not_an_implicit_comment = (pp.LineStart() + pp.Literal('@')
                                   ) | pp.stringEnd()
        self.explicit_comment = (
            pp.Suppress(comment_line_start) +
            pp.originalTextFor(pp.SkipTo(not_an_implicit_comment),
                               asString=True))('ExplicitComment')
        self.explicit_comment.addParseAction(remove_trailing_newlines)
        self.explicit_comment.addParseAction(remove_braces)
        # Previous implementation included comment until next '}'.
        # This is however not inline with bibtex behavior that is to only
        # ignore until EOL. Brace stipping is arbitrary here but avoids
        # duplication on bibtex write.

        # Empty implicit_comments lead to infinite loop of zeroOrMore
        def mustNotBeEmpty(t):
            if not t[0]:
                raise pp.ParseException("Match must not be empty.")

        # Implicit comments: not anything else
        self.implicit_comment = pp.originalTextFor(
            pp.SkipTo(not_an_implicit_comment).setParseAction(mustNotBeEmpty),
            asString=True)('ImplicitComment')
        self.implicit_comment.addParseAction(remove_trailing_newlines)

        # String definition
        self.string_def = (pp.Suppress(string_def_start) + in_braces_or_pars(
            string_name +
            pp.Suppress('=') +
            string_expr('StringValue')
            ))('StringDefinition')

        # Preamble declaration
        self.preamble_decl = (pp.Suppress(preamble_start) +
                              in_braces_or_pars(value))('PreambleDeclaration')

        # Main bibtex expression

        self.main_expression = pp.ZeroOrMore(
                self.string_def |
                self.preamble_decl |
                self.explicit_comment |
                self.entry |
                self.implicit_comment)