From 79ee98a4ddc6972b75296ffda6b0db091c7cbd3f Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Fri, 30 Jun 2017 11:28:54 +0200 Subject: [PATCH] Infer the object ID from its TL definition when not given --- telethon_generator/parser/tl_object.py | 58 +++++++++++++++++++++----- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/telethon_generator/parser/tl_object.py b/telethon_generator/parser/tl_object.py index 3d83d192c..57cc341d2 100644 --- a/telethon_generator/parser/tl_object.py +++ b/telethon_generator/parser/tl_object.py @@ -1,4 +1,5 @@ import re +from zlib import crc32 class TLObject: @@ -24,12 +25,18 @@ def __init__(self, fullname, object_id, args, result, is_function): self.namespace = None self.name = fullname - # The ID should be an hexadecimal string - self.id = int(object_id, base=16) self.args = args self.result = result self.is_function = is_function + # The ID should be an hexadecimal string or None to be inferred + if object_id is None: + self.id = self.infer_id() + else: + self.id = int(object_id, base=16) + assert self.id == self.infer_id(),\ + 'Invalid inferred ID for ' + repr(self) + @staticmethod def from_tl(tl, is_function): """Returns a TL object from the given TL scheme line""" @@ -38,8 +45,10 @@ def from_tl(tl, is_function): match = re.match(r''' ^ # We want to match from the beginning to the end ([\w.]+) # The .tl object can contain alpha_name or namespace.alpha_name - \# # After the name, comes the ID of the object - ([0-9a-f]+) # The constructor ID is in hexadecimal form + (?: + \# # After the name, comes the ID of the object + ([0-9a-f]+) # The constructor ID is in hexadecimal form + )? # If no constructor ID was given, CRC32 the 'tl' to determine it (?:\s # After that, we want to match its arguments (name:type) {? # For handling the start of the '{X:Type}' case @@ -91,16 +100,39 @@ def is_core_type(self): (and thus should be embedded in the generated code) or not""" return self.id in TLObject.CORE_TYPES - def __repr__(self): + def __repr__(self, ignore_id=False): fullname = ('{}.{}'.format(self.namespace, self.name) if self.namespace is not None else self.name) - hex_id = hex(self.id)[2:].rjust(8, - '0') # Skip 0x and add 0's for padding + if getattr(self, 'id', None) is None or ignore_id: + hex_id = '' + else: + # Skip 0x and add 0's for padding + hex_id = '#' + hex(self.id)[2:].rjust(8, '0') + + if self.args: + args = ' ' + ' '.join([repr(arg) for arg in self.args]) + else: + args = '' - return '{}#{} {} = {}'.format( - fullname, hex_id, ' '.join([str(arg) for arg in self.args]), - self.result) + return '{}{}{} = {}'.format(fullname, hex_id, args, self.result) + + def infer_id(self): + representation = self.__repr__(ignore_id=True) + + # Clean the representation + representation = representation\ + .replace(':bytes ', ':string ')\ + .replace('?bytes ', '?string ')\ + .replace('<', ' ').replace('>', '')\ + .replace('{', '').replace('}', '') + + representation = re.sub( + r' \w+:flags\.\d+\?true', + r'', + representation + ) + return crc32(representation.encode('ascii')) def __str__(self): fullname = ('{}.{}'.format(self.namespace, self.name) @@ -214,3 +246,9 @@ def __str__(self): return '{{{}:{}}}'.format(self.name, real_type) else: return '{}:{}'.format(self.name, real_type) + + def __repr__(self): + # Get rid of our special type + return str(self)\ + .replace(':date', ':int')\ + .replace('?date', '?int')