1313import string
1414import time
1515
16- from Tkinter import N , S , E , W , TOP , BOTTOM , LEFT , RIGHT , END
17- from Gui import Gui , GuiCanvas
18-
1916# the following definitions can be accessed in the simulator
2017
18+ current_thread = None
19+
2120class Semaphore :
2221 """Represents a semaphore in the simulator.
2322
@@ -94,16 +93,19 @@ def num_threads():
9493 sync = current_thread .column .p
9594 return len (sync .threads )
9695
97- current_thread = None
9896
9997
10098# make globals and locals for the simulator
10199
102- sim_globals = globals ()
103- sim_locals = locals ()
100+ sim_globals = copy . copy ( globals () )
101+ sim_locals = dict ()
104102
105103# anything defined after this point is not available inside the simulator
106104
105+ from Tkinter import N , S , E , W , TOP , BOTTOM , LEFT , RIGHT , END
106+ from Gui import Gui , GuiCanvas
107+
108+
107109# get the version of Python
108110v = sys .version .split ()[0 ].split ('.' )
109111major = int (v [0 ])
@@ -125,6 +127,11 @@ def __init__(self, filename=None):
125127 Gui .__init__ (self )
126128 #self.geometry('1260x800+74+32')
127129 self .filename = filename
130+ self .namer = Namer ()
131+
132+ self .locals = sim_locals
133+ self .globals = sim_globals
134+
128135 self .views = {}
129136 self .w = self
130137 self .threads = []
@@ -135,6 +142,18 @@ def __init__(self, filename=None):
135142 for col in self .cols :
136143 col .create_thread ()
137144
145+ def get_name (self , name = None ):
146+ return self .namer .next (name )
147+
148+ def get_threads (self ):
149+ return self .threads
150+
151+ def set_global (self , ** kwds ):
152+ self .globals .update (kwds )
153+
154+ def get_global (self , attr ):
155+ return self .globals [attr ]
156+
138157 def destroy (self ):
139158 """Closes the top window."""
140159 self .running = False
@@ -244,9 +263,6 @@ def run_init(self):
244263 self .clear_views ()
245264 self .views = {}
246265
247- self .locals = copy .copy (sim_locals )
248- self .globals = copy .copy (sim_globals )
249-
250266 thread = Thread (self .topcol , name = '0' )
251267 while 1 :
252268 thread .step ()
@@ -283,7 +299,7 @@ def subtract(d1, d2):
283299 return d
284300
285301
286- def diff (d1 , d2 ):
302+ def diff_dict (d1 , d2 ):
287303 """Diffs two dictionaries.
288304
289305 Returns two dictionaries: the first contains all the keys
@@ -484,108 +500,159 @@ def display_text(self, text):
484500 tag = self .text ([15 , 15 ], text , font = font )
485501 return tag
486502
503+ class Namer (object ):
504+ def __init__ (self ):
505+ self .names = all_thread_names
506+ self .next_name = 0
507+ self .colors = ['red' , 'orange' , 'yellow' , 'greenyellow' ,
508+ 'green' , 'mediumseagreen' , 'skyblue' ,
509+ 'violet' , 'magenta' ]
510+ self .next_color = 0
511+
512+ def next (self , name = None ):
513+ if name == None :
514+ name = self .names [self .next_name ]
515+ self .next_name += 1
516+ self .next_name %= len (self .names )
517+
518+ color = self .colors [self .next_color ]
519+ self .next_color += 1
520+ self .next_color %= len (self .colors )
521+ return name , color
522+ else :
523+ return name , 'white'
524+
487525
488526class Thread :
489527 """Represents simulated threads."""
490- names = all_thread_names
491- next_name = 0
492- colors = ['red' , 'orange' , 'yellow' , 'greenyellow' ,
493- 'green' , 'mediumseagreen' , 'skyblue' ,
494- 'violet' , 'magenta' ]
495- next_color = 0
496528
497529 def __init__ (self , column , name = None ):
498530 self .column = column
499- if name == None :
500- self .name = Thread .names [Thread .next_name ]
501- Thread .next_name += 1
502- Thread .next_name %= len (Thread .names )
503-
504- self .color = Thread .colors [Thread .next_color ]
505- Thread .next_color += 1
506- Thread .next_color %= len (Thread .colors )
507- else :
508- self .name = name
509- self .color = 'white'
510-
511- sync = self .column .p
512- sync .register (self )
531+ self .sync = column .p
532+ self .name , self .color = self .sync .get_name (name )
533+ self .sync .register (self )
513534 self .start ()
514535
536+ def get_column (self ):
537+ return self .column
538+
515539 def __str__ (self ):
516540 return '<' + self .name + '>'
517541
518542 def enqueue (self ):
543+ """Puts this thread into queue."""
519544 self .queued = True
520545 self .row .remove_thread (self )
521546 self .row .enqueue_thread (self )
522547
523548 def dequeue (self ):
549+ """Removes this thread from queue."""
524550 self .queued = False
525551 self .row .dequeue_thread (self )
526552 self .row .add_thread (self )
527553
528554 def start (self ):
555+ """Moves this thread to the top of the column."""
529556 self .queued = False
530557 self .iter = self .column .__iter__ ()
531558 self .row = None
532559 self .next_loop ()
533560
534561 def next_row (self ):
535- "move this thread to the next row in the column"
536- if self .queued : return
562+ """Moves this thread to the next row in the column."""
563+ if self .queued :
564+ return
565+
537566 if self .row :
538567 self .row .remove_thread (self )
568+
539569 try :
540570 self .row = self .iter .next ()
541571 self .row .add_thread (self )
542572 except StopIteration :
543573 self .row = None
544574
575+ def skip_body (self ):
576+ """Skips the body of a conditional."""
577+ self .next_row ()
578+
545579 def next_loop (self ):
546- "move to the next row, looping to the top if necessary"
580+ """Moves to the next row, looping to the top if necessary."" "
547581 self .next_row ()
548- if self .row == None : self .start ()
582+ if self .row == None :
583+ self .start ()
549584
550585 def step (self , event = None ):
551- """execute the current line of code, then move to the next row.
586+ """Executes the current line of code, then move to the next row.
587+
552588 The current limitation of this simulator is that each row
553589 has to contain a complete Python statement. Also, each line
554590 of code is executed atomically.
591+
592+ Args:
593+ event: unused, provided so that this method can be used
594+ as a binding callback
595+
596+ Returns:
597+ line of code that executed or None
555598 """
556- if self .queued : return
599+ if self .queued :
600+ return None
601+
557602 source = self .row .get ()
558- source = source .strip ()
559- print self , source
560603
561- code = compile ( source , '<user-provided code>' , 'exec' )
604+ before = copy . copy ( self . sync . locals )
562605
563- # debugging code for catching certain exceptions
564- # try:
565- # except:
566- # (type, value, traceback) = sys.exc_info()
567- # print traceback
568- # print type, value
569- # self.next()
570- # return
606+ flag = self .exec_line (source , self .sync )
571607
572- global current_thread
573- current_thread = self
608+ if flag :
609+ self .next_row ()
610+ else :
611+ self .skip_body ()
612+
613+ return source
574614
575- sync = self .column .p
576- before = copy .copy (sync .locals )
577- exec code in sync .globals , sync .locals
615+ after = self .sync .locals
616+ defined , changed = diff_dict (after , before )
578617
579- defined , changed = diff (sync .locals , before )
580618 for key in defined :
581619 sync .views [key ] = self .row
582620
583621 sync .update_views ()
584- self .next_row ()
622+
623+ return source
624+
625+ def exec_line (self , source , sync ):
626+ source = source .strip ()
627+ print self , source
628+
629+ global current_thread
630+ current_thread = self
631+
632+ try :
633+ code = compile (source , '<user-provided code>' , 'exec' )
634+ exec code in sync .globals , sync .locals
635+ return True
636+ except SyntaxError as error :
637+ # this had better be an if statement
638+ pass
639+
640+ flag = self .handle_conditional (source , sync )
641+ return flag
642+
643+ def handle_conditional (self , source , sync ):
644+ if not (source .startswith ('if' ) and source .endswith (':' )):
645+ raise SyntaxError ('Python blocks must be if statements' )
646+
647+ condition = source [2 :- 1 ].strip ()
648+ flag = eval (condition , sync .globals , sync .locals )
649+
650+ return flag
585651
586652 def step_loop (self , event = None ):
587653 self .step ()
588- if self .row == None : self .start ()
654+ if self .row == None :
655+ self .start ()
589656
590657 def run (self ):
591658 while 1 :
0 commit comments