from typing import Dict from util import parse_param, to_camel_case, to_snake_case, SCALAR_MAPPING from entity import Field, Struct, Enum, Method, Type, Scalar def render(parsed, entities, log): structs: Dict[str, Type] = dict() enums: Dict[str, Enum] = dict() methods: Dict[str, Method] = dict() for (scalar, _) in SCALAR_MAPPING.values(): structs.update({scalar: Scalar(name=scalar)}) def parse_decl(decl) -> tuple: # -> (description, ctor name, fields, base name) docs, derived, params, base = decl.children docs = { doc.children[0]: ''.join(doc.children[1].children) for doc in docs.children } params = params.children fields = [] for param in params: name, raw_type = param.children typ, inner_typ, deserializer = parse_param(raw_type) doc = docs[name] if name == 'description': doc = docs['param_description'] fields.append(Field(typeid=typ, name=str(name), deserializer=deserializer, doc=doc, inner_type=inner_typ)) return docs['description'], str(derived), fields, str(base) def find_type(name: str) -> Type: if name in structs: return structs[name] elif name in enums: return enums[name] else: raise ValueError(f"could not find type {name}") parsed_decls, parsed_methods = parsed.children for decl in parsed_decls.children: if decl.data == 'decl': description, type_name, fields, base_type = parse_decl(decl) rusty_type_name = to_camel_case(type_name) rusty_base_type = to_camel_case(base_type) struct = Struct(name=rusty_type_name, doc=description) structs.update({rusty_type_name: struct}) for field in fields: struct.add_field(field) if rusty_type_name != rusty_base_type: enums[to_camel_case(rusty_base_type)].add_member(struct) else: name, doc = decl.children rusty_name = to_camel_case(name) doc = ''.join(doc.children[1].children) enums[rusty_name] = Enum(name=rusty_name, doc=doc) for decl in parsed_methods.children: docs, name, params, ret = parse_decl(decl) ret_typ = find_type(to_camel_case(ret)) m = Method(orig_name=name, ret=ret_typ, docs=docs) for param in params: param.initialize_with_type(find_type(param.inner_type)) m.add_param(param) methods[m.name] = m for struct in structs.values(): if isinstance(struct, Scalar): continue for field in struct.deps: field.initialize_with_type(find_type(field.inner_type)) for e_name, enum in enums.items(): if e_name not in entities: enum.exclude = True else: for member in enum.deps: if len(member.deps) == 0: member.exclude = True else: entities.append(member.name) # force inclusion of children for s_name, struct in structs.items(): if s_name not in entities: struct.exclude = True prelude = ''' #![allow(unused)] use serde::Deserializer; use tdlib_rs::client::ClientLike; use serde_derive::{Serialize, Deserialize}; use serde_json::{json, Value as SerdeJsonValue}; use tdlib_rs::Client; use tdlib_rs::client::ResponseFuture; use super::{deserialize_i64_0, deserialize_i64_1}; ''' print(prelude) for s_name, struct in structs.items(): if not struct.is_excluded and s_name in entities: struct.render_as_decl() for e_name, enum in enums.items(): if not enum.is_excluded and e_name in entities: enum.render_as_decl() print('pub trait ClientExt: ClientLike {') for m_name, meth in methods.items(): if m_name in entities: meth.render_as_decl() print('}')