File: form.py

package info (click to toggle)
pypy 5.6.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 97,040 kB
  • ctags: 185,069
  • sloc: python: 1,147,862; ansic: 49,642; cpp: 5,245; asm: 5,169; makefile: 529; sh: 481; xml: 232; lisp: 45
file content (194 lines) | stat: -rw-r--r-- 6,650 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194

# XXX there is much grot here.

# some of this comes from trying to present a reasonably intuitive and
# useful interface, which implies a certain amount of DWIMmery.
# things surely still could be more transparent.

class FormException(Exception):
    pass


class Instruction(object):
    def __init__(self, fields):
        self.fields = fields
        self.lfields = [k for (k,v) in fields.iteritems()
                        if isinstance(v, str)]
        #if not self.lfields:
        #    self.assemble() # for error checking only
    def assemble(self):
        r = 0
        for field in self.fields:
            r |= field.encode(self.fields[field])
        return r


class IBoundDesc(object):
    def __init__(self, desc, fieldmap, assembler):
        self.fieldmap = fieldmap
        self.desc = desc
        self.assembler = assembler
    def calc_fields(self, args, kw):
        fieldsleft = list(self.desc.fields)
        fieldvalues = {}
        for fname in kw:
            kw[fname] = self.fieldmap[fname]
        for d in (self.desc.specializations, kw):
            for field in d:
                fieldsleft.remove(field)
                fieldvalues[field] = d[field]
        for i in range(min(len(self.desc.defaults), len(fieldsleft) - len(args))):
            f, v = self.desc.defaults[i]
            fieldvalues[f] = v
            fieldsleft.remove(f)            
        for a in args:
            field = fieldsleft.pop(0)
            fieldvalues[field] = a
        return fieldvalues, fieldsleft
    def __call__(self, *args, **kw):
        fieldvalues, sparefields = self.calc_fields(args, kw)
        if sparefields:
            raise FormException('fields %s left'%sparefields)
        self.assembler.insts.append(Instruction(fieldvalues))


class IBoundDupDesc(IBoundDesc):
    def calc_fields(self, args, kw):
        s = super(IBoundDupDesc, self)
        fieldvalues, sparefields = s.calc_fields(args, kw)
        for k, v in self.desc.dupfields.iteritems():
            fieldvalues[k] = fieldvalues[v]
        return fieldvalues, sparefields


class IDesc(object):
    boundtype = IBoundDesc
    def __init__(self, fieldmap, fields, specializations, boundtype=None):
        self.fieldmap = fieldmap
        self.fields = fields
        self.specializations = specializations
        self.defaults = ()
        if boundtype is not None:
            self.boundtype = boundtype
        for field in specializations:
            if field not in fields:
                raise FormException(field)

    def __get__(self, ob, cls=None):
        if ob is None: return self
        return self.boundtype(self, self.fieldmap, ob)

    def default(self, **defs):
        assert len(defs) == 1
        f, v = defs.items()[0]
        self.defaults = self.defaults + ((self.fieldmap[f], v),)
        return self

    def __call__(self, **more_specializatons):
        s = self.specializations.copy()
        ms = {}
        ds = {}
        for fname, v in more_specializatons.iteritems():
            field = self.fieldmap[fname]
            if field not in self.fields:
                raise FormException("don't know about '%s' here" % field)
            if isinstance(v, str):
                ds[field] = self.fieldmap[v]
            else:
                ms[field] = v
        s.update(ms)
        if len(s) != len(self.specializations) + len(ms):
            raise FormException("respecialization not currently allowed")
        if ds:
            fields = list(self.fields)
            for field in ds:
                fields.remove(field)
            return IDupDesc(self.fieldmap, tuple(fields), s, ds)
        else:
            r = IDesc(self.fieldmap, self.fields, s, self.boundtype)
            r.defaults = tuple([(f, d) for (f, d) in self.defaults if f not in s])
            return r

    def match(self, inst):
        c = 0
        for field in self.fields:
            if field in self.specializations:
                if field.decode(inst) != self.specializations[field]:
                    return 0
                else:
                    c += 1
        return c

    def __repr__(self):
        l = []
        for field in self.fields:
            if field in self.specializations:
                l.append('%s=%r'%(field.name, self.specializations[field]))
            else:
                l.append(field.name)
        r = '%s(%s)'%(self.__class__.__name__, ', '.join(l))
        if self.boundtype is not self.__class__.boundtype:
            r += ' => ' + self.boundtype.__name__
        return r

    def disassemble(self, name, inst, labels, pc):
        kws = []
        for field in self.fields:
            if field not in self.specializations:
                v = field.decode(inst)
                for f, d in self.defaults:
                    if f is field:
                        if d == v:
                            break
                else:
                    kws.append('%s=%s'%(field.name, field.r(inst, labels, pc)))
        return "%-5s %s"%(name, ', '.join(kws))


class IDupDesc(IDesc):
    boundtype = IBoundDupDesc
    def __init__(self, fieldmap, fields, specializations, dupfields):
        super(IDupDesc, self).__init__(fieldmap, fields, specializations)
        self.dupfields = dupfields

    def match(self, inst):
        for field in self.dupfields:
            df = self.dupfields[field]
            if field.decode(inst) != df.decode(inst):
                return 0
        else:
            return super(IDupDesc, self).match(inst)


class Form(object):
    fieldmap = None
    def __init__(self, *fnames):
        self.fields = []
        bits = {}
        overlap = False
        for fname in fnames:
            if isinstance(fname, str):
                field = self.fieldmap[fname]
            else:
                field = fname
            if field.overlap:
                overlap = True
            for b in range(field.left, field.right+1):
                if not overlap and b in bits:
                    raise FormException("'%s' and '%s' clash at bit '%s'"%(
                        bits[b], fname, b))
                else:
                    bits[b] = fname
            self.fields.append(field)

    def __call__(self, **specializations):
        s = {}
        for fname in specializations:
            field = self.fieldmap[fname]
            if field not in self.fields:
                raise FormException("no nothin bout '%s'"%fname)
            s[field] = specializations[fname]
        return IDesc(self.fieldmap, self.fields, s)

    def __repr__(self):
        return '%s(%r)'%(self.__class__.__name__, [f.name for f in self.fields])