| #! /usr/bin/env python |
| # |
| # Modulator - Generate skeleton modules. |
| # |
| # The user fills out some forms with information about what the module |
| # should support (methods, objects), names of these things, prefixes to |
| # use for C code, whether the objects should also support access as numbers, |
| # etc etc etc. |
| # When the user presses 'Generate code' we generate a complete skeleton |
| # module in C. |
| # |
| # Alternatively, the selections made can be save to a python sourcefile and |
| # this sourcefile can be passed on the command line (resulting in the same |
| # skeleton C code). |
| # |
| # Jack Jansen, CWI, October 1994. |
| # |
| |
| import sys, os |
| if os.name <> 'mac': |
| sys.path.append(os.path.join(os.environ['HOME'], |
| 'src/python/Tools/modulator')) |
| |
| from Tkinter import * |
| from Tkextra import * |
| from ScrolledListbox import ScrolledListbox |
| import sys |
| import genmodule |
| import string |
| |
| oops = 'oops' |
| |
| IDENTSTARTCHARS = string.letters + '_' |
| IDENTCHARS = string.letters + string.digits + '_' |
| |
| # Check that string is a legal C identifier |
| def checkid(str): |
| if not str: return 0 |
| if not str[0] in IDENTSTARTCHARS: |
| return 0 |
| for c in str[1:]: |
| if not c in IDENTCHARS: |
| return 0 |
| return 1 |
| |
| def getlistlist(list): |
| rv = [] |
| n = list.size() |
| for i in range(n): |
| rv.append(list.get(i)) |
| return rv |
| |
| class UI: |
| def __init__(self): |
| self.main = Frame() |
| self.main.pack() |
| self.main.master.title('Modulator: Module view') |
| self.cmdframe = Frame(self.main, {'relief':'raised', 'bd':'0.5m', |
| Pack:{'side':'top', |
| 'fill':'x'}}) |
| self.objframe = Frame(self.main, {Pack:{'side':'top', 'fill':'x', |
| 'expand':1}}) |
| |
| |
| self.check_button = Button(self.cmdframe, |
| {'text':'Check', 'command':self.cb_check, |
| Pack:{'side':'left', 'padx':'0.5m'}}) |
| self.save_button = Button(self.cmdframe, |
| {'text':'Save...', 'command':self.cb_save, |
| Pack:{'side':'left', 'padx':'0.5m'}}) |
| self.code_button = Button(self.cmdframe, |
| {'text':'Generate code...', |
| 'command':self.cb_gencode, |
| Pack:{'side':'left', 'padx':'0.5m'}}) |
| self.quit_button = Button(self.cmdframe, |
| {'text':'Quit', |
| 'command':self.cb_quit, |
| Pack:{'side':'right', 'padx':'0.5m'}}) |
| |
| self.module = UI_module(self) |
| self.objects = [] |
| self.modified = 0 |
| |
| def run(self): |
| self.main.mainloop() |
| |
| def cb_quit(self, *args): |
| if self.modified: |
| if not askyn('You have not saved\nAre you sure you want to quit?'): |
| return |
| sys.exit(0) |
| |
| def cb_check(self, *args): |
| try: |
| self.module.synchronize() |
| for o in self.objects: |
| o.synchronize() |
| except oops: |
| pass |
| |
| def cb_save(self, *args): |
| try: |
| pycode = self.module.gencode('m', self.objects) |
| except oops: |
| return |
| |
| fn = askfile('Python file name: ') |
| if not fn: |
| return |
| |
| fp = open(fn, 'w') |
| |
| fp.write(pycode) |
| fp.close() |
| |
| def cb_gencode(self, *args): |
| try: |
| pycode = self.module.gencode('m', self.objects) |
| except oops: |
| pass |
| |
| fn = askfile('C file name: ') |
| if not fn: |
| return |
| |
| fp = open(fn, 'w') |
| |
| try: |
| exec pycode |
| except: |
| message('An error occurred:-)') |
| return |
| genmodule.write(fp, m) |
| fp.close() |
| |
| class UI_module: |
| def __init__(self, parent): |
| self.parent = parent |
| self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m', |
| Pack:{'side':'top', |
| 'fill':'x'}}) |
| self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
| 'fill':'x'}}) |
| self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
| 'fill':'x'}}) |
| self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
| 'fill':'x'}}) |
| self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
| 'fill':'x'}}) |
| |
| self.l1 = Label(self.f1, {'text':'Module:', Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.name_entry = Entry(self.f1, {'relief':'sunken', |
| Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) |
| self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5, |
| Pack:{'side':'left', 'padx':'0.5m'}}) |
| |
| self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2, |
| Pack:{'side':'left', 'expand':1, |
| 'padx':'0.5m', 'fill':'both'}}) |
| |
| self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.method_entry = Entry(self.f3, {'relief':'sunken', |
| Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) |
| self.method_entry.bind('<Return>', self.cb_method) |
| self.delete_button = Button(self.f3, {'text':'Delete method', |
| 'command':self.cb_delmethod, |
| Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| |
| self.newobj_button = Button(self.f4, {'text':'new object', |
| 'command':self.cb_newobj, |
| Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| |
| def cb_delmethod(self, *args): |
| list = self.method_list.curselection() |
| for i in list: |
| self.method_list.delete(i) |
| |
| def cb_newobj(self, *arg): |
| self.parent.objects.append(UI_object(self.parent)) |
| |
| def cb_method(self, *arg): |
| name = self.method_entry.get() |
| if not name: |
| return |
| self.method_entry.delete('0', 'end') |
| self.method_list.insert('end', name) |
| |
| def synchronize(self): |
| n = self.name_entry.get() |
| if not n: |
| message('Module name not set') |
| raise oops |
| if not checkid(n): |
| message('Module name not an identifier:\n'+n) |
| raise oops |
| if not self.abbrev_entry.get(): |
| self.abbrev_entry.insert('end', n) |
| m = getlistlist(self.method_list) |
| for n in m: |
| if not checkid(n): |
| message('Method name not an identifier:\n'+n) |
| raise oops |
| |
| def gencode(self, name, objects): |
| rv = '' |
| self.synchronize() |
| for o in objects: |
| o.synchronize() |
| onames = [] |
| for i in range(len(objects)): |
| oname = 'o%d' % (i+1) |
| rv = rv + objects[i].gencode(oname) |
| onames.append(oname) |
| rv = rv + '%s = genmodule.module()\n' % (name,) |
| rv = rv + '%s.name = %r\n' % (name, self.name_entry.get()) |
| rv = rv + '%s.abbrev = %r\n' % (name, self.abbrev_entry.get()) |
| rv = rv + '%s.methodlist = %r\n' % (name, getlistlist(self.method_list)) |
| rv = rv + '%s.objects = [%s]\n' % (name, ','.join(onames)) |
| rv = rv + '\n' |
| return rv |
| |
| object_number = 0 |
| |
| class UI_object: |
| def __init__(self, parent): |
| global object_number |
| |
| object_number = object_number + 1 |
| self.num = object_number |
| self.vpref = 'o%r_' % self.num |
| self.frame = Toplevel(parent.objframe) |
| # self.frame.pack() |
| self.frame.title('Modulator: object view') |
| # self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m', |
| # Pack:{'side':'top', |
| # 'fill':'x'}}) |
| self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
| 'fill':'x'}}) |
| self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
| 'fill':'x'}}) |
| self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
| 'fill':'x'}}) |
| self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', |
| 'fill':'x'}}) |
| |
| |
| self.l1 = Label(self.f1, {'text':'Object:', Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.name_entry = Entry(self.f1, {'relief':'sunken', |
| Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) |
| self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5, |
| Pack:{'side':'left', 'padx':'0.5m'}}) |
| |
| self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2, |
| Pack:{'side':'left', 'expand':1, |
| 'padx':'0.5m', 'fill':'both'}}) |
| |
| self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.method_entry = Entry(self.f3, {'relief':'sunken', |
| Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) |
| self.method_entry.bind('<Return>', self.cb_method) |
| self.delete_button = Button(self.f3, {'text':'Delete method', |
| 'command':self.cb_delmethod, |
| Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| |
| |
| self.l5 = Label(self.f4, {'text':'functions:', |
| Pack:{'side':'left', |
| 'padx':'0.5m'}}) |
| self.f5 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m', |
| 'fill':'both'}}) |
| self.l6 = Label(self.f4, {'text':'Types:', |
| Pack:{'side':'left', 'padx':'0.5m'}}) |
| self.f6 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m', |
| 'fill':'x'}}) |
| self.funcs = {} |
| for i in genmodule.FUNCLIST: |
| vname = self.vpref+i |
| self.f5.setvar(vname, 0) |
| b = Checkbutton(self.f5, {'variable':vname, 'text':i, |
| Pack:{'side':'top', 'pady':'0.5m', |
| 'anchor':'w','expand':1}}) |
| self.funcs[i] = b |
| self.f5.setvar(self.vpref+'new', 1) |
| |
| self.types = {} |
| for i in genmodule.TYPELIST: |
| vname = self.vpref + i |
| self.f6.setvar(vname, 0) |
| b = Checkbutton(self.f6, {'variable':vname, 'text':i, |
| Pack:{'side':'top', 'pady':'0.5m', |
| 'anchor':'w'}}) |
| self.types[i] = b |
| |
| def cb_method(self, *arg): |
| name = self.method_entry.get() |
| if not name: |
| return |
| self.method_entry.delete('0', 'end') |
| self.method_list.insert('end', name) |
| |
| def cb_delmethod(self, *args): |
| list = self.method_list.curselection() |
| for i in list: |
| self.method_list.delete(i) |
| |
| def synchronize(self): |
| n = self.name_entry.get() |
| if not n: |
| message('Object name not set') |
| raise oops |
| if not self.abbrev_entry.get(): |
| self.abbrev_entry.insert('end', n) |
| n = self.abbrev_entry.get() |
| if not checkid(n): |
| message('Abbreviation not an identifier:\n'+n) |
| raise oops |
| m = getlistlist(self.method_list) |
| for n in m: |
| if not checkid(n): |
| message('Method name not an identifier:\n'+n) |
| raise oops |
| if m: |
| self.f5.setvar(self.vpref+'tp_getattr', 1) |
| pass |
| |
| def gencode(self, name): |
| rv = '' |
| rv = rv + '%s = genmodule.object()\n' % (name,) |
| rv = rv + '%s.name = %r\n' % (name, self.name_entry.get()) |
| rv = rv + '%s.abbrev = %r\n' % (name, self.abbrev_entry.get()) |
| rv = rv + '%s.methodlist = %r\n' % (name, getlistlist(self.method_list)) |
| fl = [] |
| for fn in genmodule.FUNCLIST: |
| vname = self.vpref + fn |
| if self.f5.getvar(vname) == '1': |
| fl.append(fn) |
| rv = rv + '%s.funclist = %r\n' % (name, fl) |
| |
| fl = [] |
| for fn in genmodule.TYPELIST: |
| vname = self.vpref + fn |
| if self.f5.getvar(vname) == '1': |
| fl.append(fn) |
| |
| rv = rv + '%s.typelist = %r\n' % (name, fl) |
| |
| rv = rv + '\n' |
| return rv |
| |
| |
| def main(): |
| if len(sys.argv) < 2: |
| ui = UI() |
| ui.run() |
| elif len(sys.argv) == 2: |
| fp = open(sys.argv[1]) |
| pycode = fp.read() |
| try: |
| exec pycode |
| except: |
| sys.stderr.write('An error occurred:-)\n') |
| sys.exit(1) |
| ##genmodule.write(sys.stdout, m) |
| else: |
| sys.stderr.write('Usage: modulator [file]\n') |
| sys.exit(1) |
| |
| main() |