|
1 #! /usr/bin/env python |
|
2 # |
|
3 # Modulator - Generate skeleton modules. |
|
4 # |
|
5 # The user fills out some forms with information about what the module |
|
6 # should support (methods, objects), names of these things, prefixes to |
|
7 # use for C code, whether the objects should also support access as numbers, |
|
8 # etc etc etc. |
|
9 # When the user presses 'Generate code' we generate a complete skeleton |
|
10 # module in C. |
|
11 # |
|
12 # Alternatively, the selections made can be save to a python sourcefile and |
|
13 # this sourcefile can be passed on the command line (resulting in the same |
|
14 # skeleton C code). |
|
15 # |
|
16 # Jack Jansen, CWI, October 1994. |
|
17 # |
|
18 |
|
19 import sys, os |
|
20 if os.name <> 'mac': |
|
21 sys.path.append(os.path.join(os.environ['HOME'], |
|
22 'src/python/Tools/modulator')) |
|
23 |
|
24 from Tkinter import * |
|
25 from Tkextra import * |
|
26 from ScrolledListbox import ScrolledListbox |
|
27 import sys |
|
28 import genmodule |
|
29 import string |
|
30 |
|
31 oops = 'oops' |
|
32 |
|
33 IDENTSTARTCHARS = string.letters + '_' |
|
34 IDENTCHARS = string.letters + string.digits + '_' |
|
35 |
|
36 # Check that string is a legal C identifier |
|
37 def checkid(str): |
|
38 if not str: return 0 |
|
39 if not str[0] in IDENTSTARTCHARS: |
|
40 return 0 |
|
41 for c in str[1:]: |
|
42 if not c in IDENTCHARS: |
|
43 return 0 |
|
44 return 1 |
|
45 |
|
46 def getlistlist(list): |
|
47 rv = [] |
|
48 n = list.size() |
|
49 for i in range(n): |
|
50 rv.append(list.get(i)) |
|
51 return rv |
|
52 |
|
53 class UI: |
|
54 def __init__(self): |
|
55 self.main = Frame() |
|
56 self.main.pack() |
|
57 self.main.master.title('Modulator: Module view') |
|
58 self.cmdframe = Frame(self.main, {'relief':'raised', 'bd':'0.5m', |
|
59 Pack:{'side':'top', |
|
60 'fill':'x'}}) |
|
61 self.objframe = Frame(self.main, {Pack:{'side':'top', 'fill':'x', |
|
62 'expand':1}}) |
|
63 |
|
64 |
|
65 self.check_button = Button(self.cmdframe, |
|
66 {'text':'Check', 'command':self.cb_check, |
|
67 Pack:{'side':'left', 'padx':'0.5m'}}) |
|
68 self.save_button = Button(self.cmdframe, |
|
69 {'text':'Save...', 'command':self.cb_save, |
|
70 Pack:{'side':'left', 'padx':'0.5m'}}) |
|
71 self.code_button = Button(self.cmdframe, |
|
72 {'text':'Generate code...', |
|
73 'command':self.cb_gencode, |
|
74 Pack:{'side':'left', 'padx':'0.5m'}}) |
|
75 self.quit_button = Button(self.cmdframe, |
|
76 {'text':'Quit', |
|
77 'command':self.cb_quit, |
|
78 Pack:{'side':'right', 'padx':'0.5m'}}) |
|
79 |
|
80 self.module = UI_module(self) |
|
81 self.objects = [] |
|
82 self.modified = 0 |
|
83 |
|
84 def run(self): |
|
85 self.main.mainloop() |
|
86 |
|
87 def cb_quit(self, *args): |
|
88 if self.modified: |
|
89 if not askyn('You have not saved\nAre you sure you want to quit?'): |
|
90 return |
|
91 sys.exit(0) |
|
92 |
|
93 def cb_check(self, *args): |
|
94 try: |
|
95 self.module.synchronize() |
|
96 for o in self.objects: |
|
97 o.synchronize() |
|
98 except oops: |
|
99 pass |
|
100 |
|
101 def cb_save(self, *args): |
|
102 try: |
|
103 pycode = self.module.gencode('m', self.objects) |
|
104 except oops: |
|
105 return |
|
106 |
|
107 fn = askfile('Python file name: ') |
|
108 if not fn: |
|
109 return |
|
110 |
|
111 fp = open(fn, 'w') |
|
112 |
|
113 fp.write(pycode) |
|
114 fp.close() |
|
115 |
|
116 def cb_gencode(self, *args): |
|
117 try: |
|
118 pycode = self.module.gencode('m', self.objects) |
|
119 except oops: |
|
120 pass |
|
121 |
|
122 fn = askfile('C file name: ') |
|
123 if not fn: |
|
124 return |
|
125 |
|
126 fp = open(fn, 'w') |
|
127 |
|
128 try: |
|
129 exec pycode |
|
130 except: |
|
131 message('An error occurred:-)') |
|
132 return |
|
133 genmodule.write(fp, m) |
|
134 fp.close() |
|
135 |
|
136 class UI_module: |
|
137 def __init__(self, parent): |
|
138 self.parent = parent |
|
139 self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m', |
|
140 Pack:{'side':'top', |
|
141 'fill':'x'}}) |
|
142 self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
|
143 'fill':'x'}}) |
|
144 self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
|
145 'fill':'x'}}) |
|
146 self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
|
147 'fill':'x'}}) |
|
148 self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
|
149 'fill':'x'}}) |
|
150 |
|
151 self.l1 = Label(self.f1, {'text':'Module:', Pack:{'side':'left', |
|
152 'padx':'0.5m'}}) |
|
153 self.name_entry = Entry(self.f1, {'relief':'sunken', |
|
154 Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) |
|
155 self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left', |
|
156 'padx':'0.5m'}}) |
|
157 self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5, |
|
158 Pack:{'side':'left', 'padx':'0.5m'}}) |
|
159 |
|
160 self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left', |
|
161 'padx':'0.5m'}}) |
|
162 self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2, |
|
163 Pack:{'side':'left', 'expand':1, |
|
164 'padx':'0.5m', 'fill':'both'}}) |
|
165 |
|
166 self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left', |
|
167 'padx':'0.5m'}}) |
|
168 self.method_entry = Entry(self.f3, {'relief':'sunken', |
|
169 Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) |
|
170 self.method_entry.bind('<Return>', self.cb_method) |
|
171 self.delete_button = Button(self.f3, {'text':'Delete method', |
|
172 'command':self.cb_delmethod, |
|
173 Pack:{'side':'left', |
|
174 'padx':'0.5m'}}) |
|
175 |
|
176 self.newobj_button = Button(self.f4, {'text':'new object', |
|
177 'command':self.cb_newobj, |
|
178 Pack:{'side':'left', |
|
179 'padx':'0.5m'}}) |
|
180 |
|
181 def cb_delmethod(self, *args): |
|
182 list = self.method_list.curselection() |
|
183 for i in list: |
|
184 self.method_list.delete(i) |
|
185 |
|
186 def cb_newobj(self, *arg): |
|
187 self.parent.objects.append(UI_object(self.parent)) |
|
188 |
|
189 def cb_method(self, *arg): |
|
190 name = self.method_entry.get() |
|
191 if not name: |
|
192 return |
|
193 self.method_entry.delete('0', 'end') |
|
194 self.method_list.insert('end', name) |
|
195 |
|
196 def synchronize(self): |
|
197 n = self.name_entry.get() |
|
198 if not n: |
|
199 message('Module name not set') |
|
200 raise oops |
|
201 if not checkid(n): |
|
202 message('Module name not an identifier:\n'+n) |
|
203 raise oops |
|
204 if not self.abbrev_entry.get(): |
|
205 self.abbrev_entry.insert('end', n) |
|
206 m = getlistlist(self.method_list) |
|
207 for n in m: |
|
208 if not checkid(n): |
|
209 message('Method name not an identifier:\n'+n) |
|
210 raise oops |
|
211 |
|
212 def gencode(self, name, objects): |
|
213 rv = '' |
|
214 self.synchronize() |
|
215 for o in objects: |
|
216 o.synchronize() |
|
217 onames = [] |
|
218 for i in range(len(objects)): |
|
219 oname = 'o%d' % (i+1) |
|
220 rv = rv + objects[i].gencode(oname) |
|
221 onames.append(oname) |
|
222 rv = rv + '%s = genmodule.module()\n' % (name,) |
|
223 rv = rv + '%s.name = %r\n' % (name, self.name_entry.get()) |
|
224 rv = rv + '%s.abbrev = %r\n' % (name, self.abbrev_entry.get()) |
|
225 rv = rv + '%s.methodlist = %r\n' % (name, getlistlist(self.method_list)) |
|
226 rv = rv + '%s.objects = [%s]\n' % (name, ','.join(onames)) |
|
227 rv = rv + '\n' |
|
228 return rv |
|
229 |
|
230 object_number = 0 |
|
231 |
|
232 class UI_object: |
|
233 def __init__(self, parent): |
|
234 global object_number |
|
235 |
|
236 object_number = object_number + 1 |
|
237 self.num = object_number |
|
238 self.vpref = 'o%r_' % self.num |
|
239 self.frame = Toplevel(parent.objframe) |
|
240 # self.frame.pack() |
|
241 self.frame.title('Modulator: object view') |
|
242 # self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m', |
|
243 # Pack:{'side':'top', |
|
244 # 'fill':'x'}}) |
|
245 self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
|
246 'fill':'x'}}) |
|
247 self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
|
248 'fill':'x'}}) |
|
249 self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
|
250 'fill':'x'}}) |
|
251 self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
|
252 'fill':'x'}}) |
|
253 |
|
254 |
|
255 self.l1 = Label(self.f1, {'text':'Object:', Pack:{'side':'left', |
|
256 'padx':'0.5m'}}) |
|
257 self.name_entry = Entry(self.f1, {'relief':'sunken', |
|
258 Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) |
|
259 self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left', |
|
260 'padx':'0.5m'}}) |
|
261 self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5, |
|
262 Pack:{'side':'left', 'padx':'0.5m'}}) |
|
263 |
|
264 self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left', |
|
265 'padx':'0.5m'}}) |
|
266 self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2, |
|
267 Pack:{'side':'left', 'expand':1, |
|
268 'padx':'0.5m', 'fill':'both'}}) |
|
269 |
|
270 self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left', |
|
271 'padx':'0.5m'}}) |
|
272 self.method_entry = Entry(self.f3, {'relief':'sunken', |
|
273 Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) |
|
274 self.method_entry.bind('<Return>', self.cb_method) |
|
275 self.delete_button = Button(self.f3, {'text':'Delete method', |
|
276 'command':self.cb_delmethod, |
|
277 Pack:{'side':'left', |
|
278 'padx':'0.5m'}}) |
|
279 |
|
280 |
|
281 self.l5 = Label(self.f4, {'text':'functions:', |
|
282 Pack:{'side':'left', |
|
283 'padx':'0.5m'}}) |
|
284 self.f5 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m', |
|
285 'fill':'both'}}) |
|
286 self.l6 = Label(self.f4, {'text':'Types:', |
|
287 Pack:{'side':'left', 'padx':'0.5m'}}) |
|
288 self.f6 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m', |
|
289 'fill':'x'}}) |
|
290 self.funcs = {} |
|
291 for i in genmodule.FUNCLIST: |
|
292 vname = self.vpref+i |
|
293 self.f5.setvar(vname, 0) |
|
294 b = Checkbutton(self.f5, {'variable':vname, 'text':i, |
|
295 Pack:{'side':'top', 'pady':'0.5m', |
|
296 'anchor':'w','expand':1}}) |
|
297 self.funcs[i] = b |
|
298 self.f5.setvar(self.vpref+'new', 1) |
|
299 |
|
300 self.types = {} |
|
301 for i in genmodule.TYPELIST: |
|
302 vname = self.vpref + i |
|
303 self.f6.setvar(vname, 0) |
|
304 b = Checkbutton(self.f6, {'variable':vname, 'text':i, |
|
305 Pack:{'side':'top', 'pady':'0.5m', |
|
306 'anchor':'w'}}) |
|
307 self.types[i] = b |
|
308 |
|
309 def cb_method(self, *arg): |
|
310 name = self.method_entry.get() |
|
311 if not name: |
|
312 return |
|
313 self.method_entry.delete('0', 'end') |
|
314 self.method_list.insert('end', name) |
|
315 |
|
316 def cb_delmethod(self, *args): |
|
317 list = self.method_list.curselection() |
|
318 for i in list: |
|
319 self.method_list.delete(i) |
|
320 |
|
321 def synchronize(self): |
|
322 n = self.name_entry.get() |
|
323 if not n: |
|
324 message('Object name not set') |
|
325 raise oops |
|
326 if not self.abbrev_entry.get(): |
|
327 self.abbrev_entry.insert('end', n) |
|
328 n = self.abbrev_entry.get() |
|
329 if not checkid(n): |
|
330 message('Abbreviation not an identifier:\n'+n) |
|
331 raise oops |
|
332 m = getlistlist(self.method_list) |
|
333 for n in m: |
|
334 if not checkid(n): |
|
335 message('Method name not an identifier:\n'+n) |
|
336 raise oops |
|
337 if m: |
|
338 self.f5.setvar(self.vpref+'tp_getattr', 1) |
|
339 pass |
|
340 |
|
341 def gencode(self, name): |
|
342 rv = '' |
|
343 rv = rv + '%s = genmodule.object()\n' % (name,) |
|
344 rv = rv + '%s.name = %r\n' % (name, self.name_entry.get()) |
|
345 rv = rv + '%s.abbrev = %r\n' % (name, self.abbrev_entry.get()) |
|
346 rv = rv + '%s.methodlist = %r\n' % (name, getlistlist(self.method_list)) |
|
347 fl = [] |
|
348 for fn in genmodule.FUNCLIST: |
|
349 vname = self.vpref + fn |
|
350 if self.f5.getvar(vname) == '1': |
|
351 fl.append(fn) |
|
352 rv = rv + '%s.funclist = %r\n' % (name, fl) |
|
353 |
|
354 fl = [] |
|
355 for fn in genmodule.TYPELIST: |
|
356 vname = self.vpref + fn |
|
357 if self.f5.getvar(vname) == '1': |
|
358 fl.append(fn) |
|
359 |
|
360 rv = rv + '%s.typelist = %r\n' % (name, fl) |
|
361 |
|
362 rv = rv + '\n' |
|
363 return rv |
|
364 |
|
365 |
|
366 def main(): |
|
367 if len(sys.argv) < 2: |
|
368 ui = UI() |
|
369 ui.run() |
|
370 elif len(sys.argv) == 2: |
|
371 fp = open(sys.argv[1]) |
|
372 pycode = fp.read() |
|
373 try: |
|
374 exec pycode |
|
375 except: |
|
376 sys.stderr.write('An error occurred:-)\n') |
|
377 sys.exit(1) |
|
378 ##genmodule.write(sys.stdout, m) |
|
379 else: |
|
380 sys.stderr.write('Usage: modulator [file]\n') |
|
381 sys.exit(1) |
|
382 |
|
383 main() |