DSPython  00.03.03 — 25 juin 2012
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
combinatorTk.py
Aller à la documentation de ce fichier.
1 #!/usr/bin/env python
2 # -*- coding: latin-1 -*-
3 ##\file
4 # Application <b>Combinator Tk</b> permettant de manipuler les combinateurs
5 #
6 # \htmlonly <a class="relative" href="combinatorTk.png" target="_blank"><img
7 # src="combinatorTk_th.png" border="0" align="top" alt="[combinatorTk_th.png]"></a>\endhtmlonly\n
8 # Cf. \htmlonly <a href="http://www.opimedia.be/Bruno_Marchal/index.htm#Theo" target="_blank">
9 # <tt>http://www.opimedia.be/Bruno_Marchal/index.htm#Theo</tt></a>\endhtmlonly\n
10 # et \htmlonly <a href="http://fr.wikipedia.org/wiki/Logique_combinatoire" target="_blank">
11 # <tt>http://fr.wikipedia.org/wiki/Logique_combinatoire</tt></a>\endhtmlonly
12 # pour une présentation de la logique combinatoire.
13 
14 # (c) Olivier Pirson --- DragonSoft
15 # http://www.opimedia.be/DS/
16 # Débuté le 14 février 2008
17 # v.00.00 --- 2 mars 2008
18 # --- 19 mai 2008
19 # v.00.01 --- 14 novembre 2008
20 # v.00.02 --- 20 novembre 2008
21 # v.00.03 --- 22 novembre 2008
22 # v.00.04 --- 26 février 2009
23 # --- 29 septembre 2009 : nouveau site web
24 # v.00.05 --- 14 décembre 2009 : from __future__ import division
25 # v.00.06 --- 20 décembre 2009 : adapte pour Python 3
26 # v.00.07 --- 16 mars 2010 : nouveau site web et changement des % en .format()
27 # --- 12 avril 2010 : cfr. -> cf.
28 ###############################################################################
29 from __future__ import division
30 
31 ## Version
32 VERSION = 'v.00.07 --- 2010 April 12'
33 
34 import string, sys, time
35 
36 if sys.version_info[0] >= 3: # Python >= 3
37  import tkinter as tk
38  import tkinter.font as tkFont
39  import tkinter.messagebox as tkMessageBox
40 
41  ## Remplacement de la fonction disparue dans Python 3
42  def unichr(i):
43  return chr(i)
44 
45 else: # 2.6 <= Python < 3
46  import Tkinter as tk
47  import tkFont
48  import tkMessageBox
49 
50 import DSPython
51 import DSPython.combinator as combinator
52 
53 try:
54  if not 'profile' in dir():
55  import psyco
56  psyco.full()
57 except ImportError:
58  pass
59 
60 
61 
62 # ####################
63 # Variables globales #
64 ######################
65 ## Combinateur courant (ou None si champ de saisie vide ou incorrect)
66 comb = None
67 
68 
69 ## Nombre d'étapes évaluées
70 nb_eval = 0
71 
72 ## Nombre d'étapes à évaluer d'un coup
73 nb_eval_step = 1
74 
75 ## Naturel pour combinateur
76 numeral = 0
77 
78 ## Si True alors suspend l'évaluation en cours
79 pause = False
80 
81 ## Si True alors une évaluation est en cours
82 running = False
83 
84 ## Durée en ms de l'attente entre deux exécutions (si tk_Var_sleep)
85 sleep_delay = 100
86 
87 
88 
89 # ###################################
90 # Variables globales de l'interface #
91 #####################################
92 ## Fenêtre principale
93 tk_Win = tk.Tk()
94 
95 ## Police de caractères à taille fixe
96 tk_Font_monospace = tkFont.Font(tk_Win, size=10, family='courier')
97 
98 ## Police de caractères à taille fixe
99 tk_Font_monospace8 = tkFont.Font(tk_Win, size=8, family='courier')
100 
101 
102 ## Si True alors numeral est transformé en naturel de Church
103 tk_Var_numeral_Church = tk.BooleanVar()
104 
105 
106 ## Si True alors affiche toutes les parenthèses dans les combinateurs
107 tk_Var_show_allparent = tk.BooleanVar()
108 
109 ## Si True alors affiche les espaces dans les combinateurs
110 tk_Var_show_space = tk.BooleanVar()
111 
112 
113 ## Si True alors temporise entre chaque instruction exécutée
114 tk_Var_sleep = tk.BooleanVar()
115 tk_Var_sleep.set(True)
116 
117 
118 
119 # ##########
120 # Fonction #
121 ############
122 ## Renvoie le combinateur c sous forme de string
123 def comb_to_str(c):
124  """Renvoie le combinateur c sous forme de string
125 
126  Pre: c: None ou Combinator"""
127  assert (c == None) or isinstance(c, combinator.Combinator), type(c)
128 
129  return (c.__str__(allparent=tk_Var_show_allparent.get(),
130  space=(' ' if tk_Var_show_space.get()
131  else '')) if c != None
132  else '')
133 
134 
135 
136 # ############################
137 # Fonctions pour l'interface #
138 ##############################
139 ## MessageBox About...
140 def cmd_about():
141  tkMessageBox.showinfo('About...',
142  """Combinator Tk
143 
144 {0}
145 (c) Olivier Pirson --- DragonSoft
146 {1}
147 
148 
149 Infos:
150 {2}
151 Python {3}""".format(VERSION, DSPython.DS_web, DSPython.VERSION, sys.version))
152 
153 
154 ## Initialise sleep_delay avec la valeur saisie
155 def cmd_change_delay(event=None):
156  global sleep_delay
157 
158  s = tk_Entry_delay.get()
159  try:
160  sleep_delay = int(s)
161  except:
162  sleep_delay = -1
163 
164  if sleep_delay < 0:
165  sleep_delay = 0
166  tk_Entry_delay.delete(0, tk.END)
167 
168 
169 ## Initialise nb_eval_step avec la valeur saisie
170 def cmd_change_step(event=None):
171  global nb_eval_step
172 
173  s = tk_Entry_step.get()
174  try:
175  nb_eval_step = int(s)
176  except:
177  nb_eval_step = -1
178 
179  if nb_eval_step <= 0:
180  nb_eval_step = 0
181  tk_Entry_step.delete(0, tk.END)
182  if not tkMessageBox.askyesno('No step?',
183  """Do you want no limitation in evaluation?
184 (Some combinators run for ever!)"""):
185  nb_eval_step = 1
186  tk_Entry_step.delete(0, tk.END)
187  tk_Entry_step.insert(tk.END, str(nb_eval_step))
188 
189 
190 ## Initialise numeral avec la valeur saisie
191 def cmd_change_numeral(event=None):
192  global numeral
193 
194  s = tk_Entry_numeral.get()
195  try:
196  numeral = int(s)
197  except:
198  numeral = -1
199 
200  if numeral < 0:
201  numeral = 0
202  tk_Entry_numeral.delete(0, tk.END)
203 
204  cmd_insert_comb(combinator.Combinator.n_to_Church(numeral) if tk_Var_numeral_Church.get()
205  else combinator.Combinator.n_to_Barendregt(numeral))
206  cmd_comb_update()
207 
208 
209 ## Callback pour le Button 'Clear'
210 def cmd_clear(event=None):
211  global comb, nb_eval
212 
213  cmd_stop()
214  comb = None
215  tk_Entry_comb.delete(0, tk.END)
216  tk_Label_comb.config(text='')
217  tk_Listbox_combeval.delete(0, tk.END)
218  nb_eval = 0
219  tk_Label_nb_eval.config(text=str(nb_eval))
220  tk_Button_eval.config(state=tk.DISABLED)
221 
222 
223 ## Mise à jour
224 def cmd_comb_update(event=None):
225  global comb
226 
227  # Sépare les caractères saisis dans tk_Entry_comb par des espaces
228  # et change les [] ou {} par des ()
229  s = ' '.join([c
230  for c in tk_Entry_comb.get().translate(cmd_comb_update.TRANS)])
231 
232  # Tente de convertir s en Combinator
233  try:
234  comb = combinator.Combinator(s)
235  tk_Label_comb.config(text=comb_to_str(comb))
236  except:
237  comb = None
238  s = s[:-1]
239  while (comb == None) and (s != ''): # essaie avec les chaînes de plus en plus courtes
240  try:
241  comb = combinator.Combinator(s)
242  except:
243  comb = None
244  s = s[:-1]
245  tk_Label_comb.config(text=comb_to_str(comb) + ' ..?')
246 
247  # Active ou désactive le bouton d'évaluation en fonction de la stabilité de comb
248  tk_Button_eval.config(state=(tk.DISABLED if (comb == None) or comb.stable_is()
249  else tk.NORMAL))
250 
251 ## Table de translation : [] ou {} --> ()
252 if sys.version_info[0] >= 3: # Python >= 3
253  cmd_comb_update.TRANS = str.maketrans('[]{}', '()()')
254 else:
255  cmd_comb_update.TRANS = string.maketrans('[]{}', '()()')
256 
257 
258 ## Callback pour le Button 'Eval'
259 def cmd_eval():
260  global nb_eval, pause, running
261 
262  cmd_change_delay()
263  cmd_change_step()
264  if not running:
265  tk_Button_eval.config(relief=tk.SUNKEN)
266  tk_Button_stop.config(state=tk.NORMAL)
267  tk_Listbox_combeval.delete(0, tk.END)
268  nb_eval = 0
269  if comb != None:
270  ds = {} # dictionnaire des combinateurs rencontrés au cours de l'évaluation
271  ds[comb.__str__(space='')] = 0
272  c = comb
273  running = True
274  while running:
275  while pause and running:
276  tk_Win.update()
277  if running:
278  tk_Win.update()
279  if tk_Var_sleep.get():
280  time.sleep(sleep_delay/1000)
281 
282  # C'est ici que le combinateur c est évalué (pour nb_eval_step étapes)
283  c, nb_eval_last = c(nb=(nb_eval_step if nb_eval_step > 0
284  else None))
285 
286  nb_eval += nb_eval_last
287  tk_Label_nb_eval.config(text=str(nb_eval))
288  if nb_eval_last > 0:
289  tk_Listbox_combeval.insert(tk.END, comb_to_str(c))
290  s = c.__str__(space='')
291  if s in ds: # ce combinateur c a déjà été rencontré
292  # ??? ne fonctionne pas ?
293  tk_Listbox_combeval.insert(tk.END, '... {0}'.format(ds[s]))
294  running = False
295  else: # nouveau combinateur c dans l'évaluation de comb
296  ds[s] = nb_eval
297  tk_Listbox_combeval.see(tk.END)
298  else:
299  running = False
300  pause = False
301  tk_Button_eval.config(relief=tk.RAISED)
302  tk_Button_stop.config(state=tk.DISABLED)
303  else:
304  pause = not pause
305  tk_Button_eval.config(relief=(tk.RAISED if pause
306  else tk.SUNKEN))
307 
308 
309 ## Ajoute le combinateur c à la fin du champ de saisie tk_Entry_comb
310 def cmd_insert_comb(c):
311  if c != None:
312  s = str(c)
313  if tk_Entry_comb.get() != '':
314  s = (' {0}' if s.find(' ') < 0
315  else ' [{0}]').format(s)
316  tk_Entry_comb.insert(tk.INSERT, s)
317  cmd_comb_update()
318 
319 
320 ## Callback pour le Button 'Quit'
321 def cmd_quit():
322  if tkMessageBox.askyesno('Quit?', 'Quit Combinator Tk?'):
323  cmd_stop()
324  tk_Win.quit()
325 
326 
327 ## Callback pour le Button 'Stop'
328 def cmd_stop():
329  global running
330 
331  if running:
332  running = False
333 
334 
335 ## Copie le combinateur courant dans la "méta-variable" x
336 def cmd_to_var_x():
337  combinator.var_x = comb
338  tk_Label_var_x.config(text=('' if comb == None
339  else str(comb.__str__(space=''))))
340 
341  # Active ou désactive le bouton d'évaluation en fonction de la stabilité de comb
342  tk_Button_eval.config(state=(tk.DISABLED if (comb == None) or comb.stable_is()
343  else tk.NORMAL))
344 
345 
346 ## Copie le combinateur courant dans la "méta-variable" y
347 def cmd_to_var_y():
348  combinator.var_y = comb
349  tk_Label_var_y.config(text=('' if comb == None
350  else str(comb)))
351 
352  # Active ou désactive le bouton d'évaluation en fonction de la stabilité de comb
353  tk_Button_eval.config(state=(tk.DISABLED if (comb == None) or comb.stable_is()
354  else tk.NORMAL))
355 
356 
357 ## Copie le combinateur courant dans la "méta-variable" z
358 def cmd_to_var_z():
359  combinator.var_z = comb
360  tk_Label_var_z.config(text=('' if comb == None
361  else str(comb)))
362 
363  # Active ou désactive le bouton d'évaluation en fonction de la stabilité de comb
364  tk_Button_eval.config(state=(tk.DISABLED if (comb == None) or comb.stable_is()
365  else tk.NORMAL))
366 
367 
368 
369 # ######\cond MAIN
370 # Main #
371 ########
372 tk_Win.title('Combinator Tk')
373 tk_Win.resizable(0,0)
374 tk_Win.protocol('WM_DELETE_WINDOW', cmd_quit)
375 
376 
377 ## Frame temporaire utilisé pour disposer les éléments
378 tk_Frame = tk.Frame(tk_Win)
379 
380 for c in ('B', 'C', 'I', 'K', 'KI', 'L', 'M', 'O', 'R', 'S', 'T', 'U', 'V', 'W', 'Y'):
381  exec('tk.Button(tk_Frame,'
382  + ' text="{0}", command=lambda : cmd_insert_comb(combinator.{1})).pack(side=tk.LEFT)'
383  .format(c, c))
384 
385 tk.Frame(tk_Frame, width=5).pack(side=tk.LEFT)
386 
387 for c in ((unichr(953), 'iota'),
388  (unichr(937), 'Omega')):
389  exec('tk.Button(tk_Frame,'
390  + ' text="{0}", command=lambda : cmd_insert_comb(combinator.{1})).pack(side=tk.LEFT)'
391  .format(*c))
392 
393 tk.Frame(tk_Frame, width=10).pack(side=tk.LEFT)
394 
395 for c in ('not', 'and', 'or', 'imp'):
396  exec('tk.Button(tk_Frame,'
397  + ' text="{0}", command=lambda : cmd_insert_comb(combinator.B{1})).pack(side=tk.LEFT)'
398  .format(c, c))
399 
400 tk.Frame(tk_Frame, width=10).pack(side=tk.LEFT)
401 
402 ## Entry pour le nombre
403 tk_Entry_numeral = tk.Entry(tk_Frame, width=5)
404 tk_Entry_numeral.insert(tk.END, str(numeral))
405 tk_Entry_numeral.bind('<Return>', cmd_change_numeral)
406 tk_Entry_numeral.pack(side=tk.LEFT)
407 
408 tk.Checkbutton(tk_Frame, text='Church', variable=tk_Var_numeral_Church,
409  command=cmd_change_numeral).pack(side=tk.LEFT)
410 
411 tk.Frame(tk_Frame, width=5).pack(side=tk.LEFT)
412 
413 for c in ('x', 'y', 'z'):
414  exec('tk.Button(tk_Frame,'
415  + ' text="{0}", command=lambda : cmd_insert_comb(combinator.V{1})).pack(side=tk.LEFT)'
416  .format(c, c))
417 
418  exec('tk.Button(tk_Frame, text=unichr(8593), command=cmd_to_var_{0}).pack(side=tk.LEFT)'
419  .format(c))
420  exec('tk.Button(tk_Frame, text=unichr(8595),'
421  + ' command=lambda : cmd_insert_comb(combinator.var_{0})).pack(side=tk.LEFT)'
422  .format(c))
423 
424  exec('tk_Label_var_{0} = tk.Label(tk_Frame, font=tk_Font_monospace8, width=5)'.format(c))
425  exec('tk_Label_var_{0}.pack(side=tk.LEFT)'.format(c))
426 
427  tk.Frame(tk_Frame, width=5).pack(side=tk.LEFT)
428 
429 tk.Frame(tk_Frame, width=10).pack(side=tk.LEFT)
430 
431 ## Bouton 'Eval'
432 tk_Button_eval = tk.Button(tk_Frame, text='Eval', command=cmd_eval, state=tk.DISABLED)
433 tk_Button_eval.pack(side=tk.LEFT)
434 
435 ## Bouton 'Stop'
436 tk_Button_stop = tk.Button(tk_Frame, text='Stop', command=cmd_stop, foreground='red',
437  state=tk.DISABLED)
438 tk_Button_stop.pack(side=tk.LEFT)
439 
440 tk.Frame(tk_Frame, width=10).pack(side=tk.LEFT)
441 tk.Button(tk_Frame, text='Clear', command=cmd_clear).pack(side=tk.LEFT)
442 
443 tk.Frame(tk_Frame, width=10).pack(side=tk.LEFT)
444 tk.Button(tk_Frame, text='About', command=cmd_about).pack(side=tk.LEFT)
445 tk.Button(tk_Frame, text='Quit', command=cmd_quit).pack(side=tk.LEFT)
446 
447 tk_Frame.pack(side=tk.TOP, fill=tk.X)
448 
449 
450 #
451 
452 ## Entry pour le combinateur
453 tk_Entry_comb = tk.Entry(tk_Win, width=100, font=tk_Font_monospace)
454 tk_Entry_comb.bind('<Return>', cmd_comb_update)
455 tk_Entry_comb.pack(side=tk.TOP, fill=tk.X)
456 
457 tk_Frame = tk.Frame(tk_Win)
458 ## Label pour afficher le combinateur
459 tk_Label_comb = tk.Label(tk_Frame, font=tk_Font_monospace)
460 tk_Label_comb.pack(side=tk.LEFT, fill=tk.X)
461 
462 tk_Frame.pack(side=tk.TOP, fill=tk.X)
463 
464 
465 tk_Frame = tk.Frame(tk_Win)
466 ## Listbox pour afficher l'évaluation du combinateur
467 tk_Listbox_combeval = tk.Listbox(tk_Frame, width=120, height=20, font=tk_Font_monospace)
468 tk_Listbox_combeval.grid(sticky=tk.N + tk.S)
469 
470 ## Scrollbar
471 tk_Scrollbar = tk.Scrollbar(tk_Frame)
472 tk_Listbox_combeval.config(yscrollcommand=tk_Scrollbar.set)
473 tk_Scrollbar.config(command=tk_Listbox_combeval.yview)
474 tk_Scrollbar.grid(row=0, column=1, sticky=tk.N + tk.S)
475 
476 tk_Scrollbar = tk.Scrollbar(tk_Frame, orient=tk.HORIZONTAL)
477 tk_Listbox_combeval.config(xscrollcommand=tk_Scrollbar.set)
478 tk_Scrollbar.config(command=tk_Listbox_combeval.xview)
479 tk_Scrollbar.grid(row=1, sticky=tk.E + tk.W)
480 
481 tk_Frame.pack(side=tk.TOP, fill=tk.X)
482 
483 
484 #
485 tk_Frame = tk.Frame(tk_Win)
486 
487 ## Checkbutton
488 tk.Checkbutton(tk_Frame, text='All parenthesis ', variable=tk_Var_show_allparent,
489  command=cmd_comb_update).pack(side=tk.LEFT)
490 tk.Checkbutton(tk_Frame, text='Space ', variable=tk_Var_show_space,
491  command=cmd_comb_update).pack(side=tk.LEFT)
492 
493 tk.Checkbutton(tk_Frame, text='Delay:', variable=tk_Var_sleep,
494  command=cmd_change_delay).pack(side=tk.LEFT)
495 ## Entry pour le délai
496 tk_Entry_delay = tk.Entry(tk_Frame, width=5)
497 tk_Entry_delay.insert(tk.END, str(sleep_delay))
498 tk_Entry_delay.bind('<Return>', cmd_change_delay)
499 tk_Entry_delay.pack(side=tk.LEFT)
500 tk.Label(tk_Frame, text='ms').pack(side=tk.LEFT)
501 
502 tk.Label(tk_Frame, text=' Step:').pack(side=tk.LEFT)
503 ## Entry pour la valeur de nb_eval_step
504 tk_Entry_step = tk.Entry(tk_Frame, width=5)
505 tk_Entry_step.insert(tk.END, str(nb_eval_step))
506 tk_Entry_step.bind('<Return>', cmd_change_step)
507 tk_Entry_step.pack(side=tk.LEFT)
508 
509 tk.Label(tk_Frame, text=' Nb triggers: ').pack(side=tk.LEFT)
510 ## Label pour afficher le nombre d'étapes évaluées
511 tk_Label_nb_eval = tk.Label(tk_Frame, text='0')
512 tk_Label_nb_eval.pack(side=tk.LEFT)
513 
514 tk_Frame.pack(side=tk.TOP, fill=tk.X)
515 
516 
517 
518 #
519 tk_Frame = None
520 tk_Win.bind('<Escape>', cmd_clear)
521 tk_Win.mainloop()
522 ##\endcond MAIN