26 class fmterror(Exception):
29 class eoferror(fmterror):
31 super().__init__("unexpected end-of-data")
33 class referror(fmterror):
35 super().__init__("bad backref")
37 class namedtype(type):
40 class decoder(object):
58 ret += (b & 0x7f) << p
74 return buf.decode("utf-8")
76 def loadsym(self, fp):
79 nsref = self.loadint(fp)
80 if not 0 <= nsref < len(self.reftab):
81 raise fmterror("illegal namespace ref: " + str(nsref))
82 nssym = self.reftab[nsref]
83 if not isinstance(nssym, data.symbol):
84 raise fmterror("illegal namespace ref: " + str(nsref))
89 ret = data.symbol.get(ns, nm)
92 def loadlist(self, fp, buf):
97 buf.append(self.loadtagged(fp, tag))
99 def loadmap(self, fp, buf):
104 key = self.loadtagged(fp, tag)
108 buf[key] = self.loadtagged(fp, tag)
110 def loadobj(self, fp, ref=False):
112 refid = len(self.reftab)
113 self.reftab.append(None)
115 typ = self.namedtypes.get(nm)
117 typ = self.namedtypes[nm] = namedtype(str(nm), (data.obj, object), {})
121 self.reftab[refid] = ret
123 # print(">", nm, hex(st))
124 ret.__dict__.update(self.loadmap(fp, {}))
125 # print("<", nm, hex(fp.tell()), hex(st))
128 def addref(self, obj):
129 self.reftab.append(obj)
132 def loadtagged(self, fp, tag):
133 pri, sec = (tag & 0x7), (tag & 0xf8) >> 3
135 raise fmterror("unexpected end-tag")
138 idx = self.loadint(fp)
139 if not 0 <= idx < len(self.reftab):
141 # print(idx, self.reftab[idx], hex(fp.tell()))
142 return self.reftab[idx]
143 return self.addref(self.loadint(fp))
145 ret = self.addref(self.loadstr(fp))
147 return data.symbol.get("", ret)
150 ln = self.loadint(fp)
151 ret = self.addref(fp.read(ln))
157 return self.addref(True)
158 elif sec == NIL_FALSE:
159 return self.addref(False)
160 return self.addref(None)
162 return self.addref(self.loadsym(fp))
165 return self.loadmap(fp, self.addref({}))
167 return self.loadobj(fp, ref=True)
169 return self.loadlist(fp, self.addref([]))
171 raise fmterror("unknown primary: " + str(pri))
175 return self.loadtagged(fp, tag)