generate_tl.py 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682
  1. # This file is part of Desktop App Toolkit,
  2. # a set of libraries for developing nice desktop applications.
  3. #
  4. # For license and copyright information please follow this link:
  5. # https://github.com/desktop-app/legal/blob/master/LEGAL
  6. import glob, re, binascii, os, sys
  7. from pprint import pprint
  8. def readInputs(inputFiles):
  9. lines = []
  10. names = []
  11. layer = 0
  12. for inputFile in inputFiles:
  13. names.append(os.path.basename(inputFile))
  14. lines.append('---types---')
  15. with open(inputFile, encoding="utf-8") as f:
  16. for line in f:
  17. layerline = re.match(r'// LAYER (\d+)', line)
  18. if (layerline):
  19. layer = int(layerline.group(1))
  20. else:
  21. lines.append(line)
  22. return lines, layer, names
  23. # text serialization: types and funcs
  24. def addTextSerialize(typeList, typeData, typesDict, idPrefix, primeType, boxed, prefix):
  25. result = ''
  26. for restype in typeList:
  27. v = typeData[restype]
  28. for data in v:
  29. name = data[0]
  30. prmsList = data[2]
  31. prms = data[3]
  32. hasFlags = data[4]
  33. hasFlags64 = data[5]
  34. conditionsList = data[6]
  35. conditions = data[7]
  36. trivialConditions = data[8]
  37. isTemplate = data[9]
  38. flagRawType = 'uint64' if hasFlags64 != '' else 'uint32'
  39. templateArgument = ''
  40. if (isTemplate != ''):
  41. templateArgument = '<SerializedRequest>'
  42. result += 'bool Serialize_' + name + '(DumpToTextBuffer &to, int32 stage, int32 lev, Types &types, Types &vtypes, Stages &stages, Flags &flags, const ' + primeType + ' *start, const ' + primeType + ' *end, uint64 iflag) {\n'
  43. if (len(conditions)):
  44. result += '\tauto flag = ' + prefix + name + templateArgument + '::Flags::from_raw(' + flagRawType + '(iflag));\n\n'
  45. if (len(prms)):
  46. result += '\tif (stage) {\n'
  47. result += '\t\tto.add(",\\n").addSpaces(lev);\n'
  48. result += '\t} else {\n'
  49. result += '\t\tto.add("{ ' + name + '");\n'
  50. result += '\t\tto.add("\\n").addSpaces(lev);\n'
  51. result += '\t}\n'
  52. result += '\tswitch (stage) {\n'
  53. stage = 0
  54. for k in prmsList:
  55. v = prms[k]
  56. result += '\tcase ' + str(stage) + ': to.add(" ' + k + ': "); ++stages.back(); '
  57. if (k == hasFlags):
  58. if (hasFlags64 != ''):
  59. result += 'if (start + 1 >= end) return false; else flags.back() = int64(*start) + (int64(*(start + 1)) << 32); '
  60. else:
  61. result += 'if (start >= end) return false; else flags.back() = *start; '
  62. if (k in trivialConditions):
  63. flagBitValue = int(conditions[k])
  64. flagFieldName = hasFlags64 if flagBitValue >= 32 else hasFlags
  65. flagBitLogged = (flagBitValue - 32) if flagBitValue >= 32 else flagBitValue
  66. result += 'if (flag & ' + prefix + name + templateArgument + '::Flag::f_' + k + ') { '
  67. result += 'to.add("YES [ BY BIT ' + str(flagBitLogged) + ' IN FIELD ' + flagFieldName + ' ]"); '
  68. result += '} else { to.add("[ SKIPPED BY BIT ' + str(flagBitLogged) + ' IN FIELD ' + flagFieldName + ' ]"); } '
  69. else:
  70. if (k in conditions):
  71. result += 'if (flag & ' + prefix + name + templateArgument + '::Flag::f_' + k + ') { '
  72. result += 'types.push_back('
  73. vtypeget = re.match(r'^[Vv]ector<MTP([A-Za-z0-9\._]+)>', v)
  74. if (vtypeget):
  75. if (not re.match(r'^[A-Z]', v)):
  76. result += idPrefix + 'vector'
  77. else:
  78. result += '0'
  79. restype = vtypeget.group(1)
  80. try:
  81. if boxed[restype]:
  82. restype = 0
  83. except KeyError:
  84. if re.match(r'^[A-Z]', restype):
  85. restype = 0
  86. else:
  87. restype = v
  88. try:
  89. if boxed[restype]:
  90. restype = 0
  91. except KeyError:
  92. if re.match(r'^[A-Z]', restype):
  93. restype = 0
  94. if (restype):
  95. try:
  96. conses = typesDict[restype]
  97. if (len(conses) > 1):
  98. print('Complex bare type found: "' + restype + '" trying to serialize "' + k + '" of type "' + v + '"')
  99. continue
  100. if (vtypeget):
  101. result += '); vtypes.push_back('
  102. result += idPrefix + conses[0][0]
  103. if (not vtypeget):
  104. result += '); vtypes.push_back(0'
  105. except KeyError:
  106. if (vtypeget):
  107. result += '); vtypes.push_back('
  108. if (re.match(r'^flags<', restype)):
  109. result += idPrefix + 'flags'
  110. if (k == hasFlags):
  111. if (hasFlags64 != ''):
  112. result += '64'
  113. else:
  114. result += idPrefix + restype + '+0'
  115. if (not vtypeget):
  116. result += '); vtypes.push_back(0'
  117. else:
  118. if (not vtypeget):
  119. result += '0'
  120. result += '); vtypes.push_back(0'
  121. result += '); stages.push_back(0); flags.push_back(0); '
  122. if (k in conditions):
  123. flagBitValue = int(conditions[k])
  124. flagFieldName = hasFlags64 if flagBitValue >= 32 else hasFlags
  125. flagBitLogged = (flagBitValue - 32) if flagBitValue >= 32 else flagBitValue
  126. result += '} else { to.add("[ SKIPPED BY BIT ' + str(flagBitLogged) + ' IN FIELD ' + flagFieldName + ' ]"); } '
  127. result += 'break;\n'
  128. stage = stage + 1
  129. result += '\tdefault: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;\n'
  130. result += '\t}\n'
  131. else:
  132. result += '\tto.add("{ ' + name + ' }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();\n'
  133. result += '\treturn true;\n'
  134. result += '}\n\n'
  135. return result
  136. # text serialization: types and funcs
  137. def addTextSerializeInit(typeList, typeData, idPrefix):
  138. result = ''
  139. for restype in typeList:
  140. v = typeData[restype]
  141. for data in v:
  142. name = data[0]
  143. result += '\t\t{ ' + idPrefix + name + ', Serialize_' + name + ' },\n'
  144. return result
  145. def generate(scheme):
  146. inputFiles = []
  147. outputPath = ''
  148. nextOutputPath = False
  149. for arg in sys.argv[1:]:
  150. if nextOutputPath:
  151. nextOutputPath = False
  152. outputPath = arg
  153. elif arg == '-o':
  154. nextOutputPath = True
  155. elif re.match(r'^-o(.+)', arg):
  156. outputPath = arg[2:]
  157. else:
  158. inputFiles.append(arg)
  159. if len(inputFiles) == 0:
  160. raise ValueError('Input file required.')
  161. if outputPath == '':
  162. raise ValueError('Output path required.')
  163. readAndGenerate(inputFiles, outputPath, scheme)
  164. def endsWithForTag(comments, tag, ending):
  165. position = comments.find('@' + tag + ' ')
  166. if (position < 0):
  167. return False
  168. tail = comments[(position + len(tag) + 1):]
  169. till = tail.find('@')
  170. line = tail[:till] if till >= 0 else tail
  171. stripped = line.strip()
  172. fullending = '; ' + ending.strip()
  173. if len(stripped) < len(fullending):
  174. return False
  175. if stripped.endswith(fullending) or stripped.find(fullending + '.') >= 0 or stripped.find(fullending + ';') >= 0 or stripped.find(fullending + ' if') >= 0 or stripped.find(fullending + ' to') >= 0 or stripped.find(fullending + ' otherwise') >= 0 or stripped.find(fullending + ' unless') >= 0 or stripped.find(fullending + ' even') >= 0 or stripped.find(fullending + ' for') >= 0:
  176. return True
  177. if line.find(ending) >= 0:
  178. print('WARNING: Found "' + ending + '" in "' + stripped + '"')
  179. return False
  180. def paramNameTag(name):
  181. return 'param_description' if name == 'description' else name
  182. def isBotsOnlyLine(comments):
  183. return endsWithForTag(comments, 'description', 'for bots only')
  184. def isBotsOnlyParam(comments, name):
  185. return endsWithForTag(comments, paramNameTag(name), 'for bots only')
  186. def isNullableVector(comments, name):
  187. return name.endswith('s') and endsWithForTag(comments, paramNameTag(name), name + ' may be null')
  188. def isNullableParam(comments, name):
  189. return endsWithForTag(comments, paramNameTag(name), 'may be null') or endsWithForTag(comments, paramNameTag(name), 'pass null')
  190. def readAndGenerate(inputFiles, outputPath, scheme):
  191. outputHeader = outputPath + '.h'
  192. outputSource = outputPath + '.cpp'
  193. outputConversionHeaderFrom = outputPath + '-conversion-from.h'
  194. outputConversionSourceFrom = outputPath + '-conversion-from.cpp'
  195. outputConversionHeaderTo = outputPath + '-conversion-to.h'
  196. outputConversionSourceTo = outputPath + '-conversion-to.cpp'
  197. outputSerializationHeader = outputPath + '-dump_to_text.h'
  198. outputSerializationSource = outputPath + '-dump_to_text.cpp'
  199. outputHeaderBasename = os.path.basename(outputHeader)
  200. outputConversionHeaderFromBasename = os.path.basename(outputConversionHeaderFrom)
  201. outputConversionHeaderToBasename = os.path.basename(outputConversionHeaderTo)
  202. outputSerializationHeaderBasename = os.path.basename(outputSerializationHeader)
  203. prefixes = scheme.get('prefixes', {})
  204. dataPrefix = prefixes.get('data', '')
  205. typePrefix = prefixes.get('type', '')
  206. idPrefix = prefixes.get('id') + '_'
  207. constructPrefix = prefixes.get('construct')
  208. def normalizedName(name):
  209. return name.replace('.', '_')
  210. def normalizedBareName(name):
  211. full = re.match(r'^([a-zA-Z0-9])+\.([A-Z][a-zA-Z0-9]+)$', name)
  212. if (full):
  213. return full.group(1) + '_' + full.group(2)[0:1].lower() + full.group(2)[1:]
  214. elif name.find('.') >= 0:
  215. raise ValueError('Bad name: ' + name)
  216. return name[0:1].lower() + name[1:]
  217. def fullTypeName(name):
  218. return typePrefix + normalizedName(name)
  219. def fullBareTypeName(name):
  220. return typePrefix + normalizedBareName(name)
  221. def fullDataName(name):
  222. return dataPrefix + normalizedName(name)
  223. def optionalInVector(name):
  224. templ = re.match(r'(.*?)([vV]ector<)([A-Za-z0-9_]+)>$', name)
  225. if templ:
  226. return templ.group(1) + templ.group(2) + 'std::optional<' + templ.group(3) + '>>';
  227. else:
  228. raise ValueError('Bad optional vector: ' + name)
  229. def handleTemplate(name, process = fullTypeName):
  230. templ = re.match(r'^([vV]ector<)([A-Za-z0-9\._<>]+)>$', name)
  231. if (templ):
  232. vectemplate = templ.group(2)
  233. if (vectemplate.find('<') >= 0):
  234. return templ.group(1) + process(handleTemplate(vectemplate, process)) + '>'
  235. elif (re.match(r'^[A-Z]', vectemplate) or re.match(r'^[a-zA-Z0-9]+\.[A-Z]', vectemplate)):
  236. return templ.group(1) + process(vectemplate) + '>'
  237. elif (vectemplate in builtinTypes):
  238. return templ.group(1) + process(vectemplate) + '>'
  239. else:
  240. foundmeta = ''
  241. for metatype in typesDict:
  242. for typedata in typesDict[metatype]:
  243. if (typedata[0] == normalizedName(vectemplate)):
  244. foundmeta = metatype
  245. break
  246. if (len(foundmeta) > 0):
  247. break
  248. if (len(foundmeta) > 0):
  249. return templ.group(1) + process(foundmeta) + '>'
  250. else:
  251. raise ValueError('Bad vector param: ' + vectemplate)
  252. else:
  253. raise ValueError('Bad template type: ' + name)
  254. namespaces = scheme.get('namespaces')
  255. globalNamespace = namespaces.get('global', '')
  256. creatorNamespace = namespaces.get('creator', '')
  257. creatorNamespaceFull = (globalNamespace + '::' if creatorNamespace != '' and globalNamespace != '' else globalNamespace) + creatorNamespace
  258. # this is a map (key flags -> map (flag name -> flag bit))
  259. # each key flag of parentFlags should be a subset of the value flag here
  260. parentFlagsCheck = {}
  261. flagInheritance = scheme.get('flagInheritance', {})
  262. typeIdExceptions = scheme.get('typeIdExceptions', [])
  263. renamedTypes = scheme.get('renamedTypes', {})
  264. skipLines = scheme.get('skip', [])
  265. builtinTypes = scheme.get('builtin', [])
  266. builtinTemplateTypes = scheme.get('builtinTemplates', [])
  267. builtinInclude = scheme.get('builtinInclude', '')
  268. nullableTypes = scheme.get('nullable', [])
  269. synonyms = scheme.get('synonyms', {})
  270. writeSections = scheme.get('sections', [])
  271. readWriteSection = 'read-write' in writeSections
  272. primitiveTypeNames = scheme.get('types')
  273. typeIdType = primitiveTypeNames.get('typeId')
  274. primeType = primitiveTypeNames.get('prime', '')
  275. bufferType = primitiveTypeNames.get('buffer', '')
  276. writeConversion = 'conversion' in scheme
  277. optimizeSingleData = 'optimizeSingleData' in scheme
  278. conversionScheme = scheme.get('conversion', {})
  279. conversionInclude = conversionScheme.get('include') if writeConversion else ''
  280. conversionNamespace = conversionScheme.get('namespace') if writeConversion else ''
  281. conversionBuiltinTypes = conversionScheme.get('builtinAdditional', [])
  282. conversionBuiltinIncludeFrom = conversionScheme.get('builtinIncludeFrom', '')
  283. conversionBuiltinIncludeTo = conversionScheme.get('builtinIncludeTo', '')
  284. def conversionName(name):
  285. return '::' + conversionNamespace + '::' + name
  286. def conversionTemplate(name, param):
  287. return conversionName(name) + '<' + conversionName(param) + '>'
  288. def conversionPointer(name):
  289. return conversionTemplate('object_ptr', name)
  290. def conversionMake(name):
  291. return conversionTemplate('make_object', name)
  292. def conversionMove(name):
  293. return conversionTemplate('move_object_as', name)
  294. writeSerialization = 'dumpToText' in scheme
  295. serializationScheme = scheme.get('dumpToText', {})
  296. serializationInclude = serializationScheme.get('include') if writeSerialization else ''
  297. if primeType == '' or bufferType == '':
  298. if readWriteSection or writeSerialization:
  299. raise ValueError('Required types not provided.')
  300. def isBuiltinType(name):
  301. return name in builtinTypes or name in builtinTemplateTypes
  302. funcs = 0
  303. types = 0
  304. consts = 0
  305. funcsNow = 0
  306. enums = []
  307. funcsDict = {}
  308. funcsList = []
  309. typesDict = {}
  310. TypesDict = {}
  311. typesList = []
  312. TypeConstructors = {}
  313. boxed = {}
  314. funcsText = ''
  315. typesText = ''
  316. dataTexts = ''
  317. creatorProxyText = ''
  318. factories = ''
  319. flagOperators = ''
  320. methods = ''
  321. inlineMethods = ''
  322. visitorMethods = ''
  323. textSerializeInit = ''
  324. textSerializeMethods = ''
  325. forwards = ''
  326. forwTypedefs = ''
  327. conversionHeaderFrom = ''
  328. conversionHeaderTo = ''
  329. conversionSourceFrom = ''
  330. conversionSourceTo = ''
  331. accumulatedComments = ''
  332. lines, layer, names = readInputs(inputFiles)
  333. inputNames = '\'' + '\', \''.join(names) + '\''
  334. for line in lines:
  335. comment = ''
  336. nocomment = re.match(r'^(.*?)//(.*?)$', line)
  337. if (nocomment):
  338. line = nocomment.group(1)
  339. comment = nocomment.group(2)
  340. if (re.match(r'\-\-\-functions\-\-\-', line)):
  341. funcsNow = 1
  342. continue
  343. if (re.match(r'\-\-\-types\-\-\-', line)):
  344. funcsNow = 0
  345. continue
  346. if (re.match(r'^\s*$', line)):
  347. if not nocomment:
  348. accumulatedComments = ''
  349. elif comment != '':
  350. accumulatedComments += ' ' + comment
  351. continue
  352. if line.strip() in skipLines:
  353. continue
  354. nametype = re.match(r'([a-zA-Z\.0-9_]+)(#[0-9a-f]+)?([^=]*)=\s*([a-zA-Z\.<>0-9_]+);', line)
  355. if (not nametype):
  356. raise ValueError('Bad line found: ' + line)
  357. comments = accumulatedComments
  358. accumulatedComments = ''
  359. if isBotsOnlyLine(comments):
  360. continue
  361. originalname = nametype.group(1)
  362. name = originalname
  363. if (name in renamedTypes):
  364. name = renamedTypes[name]
  365. nameInd = name.rfind('.')
  366. if (nameInd >= 0):
  367. Name = name[0:nameInd] + '_' + name[nameInd + 1:nameInd + 2].upper() + name[nameInd + 2:]
  368. name = normalizedName(name)
  369. else:
  370. Name = name[0:1].upper() + name[1:]
  371. typeid = nametype.group(2)
  372. if (typeid and len(typeid) > 0):
  373. typeid = typeid[1:]; # Skip '#'
  374. while (typeid and len(typeid) > 0 and typeid[0] == '0'):
  375. typeid = typeid[1:]
  376. cleanline = nametype.group(1) + nametype.group(3) + '= ' + nametype.group(4)
  377. cleanline = re.sub(r' [a-zA-Z0-9_]+\:flags2?\.[0-9]+\?true', '', cleanline)
  378. cleanline = cleanline.replace('<', ' ').replace('>', ' ').replace(' ', ' ')
  379. cleanline = re.sub(r'^ ', '', cleanline)
  380. cleanline = re.sub(r' $', '', cleanline)
  381. for synonym in synonyms:
  382. synonymOf = synonyms[synonym]
  383. cleanline = cleanline.replace(':' + synonym + ' ', ':' + synonymOf + ' ')
  384. cleanline = cleanline.replace('?' + synonym + ' ', '?' + synonymOf + ' ')
  385. cleanline = cleanline.replace('{', '')
  386. cleanline = cleanline.replace('}', '')
  387. countTypeId = binascii.crc32(binascii.a2b_qp(cleanline))
  388. if (countTypeId < 0):
  389. countTypeId += 2 ** 32
  390. countTypeId = re.sub(r'^0x|L$', '', hex(countTypeId))
  391. if (typeid and len(typeid) > 0):
  392. typeid = typeid
  393. if (typeid != countTypeId):
  394. key = originalname + '#' + typeid
  395. if (not key in typeIdExceptions):
  396. print('Warning: counted ' + countTypeId + ' mismatch with provided ' + typeid + ' (' + key + ', ' + cleanline + ')')
  397. continue
  398. else:
  399. typeid = countTypeId
  400. typeid = '0x' + typeid
  401. params = nametype.group(3)
  402. restype = nametype.group(4)
  403. if (restype.find('<') >= 0):
  404. restype = handleTemplate(restype)
  405. resType = normalizedName(restype)
  406. if (restype.find('.') >= 0):
  407. parts = re.match(r'([a-zA-Z0-9\.]+)\.([A-Z][A-Za-z0-9<>_]+)', restype)
  408. if (parts):
  409. restype = parts.group(1).replace('.', '_') + '_' + parts.group(2)[0:1].lower() + parts.group(2)[1:]
  410. else:
  411. raise ValueError('Bad result type name with dot: ' + restype)
  412. else:
  413. if (re.match(r'^[A-Z]', restype)):
  414. restype = restype[:1].lower() + restype[1:]
  415. else:
  416. raise ValueError('Bad result type name: ' + restype)
  417. boxed[resType] = restype
  418. boxed[Name] = name
  419. enums.append('\t' + idPrefix + name + ' = ' + typeid)
  420. paramsList = params.strip().split(' ')
  421. prms = {}
  422. conditions = {}
  423. trivialConditions = {} # true type
  424. nullablePrms = {}
  425. nullableVectors = {}
  426. botsOnlyPrms = {}
  427. prmsList = []
  428. conditionsList = []
  429. isTemplate = hasFlags = hasFlags64 = hasTemplate = ''
  430. for param in paramsList:
  431. if (re.match(r'^\s*$', param)):
  432. continue
  433. templ = re.match(r'^{([A-Za-z]+):Type}$', param)
  434. if (templ):
  435. hasTemplate = templ.group(1)
  436. continue
  437. pnametype = re.match(r'([a-zA-Z_][a-zA-Z0-9_]*):([A-Za-z0-9<>\._]+|![a-zA-Z]+|\#|[a-z_][a-z0-9_]*\.[0-9]+\?[A-Za-z0-9<>\._]+)$', param)
  438. if (not pnametype):
  439. raise ValueError('Bad param found: "' + param + '" in line: ' + line)
  440. pname = pnametype.group(1)
  441. ptypewide = pnametype.group(2)
  442. botsOnlyPrm = isBotsOnlyParam(comments, pname)
  443. nullableVector = not botsOnlyPrm and isNullableVector(comments, pname)
  444. nullablePrm = not botsOnlyPrm and not nullableVector and isNullableParam(comments, pname)
  445. if (re.match(r'^!([a-zA-Z]+)$', ptypewide)):
  446. if ('!' + hasTemplate == ptypewide):
  447. isTemplate = pname
  448. ptype = 'TQueryType'
  449. else:
  450. raise ValueError('Bad template param name: "' + param + '" in line: ' + line)
  451. if nullablePrm or nullableVector:
  452. raise ValueError('Template param should not be nullable: "' + param + '" in line: ' + line + ', comments: ' + comments)
  453. elif (ptypewide == '#'):
  454. if hasFlags != '' and pname == hasFlags + '2':
  455. hasFlags64 = pname
  456. continue
  457. hasFlags = pname
  458. if funcsNow:
  459. ptype = 'flags<' + fullTypeName(name) + '::Flags>'
  460. else:
  461. ptype = 'flags<' + fullDataName(name) + '::Flags>'
  462. if nullablePrm or nullableVector:
  463. raise ValueError('Flags param should not be nullable: "' + param + '" in line: ' + line + ', comments: ' + comments)
  464. else:
  465. ptype = ptypewide
  466. if botsOnlyPrm:
  467. botsOnlyPrms[pname] = 1
  468. if (ptype.find('?') >= 0):
  469. pmasktype = re.match(r'([a-z_][a-z0-9_]*)\.([0-9]+)\?([A-Za-z0-9<>\._]+)', ptype)
  470. if not pmasktype:
  471. raise ValueError('Bad param found: "' + param + '" in line: ' + line)
  472. flagsName = pmasktype.group(1)
  473. if flagsName != hasFlags and flagsName != hasFlags64:
  474. raise ValueError('Bad param found: "' + param + '" in line: ' + line)
  475. if nullablePrm or nullableVector:
  476. raise ValueError('Conditional param should not be nullable: "' + param + '" in line: ' + line + ', comments: ' + comments)
  477. ptype = pmasktype.group(3)
  478. if (ptype.find('<') >= 0):
  479. if not readWriteSection:
  480. ptype = handleTemplate(ptype, fullBareTypeName)
  481. else:
  482. ptype = handleTemplate(ptype)
  483. if (not pname in conditions):
  484. conditionsList.append(pname)
  485. if flagsName == hasFlags64:
  486. conditions[pname] = str(int(pmasktype.group(2)) + 32)
  487. else:
  488. conditions[pname] = pmasktype.group(2)
  489. if (ptype == 'true'):
  490. trivialConditions[pname] = flagsName
  491. elif (ptype.find('<') >= 0):
  492. if nullablePrm:
  493. raise ValueError('Vector param should not be nullable: "' + param + '" in line: ' + line + ', comments: ' + comments)
  494. if nullableVector:
  495. nullableVectors[pname] = 1
  496. if not readWriteSection:
  497. ptype = handleTemplate(ptype, fullBareTypeName)
  498. else:
  499. ptype = handleTemplate(ptype)
  500. elif nullableVector:
  501. raise ValueError('Non-vector param should not be vector-nullable: "' + param + '" in line: ' + line + ', comments: ' + comments)
  502. elif nullablePrm:
  503. nullablePrms[pname] = 1
  504. prmsList.append(pname)
  505. if not readWriteSection:
  506. normalizedType = normalizedBareName(ptype)
  507. else:
  508. normalizedType = normalizedName(ptype)
  509. if (normalizedType in TypeConstructors):
  510. prms[pname] = TypeConstructors[normalizedType]['typeBare']
  511. else:
  512. prms[pname] = normalizedType
  513. if (isTemplate == '' and resType == 'X'):
  514. raise ValueError('Bad response type "X" in "' + name +'" in line: ' + line)
  515. if funcsNow:
  516. methodBodies = ''
  517. if (isTemplate != ''):
  518. funcsText += '\ntemplate <typename TQueryType>'
  519. funcsText += '\nclass ' + fullTypeName(name) + ' { // RPC method \'' + nametype.group(1) + '\'\n'; # class
  520. funcsText += 'public:\n'
  521. prmsStr = []
  522. prmsInit = []
  523. prmsNames = []
  524. if hasFlags != '':
  525. flagsType = 'uint64' if hasFlags64 != '' else 'uint32'
  526. flagsBit = '1ULL' if hasFlags64 != '' else '1U'
  527. funcsText += '\tenum class Flag : ' + flagsType + ' {\n'
  528. maxbit = 0
  529. parentFlagsCheck[fullTypeName(name)] = {}
  530. for paramName in conditionsList:
  531. funcsText += '\t\tf_' + paramName + ' = (' + flagsBit + ' << ' + conditions[paramName] + '),\n'
  532. parentFlagsCheck[fullTypeName(name)][paramName] = conditions[paramName]
  533. maxbit = max(maxbit, int(conditions[paramName]))
  534. if (maxbit > 0):
  535. funcsText += '\n'
  536. funcsText += '\t\tMAX_FIELD = (' + flagsBit + ' << ' + str(maxbit) + '),\n'
  537. funcsText += '\t};\n'
  538. funcsText += '\tusing Flags = base::flags<Flag>;\n'
  539. funcsText += '\tfriend inline constexpr bool is_flag_type(Flag) { return true; };\n'
  540. funcsText += '\n'
  541. if (len(prms) > len(trivialConditions) + len(botsOnlyPrms)):
  542. for paramName in prmsList:
  543. if (paramName in trivialConditions or paramName in botsOnlyPrms):
  544. continue
  545. paramType = prms[paramName]
  546. prmsInit.append('_' + paramName + '(' + paramName + '_)')
  547. prmsNames.append(paramName + '_')
  548. if (paramName == isTemplate):
  549. ptypeFull = paramType
  550. else:
  551. ptypeFull = fullTypeName(paramType)
  552. if (paramType in ['int', 'Int', 'bool', 'Bool', 'flags<Flags>', 'long', 'int32', 'int53', 'int64', 'double']):
  553. prmsStr.append(ptypeFull + ' ' + paramName + '_')
  554. elif paramName in nullableVectors:
  555. prmsStr.append('const ' + optionalInVector(ptypeFull) + ' &' + paramName + '_')
  556. elif paramName in nullablePrms:
  557. prmsStr.append('const std::optional<' + ptypeFull + '> &' + paramName + '_')
  558. else:
  559. prmsStr.append('const ' + ptypeFull + ' &' + paramName + '_')
  560. funcsText += '\t' + fullTypeName(name) + '();\n';# = default; # constructor
  561. if (isTemplate != ''):
  562. methodBodies += 'template <typename TQueryType>\n'
  563. methodBodies += fullTypeName(name) + '<TQueryType>::' + fullTypeName(name) + '() = default;\n'
  564. else:
  565. methodBodies += fullTypeName(name) + '::' + fullTypeName(name) + '() = default;\n'
  566. if (len(prms) > len(trivialConditions) + len(botsOnlyPrms)):
  567. explicitText = 'explicit ' if (len(prms) - len(trivialConditions) - len(botsOnlyPrms) == 1) else ''
  568. funcsText += '\t' + explicitText + fullTypeName(name) + '(' + ', '.join(prmsStr) + ');\n'
  569. if (isTemplate != ''):
  570. methodBodies += 'template <typename TQueryType>\n'
  571. methodBodies += fullTypeName(name) + '<TQueryType>::' + fullTypeName(name) + '(' + ', '.join(prmsStr) + ') : ' + ', '.join(prmsInit) + ' {\n}\n'
  572. else:
  573. methodBodies += fullTypeName(name) + '::' + fullTypeName(name) + '(' + ', '.join(prmsStr) + ') : ' + ', '.join(prmsInit) + ' {\n}\n'
  574. funcsText += '\t' + typeIdType + ' type() const {\n\t\treturn ' + idPrefix + name + ';\n\t}\n'; # type id
  575. if readWriteSection:
  576. funcsText += '\n'
  577. funcsText += '\ttemplate <typename Prime>\n'
  578. funcsText += '\t[[nodiscard]] bool read(const Prime *&from, const Prime *end, ' + typeIdType + ' cons = ' + idPrefix + name + ');\n'; # read method
  579. if (isTemplate != ''):
  580. methodBodies += 'template <typename TQueryType>\n'
  581. methodBodies += 'template <typename Prime>\n'
  582. methodBodies += 'bool ' + fullTypeName(name) + '<TQueryType>::read(const Prime *&from, const Prime *end, ' + typeIdType + ' cons) {\n'
  583. else:
  584. methodBodies += 'template <typename Prime>\n'
  585. methodBodies += 'bool ' + fullTypeName(name) + '::read(const Prime *&from, const Prime *end, ' + typeIdType + ' cons) {\n'
  586. readFunc = ''
  587. for k in prmsList:
  588. v = prms[k]
  589. if k in conditionsList:
  590. if not k in trivialConditions:
  591. readFunc += '\t\t&& ((_' + hasFlags + '.v & Flag::f_' + k + ') ? _' + k + '.read(from, end) : ((_' + k + ' = ' + fullTypeName(v) + '()), true))\n'
  592. else:
  593. readFunc += '\t\t&& _' + k + '.read(from, end)\n'
  594. if readFunc != '':
  595. methodBodies += '\treturn' + readFunc[4:len(readFunc)-1] + ';\n'
  596. else:
  597. methodBodies += '\treturn true;\n'
  598. methodBodies += '}\n'
  599. if isTemplate == '':
  600. methodBodies += 'template bool ' + fullTypeName(name) + '::read<' + primeType + '>(const ' + primeType + ' *&from, const ' + primeType + ' *end, ' + typeIdType + ' cons);\n'
  601. funcsText += '\ttemplate <typename Accumulator>\n'
  602. funcsText += '\tvoid write(Accumulator &to) const;\n'; # write method
  603. if (isTemplate != ''):
  604. methodBodies += 'template <typename TQueryType>\n'
  605. methodBodies += 'template <typename Accumulator>\n'
  606. methodBodies += 'void ' + fullTypeName(name) + '<TQueryType>::write(Accumulator &to) const {\n'
  607. else:
  608. methodBodies += 'template <typename Accumulator>\n'
  609. methodBodies += 'void ' + fullTypeName(name) + '::write(Accumulator &to) const {\n'
  610. for k in prmsList:
  611. if k in conditionsList:
  612. if not k in trivialConditions:
  613. methodBodies += '\tif (_' + hasFlags + '.v & Flag::f_' + k + ') _' + k + '.write(to);\n'
  614. else:
  615. methodBodies += '\t_' + k + '.write(to);\n'
  616. methodBodies += '}\n'
  617. if isTemplate == '':
  618. methodBodies += 'template void ' + fullTypeName(name) + '::write<' + bufferType + '>(' + bufferType + ' &to) const;\n'
  619. methodBodies += 'template void ' + fullTypeName(name) + '::write<::tl::details::LengthCounter>(::tl::details::LengthCounter &to) const;\n'
  620. if writeConversion:
  621. conversionSourceTo += '\n\
  622. template <>\n\
  623. ExternalGenerator tl_to_generator('+ fullTypeName(name) + ' &&request) {\n\
  624. \treturn [value = std::move(request)]() -> ExternalRequest {\n\
  625. \t\treturn new ' + conversionName(name) + '('
  626. conversionArguments = []
  627. for k in prmsList:
  628. prmsTypeBare = prms[k]
  629. if (k in conditionsList):
  630. raise ValueError('Conversion with flags :(')
  631. elif k in botsOnlyPrms:
  632. conversionArguments.append('{}')
  633. elif prmsTypeBare in builtinTypes or prmsTypeBare == 'bool':
  634. conversionArguments.append('tl_to_simple(value.v' + k + '())')
  635. elif prmsTypeBare.find('<') >= 0:
  636. if (k in nullableVectors):
  637. conversionArguments.append('tl_to_vector_optional(value.v' + k + '())')
  638. else:
  639. conversionArguments.append('tl_to_vector(value.v' + k + '())')
  640. else:
  641. if (k in nullablePrms):
  642. conversionValue = 'value.v' + k + '() ? tl_to(*value.v' + k + '()) : nullptr'
  643. else:
  644. conversionValue = 'tl_to(value.v' + k + '())'
  645. if len(typesDict[prmsTypeBare]) > 1:
  646. conversionArguments.append('::td::td_api::object_ptr<' + conversionName(prmsTypeBare[0:1].upper() + prmsTypeBare[1:]) + '>(' + conversionValue + ')')
  647. else:
  648. conversionArguments.append('::td::td_api::object_ptr<' + conversionName(prmsTypeBare) + '>(' + conversionValue + ')')
  649. conversionSourceTo += ', '.join(conversionArguments) + ');\n\
  650. \t};\n\
  651. }\n'
  652. if len(prmsList) > 0:
  653. funcsText += '\n'
  654. for paramName in prmsList: # getters
  655. if (paramName in trivialConditions or paramName in botsOnlyPrms):
  656. continue
  657. paramType = prms[paramName]
  658. ptypeFull = fullTypeName(paramType)
  659. if (paramName in conditions):
  660. funcsText += '\t[[nodiscard]] tl::conditional<' + ptypeFull + '> v' + paramName + '() const;\n'
  661. methodBodies += 'tl::conditional<' + ptypeFull + '> ' + fullTypeName(name) + '::v' + paramName + '() const {\n'
  662. methodBodies += '\treturn (_' + hasFlags + '.v & Flag::f_' + paramName + ') ? &_' + paramName + ' : nullptr;\n'
  663. methodBodies += '}\n'
  664. elif (paramName in nullableVectors):
  665. funcsText += '\t[[nodiscard]] const ' + optionalInVector(ptypeFull) + ' &v' + paramName + '() const;\n'
  666. methodBodies += 'const ' + optionalInVector(ptypeFull) + ' &' + fullTypeName(name) + '::v' + paramName + '() const {\n'
  667. methodBodies += '\treturn _' + paramName + ';\n'
  668. methodBodies += '}\n'
  669. elif (paramName in nullablePrms):
  670. funcsText += '\t[[nodiscard]] tl::conditional<' + ptypeFull + '> v' + paramName + '() const;\n'
  671. methodBodies += 'tl::conditional<' + ptypeFull + '> ' + fullTypeName(name) + '::v' + paramName + '() const {\n'
  672. methodBodies += '\treturn _' + paramName + ' ? &*_' + paramName + ' : nullptr;\n'
  673. methodBodies += '}\n'
  674. else:
  675. funcsText += '\t[[nodiscard]] const ' + ptypeFull + ' &v' + paramName + '() const;\n'
  676. methodBodies += 'const ' + ptypeFull + ' &' + fullTypeName(name) + '::v' + paramName + '() const {\n'
  677. methodBodies += '\treturn _' + paramName + ';\n'
  678. methodBodies += '}\n'
  679. if (isTemplate != ''):
  680. funcsText += '\n\tusing ResponseType = typename TQueryType::ResponseType;\n\n'
  681. inlineMethods += methodBodies
  682. else:
  683. # method return type
  684. if not readWriteSection:
  685. funcsText += '\n\tusing ResponseType = ' + fullTypeName(restype) + ';\n\n'
  686. else:
  687. funcsText += '\n\tusing ResponseType = ' + fullTypeName(resType) + ';\n\n'
  688. methods += methodBodies
  689. if (len(prms) > len(trivialConditions) + len(botsOnlyPrms)):
  690. funcsText += 'private:\n'
  691. for paramName in prmsList:
  692. if (paramName in trivialConditions or paramName in botsOnlyPrms):
  693. continue
  694. paramType = prms[paramName]
  695. if (paramName == isTemplate):
  696. ptypeFull = paramType
  697. else:
  698. ptypeFull = fullTypeName(paramType)
  699. if (paramName in nullableVectors):
  700. funcsText += '\t' + optionalInVector(ptypeFull) + ' _' + paramName + ';\n'
  701. elif (paramName in nullablePrms):
  702. funcsText += '\tstd::optional<' + ptypeFull + '> _' + paramName + ';\n'
  703. else:
  704. funcsText += '\t' + ptypeFull + ' _' + paramName + ';\n'
  705. funcsText += '\n'
  706. funcsText += '};\n'; # class ending
  707. if readWriteSection:
  708. if (isTemplate != ''):
  709. funcsText += 'template <typename TQueryType>\n'
  710. funcsText += 'using ' + fullTypeName(Name) + ' = tl::boxed<' + fullTypeName(name) + '<TQueryType>>;\n'
  711. else:
  712. funcsText += 'using ' + fullTypeName(Name) + ' = tl::boxed<' + fullTypeName(name) + '>;\n'
  713. funcs = funcs + 1
  714. if (not restype in funcsDict):
  715. funcsList.append(restype)
  716. funcsDict[restype] = []
  717. # TypesDict[restype] = resType
  718. funcsDict[restype].append([name, typeid, prmsList, prms, hasFlags, hasFlags64, conditionsList, conditions, trivialConditions, isTemplate, nullablePrms, nullableVectors, botsOnlyPrms])
  719. else:
  720. if (isTemplate != ''):
  721. print('Template types not allowed: "' + resType + '" in line: ' + line)
  722. continue
  723. if (not restype in typesDict):
  724. typesList.append(restype)
  725. typesDict[restype] = []
  726. TypesDict[restype] = resType
  727. typesDict[restype].append([name, typeid, prmsList, prms, hasFlags, hasFlags64, conditionsList, conditions, trivialConditions, isTemplate, nullablePrms, nullableVectors, botsOnlyPrms])
  728. TypeConstructors[name] = {'typeBare': restype, 'typeBoxed': resType}
  729. consts = consts + 1
  730. if readWriteSection:
  731. for typeName in builtinTypes:
  732. forwTypedefs += 'using ' + fullTypeName(typeName[:1].upper() + typeName[1:]) + ' = tl::boxed<' + fullTypeName(typeName) + '>;\n'
  733. for typeName in builtinTemplateTypes:
  734. forwTypedefs += 'template <typename T>\n'
  735. forwTypedefs += 'using ' + fullTypeName(typeName[:1].upper() + typeName[1:]) + ' = tl::boxed<' + fullTypeName(typeName) + '<T>>;\n'
  736. if writeSerialization:
  737. textSerializeMethods += addTextSerialize(typesList, typesDict, typesDict, idPrefix, primeType, boxed, dataPrefix)
  738. textSerializeInit += addTextSerializeInit(typesList, typesDict, idPrefix) + '\n'
  739. textSerializeMethods += addTextSerialize(funcsList, funcsDict, typesDict, idPrefix, primeType, boxed, typePrefix)
  740. textSerializeInit += addTextSerializeInit(funcsList, funcsDict, idPrefix) + '\n'
  741. for restype in typesList:
  742. v = typesDict[restype]
  743. resType = TypesDict[restype]
  744. withData = 0
  745. creatorsDeclarations = ''
  746. creatorsBodies = ''
  747. flagDeclarations = ''
  748. constructsText = ''
  749. constructsBodies = ''
  750. forwards += 'class ' + fullTypeName(restype) + ';\n'
  751. if readWriteSection:
  752. forwTypedefs += 'using ' + fullTypeName(resType) + ' = tl::boxed<' + fullTypeName(restype) + '>;\n'
  753. withType = (len(v) > 1)
  754. nullable = restype in nullableTypes
  755. switchLines = ''
  756. friendDecl = ''
  757. getters = ''
  758. visitor = ''
  759. reader = ''
  760. writer = ''
  761. newFast = ''
  762. if writeConversion:
  763. if not restype in builtinTypes and not restype in conversionBuiltinTypes:
  764. if len(v) > 1:
  765. conversionType = resType
  766. conversionHeaderFrom += 'template <>\n' + fullTypeName(restype) + ' tl_from<' + fullTypeName(restype) + '>(ExternalResponse response);\n'
  767. conversionSourceFrom += '\ntemplate <>\n' + fullTypeName(restype) + ' tl_from<' + fullTypeName(restype) + '>(ExternalResponse response) {\n'
  768. if nullable:
  769. conversionSourceFrom += '\tif (!response) {\n\t\treturn nullptr;\n\t}\n\n'
  770. else:
  771. conversionSourceFrom += '\tExpects(response != nullptr);\n\n'
  772. conversionSourceFrom += '\tswitch (response->get_id()) {\n'
  773. for data in v:
  774. name = data[0]
  775. prmsList = data[2]
  776. prms = data[3]
  777. trivialConditions = data[8]
  778. isTemplate = data[9]
  779. nullablePrms = data[10]
  780. nullableVectors = data[11]
  781. botsOnlyPrms = data[12]
  782. conversionSourceFrom += '\tcase ' + conversionName(name) + '::ID: '
  783. if (len(prmsList) == 0):
  784. conversionSourceFrom += 'return ' + constructPrefix + name + '();\n'
  785. else:
  786. conversionSourceFrom += '{\n\t\tconst auto specific = static_cast<const ' + conversionName(name) + '*>(response);\n'
  787. conversionSourceFrom += '\t\treturn ' + constructPrefix + name + '('
  788. conversionArguments = []
  789. for k in prmsList:
  790. prmsTypeBare = prms[k]
  791. ptypeFullBare = fullTypeName(prmsTypeBare)
  792. if k in conditionsList:
  793. raise ValueError('Conversion with flags :(')
  794. elif k in botsOnlyPrms:
  795. continue
  796. elif prmsTypeBare == 'string':
  797. conversionArguments.append('tl_from_string(specific->' + k + '_)')
  798. elif prmsTypeBare in builtinTypes or prmsTypeBare == 'bool':
  799. conversionArguments.append('tl_from_simple(specific->' + k + '_)')
  800. elif prmsTypeBare.find('<') >= 0:
  801. if k in nullableVectors:
  802. conversionArguments.append('tl_from_vector_optional<' + ptypeFullBare + '>(specific->' + k + '_)')
  803. else:
  804. conversionArguments.append('tl_from_vector<' + ptypeFullBare + '>(specific->' + k + '_)')
  805. else:
  806. if k in nullablePrms:
  807. conversionArguments.append('specific->' + k + '_.get() ? std::make_optional(tl_from<' + ptypeFullBare + '>(specific->' + k + '_.get())) : std::nullopt')
  808. else:
  809. conversionArguments.append('tl_from<' + ptypeFullBare + '>(specific->' + k + '_.get())')
  810. conversionSourceFrom += ', '.join(conversionArguments) + ');\n'
  811. conversionSourceFrom += '\t} break;\n'
  812. conversionSourceFrom += '\tdefault: Unexpected("Type in ' + fullTypeName(restype) + ' tl_from.");\n\t}\n}\n'
  813. else:
  814. conversionType = v[0][0]
  815. conversionHeaderTo += conversionName(conversionType) + ' *tl_to(const ' + fullTypeName(restype) + ' &value);\n'
  816. conversionSourceTo += '\n' + conversionName(conversionType) + ' *tl_to(const ' + fullTypeName(restype) + ' &value) {\n'
  817. if withType:
  818. conversionSourceTo += '\tswitch (value.type()) {\n'
  819. if nullable:
  820. conversionSourceTo += '\tcase ' + typeIdType + '(0): return nullptr;\n'
  821. for data in v:
  822. name = data[0]
  823. prms = data[3]
  824. trivialConditions = data[8]
  825. isTemplate = data[9]
  826. nullablePrms = data[10]
  827. nullableVectors = data[11]
  828. botsOnlyPrms = data[12]
  829. if (len(prms) == len(trivialConditions)):
  830. conversionSourceTo += '\tcase ' + idPrefix + name + ': return new ' + conversionName(name) + '();\n'
  831. else:
  832. conversionSourceTo += '\tcase ' + idPrefix + name + ': return tl_to(value.c_' + name + '());\n'
  833. conversionSourceTo += '\tdefault: Unexpected("Type in tl_to(' + fullTypeName(restype) + ').");\n\t}\n'
  834. else:
  835. if nullable:
  836. conversionSourceTo += '\tif (!value) {\n\t\treturn nullptr;\n\t}\n'
  837. conversionSourceTo += '\treturn tl_to(value.c_' + v[0][0] + '());\n'
  838. conversionSourceTo += '}\n'
  839. for data in v:
  840. name = data[0]
  841. typeid = data[1]
  842. prmsList = data[2]
  843. prms = data[3]
  844. hasFlags = data[4]
  845. hasFlags64 = data[5]
  846. conditionsList = data[6]
  847. conditions = data[7]
  848. trivialConditions = data[8]
  849. isTemplate = data[9]
  850. nullablePrms = data[10]
  851. nullableVectors = data[11]
  852. botsOnlyPrms = data[12]
  853. dataText = ''
  854. if (len(prms) > len(trivialConditions) + len(botsOnlyPrms)):
  855. withData = 1
  856. dataText += '\nclass ' + fullDataName(name) + ' : public tl::details::type_data {\n'; # data class
  857. else:
  858. dataText += '\nclass ' + fullDataName(name) + ' {\n'; # empty data class for visitors
  859. dataText += 'public:\n'
  860. dataText += '\ttemplate <typename Other>\n'
  861. dataText += '\tstatic constexpr bool Is() { return std::is_same_v<std::decay_t<Other>, ' + fullDataName(name) + '>; };\n\n'
  862. creatorParams = []
  863. creatorParamsList = []
  864. readText = ''
  865. writeText = ''
  866. if (hasFlags != ''):
  867. flagsType = 'uint64' if hasFlags64 != '' else 'uint32'
  868. flagsBit = '1ULL' if hasFlags64 != '' else '1U'
  869. dataText += '\tenum class Flag : ' + flagsType + ' {\n'
  870. maxbit = 0
  871. parentFlagsCheck[fullDataName(name)] = {}
  872. for paramName in conditionsList:
  873. dataText += '\t\tf_' + paramName + ' = (' + flagsBit + ' << ' + conditions[paramName] + '),\n'
  874. parentFlagsCheck[fullDataName(name)][paramName] = conditions[paramName]
  875. maxbit = max(maxbit, int(conditions[paramName]))
  876. if (maxbit > 0):
  877. dataText += '\n'
  878. dataText += '\t\tMAX_FIELD = (' + flagsBit + ' << ' + str(maxbit) + '),\n'
  879. dataText += '\t};\n'
  880. dataText += '\tusing Flags = base::flags<Flag>;\n'
  881. dataText += '\tfriend inline constexpr bool is_flag_type(Flag) { return true; };\n'
  882. dataText += '\n'
  883. if (len(conditions)):
  884. for paramName in conditionsList:
  885. if paramName in trivialConditions:
  886. dataText += '\t[[nodiscard]] bool is_' + paramName + '() const;\n'
  887. constructsBodies += 'bool ' + fullDataName(name) + '::is_' + paramName + '() const {\n'
  888. constructsBodies += '\treturn _' + hasFlags + '.v & Flag::f_' + paramName + ';\n'
  889. constructsBodies += '}\n'
  890. dataText += '\n'
  891. switchLines += '\tcase ' + idPrefix + name + ': '; # for by-type-id type constructor
  892. getters += '\t[[nodiscard]] const ' + fullDataName(name) + ' &c_' + name + '() const;\n'; # const getter
  893. if optimizeSingleData and withData and not withType:
  894. getters += '\t[[nodiscard]] const ' + fullDataName(name) + ' &data() const;\n';
  895. visitor += '\tcase ' + idPrefix + name + ': return base::match_method(c_' + name + '(), std::forward<Method>(method), std::forward<Methods>(methods)...);\n'
  896. forwards += 'class ' + fullDataName(name) + ';\n'; # data class forward declaration
  897. if (len(prms) > len(trivialConditions) + len(botsOnlyPrms)):
  898. dataText += '\t' + fullDataName(name) + '();\n'; # default constructor
  899. switchLines += 'setData(new ' + fullDataName(name) + '()); '
  900. constructsBodies += fullDataName(name) + '::' + fullDataName(name) + '() = default;\n'
  901. constructsBodies += 'const ' + fullDataName(name) + ' &' + fullTypeName(restype) + '::c_' + name + '() const {\n'
  902. if (withType):
  903. constructsBodies += '\tExpects(_type == ' + idPrefix + name + ');\n\n'
  904. constructsBodies += '\treturn queryData<' + fullDataName(name) + '>();\n'
  905. constructsBodies += '}\n'
  906. if optimizeSingleData and withData and not withType:
  907. constructsBodies += 'const ' + fullDataName(name) + ' &' + fullTypeName(restype) + '::data() const {\n'
  908. constructsBodies += '\treturn queryData<' + fullDataName(name) + '>();\n'
  909. constructsBodies += '}\n'
  910. constructsText += '\texplicit ' + fullTypeName(restype) + '(const ' + fullDataName(name) + ' *data);\n'; # by-data type constructor
  911. constructsBodies += fullTypeName(restype) + '::' + fullTypeName(restype) + '(const ' + fullDataName(name) + ' *data) : type_owner(data)'
  912. if (withType):
  913. constructsBodies += ', _type(' + idPrefix + name + ')'
  914. constructsBodies += ' {\n}\n'
  915. dataText += '\t' + fullDataName(name) + '('; # params constructor
  916. prmsStr = []
  917. prmsInit = []
  918. for paramName in prmsList:
  919. if (paramName in trivialConditions or paramName in botsOnlyPrms):
  920. continue
  921. paramType = prms[paramName]
  922. ptypeFull = fullTypeName(paramType)
  923. if (paramType in ['int', 'Int', 'bool', 'Bool', 'flags<Flags>', 'long', 'int32', 'int53', 'int64', 'double']):
  924. prmsStr.append(ptypeFull + ' ' + paramName + '_')
  925. creatorParams.append(ptypeFull + ' ' + paramName + '_')
  926. elif paramName in nullableVectors:
  927. prmsStr.append('const ' + optionalInVector(ptypeFull) + ' &' + paramName + '_')
  928. creatorParams.append('const ' + optionalInVector(ptypeFull) + ' &' + paramName + '_')
  929. elif paramName in nullablePrms:
  930. prmsStr.append('const std::optional<' + ptypeFull + '> &' + paramName + '_')
  931. creatorParams.append('const std::optional<' + ptypeFull + '> &' + paramName + '_')
  932. else:
  933. prmsStr.append('const ' + ptypeFull + ' &' + paramName + '_')
  934. creatorParams.append('const ' + ptypeFull + ' &' + paramName + '_')
  935. creatorParamsList.append(paramName + '_')
  936. prmsInit.append('_' + paramName + '(' + paramName + '_)')
  937. if withType:
  938. writeText += '\t'
  939. if (paramName in conditions):
  940. readText += '\t\t&& (v' + paramName + '() ? _' + paramName + '.read(from, end) : ((_' + paramName + ' = ' + fullTypeName(paramType) + '()), true))\n'
  941. writeText += '\tif (const auto v' + paramName + ' = v.v' + paramName + '()) v' + paramName + '->write(to);\n'
  942. else:
  943. readText += '\t\t&& _' + paramName + '.read(from, end)\n'
  944. writeText += '\tv.v' + paramName + '().write(to);\n'
  945. dataText += ', '.join(prmsStr) + ');\n'
  946. constructsBodies += fullDataName(name) + '::' + fullDataName(name) + '(' + ', '.join(prmsStr) + ') : ' + ', '.join(prmsInit) + ' {\n}\n'
  947. if readWriteSection:
  948. dataText += '\n'
  949. dataText += '\t[[nodiscard]] bool read(const ' + primeType + ' *&from, const ' + primeType + ' *end);\n'
  950. constructsBodies += 'bool ' + fullDataName(name) + '::read(const ' + primeType + ' *&from, const ' + primeType + ' *end) {\n'
  951. if readText != '':
  952. constructsBodies += '\treturn' + readText[4:len(readText)-1] + ';\n'
  953. else:
  954. constructsBodies += '\treturn true;\n'
  955. constructsBodies += '}\n'
  956. dataText += '\n'
  957. if len(prmsList) > 0:
  958. for paramName in prmsList: # getters
  959. if (paramName in trivialConditions or paramName in botsOnlyPrms):
  960. continue
  961. paramType = prms[paramName]
  962. ptypeFull = fullTypeName(paramType)
  963. if paramName in conditions:
  964. dataText += '\t[[nodiscard]] tl::conditional<' + ptypeFull + '> v' + paramName + '() const;\n'
  965. constructsBodies += 'tl::conditional<' + ptypeFull + '> ' + fullDataName(name) + '::v' + paramName + '() const {\n'
  966. constructsBodies += '\treturn (_' + hasFlags + '.v & Flag::f_' + paramName + ') ? &_' + paramName + ' : nullptr;\n'
  967. constructsBodies += '}\n'
  968. elif (paramName in nullableVectors):
  969. dataText += '\t[[nodiscard]] const ' + optionalInVector(ptypeFull) + ' &v' + paramName + '() const;\n'
  970. constructsBodies += 'const ' + optionalInVector(ptypeFull) + ' &' + fullDataName(name) + '::v' + paramName + '() const {\n'
  971. constructsBodies += '\treturn _' + paramName + ';\n'
  972. constructsBodies += '}\n'
  973. elif (paramName in nullablePrms):
  974. dataText += '\t[[nodiscard]] tl::conditional<' + ptypeFull + '> v' + paramName + '() const;\n'
  975. constructsBodies += 'tl::conditional<' + ptypeFull + '> ' + fullDataName(name) + '::v' + paramName + '() const {\n'
  976. constructsBodies += '\treturn _' + paramName + ' ? &*_' + paramName + ' : nullptr;\n'
  977. constructsBodies += '}\n'
  978. else:
  979. dataText += '\t[[nodiscard]] const ' + ptypeFull + ' &v' + paramName + '() const;\n'
  980. constructsBodies += 'const ' + ptypeFull + ' &' + fullDataName(name) + '::v' + paramName + '() const {\n'
  981. constructsBodies += '\treturn _' + paramName + ';\n'
  982. constructsBodies += '}\n'
  983. dataText += '\n'
  984. dataText += 'private:\n'
  985. for paramName in prmsList: # fields declaration
  986. paramType = prms[paramName]
  987. ptypeFull = fullTypeName(paramType)
  988. if (paramName in trivialConditions or paramName in botsOnlyPrms):
  989. continue
  990. elif (paramName in nullableVectors):
  991. dataText += '\t' + optionalInVector(ptypeFull) + ' _' + paramName + ';\n'
  992. elif (paramName in nullablePrms):
  993. dataText += '\tstd::optional<' + ptypeFull + '> _' + paramName + ';\n'
  994. else:
  995. dataText += '\t' + ptypeFull + ' _' + paramName + ';\n'
  996. dataText += '\n'
  997. newFast = 'new ' + fullDataName(name) + '()'
  998. else:
  999. constructsBodies += 'const ' + fullDataName(name) + ' &' + fullTypeName(restype) + '::c_' + name + '() const {\n'
  1000. if (withType):
  1001. constructsBodies += '\tExpects(_type == ' + idPrefix + name + ');\n\n'
  1002. constructsBodies += '\tstatic const ' + fullDataName(name) + ' result;\n'
  1003. constructsBodies += '\treturn result;\n'
  1004. constructsBodies += '}\n'
  1005. if writeConversion and not restype in builtinTypes and not restype in conversionBuiltinTypes:
  1006. if (len(v) == 1):
  1007. conversionHeaderFrom += 'template <>\n' + fullTypeName(restype) + ' tl_from<' + fullTypeName(restype) + '>(ExternalResponse response);\n'
  1008. conversionSourceFrom += '\ntemplate <>\n' + fullTypeName(restype) + ' tl_from<' + fullTypeName(restype) + '>(ExternalResponse response) {\n'
  1009. if nullable:
  1010. conversionSourceFrom += '\tif (!response) {\n\t\treturn nullptr;\n\t}\n\n'
  1011. else:
  1012. conversionSourceFrom += '\tExpects(response != nullptr);\n'
  1013. conversionSourceFrom += '\tExpects(response->get_id() == ' + conversionName(name) + '::ID);\n\n'
  1014. if (len(prmsList) > 0):
  1015. conversionSourceFrom += '\tconst auto specific = static_cast<const ' + conversionName(name) + '*>(response);\n'
  1016. conversionSourceFrom += '\treturn ' + constructPrefix + normalizedName(name) + '('
  1017. conversionArguments = []
  1018. for k in prmsList:
  1019. prmsTypeBare = prms[k]
  1020. ptypeFullBare = fullTypeName(prmsTypeBare)
  1021. if k in conditionsList:
  1022. raise ValueError('Conversion with flags :(')
  1023. elif k in botsOnlyPrms:
  1024. continue
  1025. elif prmsTypeBare == 'string':
  1026. conversionArguments.append('tl_from_string(specific->' + k + '_)')
  1027. elif prmsTypeBare in builtinTypes or prmsTypeBare == 'bool':
  1028. conversionArguments.append('tl_from_simple(specific->' + k + '_)')
  1029. elif prmsTypeBare.find('<') >= 0:
  1030. if k in nullableVectors:
  1031. conversionArguments.append('tl_from_vector_optional<' + ptypeFullBare + '>(specific->' + k + '_)')
  1032. else:
  1033. conversionArguments.append('tl_from_vector<' + ptypeFullBare + '>(specific->' + k + '_)')
  1034. else:
  1035. if k in nullablePrms:
  1036. conversionArguments.append('specific->' + k + '_.get() ? std::make_optional(tl_from<' + ptypeFullBare + '>(specific->' + k + '_.get())) : std::nullopt')
  1037. else:
  1038. conversionArguments.append('tl_from<' + ptypeFullBare + '>(specific->' + k + '_.get())')
  1039. conversionSourceFrom += ', '.join(conversionArguments) + ');\n'
  1040. conversionSourceFrom += '}\n'
  1041. conversionHeaderTo += conversionName(name) + ' *tl_to(const ' + fullDataName(name) + ' &value);\n'
  1042. conversionSourceTo += '\n' + conversionName(name) + ' *tl_to(const ' + fullDataName(name) + ' &value) {\n'
  1043. conversionSourceTo += '\treturn new ' + conversionName(name) + '('
  1044. conversionArguments = []
  1045. for k in prmsList:
  1046. prmsTypeBare = prms[k]
  1047. if (k in conditionsList):
  1048. raise ValueError('Conversion with flags :(')
  1049. elif k in botsOnlyPrms:
  1050. conversionArguments.append('{}')
  1051. elif prmsTypeBare in builtinTypes or prmsTypeBare == 'bool':
  1052. conversionArguments.append('tl_to_simple(value.v' + k + '())')
  1053. elif prmsTypeBare.find('<') >= 0:
  1054. if (k in nullableVectors):
  1055. conversionArguments.append('tl_to_vector_optional(value.v' + k + '())')
  1056. else:
  1057. conversionArguments.append('tl_to_vector(value.v' + k + '())')
  1058. else:
  1059. if (k in nullablePrms):
  1060. conversionValue = 'value.v' + k + '() ? tl_to(*value.v' + k + '()) : nullptr'
  1061. else:
  1062. conversionValue = 'tl_to(value.v' + k + '())'
  1063. if len(typesDict[prmsTypeBare]) > 1:
  1064. conversionArguments.append('::td::td_api::object_ptr<' + conversionName(prmsTypeBare[0:1].upper() + prmsTypeBare[1:]) + '>(' + conversionValue + ')')
  1065. else:
  1066. conversionArguments.append('::td::td_api::object_ptr<' + conversionName(prmsTypeBare) + '>(' + conversionValue + ')')
  1067. conversionSourceTo += ', '.join(conversionArguments) + ');\n}\n'
  1068. switchLines += 'break;\n'
  1069. dataText += '};\n'; # class ending
  1070. dataTexts += dataText; # add data class
  1071. if not friendDecl:
  1072. friendDecl += '\tfriend class ::' + creatorNamespaceFull + '::TypeCreator;\n'
  1073. creatorProxyText += '\tinline static ' + fullTypeName(restype) + ' new_' + name + '(' + ', '.join(creatorParams) + ') {\n'
  1074. if len(prms) > len(trivialConditions): # creator with params
  1075. creatorProxyText += '\t\treturn ' + fullTypeName(restype) + '(new ' + fullDataName(name) + '(' + ', '.join(creatorParamsList) + '));\n'
  1076. else:
  1077. if withType: # creator by type
  1078. creatorProxyText += '\t\treturn ' + fullTypeName(restype) + '(' + idPrefix + name + ');\n'
  1079. else: # single creator
  1080. creatorProxyText += '\t\treturn ' + fullTypeName(restype) + '();\n'
  1081. creatorProxyText += '\t}\n'
  1082. creatorsDeclarations += fullTypeName(restype) + ' ' + constructPrefix + name + '(' + ', '.join(creatorParams) + ');\n'
  1083. creatorsBodies += fullTypeName(restype) + ' ' + constructPrefix + name + '(' + ', '.join(creatorParams) + ') {\n'
  1084. creatorsBodies += '\treturn ::' + creatorNamespaceFull + '::TypeCreator::new_' + name + '(' + ', '.join(creatorParamsList) + ');\n'
  1085. creatorsBodies += '}\n'
  1086. if (withType):
  1087. reader += '\tcase ' + idPrefix + name + ': _type = cons; '; # read switch line
  1088. if (len(prms) > len(trivialConditions)):
  1089. reader += '{\n'
  1090. reader += '\t\tif (const auto data = new ' + fullDataName(name) + '(); data->read(from, end)) {\n'
  1091. reader += '\t\t\tsetData(data);\n'
  1092. reader += '\t\t} else {\n'
  1093. reader += '\t\t\tdelete data;\n'
  1094. reader += '\t\t\treturn false;\n'
  1095. reader += '\t\t}\n'
  1096. reader += '\t} break;\n'
  1097. writer += '\tcase ' + idPrefix + name + ': {\n'; # write switch line
  1098. writer += '\t\tconst ' + fullDataName(name) + ' &v = c_' + name + '();\n'
  1099. writer += writeText
  1100. writer += '\t} break;\n'
  1101. else:
  1102. reader += 'break;\n'
  1103. else:
  1104. if (len(prms) > len(trivialConditions)):
  1105. reader += '\tif (const auto data = new ' + fullDataName(name) + '(); data->read(from, end)) {\n'
  1106. reader += '\t\tsetData(data);\n'
  1107. reader += '\t} else {\n'
  1108. reader += '\t\tdelete data;\n'
  1109. reader += '\t\treturn false;\n'
  1110. reader += '\t}\n'
  1111. writer += '\tconst ' + fullDataName(name) + ' &v = c_' + name + '();\n'
  1112. writer += writeText
  1113. if nullable:
  1114. if not withType and not withData:
  1115. raise ValueError('No way to make a nullable non-data-owner non-type-distinct type')
  1116. elif readWriteSection:
  1117. raise ValueError('No way to make read-write code for a nullable type')
  1118. forwards += '\n'
  1119. typesText += '\nclass ' + fullTypeName(restype); # type class declaration
  1120. if withData:
  1121. typesText += ' : private tl::details::type_owner'; # if has data fields
  1122. typesText += ' {\n'
  1123. typesText += 'public:\n'
  1124. typesText += '\t' + fullTypeName(restype) + '();\n'; # default constructor
  1125. if withData and not withType:
  1126. methods += '\n' + fullTypeName(restype) + '::' + fullTypeName(restype) + '() : type_owner(' + newFast + ') {\n}\n'
  1127. else:
  1128. methods += '\n' + fullTypeName(restype) + '::' + fullTypeName(restype) + '() = default;\n'
  1129. if nullable:
  1130. typesText += '\t' + fullTypeName(restype) + '(std::nullptr_t);\n'
  1131. methods += fullTypeName(restype) + '::' + fullTypeName(restype) + '(std::nullptr_t) {\n}\n'
  1132. typesText += '\n'
  1133. if nullable:
  1134. typesText += '\texplicit operator bool() const;\n'
  1135. methods += fullTypeName(restype) + '::operator bool() const {\n\t'
  1136. if withData:
  1137. methods += '\treturn hasData();\n'
  1138. else:
  1139. methods += '\treturn _type != 0;\n'
  1140. methods += '}\n'
  1141. typesText += getters
  1142. typesText += '\n'
  1143. typesText += '\ttemplate <typename Method, typename ...Methods>\n'
  1144. typesText += '\tdecltype(auto) match(Method &&method, Methods &&...methods) const;\n'
  1145. visitorMethods += 'template <typename Method, typename ...Methods>\n'
  1146. visitorMethods += 'decltype(auto) ' + fullTypeName(restype) + '::match(Method &&method, Methods &&...methods) const {\n'
  1147. if withType:
  1148. visitorMethods += '\tswitch (_type) {\n'
  1149. visitorMethods += visitor
  1150. visitorMethods += '\t}\n'
  1151. visitorMethods += '\tUnexpected("Type in ' + fullTypeName(restype) + '::match.");\n'
  1152. else:
  1153. visitorMethods += '\treturn base::match_method(c_' + v[0][0] + '(), std::forward<Method>(method), std::forward<Methods>(methods)...);\n'
  1154. visitorMethods += '}\n\n'
  1155. typesText += '\t' + typeIdType + ' type() const;\n'; # type id method
  1156. methods += typeIdType + ' ' + fullTypeName(restype) + '::type() const {\n'
  1157. if withType:
  1158. if nullable:
  1159. methods += '\treturn _type;\n'
  1160. else:
  1161. methods += '\tExpects(_type != 0);\n\n'
  1162. methods += '\treturn _type;\n'
  1163. else:
  1164. if nullable:
  1165. methods += '\treturn hasData() ? ' + idPrefix + v[0][0] + ' : ' + typeIdType + '(0);\n'
  1166. else:
  1167. methods += '\treturn ' + idPrefix + v[0][0] + ';\n'
  1168. methods += '}\n'
  1169. if readWriteSection:
  1170. typesText += '\n'
  1171. typesText += '\t[[nodiscard]] bool read(const ' + primeType + ' *&from, const ' + primeType + ' *end, ' + typeIdType + ' cons'; # read method
  1172. if (not withType):
  1173. typesText += ' = ' + idPrefix + name
  1174. typesText += ');\n'
  1175. methods += 'bool ' + fullTypeName(restype) + '::read(const ' + primeType + ' *&from, const ' + primeType + ' *end, ' + typeIdType + ' cons) {\n'
  1176. if (withData):
  1177. if not (withType):
  1178. methods += '\tif (cons != ' + idPrefix + v[0][0] + ') return false;\n'
  1179. if (withType):
  1180. methods += '\tswitch (cons) {\n'
  1181. methods += reader
  1182. methods += '\tdefault: return false;\n'
  1183. methods += '\t}\n'
  1184. else:
  1185. methods += reader
  1186. methods += '\treturn true;\n'
  1187. methods += '}\n'
  1188. typesText += '\ttemplate <typename Accumulator>\n' # write method
  1189. typesText += '\tvoid write(Accumulator &to) const;\n'
  1190. methods += 'template <typename Accumulator>\n'
  1191. methods += 'void ' + fullTypeName(restype) + '::write(Accumulator &to) const {\n'
  1192. if (withType and writer != ''):
  1193. methods += '\tswitch (_type) {\n'
  1194. methods += writer
  1195. methods += '\t}\n'
  1196. else:
  1197. methods += writer
  1198. methods += '}\n'
  1199. methods += 'template void ' + fullTypeName(restype) + '::write<' + bufferType + '>(' + bufferType + ' &to) const;\n'
  1200. methods += 'template void ' + fullTypeName(restype) + '::write<::tl::details::LengthCounter>(::tl::details::LengthCounter &to) const;\n'
  1201. typesText += '\n\tusing ResponseType = void;\n'; # no response types declared
  1202. if optimizeSingleData:
  1203. if withData and not withType:
  1204. for data in v:
  1205. name = data[0]
  1206. typesText += '\tusing SingleDataType = ' + fullDataName(name) + ';\n'
  1207. else:
  1208. typesText += '\tusing SingleDataType = NotSingleDataTypePlaceholder;\n';
  1209. typesText += '\nprivate:\n'; # private constructors
  1210. if (withType): # by-type-id constructor
  1211. typesText += '\texplicit ' + fullTypeName(restype) + '(' + typeIdType + ' type);\n'
  1212. methods += fullTypeName(restype) + '::' + fullTypeName(restype) + '(' + typeIdType + ' type) : '
  1213. methods += '_type(type)'
  1214. methods += ' {\n'
  1215. methods += '\tswitch (type) {\n'; # type id check
  1216. methods += switchLines
  1217. methods += '\tdefault: Unexpected("Type in ' + fullTypeName(restype) + '::' + fullTypeName(restype) + '.");\n'
  1218. methods += '\t}\n'
  1219. methods += '}\n'; # by-type-id constructor end
  1220. if (withData):
  1221. typesText += constructsText
  1222. methods += constructsBodies
  1223. if (friendDecl):
  1224. typesText += '\n' + friendDecl
  1225. if (withType):
  1226. typesText += '\n\t' + typeIdType + ' _type = 0;\n'; # type field var
  1227. typesText += '};\n'; # type class ended
  1228. flagOperators += flagDeclarations
  1229. factories += creatorsDeclarations
  1230. methods += creatorsBodies
  1231. if readWriteSection:
  1232. typesText += 'using ' + fullTypeName(resType) + ' = tl::boxed<' + fullTypeName(restype) + '>;\n'; # boxed type definition
  1233. flagOperators += '\n'
  1234. for pureChildName in flagInheritance:
  1235. childName = dataPrefix + pureChildName
  1236. parentName = dataPrefix + flagInheritance[pureChildName]
  1237. for flag in parentFlagsCheck[childName]:
  1238. #
  1239. # 'channelForbidden' has 'until_date' flag and 'channel' doesn't have it.
  1240. # But as long as flags don't collide this is not a problem.
  1241. #
  1242. # if (not flag in parentFlagsCheck[parentName]):
  1243. # raise ValueError('Flag ' + flag + ' not found in ' + parentName + ' which should be a flags-parent of ' + childName)
  1244. #
  1245. if (flag in parentFlagsCheck[parentName]):
  1246. if (parentFlagsCheck[childName][flag] != parentFlagsCheck[parentName][flag]):
  1247. raise ValueError('Flag ' + flag + ' has different value in ' + parentName + ' which should be a flags-parent of ' + childName)
  1248. else:
  1249. parentFlagsCheck[parentName][flag] = parentFlagsCheck[childName][flag]
  1250. flagOperators += 'inline ' + parentName + '::Flags mtpCastFlags(' + childName + '::Flags flags) { return static_cast<' + parentName + '::Flag>(flags.value()); }\n'
  1251. flagOperators += 'inline ' + parentName + '::Flags mtpCastFlags(MTPflags<' + childName + '::Flags> flags) { return mtpCastFlags(flags.v); }\n'
  1252. textSerializeSource = ''
  1253. if writeSerialization:
  1254. # manual types added here
  1255. textSerializeMethods += '\
  1256. bool Serialize_rpc_result(DumpToTextBuffer &to, int32 stage, int32 lev, Types &types, Types &vtypes, Stages &stages, Flags &flags, const ' + primeType + ' *start, const ' + primeType + ' *end, uint64 iflag) {\n\
  1257. if (stage) {\n\
  1258. to.add(",\\n").addSpaces(lev);\n\
  1259. } else {\n\
  1260. to.add("{ rpc_result");\n\
  1261. to.add("\\n").addSpaces(lev);\n\
  1262. }\n\
  1263. switch (stage) {\n\
  1264. case 0: to.add(" req_msg_id: "); ++stages.back(); types.push_back(' + idPrefix + 'long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;\n\
  1265. case 1: to.add(" result: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;\n\
  1266. default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;\n\
  1267. }\n\
  1268. return true;\n\
  1269. }\n\
  1270. \n\
  1271. bool Serialize_msg_container(DumpToTextBuffer &to, int32 stage, int32 lev, Types &types, Types &vtypes, Stages &stages, Flags &flags, const ' + primeType + ' *start, const ' + primeType + ' *end, uint64 iflag) {\n\
  1272. if (stage) {\n\
  1273. to.add(",\\n").addSpaces(lev);\n\
  1274. } else {\n\
  1275. to.add("{ msg_container");\n\
  1276. to.add("\\n").addSpaces(lev);\n\
  1277. }\n\
  1278. switch (stage) {\n\
  1279. case 0: to.add(" messages: "); ++stages.back(); types.push_back(' + idPrefix + 'vector); vtypes.push_back(' + idPrefix + 'core_message); stages.push_back(0); flags.push_back(0); break;\n\
  1280. default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;\n\
  1281. }\n\
  1282. return true;\n\
  1283. }\n\
  1284. \n\
  1285. bool Serialize_core_message(DumpToTextBuffer &to, int32 stage, int32 lev, Types &types, Types &vtypes, Stages &stages, Flags &flags, const ' + primeType + ' *start, const ' + primeType + ' *end, uint64 iflag) {\n\
  1286. if (stage) {\n\
  1287. to.add(",\\n").addSpaces(lev);\n\
  1288. } else {\n\
  1289. to.add("{ core_message");\n\
  1290. to.add("\\n").addSpaces(lev);\n\
  1291. }\n\
  1292. switch (stage) {\n\
  1293. case 0: to.add(" msg_id: "); ++stages.back(); types.push_back(' + idPrefix + 'long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;\n\
  1294. case 1: to.add(" seq_no: "); ++stages.back(); types.push_back(' + idPrefix + 'int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;\n\
  1295. case 2: to.add(" bytes: "); ++stages.back(); types.push_back(' + idPrefix + 'int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;\n\
  1296. case 3: to.add(" body: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;\n\
  1297. default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;\n\
  1298. }\n\
  1299. return true;\n\
  1300. }\n\
  1301. \n'
  1302. textSerializeInit += '\
  1303. { ' + idPrefix + 'rpc_result, Serialize_rpc_result },\n\
  1304. { ' + idPrefix + 'msg_container, Serialize_msg_container },\n\
  1305. { ' + idPrefix + 'core_message, Serialize_core_message },\n'
  1306. textSerializeSource = '\
  1307. namespace {\n\
  1308. \n\
  1309. using Types = QVector<' + typeIdType + '>;\n\
  1310. using Stages = QVector<int32>;\n\
  1311. using Flags = QVector<int64>;\n\
  1312. \n\
  1313. ' + textSerializeMethods + '\n\
  1314. \n\
  1315. using TextSerializer = bool (*)(DumpToTextBuffer &to, int32 stage, int32 lev, Types &types, Types &vtypes, Stages &stages, Flags &flags, const ' + primeType + ' *start, const ' + primeType + ' *end, uint64 iflag);\n\
  1316. \n\
  1317. base::flat_map<' + typeIdType + ', TextSerializer> CreateTextSerializers() {\n\
  1318. return {\n\
  1319. ' + textSerializeInit + '\n\
  1320. };\n\
  1321. }\n\
  1322. \n\
  1323. } // namespace\n\
  1324. \n\
  1325. bool DumpToTextType(DumpToTextBuffer &to, const ' + primeType + ' *&from, const ' + primeType + ' *end, ' + primeType + ' cons, uint32 level, ' + primeType + ' vcons) {\n\
  1326. static auto kSerializers = CreateTextSerializers();\n\
  1327. \n\
  1328. Types types, vtypes;\n\
  1329. Stages stages;\n\
  1330. Flags flags;\n\
  1331. types.reserve(20); vtypes.reserve(20); stages.reserve(20); flags.reserve(20);\n\
  1332. types.push_back(' + typeIdType + '(cons)); vtypes.push_back(' + typeIdType + '(vcons)); stages.push_back(0); flags.push_back(0);\n\
  1333. \n\
  1334. ' + typeIdType + ' type = cons, vtype = vcons;\n\
  1335. int32 stage = 0;\n\
  1336. int64 flag = 0;\n\
  1337. \n\
  1338. while (!types.isEmpty()) {\n\
  1339. type = types.back();\n\
  1340. vtype = vtypes.back();\n\
  1341. stage = stages.back();\n\
  1342. flag = flags.back();\n\
  1343. if (!type) {\n\
  1344. if (from >= end) {\n\
  1345. to.error("insufficient data");\n\
  1346. return false;\n\
  1347. } else if (stage) {\n\
  1348. to.error("unknown type on stage > 0");\n\
  1349. return false;\n\
  1350. }\n\
  1351. types.back() = type = *from;\n\
  1352. ++from;\n\
  1353. }\n\
  1354. \n\
  1355. int32 lev = level + types.size() - 1;\n\
  1356. auto it = kSerializers.find(type);\n\
  1357. if (it != kSerializers.end()) {\n\
  1358. if (!(*it->second)(to, stage, lev, types, vtypes, stages, flags, from, end, flag)) {\n\
  1359. to.error();\n\
  1360. return false;\n\
  1361. }\n\
  1362. } else if (DumpToTextCore(to, from, end, type, lev, vtype)) {\n\
  1363. types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();\n\
  1364. } else {\n\
  1365. to.error();\n\
  1366. return false;\n\
  1367. }\n\
  1368. }\n\
  1369. return true;\n\
  1370. }\n'
  1371. if forwTypedefs != '':
  1372. forwTypedefs = '// Boxed types definitions\n' + forwTypedefs + '\n'
  1373. # module itself
  1374. header = '\
  1375. // WARNING! All changes made in this file will be lost!\n\
  1376. // Created from ' + inputNames + ' by \'generate.py\'\n\
  1377. //\n\
  1378. #pragma once\n\
  1379. \n\
  1380. ' + ('#include "' + builtinInclude + '"\n' if builtinInclude != '' else '') + '\
  1381. #include "base/assertion.h"\n\
  1382. #include "base/flags.h"\n\
  1383. #include "tl/tl_boxed.h"\n\
  1384. #include "tl/tl_type_owner.h"\n\
  1385. \n\
  1386. ' + ('namespace ' + globalNamespace + ' {\n' if globalNamespace != '' else '') + '\
  1387. ' + ('namespace ' + creatorNamespace + ' {\n' if creatorNamespace != '' else '') + '\
  1388. \n\
  1389. ' + ('inline constexpr auto kCurrentLayer = ' + primeType + '(' + str(layer) + ');\n\n' if layer != 0 else '') +'\
  1390. class TypeCreator;\n\
  1391. \n\
  1392. ' + ('} // namespace ' + creatorNamespace + '\n\n' if creatorNamespace != '' else '') + '\
  1393. // Type id constants\n\
  1394. enum {\n\
  1395. ' + ',\n'.join(enums) + '\n\
  1396. };\n\
  1397. \n\
  1398. // Type forward declarations\n\
  1399. ' + forwards + '\n\
  1400. ' + forwTypedefs + '\
  1401. // Type classes definitions\n\
  1402. ' + typesText + '\n\
  1403. // Type constructors with data\n\
  1404. ' + dataTexts + '\n\
  1405. // RPC methods\n\
  1406. ' + funcsText + '\n\
  1407. // Template methods definition\n\
  1408. ' + inlineMethods + '\n\
  1409. // Visitor definition\n\
  1410. ' + visitorMethods + '\n\
  1411. // Flag operators definition\n\
  1412. ' + flagOperators + '\n\
  1413. // Factory methods declaration\n\
  1414. ' + factories + '\n\
  1415. ' + ('} // namespace ' + globalNamespace + '\n' if globalNamespace != '' else '')
  1416. source = '\
  1417. // WARNING! All changes made in this file will be lost!\n\
  1418. // Created from ' + inputNames + ' by \'generate.py\'\n\
  1419. //\n\
  1420. #include "' + outputHeaderBasename + '"\n\
  1421. \n\
  1422. // Creator proxy class definition\n\
  1423. ' + ('namespace ' + globalNamespace + ' {\n' if globalNamespace != '' else '') + '\
  1424. ' + ('namespace ' + creatorNamespace + ' {\n' if creatorNamespace != '' else '') + '\
  1425. \n\
  1426. class TypeCreator final {\n\
  1427. public:\n\
  1428. ' + creatorProxyText + '\n\
  1429. };\n\
  1430. \n\
  1431. ' + ('} // namespace ' + creatorNamespace + '\n\n' if creatorNamespace != '' else '') + '\
  1432. // Methods definition\n\
  1433. ' + methods + '\n\
  1434. ' + ('} // namespace ' + globalNamespace + '\n' if globalNamespace != '' else '')
  1435. conversionHeaderFrom = '\
  1436. // WARNING! All changes made in this file will be lost!\n\
  1437. // Created from ' + inputNames + ' by \'generate.py\'\n\
  1438. //\n\
  1439. #pragma once\n\
  1440. \n\
  1441. #include "' + conversionInclude + '"\n\
  1442. #include "' + outputHeaderBasename + '"\n\
  1443. \n\
  1444. ' + ('namespace ' + globalNamespace + ' {\n\n' if globalNamespace != '' else '') + '\
  1445. ' + conversionHeaderFrom + '\n\
  1446. ' + ('} // namespace ' + globalNamespace + '\n' if globalNamespace != '' else '') +'\
  1447. ' + ('\n#include "' + conversionBuiltinIncludeFrom + '"\n' if conversionBuiltinIncludeFrom != '' else '')
  1448. conversionHeaderTo = '\
  1449. // WARNING! All changes made in this file will be lost!\n\
  1450. // Created from ' + inputNames + ' by \'generate.py\'\n\
  1451. //\n\
  1452. #pragma once\n\
  1453. \n\
  1454. #include "' + conversionInclude + '"\n\
  1455. #include "' + outputHeaderBasename + '"\n\
  1456. \n\
  1457. ' + ('namespace ' + globalNamespace + ' {\n\n' if globalNamespace != '' else '') + '\
  1458. ' + conversionHeaderTo + '\n\
  1459. ' + ('} // namespace ' + globalNamespace + '\n' if globalNamespace != '' else '') +'\
  1460. ' + ('\n#include "' + conversionBuiltinIncludeTo + '"\n' if conversionBuiltinIncludeTo != '' else '')
  1461. conversionSourceFrom = '\
  1462. // WARNING! All changes made in this file will be lost!\n\
  1463. // Created from ' + inputNames + ' by \'generate.py\'\n\
  1464. //\n\
  1465. #include "' + outputConversionHeaderFromBasename + '"\n\
  1466. \n\
  1467. ' + ('namespace ' + globalNamespace + ' {\n' if globalNamespace != '' else '') + '\
  1468. ' + conversionSourceFrom + '\n\
  1469. ' + ('} // namespace ' + globalNamespace + '\n' if globalNamespace != '' else '')
  1470. conversionSourceTo = '\
  1471. // WARNING! All changes made in this file will be lost!\n\
  1472. // Created from ' + inputNames + ' by \'generate.py\'\n\
  1473. //\n\
  1474. #include "' + outputConversionHeaderToBasename + '"\n\
  1475. \n\
  1476. ' + ('namespace ' + globalNamespace + ' {\n' if globalNamespace != '' else '') + '\
  1477. ' + conversionSourceTo + '\n\
  1478. ' + ('} // namespace ' + globalNamespace + '\n' if globalNamespace != '' else '')
  1479. serializationHeader = '\
  1480. // WARNING! All changes made in this file will be lost!\n\
  1481. // Created from ' + inputNames + ' by \'generate.py\'\n\
  1482. //\n\
  1483. #pragma once\n\
  1484. \n\
  1485. ' + ('#include "' + builtinInclude + '"\n\n' if builtinInclude != '' else '') + '\
  1486. namespace MTP::details {\n\
  1487. \n\
  1488. struct DumpToTextBuffer;\n\
  1489. \n\
  1490. [[nodiscard]] bool DumpToTextType(DumpToTextBuffer &to, const ' + primeType + ' *&from, const ' + primeType + ' *end, ' + primeType + ' cons = 0, uint32 level = 0, ' + primeType + ' vcons = 0);\n\
  1491. \n\
  1492. } // namespace MTP::details\n'
  1493. serializationSource = '\
  1494. // WARNING! All changes made in this file will be lost!\n\
  1495. // Created from ' + inputNames + ' by \'generate.py\'\n\
  1496. //\n\
  1497. #include "' + outputSerializationHeaderBasename + '"\n\
  1498. #include "' + outputHeaderBasename + '"\n\
  1499. #include "' + serializationInclude + '"\n\
  1500. #include "base/flat_map.h"\n\
  1501. \n\
  1502. namespace MTP::details {\n\
  1503. ' + textSerializeSource + '\n\
  1504. } // namespace MTP::details\n'
  1505. alreadyHeader = ''
  1506. if os.path.isfile(outputHeader):
  1507. with open(outputHeader, 'r') as already:
  1508. alreadyHeader = already.read()
  1509. if alreadyHeader != header:
  1510. with open(outputHeader, 'w') as out:
  1511. out.write(header)
  1512. alreadySource = ''
  1513. if os.path.isfile(outputSource):
  1514. with open(outputSource, 'r') as already:
  1515. alreadySource = already.read()
  1516. if alreadySource != source:
  1517. with open(outputSource, 'w') as out:
  1518. out.write(source)
  1519. if writeConversion:
  1520. alreadyHeader = ''
  1521. if os.path.isfile(outputConversionHeaderFrom):
  1522. with open(outputConversionHeaderFrom, 'r') as already:
  1523. alreadyHeader = already.read()
  1524. if alreadyHeader != conversionHeaderFrom:
  1525. with open(outputConversionHeaderFrom, 'w') as out:
  1526. out.write(conversionHeaderFrom)
  1527. if writeConversion:
  1528. alreadyHeader = ''
  1529. if os.path.isfile(outputConversionHeaderTo):
  1530. with open(outputConversionHeaderTo, 'r') as already:
  1531. alreadyHeader = already.read()
  1532. if alreadyHeader != conversionHeaderTo:
  1533. with open(outputConversionHeaderTo, 'w') as out:
  1534. out.write(conversionHeaderTo)
  1535. alreadySource = ''
  1536. if os.path.isfile(outputConversionSourceFrom):
  1537. with open(outputConversionSourceFrom, 'r') as already:
  1538. alreadySource = already.read()
  1539. if alreadySource != conversionSourceFrom:
  1540. with open(outputConversionSourceFrom, 'w') as out:
  1541. out.write(conversionSourceFrom)
  1542. alreadySource = ''
  1543. if os.path.isfile(outputConversionSourceTo):
  1544. with open(outputConversionSourceTo, 'r') as already:
  1545. alreadySource = already.read()
  1546. if alreadySource != conversionSourceTo:
  1547. with open(outputConversionSourceTo, 'w') as out:
  1548. out.write(conversionSourceTo)
  1549. if writeSerialization:
  1550. alreadyHeader = ''
  1551. if os.path.isfile(outputSerializationHeader):
  1552. with open(outputSerializationHeader, 'r') as already:
  1553. alreadyHeader = already.read()
  1554. if alreadyHeader != serializationHeader:
  1555. with open(outputSerializationHeader, 'w') as out:
  1556. out.write(serializationHeader)
  1557. alreadySource = ''
  1558. if os.path.isfile(outputSerializationSource):
  1559. with open(outputSerializationSource, 'r') as already:
  1560. alreadySource = already.read()
  1561. if alreadySource != serializationSource:
  1562. with open(outputSerializationSource, 'w') as out:
  1563. out.write(serializationSource)
  1564. with open(outputPath + '.timestamp', 'w') as out:
  1565. out.write('1')