summaryrefslogtreecommitdiffstats
path: root/src/render.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/render.py')
-rw-r--r--src/render.py122
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('}')