Esempio n. 1
0
    def parse(file_contents, filename='') -> "List of Property objects":
        """Returns list of Property objects parsed from given text"""
        open_properties = [Property(None, [])]

        for line_num, line in enumerate(file_contents, start=1):
            values = open_properties[-1].value
            freshline = utils.clean_line(line)
            if not freshline:
                # Skip blank lines!
                continue

            if freshline.startswith('"'):   # data string
                line_contents = freshline.split('"')
                name = line_contents[1]
                if not utils.is_identifier(name):
                    raise KeyValError(
                        'Invalid name ' + name + '!',
                        filename,
                        line_num,
                        )
                try:
                    value = line_contents[3]
                    if not freshline.endswith('"'):
                        raise KeyValError(
                            'Key has value, but incomplete quotes!',
                            filename,
                            line_num,
                            )
                    for orig, new in REPLACE_CHARS.items():
                        value = value.replace(orig, new)
                except IndexError:
                    value = None

                values.append(Property(name, value))
            # handle name bare on one line, will need a brace on
            # the next line
            elif utils.is_identifier(freshline):
                values.append(Property(freshline, []))
            elif freshline.startswith('{'):
                if values[-1].value:
                    raise KeyValError(
                        'Property cannot have sub-section if it already'
                        'has an in-line value.',
                        filename,
                        line_num,
                        )
                values[-1].value = []
                open_properties.append(values[-1])
            elif freshline.startswith('}'):
                open_properties.pop()
            else:
                raise KeyValError(
                    "Unexpected beginning character '"
                    + freshline[0]
                    + '"!',
                    filename,
                    line_num,
                    )

            if not open_properties:
                raise KeyValError(
                    'Too many closing brackets.',
                    filename,
                    line_num,
                    )
        if len(open_properties) > 1:
            raise KeyValError(
                'End of text reached with remaining open sections.',
                filename,
                line=None,
                )
        return open_properties[0]
Esempio n. 2
0
    def parse(file_contents, filename='') -> "Property":
        """Returns a Property tree parsed from given text.

        filename, if set should be the source of the text for debug purposes.
        file_contents should be an iterable of strings
        """
        from utils import is_identifier

        file_iter = enumerate(file_contents, start=1)

        # The block we are currently adding to.

        # The special name 'None' marks it as the root property, which
        # just outputs its children when exported. This way we can handle
        # multiple root blocks in the file, while still returning a single
        # Property object which has all the methods.
        cur_block = Property(None, [])

        # A queue of the properties we are currently in (outside to inside).
        open_properties = [cur_block]
        for line_num, line in file_iter:
            if isinstance(line, bytes):
                # Decode bytes using utf-8
                line = line.decode('utf-8')
            freshline = line.strip()

            if not freshline or freshline[:2] == '//':
                # Skip blank lines and comments!
                continue

            if freshline.startswith('"'):   # data string
                line_contents = freshline.split('"')
                name = line_contents[1]
                try:
                    value = line_contents[3]
                except IndexError:  # It doesn't have a value, likely a block
                    value = None
                else:
                    # Special case - comment between name/value sections -
                    # it's a name block then.
                    if line_contents[2].lstrip().startswith('//'):
                        value = None
                        del line_contents[3:]
                    else:
                        if len(line_contents) < 5:
                            # It's a multiline value - no ending quote!
                            value += read_multiline_value(
                                file_iter,
                                line_num,
                                filename,
                            )
                        if value and '\\' in value:
                            for orig, new in REPLACE_CHARS.items():
                                value = value.replace(orig, new)
                # Line_contents[4] is the start of the comment, ensure that it's
                # blank or starts with a comment.
                if len(line_contents) >= 5:
                    comment = line_contents[4].lstrip()
                    # same as: not (comment or comment.startswith('//'))
                    if comment and not comment.startswith('//'):
                        raise KeyValError(
                            'Extra text after '
                            'line: "{}"'.format(line_contents[4]),
                            filename,
                            line_num,
                        )

                cur_block.append(Property(name, value))
            elif freshline.startswith('{'):
                # Open a new block.
                # If we're expecting a block, the value will be None.
                if cur_block[-1].value is not None:
                    raise KeyValError(
                        'Property cannot have sub-section if it already'
                        'has an in-line value.',
                        filename,
                        line_num,
                    )
                cur_block = cur_block[-1]
                cur_block.value = []
                open_properties.append(cur_block)
            elif freshline.startswith('}'):
                # Move back a block
                open_properties.pop()
                cur_block = open_properties[-1].value

            # handle name bare on one line, will need a brace on
            # the next line
            elif is_identifier(freshline):
                cur_block.append(Property(freshline, None))
            else:
                raise KeyValError(
                    "Unexpected beginning character '"
                    + freshline[0]
                    + '"!',
                    filename,
                    line_num,
                )

            if not open_properties:
                raise KeyValError(
                    'Too many closing brackets.',
                    filename,
                    line_num,
                )
        if len(open_properties) > 1:
            raise KeyValError(
                'End of text reached with remaining open sections.',
                filename,
                line=None,
            )
        return open_properties[0]
Esempio n. 3
0
    def parse(file_contents, filename='') -> "Property":
        """Returns a Property tree parsed from given text.

        filename, if set should be the source of the text for debug purposes.
        file_contents should be an iterable of strings
        """
        open_properties = [Property(None, [])]
        for line_num, line in enumerate(file_contents, start=1):
            values = open_properties[-1].value
            freshline = utils.clean_line(line)
            if not freshline:
                # Skip blank lines!
                continue

            if freshline.startswith('"'):   # data string
                line_contents = freshline.split('"')
                name = line_contents[1]
                if not utils.is_identifier(name):
                    raise KeyValError(
                        'Invalid name ' + name + '!',
                        filename,
                        line_num,
                        )
                try:
                    value = line_contents[3]
                    if not freshline.endswith('"'):
                        raise KeyValError(
                            'Key has value, but incomplete quotes!',
                            filename,
                            line_num,
                            )
                    for orig, new in REPLACE_CHARS.items():
                        value = value.replace(orig, new)
                except IndexError:
                    value = None

                values.append(Property(name, value))
            elif freshline.startswith('{'):
                if values[-1].value:
                    raise KeyValError(
                        'Property cannot have sub-section if it already'
                        'has an in-line value.',
                        filename,
                        line_num,
                        )
                values[-1].value = []
                open_properties.append(values[-1])
            elif freshline.startswith('}'):
                open_properties.pop()
            # handle name bare on one line, will need a brace on
            # the next line
            elif utils.is_identifier(freshline):
                values.append(Property(freshline, []))
            else:
                raise KeyValError(
                    "Unexpected beginning character '"
                    + freshline[0]
                    + '"!',
                    filename,
                    line_num,
                    )

            if not open_properties:
                raise KeyValError(
                    'Too many closing brackets.',
                    filename,
                    line_num,
                    )
        if len(open_properties) > 1:
            raise KeyValError(
                'End of text reached with remaining open sections.',
                filename,
                line=None,
                )
        return open_properties[0]