diff options
Diffstat (limited to 'src/render.py')
-rw-r--r-- | src/render.py | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/render.py b/src/render.py new file mode 100644 index 0000000..2fedf7d --- /dev/null +++ b/src/render.py @@ -0,0 +1,122 @@ +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('}') |