Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import sys
2from logging import getLogger
3from jinja2 import Template
5from .parse import parse_file
7log = getLogger(__name__)
9tmpl = """
10from collections import OrderedDict
11import json
12import xdrlib
13from enum import Enum, EnumMeta
16class DefEnumMeta(EnumMeta):
17 def __call__(cls, value=None, *args, **kwargs):
18 if value is None:
19 return next(iter(cls))
20 return super().__call__(value, *args, **kwargs)
22{% if const|length != 0 %}
23class Constant(Enum):
24 'constant values'
25 {%- for cn in const %}
26 {{cn["const"]}} = {{cn["value"]}}
27 {%- endfor %}
28{%- endif %}
29{% if enum|length != 0 %}
31class xdr_enum(Enum, metaclass=DefEnumMeta):
32 def pack(self, p):
33 p.pack_int(self.value)
35 @classmethod
36 def unpack(cls, u):
37 return cls(u.unpack_int())
38{%- endif %}
39{% if struct|length + union|length != 0 %}
41class xdr_struct:
42 def to_json(self) -> str:
43 return json.dumps(self.to_dict(), default=json_encoder)
45 def to_dict(self) -> dict:
46 res = {}
47 for k, v in self._members.items():
48 val = getattr(self, k)
49 if hasattr(val, "to_dict"):
50 res[k] = val.to_dict()
51 else:
52 res[k] = val
53 return res
55 @classmethod
56 def from_dict(cls, d: dict):
57 res = cls()
58 for k, v in d.items():
59 setattr(res, k, v)
60 return res
62 def to_binary(self) -> bytes:
63 p = xdrlib.Packer()
64 self.pack(p)
65 return p.get_buf()
67 @classmethod
68 def from_binary(cls, data: bytes):
69 u = xdrlib.Unpacker(data)
70 res = cls.unpack(u)
71 return res, data[u.get_position():]
73 def pack(self, p):
74 for k, v in self._members.items():
75 val = getattr(self, k)
76 if hasattr(p, "pack_{}".format(v)):
77 fn = getattr(p, "pack_{}".format(v))
78 fn(val)
79 else:
80 val.pack(p)
82 @classmethod
83 def unpack(cls, u):
84 res = cls()
85 for k, v in cls._members.items():
86 if hasattr(u, "unpack_{}".format(v)):
87 fn = getattr(u, "unpack_{}".format(v))
88 setattr(res, k, fn())
89 else:
90 setattr(res, k, getattr(res, k).unpack(u))
91 return res
92{%- endif %}
93{% if union|length != 0 %}
95class xdr_union(xdr_struct):
96 def to_dict(self) -> dict:
97 res = {}
98 val = getattr(self, self._cond)
99 res[self._cond] = val
100 if val in self._values:
101 k = self._values[val]
102 v = getattr(self, k)
103 if hasattr(v, "to_dict"):
104 res[k] = v.to_dict()
105 else:
106 res[k] = v
107 return res
109 def pack(self, p):
110 val = getattr(self, self._cond)
111 val.pack(p)
112 if val in self._values:
113 to_pack = getattr(self, self._values[val])
114 to_pack.pack(p)
116 @classmethod
117 def unpack(cls, u):
118 res = cls()
119 cval = getattr(res, res._cond)
120 setattr(res, res._cond, cval.unpack(u))
121 cval = getattr(res, res._cond)
122 if cval in cls._values:
123 val = getattr(res, cls._values[cval])
124 setattr(res, cls._values[cval], val.unpack(u))
125 return res
126{%- endif %}
127{% if typedef|length != 0 %}
129class xdr_typedef:
130 def to_dict(self):
131 return self.data
132{%- endif %}
135def json_encoder(obj):
136{%- if enum|length != 0 %}
137 if isinstance(obj, xdr_enum):
138 return obj.name
139{%- endif %}
140{%- if union|length + struct|length != 0 %}
141 if isinstance(obj, xdr_struct):
142 return obj.to_dict()
143{%- endif %}
144{%- if typedef|length != 0 %}
145 if isinstance(obj, xdr_typedef):
146 return obj.data
147{%- endif %}
148 return obj
149{% for tp in typedef %}
151class {{tp["typedef"]}}(xdr_typedef):
152 'typedef {{tp["typedef"]}}'
154 def __init__(self):
155 # {{tp}}
156 self.data = None
158 def pack(self, p):
159 p.pack_{% if "fixed" in tp%}f{%endif%}{{tp["type"]}}(self.data)
161 @classmethod
162 def unpack(cls, u):
163{%- if "fixed" in tp and tp["fixed"] %}
164 self.data = u.unpack_f{{tp["type"]}}({{id2val[tp["length"]]}})
165{%- else %}
166 self.data = u.unpack_{{tp["type"]}}()
167{%- endif %}
168{% endfor -%}
169{% for en in enum %}
171class {{en["enum"]}}(xdr_enum):
172 'enum {{en["enum"]}}'
173 {%- for k,v in en["values"].items() %}
174 {{k}} = {{v}}
175 {%- endfor %}
176{%- endfor %}
177{% for st in struct %}
179class {{st["struct"]}}(xdr_struct):
180 'struct {{st["struct"]}}'
181 _members = OrderedDict([
182{%- for e in st["entries"] %}
183 ("{{e["name"]}}", "{{basetype[e["type"]]|default(e["type"])}}"),
184{%- endfor %}
185 ])
187 def __init__(self):
188{%- for x in st["entries"] %}
189 # {{x}}
190{%- if x["type"] in basetype %}
191 self.{{x["name"]}} = None
192{%- else %}
193 self.{{x["name"]}} = {{x["type"]}}()
194{%- endif %}
195{%- endfor %}
196{% endfor -%}
197{% for un in union %}
199class {{un["union"]}}(xdr_union):
200 'union {{un["union"]}}'
201 _cond = "{{un["cond"]["name"]}}"
202 _values = {
203{%- for c in un["cases"] %}
204{%- if "name" in c %}
205{%- if c["label"] == "default" %}
206 None: "{{c["name"]}}",
207{%- else %}
208 {{id2val[c["label"]] | default(c["label"])}}: "{{c["name"]}}",
209{%- endif %}
210{%- endif %}
211{%- endfor %}
212 }
214 def __init__(self):
215 # condition: {{un["cond"]}}
216{%- if un["cond"]["type"] in basetype %}
217 self.{{un["cond"]["name"]}} = None
218{%- else %}
219 self.{{un["cond"]["name"]}} = {{un["cond"]["type"]}}()
220{%- endif %}
221 {%- for c in un["cases"] %}
222{%- if "name" in c %}
223 # {{c}}
224{%- if c["type"] in basetype %}
225 self.{{c["name"]}} = None
226{%- else %}
227 self.{{c["name"]}} = {{c["type"]}}()
228{%- endif %}
229{%- endif %}
230 {%- endfor %}
231{% endfor %}
232{%- for p in program %}
234class {{p["program"]}}:
235 'program {{p["program"]}}'
236 ID = {{p["num"]}}
237{% for v in p["versions"] %}
238 class {{v["version"]}}:
239 'version {{v["version"]}}'
240 ID = {{v["num"]}}
241{% for proc in v["procs"] %}
242 def {{proc["name"]}}(self{% if proc["arg"] != "void" %}, arg: {{typemap[proc["arg"]]|default(proc["arg"])}}{% endif %}) -> {% if proc["res"]!="void" %}{{typemap[proc["res"]]|default(proc["res"])}}{% else %}None{% endif %}:
243 pass
244{% endfor %}
245 pass
246{% endfor %}
247 pass
248{% endfor %}
249"""
252def convert_parsed(parsed):
253 res = {
254 "const": [],
255 "enum": [],
256 "struct": [],
257 "union": [],
258 "program": [],
259 "typedef": [],
260 "id2val": {
261 "TRUE": "True",
262 "FALSE": "False",
263 },
264 "basetype": {
265 "int": "int",
266 "unsigned": "uint",
267 "bool": "bool",
268 "hyper": "hyper",
269 "uhyper": "uhyper",
270 "float": "float",
271 "double": "double",
272 "string": "string",
273 "opaque": "opaque"
274 },
275 "typemap": {
276 "unsigned": "int",
277 "opaque": "bytes",
278 "string": "str",
279 "double": "float",
280 "hyper": "int",
281 }
282 }
283 for l in parsed:
284 for k in res.keys():
285 if l.get(k, None) is not None:
286 res[k].append(l)
287 for c in res["const"]:
288 if c["value"].startswith("0") and not c["value"].startswith("0x"):
289 c["value"] = "0o" + c["value"].lstrip("0")
290 res["id2val"][c["const"]] = "Constant.{}".format(c["const"])
291 for c in res["const"]:
292 res["id2val"][c["const"]] = "Constant.{}".format(c["const"])
293 for en in res["enum"]:
294 for k, v in en["values"].items():
295 res["id2val"][k] = "{}.{}".format(en["enum"], k)
296 log.debug("converted: %s", res["struct"])
297 return res
300def generate_proto(parsed, tmpl_str=None):
301 if tmpl_str is None:
302 tmpl_str = tmpl
303 template = Template(tmpl_str)
304 res = template.render(convert_parsed(parsed))
305 return res
308if __name__ == "__main__":
309 data = parse_file(sys.stdin)
310 res = generate_proto(data)
311 print(res)