blob: c5cc79f3b318fa9b3d21ea03c2d07564c807f028 [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossumd2112201995-03-02 14:05:29 +00002#
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
19import sys, os
Guido van Rossuma0e24221996-03-07 16:16:54 +000020if os.name <> 'mac':
Guido van Rossuma16a5091998-04-10 19:15:27 +000021 sys.path.append(os.path.join(os.environ['HOME'],
22 'src/python/Tools/modulator'))
Guido van Rossumd2112201995-03-02 14:05:29 +000023
24from Tkinter import *
25from Tkextra import *
Guido van Rossumd2112201995-03-02 14:05:29 +000026from ScrolledListbox import ScrolledListbox
27import sys
28import genmodule
29import string
30
31oops = 'oops'
32
33# Check that string is a legal C identifier
34def checkid(str):
35 if not str: return 0
36 if not str[0] in string.letters+'_':
Guido van Rossuma16a5091998-04-10 19:15:27 +000037 return 0
Guido van Rossumd2112201995-03-02 14:05:29 +000038 for c in str[1:]:
Guido van Rossuma16a5091998-04-10 19:15:27 +000039 if not c in string.letters+string.digits+'_':
40 return 0
Guido van Rossumd2112201995-03-02 14:05:29 +000041 return 1
42
43def getlistlist(list):
44 rv = []
45 n = list.size()
46 for i in range(n):
Guido van Rossuma16a5091998-04-10 19:15:27 +000047 rv.append(list.get(i))
Guido van Rossumd2112201995-03-02 14:05:29 +000048 return rv
49
50class UI:
51 def __init__(self):
Guido van Rossuma16a5091998-04-10 19:15:27 +000052 self.main = Frame()
53 self.main.pack()
54 self.main.master.title('Modulator: Module view')
55 self.cmdframe = Frame(self.main, {'relief':'raised', 'bd':'0.5m',
56 Pack:{'side':'top',
57 'fill':'x'}})
58 self.objframe = Frame(self.main, {Pack:{'side':'top', 'fill':'x',
59 'expand':1}})
Guido van Rossumd2112201995-03-02 14:05:29 +000060
61
Guido van Rossuma16a5091998-04-10 19:15:27 +000062 self.check_button = Button(self.cmdframe,
63 {'text':'Check', 'command':self.cb_check,
64 Pack:{'side':'left', 'padx':'0.5m'}})
65 self.save_button = Button(self.cmdframe,
66 {'text':'Save...', 'command':self.cb_save,
67 Pack:{'side':'left', 'padx':'0.5m'}})
68 self.code_button = Button(self.cmdframe,
69 {'text':'Generate code...',
70 'command':self.cb_gencode,
71 Pack:{'side':'left', 'padx':'0.5m'}})
72 self.quit_button = Button(self.cmdframe,
73 {'text':'Quit',
74 'command':self.cb_quit,
75 Pack:{'side':'right', 'padx':'0.5m'}})
Guido van Rossumd2112201995-03-02 14:05:29 +000076
Guido van Rossuma16a5091998-04-10 19:15:27 +000077 self.module = UI_module(self)
78 self.objects = []
79 self.modified = 0
Guido van Rossumd2112201995-03-02 14:05:29 +000080
81 def run(self):
Guido van Rossuma16a5091998-04-10 19:15:27 +000082 self.main.mainloop()
Guido van Rossumd2112201995-03-02 14:05:29 +000083
84 def cb_quit(self, *args):
Guido van Rossuma16a5091998-04-10 19:15:27 +000085 if self.modified:
86 if not askyn('You have not saved\nAre you sure you want to quit?'):
87 return
88 sys.exit(0)
Guido van Rossumd2112201995-03-02 14:05:29 +000089
90 def cb_check(self, *args):
Guido van Rossuma16a5091998-04-10 19:15:27 +000091 try:
92 self.module.synchronize()
93 for o in self.objects:
94 o.synchronize()
95 except oops:
96 pass
97
Guido van Rossumd2112201995-03-02 14:05:29 +000098 def cb_save(self, *args):
Guido van Rossuma16a5091998-04-10 19:15:27 +000099 try:
100 pycode = self.module.gencode('m', self.objects)
101 except oops:
102 return
Guido van Rossumd2112201995-03-02 14:05:29 +0000103
Guido van Rossuma16a5091998-04-10 19:15:27 +0000104 fn = askfile('Python file name: ')
105 if not fn:
106 return
Guido van Rossumd2112201995-03-02 14:05:29 +0000107
Guido van Rossuma16a5091998-04-10 19:15:27 +0000108 fp = open(fn, 'w')
Guido van Rossumd2112201995-03-02 14:05:29 +0000109
Guido van Rossuma16a5091998-04-10 19:15:27 +0000110 fp.write(pycode)
111 fp.close()
Guido van Rossumd2112201995-03-02 14:05:29 +0000112
113 def cb_gencode(self, *args):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000114 try:
115 pycode = self.module.gencode('m', self.objects)
116 except oops:
117 pass
Guido van Rossumd2112201995-03-02 14:05:29 +0000118
Guido van Rossuma16a5091998-04-10 19:15:27 +0000119 fn = askfile('C file name: ')
120 if not fn:
121 return
Guido van Rossumd2112201995-03-02 14:05:29 +0000122
Guido van Rossuma16a5091998-04-10 19:15:27 +0000123 fp = open(fn, 'w')
Guido van Rossumd2112201995-03-02 14:05:29 +0000124
Guido van Rossuma16a5091998-04-10 19:15:27 +0000125 try:
126 exec pycode
127 except:
128 message('An error occurred:-)')
129 return
130 genmodule.write(fp, m)
131 fp.close()
Guido van Rossumd2112201995-03-02 14:05:29 +0000132
133class UI_module:
134 def __init__(self, parent):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000135 self.parent = parent
136 self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m',
137 Pack:{'side':'top',
138 'fill':'x'}})
139 self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m',
140 'fill':'x'}})
141 self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m',
142 'fill':'x'}})
143 self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m',
144 'fill':'x'}})
145 self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m',
146 'fill':'x'}})
Guido van Rossumd2112201995-03-02 14:05:29 +0000147
Guido van Rossuma16a5091998-04-10 19:15:27 +0000148 self.l1 = Label(self.f1, {'text':'Module:', Pack:{'side':'left',
149 'padx':'0.5m'}})
150 self.name_entry = Entry(self.f1, {'relief':'sunken',
151 Pack:{'side':'left', 'padx':'0.5m', 'expand':1}})
152 self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left',
153 'padx':'0.5m'}})
154 self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5,
155 Pack:{'side':'left', 'padx':'0.5m'}})
Guido van Rossumd2112201995-03-02 14:05:29 +0000156
Guido van Rossuma16a5091998-04-10 19:15:27 +0000157 self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left',
158 'padx':'0.5m'}})
159 self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2,
160 Pack:{'side':'left', 'expand':1,
161 'padx':'0.5m', 'fill':'both'}})
Guido van Rossumd2112201995-03-02 14:05:29 +0000162
Guido van Rossuma16a5091998-04-10 19:15:27 +0000163 self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left',
164 'padx':'0.5m'}})
165 self.method_entry = Entry(self.f3, {'relief':'sunken',
166 Pack:{'side':'left', 'padx':'0.5m', 'expand':1}})
167 self.method_entry.bind('<Return>', self.cb_method)
168 self.delete_button = Button(self.f3, {'text':'Delete method',
169 'command':self.cb_delmethod,
170 Pack:{'side':'left',
171 'padx':'0.5m'}})
Guido van Rossumd2112201995-03-02 14:05:29 +0000172
Guido van Rossuma16a5091998-04-10 19:15:27 +0000173 self.newobj_button = Button(self.f4, {'text':'new object',
174 'command':self.cb_newobj,
175 Pack:{'side':'left',
176 'padx':'0.5m'}})
177
Guido van Rossumd2112201995-03-02 14:05:29 +0000178 def cb_delmethod(self, *args):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000179 list = self.method_list.curselection()
180 for i in list:
181 self.method_list.delete(i)
182
Guido van Rossumd2112201995-03-02 14:05:29 +0000183 def cb_newobj(self, *arg):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000184 self.parent.objects.append(UI_object(self.parent))
Guido van Rossumd2112201995-03-02 14:05:29 +0000185
186 def cb_method(self, *arg):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000187 name = self.method_entry.get()
188 if not name:
189 return
190 self.method_entry.delete('0', 'end')
191 self.method_list.insert('end', name)
Guido van Rossumd2112201995-03-02 14:05:29 +0000192
193 def synchronize(self):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000194 n = self.name_entry.get()
195 if not n:
196 message('Module name not set')
197 raise oops
198 if not checkid(n):
199 message('Module name not an identifier:\n'+n)
200 raise oops
201 if not self.abbrev_entry.get():
202 self.abbrev_entry.insert('end', n)
203 m = getlistlist(self.method_list)
204 for n in m:
205 if not checkid(n):
206 message('Method name not an identifier:\n'+n)
207 raise oops
208
Guido van Rossumd2112201995-03-02 14:05:29 +0000209 def gencode(self, name, objects):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000210 rv = ''
211 self.synchronize()
212 for o in objects:
213 o.synchronize()
214 onames = []
215 for i in range(len(objects)):
216 oname = 'o'+`i+1`
217 rv = rv + objects[i].gencode(oname)
218 onames.append(oname)
219 rv = rv + (name+' = genmodule.module()\n')
220 rv = rv + (name+'.name = '+`self.name_entry.get()`+'\n')
221 rv = rv + (name+'.abbrev = '+`self.abbrev_entry.get()`+'\n')
222 rv = rv + (name+'.methodlist = '+`getlistlist(self.method_list)`+'\n')
223 rv = rv + (name+'.objects = ['+string.joinfields(onames, ',')+']\n')
224 rv = rv + ('\n')
225 return rv
226
Guido van Rossumd2112201995-03-02 14:05:29 +0000227object_number = 0
228
229class UI_object:
230 def __init__(self, parent):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000231 global object_number
Guido van Rossumd2112201995-03-02 14:05:29 +0000232
Guido van Rossuma16a5091998-04-10 19:15:27 +0000233 object_number = object_number + 1
234 self.num = object_number
235 self.vpref = 'o'+`self.num`+'_'
236 self.frame = Toplevel(parent.objframe)
237# self.frame.pack()
238 self.frame.title('Modulator: object view')
239# self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m',
240# Pack:{'side':'top',
241# 'fill':'x'}})
242 self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m',
243 'fill':'x'}})
244 self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m',
245 'fill':'x'}})
246 self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m',
247 'fill':'x'}})
248 self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m',
249 'fill':'x'}})
250
Guido van Rossumd2112201995-03-02 14:05:29 +0000251
Guido van Rossuma16a5091998-04-10 19:15:27 +0000252 self.l1 = Label(self.f1, {'text':'Object:', Pack:{'side':'left',
253 'padx':'0.5m'}})
254 self.name_entry = Entry(self.f1, {'relief':'sunken',
255 Pack:{'side':'left', 'padx':'0.5m', 'expand':1}})
256 self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left',
257 'padx':'0.5m'}})
258 self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5,
259 Pack:{'side':'left', 'padx':'0.5m'}})
Guido van Rossumd2112201995-03-02 14:05:29 +0000260
Guido van Rossuma16a5091998-04-10 19:15:27 +0000261 self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left',
262 'padx':'0.5m'}})
263 self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2,
264 Pack:{'side':'left', 'expand':1,
265 'padx':'0.5m', 'fill':'both'}})
Guido van Rossumd2112201995-03-02 14:05:29 +0000266
Guido van Rossuma16a5091998-04-10 19:15:27 +0000267 self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left',
268 'padx':'0.5m'}})
269 self.method_entry = Entry(self.f3, {'relief':'sunken',
270 Pack:{'side':'left', 'padx':'0.5m', 'expand':1}})
271 self.method_entry.bind('<Return>', self.cb_method)
272 self.delete_button = Button(self.f3, {'text':'Delete method',
273 'command':self.cb_delmethod,
274 Pack:{'side':'left',
275 'padx':'0.5m'}})
Guido van Rossumd2112201995-03-02 14:05:29 +0000276
277
Guido van Rossuma16a5091998-04-10 19:15:27 +0000278 self.l5 = Label(self.f4, {'text':'functions:',
279 Pack:{'side':'left',
280 'padx':'0.5m'}})
281 self.f5 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m',
282 'fill':'both'}})
283 self.l6 = Label(self.f4, {'text':'Types:',
284 Pack:{'side':'left', 'padx':'0.5m'}})
285 self.f6 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m',
286 'fill':'x'}})
287 self.funcs = {}
288 for i in genmodule.FUNCLIST:
289 vname = self.vpref+i
290 self.f5.setvar(vname, 0)
291 b = Checkbutton(self.f5, {'variable':vname, 'text':i,
292 Pack:{'side':'top', 'pady':'0.5m',
293 'anchor':'w','expand':1}})
294 self.funcs[i] = b
295 self.f5.setvar(self.vpref+'new', 1)
Guido van Rossumd2112201995-03-02 14:05:29 +0000296
Guido van Rossuma16a5091998-04-10 19:15:27 +0000297 self.types = {}
298 for i in genmodule.TYPELIST:
299 vname = self.vpref + i
300 self.f6.setvar(vname, 0)
301 b = Checkbutton(self.f6, {'variable':vname, 'text':i,
302 Pack:{'side':'top', 'pady':'0.5m',
303 'anchor':'w'}})
304 self.types[i] = b
305
Guido van Rossumd2112201995-03-02 14:05:29 +0000306 def cb_method(self, *arg):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000307 name = self.method_entry.get()
308 if not name:
309 return
310 self.method_entry.delete('0', 'end')
311 self.method_list.insert('end', name)
Guido van Rossumd2112201995-03-02 14:05:29 +0000312
313 def cb_delmethod(self, *args):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000314 list = self.method_list.curselection()
315 for i in list:
316 self.method_list.delete(i)
317
Guido van Rossumd2112201995-03-02 14:05:29 +0000318 def synchronize(self):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000319 n = self.name_entry.get()
320 if not n:
321 message('Object name not set')
322 raise oops
323 if not self.abbrev_entry.get():
324 self.abbrev_entry.insert('end', n)
325 n = self.abbrev_entry.get()
326 if not checkid(n):
327 message('Abbreviation not an identifier:\n'+n)
328 raise oops
329 m = getlistlist(self.method_list)
330 for n in m:
331 if not checkid(n):
332 message('Method name not an identifier:\n'+n)
333 raise oops
334 if m:
335 self.f5.setvar(self.vpref+'tp_getattr', 1)
336 pass
337
Guido van Rossumd2112201995-03-02 14:05:29 +0000338 def gencode(self, name):
Guido van Rossuma16a5091998-04-10 19:15:27 +0000339 rv = ''
340 rv = rv + (name+' = genmodule.object()\n')
341 rv = rv + (name+'.name = '+`self.name_entry.get()`+'\n')
342 rv = rv + (name+'.abbrev = '+`self.abbrev_entry.get()`+'\n')
343 rv = rv + (name+'.methodlist = '+`getlistlist(self.method_list)`+'\n')
344 fl = []
345 for fn in genmodule.FUNCLIST:
346 vname = self.vpref + fn
347 if self.f5.getvar(vname) == '1':
348 fl.append(fn)
349 rv = rv + (name+'.funclist = '+`fl`+'\n')
Guido van Rossumd2112201995-03-02 14:05:29 +0000350
Guido van Rossuma16a5091998-04-10 19:15:27 +0000351 fl = []
352 for fn in genmodule.TYPELIST:
353 vname = self.vpref + fn
354 if self.f5.getvar(vname) == '1':
355 fl.append(fn)
356
357 rv = rv + (name+'.typelist = '+`fl`+'\n')
Guido van Rossumd2112201995-03-02 14:05:29 +0000358
Guido van Rossuma16a5091998-04-10 19:15:27 +0000359 rv = rv + ('\n')
360 return rv
361
Guido van Rossumd2112201995-03-02 14:05:29 +0000362
363def main():
364 if len(sys.argv) < 2:
Guido van Rossuma16a5091998-04-10 19:15:27 +0000365 ui = UI()
366 ui.run()
Guido van Rossumd2112201995-03-02 14:05:29 +0000367 elif len(sys.argv) == 2:
Guido van Rossuma16a5091998-04-10 19:15:27 +0000368 fp = open(sys.argv[1])
369 pycode = fp.read()
370 try:
371 exec pycode
372 except:
373 sys.stderr.write('An error occurred:-)\n')
374 sys.exit(1)
375 genmodule.write(sys.stdout, m)
Guido van Rossumd2112201995-03-02 14:05:29 +0000376 else:
Guido van Rossuma16a5091998-04-10 19:15:27 +0000377 sys.stderr.write('Usage: modulator [file]\n')
378 sys.exit(1)
379
Guido van Rossumd2112201995-03-02 14:05:29 +0000380main()