def parse_dtype_line()

in tools/scraper/parser.py [0:0]


    def parse_dtype_line(self, _dtype, _line):
        """
        Figure out the fields for the described type.
        The line format is:

        Transfers are handled specially with the ill-formatted binary delivery-tag field
        Note other performatives with ill-formatted binary data might get rejected. We
        only struggle figuring out the delivery-tag because it happens so often.
        :param _dtype: @describedtypename(num)
        :param _line: [key=val [, key=val]...]
        :return:
        """
        self.dtype = _dtype
        self.line = str(_line)
        self.dtype_name = DescribedType.dtype_name(self.dtype)
        self.dtype_number = DescribedType.dtype_number(self.dtype)

        # Process transfers separately..
        # Transfer perfomatives will not call parse recursively while others might
        if self.dtype_name == "transfer":
            self.parseTransfer()
            return

        # strip leading '[' and trailing ']'
        if not (self.line.startswith('[') and self.line.endswith(']')):
            raise ValueError("Described type not delimited with square brackets: '%s'" % _line)
        self.line = self.line[1:]
        self.line = self.line[:-1]

        # process fields
        fields = proton_split(self.line)
        while len(fields) > 0 and len(fields[0]) > 0:
            if '=' not in fields[0]:
                raise ValueError("Field does not contain equal sign '%s'" % fields[0])
            key, val = DescribedType.get_key_and_val(fields[0])
            # New proton logging uses hex strings. Convert to decimal strings.
            if val.startswith("0x"):
                val = str(int(val, 0))
            del fields[0]
            if DescribedType.is_dtype_name(val):
                # recursing to process subtype
                # pull subtype's data out of fields. The fields list belongs to parent.
                subfields = []
                if fields[0] == "[]":
                    # degenerate case of empty subtype closing parent type
                    #  @disposition .. state=@accepted(36) []]
                    subfields.append("[]")
                    del fields[0]
                else:
                    # While extracting this type's fields, include nested described types
                    # and PN_SYMBOL data enclosed in brackets. Current type ends when close
                    # bracket seen and nest level is zero.
                    nest = 0
                    while len(fields) > 0:
                        if "=@" in fields[0] and "]" not in fields[0] and "=@:" not in fields[0]:
                            nest += 1
                        if nest == 0:
                            if fields[0].endswith('],'):
                                subfields.append(fields[0][:-2])
                                subfields.append(']')
                                del fields[0]
                                break
                            if fields[0].endswith(']'):
                                subfields.append(fields[0][:-1])
                                subfields.append(']')
                                del fields[0]
                                break
                        elif fields[0].endswith('],') or fields[0].endswith(']'):
                            nest -= 1
                        if fields[0].endswith(']]'):
                            subfields.append(fields[0])
                            del fields[0]
                            break
                        subfields.append(fields[0])
                        del fields[0]

                subtype = DescribedType()
                subtype.parse_dtype_line(val, ' '.join(subfields))
                self.dict[key] = subtype
            elif val.startswith("@PN_SYMBOL"):
                # symbols may end in first field or some later field
                while not val.endswith(']'):
                    val += fields[0]
                    del fields[0]
                self.dict[key] = val
            elif val.startswith('{'):
                # handle some embedded map: properties={:product=\"qpid-dispatch-router\", :version=\"1.3.0-SNAPSHOT\"}
                # pull subtype's data out of fields. The fields list belongs to parent.
                submap = {}
                fields.insert(0, val)
                skey, sval = DescribedType.get_key_and_val(fields[0][1:])
                submap[skey] = sval
                del fields[0]
                while len(fields) > 0:
                    if fields[0].endswith('},'):
                        skey, sval = DescribedType.get_key_and_val(fields[0][:-2])
                        submap[skey] = sval
                        del fields[0]
                        break
                    if fields[0].endswith('}'):
                        skey, sval = DescribedType.get_key_and_val(fields[0][:-1])
                        submap[skey] = sval
                        del fields[0]
                        break
                    skey, sval = DescribedType.get_key_and_val(fields[0])
                    submap[skey] = sval
                    del fields[0]
                self.dict[key] = submap

            else:
                self.dict[key] = val