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