Hide keyboard shortcuts

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 

4 

5from .parse import parse_file 

6 

7log = getLogger(__name__) 

8 

9tmpl = """ 

10from collections import OrderedDict 

11import json 

12import xdrlib 

13from enum import Enum, EnumMeta 

14 

15 

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) 

21 

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 %} 

30 

31class xdr_enum(Enum, metaclass=DefEnumMeta): 

32 def pack(self, p): 

33 p.pack_int(self.value) 

34 

35 @classmethod 

36 def unpack(cls, u): 

37 return cls(u.unpack_int()) 

38{%- endif %} 

39{% if struct|length + union|length != 0 %} 

40 

41class xdr_struct: 

42 def to_json(self) -> str: 

43 return json.dumps(self.to_dict(), default=json_encoder) 

44 

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 

54 

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 

61 

62 def to_binary(self) -> bytes: 

63 p = xdrlib.Packer() 

64 self.pack(p) 

65 return p.get_buf() 

66 

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():] 

72 

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) 

81 

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 %} 

94 

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 

108 

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) 

115 

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 %} 

128 

129class xdr_typedef: 

130 def to_dict(self): 

131 return self.data 

132{%- endif %} 

133 

134 

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 %} 

150 

151class {{tp["typedef"]}}(xdr_typedef): 

152 'typedef {{tp["typedef"]}}' 

153 

154 def __init__(self): 

155 # {{tp}} 

156 self.data = None 

157 

158 def pack(self, p): 

159 p.pack_{% if "fixed" in tp%}f{%endif%}{{tp["type"]}}(self.data) 

160 

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 %} 

170 

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 %} 

178 

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 ]) 

186 

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 %} 

198 

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 } 

213 

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 %} 

233 

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""" 

250 

251 

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 

298 

299 

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 

306 

307 

308if __name__ == "__main__": 

309 data = parse_file(sys.stdin) 

310 res = generate_proto(data) 

311 print(res)