diff options
author | Marion Zepf <marion.zepf@gmail.com> | 2013-10-27 02:06:05 (GMT) |
---|---|---|
committer | Walter Bender <walter@sugarlabs.org> | 2013-10-27 02:06:05 (GMT) |
commit | 629722d8859d1e8db47417673cb78963d41ce435 (patch) | |
tree | d188a0c26c724bc151c3449eb7a5613777f2ed40 /TurtleArt/talogo.py | |
parent | 8ac55749fbe9672ea3f403c93713b403efac46af (diff) |
python export
Diffstat (limited to 'TurtleArt/talogo.py')
-rw-r--r-- | TurtleArt/talogo.py | 278 |
1 files changed, 192 insertions, 86 deletions
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py index 0b178c6..ef482a1 100644 --- a/TurtleArt/talogo.py +++ b/TurtleArt/talogo.py @@ -33,10 +33,14 @@ try: except ImportError: GRID_CELL_SIZE = 55 -from taconstants import (TAB_LAYER, DEFAULT_SCALE, PREFIX_DICTIONARY) +import traceback + +from tablock import (Block, media_blocks_dictionary) +from taconstants import (TAB_LAYER, DEFAULT_SCALE) from tapalette import (block_names, value_blocks) from tautils import (get_pixbuf_from_journal, convert, data_from_file, - text_media_type, round_int, debug_output, find_group) + text_media_type, round_int, debug_output, find_group, + get_stack_name) try: from util.RtfParser import RtfTextOnly @@ -46,7 +50,6 @@ except ImportError: from gettext import gettext as _ -media_blocks_dictionary = {} # new media blocks get added here primitive_dictionary = {} # new block primitives get added here @@ -79,7 +82,7 @@ class logoerror(Exception): return str(self.value) -class HiddenBlock: +class HiddenBlock(Block): def __init__(self, name, value=None): self.name = name @@ -92,6 +95,7 @@ class HiddenBlock: self.connections = [] self.docks = [] + # Utility functions @@ -187,6 +191,10 @@ class LogoCode: self.oblist[string] = sym return sym + def get_prim_callable(self, name): + """ Return the callable primitive associated with the given name """ + return self.oblist[name].fcn + def run_blocks(self, code): """Run code generated by generate_code(). """ @@ -234,27 +242,17 @@ class LogoCode: blk = action_blk for b in blocks: - if b.name == 'hat1': - code = self._blocks_to_code(b) - self.stacks['stack1'] = self._readline(code) - elif b.name == 'hat2': - code = self._blocks_to_code(b) - self.stacks['stack2'] = self._readline(code) - elif b.name == 'hat': - if b.connections is not None and len(b.connections) > 1 and \ - b.connections[1] is not None: + if b.name in ('hat', 'hat1', 'hat2'): + stack_name = get_stack_name(b) + if stack_name: + stack_key = self._get_stack_key(stack_name) code = self._blocks_to_code(b) - try: - x = b.connections[1].values[0] - except IndexError: - self.tw.showlabel('#nostack') - self.tw.showblocks() - self.tw.running_blocks = False - return None - if isinstance(convert(x, float, False), float): - if int(float(x)) == x: - x = int(x) - self.stacks['stack3' + str(x)] = self._readline(code) + self.stacks[stack_key] = self._readline(code) + else: + self.tw.showlabel('#nostack') + self.tw.showblocks() + self.tw.running_blocks = False + return None code = self._blocks_to_code(blk) @@ -278,7 +276,7 @@ class LogoCode: return ['%nothing%', '%nothing%'] code = [] dock = blk.docks[0] - if len(dock) > 4: # There could be a '(', ')', '[' or ']'. + if len(dock) > 4 and dock[4] in ('[', ']', ']['): # There could be a '(', ')', '[' or ']'. code.append(dock[4]) if blk.primitive is not None: # make a tuple (prim, blk) if blk in self.tw.block_list.list: @@ -286,37 +284,19 @@ class LogoCode: self.tw.block_list.list.index(blk))) else: code.append(blk.primitive) # Hidden block - elif len(blk.values) > 0: # Extract the value from content blocks. - if blk.name == 'number': - try: - code.append(float(blk.values[0])) - except ValueError: - code.append(float(ord(blk.values[0][0]))) - elif blk.name == 'string' or \ - blk.name == 'title': # deprecated block - if isinstance(blk.values[0], (float, int)): - if int(blk.values[0]) == blk.values[0]: - blk.values[0] = int(blk.values[0]) - code.append('#s' + str(blk.values[0])) - else: - code.append('#s' + blk.values[0]) - elif blk.name in PREFIX_DICTIONARY: - if blk.values[0] is not None: - code.append(PREFIX_DICTIONARY[blk.name] + - str(blk.values[0])) - else: - code.append(PREFIX_DICTIONARY[blk.name] + 'None') - elif blk.name in media_blocks_dictionary: - code.append('#smedia_' + blk.name.upper()) - else: + elif blk.is_value_block(): # Extract the value from content blocks. + value = blk.get_value() + if value is None: return ['%nothing%'] + else: + code.append(value) else: return ['%nothing%'] if blk.connections is not None and len(blk.connections) > 0: for i in range(1, len(blk.connections)): b = blk.connections[i] dock = blk.docks[i] - if len(dock) > 4: # There could be a '(', ')', '[' or ']'. + if len(dock) > 4 and dock[4] in ('[', ']', ']['): # There could be a '(', ')', '[' or ']'. for c in dock[4]: code.append(c) if b is not None: @@ -394,14 +374,13 @@ class LogoCode: if self._disable_help: self.tw.no_help = False self._disable_help = False - self.tw.display_coordinates() def icall(self, fcn, *args): """ Add a function and its arguments to the program stack. """ self.istack.append(self.step) self.step = fcn(*(args)) - def evline(self, blklist): + def evline(self, blklist, call_me=True): """ Evaluate a line of code from the list. """ oldiline = self.iline self.iline = blklist[:] @@ -432,7 +411,7 @@ class LogoCode: (token, self.bindex) = self.iline[1] # Process the token and any arguments. - self.icall(self._eval) + self.icall(self._eval, call_me) yield True # Time to unhighlight the current block. @@ -455,7 +434,7 @@ class LogoCode: self.tw.display_coordinates() yield True - def _eval(self): + def _eval(self, call_me=True): """ Evaluate the next token on the line of code we are processing. """ token = self.iline.pop(0) bindex = None @@ -467,7 +446,7 @@ class LogoCode: # We highlight blocks here in case an error occurs... if not self.tw.hide and bindex is not None: self.tw.block_list.list[bindex].highlight() - self.icall(self._evalsym, token) + self.icall(self._evalsym, token, call_me) yield True # and unhighlight if everything was OK. if not self.tw.hide and bindex is not None: @@ -479,7 +458,7 @@ class LogoCode: self.ireturn(res) yield True - def _evalsym(self, token): + def _evalsym(self, token, call_me): """ Process primitive associated with symbol token """ self._undefined_check(token) oldcfun, oldarglist = self.cfun, self.arglist @@ -489,35 +468,50 @@ class LogoCode: self.tw.showblocks() self.tw.display_coordinates() raise logoerror("#noinput") + call_args = type(self.cfun.fcn).__name__ != 'Primitive' for i in range(token.nargs): self._no_args_check() - self.icall(self._eval) + self.icall(self._eval, call_args) yield True self.arglist.append(self.iresult) + need_to_pop_istack = False if self.cfun.rprim: if isinstance(self.cfun.fcn, list): # debug_output('evalsym rprim list: %s' % (str(token)), # self.tw.running_sugar) - self.icall(self._ufuncall, self.cfun.fcn) + self.icall(self._ufuncall, self.cfun.fcn, call_args) yield True + need_to_pop_istack = True + result = None else: - self.icall(self.cfun.fcn, *self.arglist) - yield True - result = None + if call_me: + self.icall(self.cfun.fcn, *self.arglist) + yield True + need_to_pop_istack = True + result = None + else: + result = (self.cfun.fcn, ) + tuple(self.arglist) else: - result = self.cfun.fcn(self, *self.arglist) + need_to_pop_istack = True + if call_me: + result = self.cfun.fcn(self, *self.arglist) + else: + result = (self.cfun.fcn, self) + tuple(self.arglist) self.cfun, self.arglist = oldcfun, oldarglist if self.arglist is not None and result is None: self.tw.showblocks() raise logoerror("%s %s %s" % (oldcfun.name, _("did not output to"), self.cfun.name)) - self.ireturn(result) - yield True + if need_to_pop_istack: + self.ireturn(result) + yield True + else: + self.iresult = result - def _ufuncall(self, body): + def _ufuncall(self, body, call_me): """ ufuncall """ - self.ijmp(self.evline, body) + self.ijmp(self.evline, body, call_me) yield True def doevalstep(self): @@ -529,28 +523,40 @@ class LogoCode: if self.step is not None: try: self.step.next() - except ValueError: - debug_output('generator already executing', - self.tw.running_sugar) - self.tw.running_blocks = False + except ValueError, ve: + if self.tw.running_turtleart: + debug_output('generator already executing', + self.tw.running_sugar) + self.tw.running_blocks = False + else: + traceback.print_exc() + self.tw.showlabel('status', 'ValueError: ' + + str(ve)) return False else: return False except StopIteration: - # self.tw.turtles.show_all() - if self.hidden_turtle is not None: - self.hidden_turtle.show() - self.hidden_turtle = None + if self.tw.running_turtleart: + # self.tw.turtles.show_all() + if self.hidden_turtle is not None: + self.hidden_turtle.show() + self.hidden_turtle = None + else: + self.tw.turtles.get_active_turtle().show() + self.tw.running_blocks = False + return False else: - self.tw.turtles.get_active_turtle().show() - self.tw.running_blocks = False - return False + self.ireturn() except logoerror, e: - self.tw.showblocks() - self.tw.display_coordinates() - self.tw.showlabel('syntaxerror', str(e)) - self.tw.turtles.show_all() - self.tw.running_blocks = False + if self.tw.running_turtleart: + self.tw.showblocks() + self.tw.display_coordinates() + self.tw.showlabel('syntaxerror', str(e)) + self.tw.turtles.show_all() + self.tw.running_blocks = False + else: + traceback.print_exc() + self.tw.showlabel('status', 'logoerror: ' + str(e)) return False return True @@ -597,19 +603,119 @@ class LogoCode: name.nargs, name.fcn = 0, body name.rprim = True + def prim_start(self, *ignored_args): + ''' Start block: recenter ''' + if self.tw.running_sugar: + self.tw.activity.recenter() + def prim_clear(self): """ Clear screen """ self.tw.clear_plugins() + self.prim_clear_helper() + self.tw.canvas.clearscreen() + self.tw.turtles.reset_turtles() + + def prim_clear_helper(self): if self.tw.gst_available: from tagplay import stop_media stop_media(self) - self.tw.canvas.clearscreen() - self.tw.turtles.reset_turtles() self.scale = DEFAULT_SCALE self.hidden_turtle = None self.start_time = time() self.clear_value_blocks() - self.tw.activity.restore_state() + if self.tw.running_turtleart: + self.tw.activity.restore_state() + + def prim_loop(self, controller, blklist): + """ Execute a loop + controller -- iterator that yields True iff the loop should be run + once more OR a callable that returns such an iterator + blklist -- list of callables that form the loop body """ + if not hasattr(controller, "next"): + if callable(controller): + controller = controller() + else: + raise TypeError("a loop controller must be either an iterator " + "or a callable that returns an iterator") + while next(controller): + self.icall(self.evline, blklist[:]) + yield True + if self.procstop: + break + self.ireturn() + yield True + + def prim_if(self, boolean, blklist): + """ If bool, do list """ + if boolean: + self.icall(self.evline, blklist[:]) + yield True + self.ireturn() + yield True + + def prim_ifelse(self, boolean, list1, list2): + """ If bool, do list1, else do list2 """ + if boolean: + self.ijmp(self.evline, list1[:]) + yield True + else: + self.ijmp(self.evline, list2[:]) + yield True + + def prim_set_box(self, name, value): + """ Store value in named box """ + (key, is_native) = self._get_box_key(name) + self.boxes[key] = value + if is_native: + if self.update_values: + self.update_label_value(name, value) + else: + if self.update_values: + self.update_label_value('box', value, label=name) + + def prim_get_box(self, name): + """ Retrieve value from named box """ + (key, is_native) = self._get_box_key(name) + try: + return self.boxes[key] + except KeyError: + raise logoerror("#emptybox") + + def _get_box_key(self, name): + """ Return the key used for this box in the boxes dictionary and a + boolean indicating whether it is a 'native' box """ + if name in ('box1', 'box2'): + return (name, True) + else: + # make sure '5' and '5.0' point to the same box + if isinstance(name, (int, long)): + name = float(name) + return ('box3' + str(name), False) + + def prim_define_stack(self, name): + """ Top of a named stack """ + pass + + def prim_invoke_stack(self, name): + """ Process a named stack """ + key = self._get_stack_key(name) + if self.stacks.get(key) is None: + raise logoerror("#nostack") + self.icall(self.evline, self.stacks[key][:]) + yield True + self.procstop = False + self.ireturn() + yield True + + def _get_stack_key(self, name): + """ Return the key used for this stack in the stacks dictionary """ + if name in ('stack1', 'stack2'): + return name + else: + # make sure '5' and '5.0' point to the same action stack + if isinstance(name, (int, long)): + name = float(name) + return 'stack3' + str(name) def clear_value_blocks(self): if not hasattr(self, 'value_blocks_to_update'): @@ -980,14 +1086,14 @@ class LogoCode: # Create a separate stacks for the forever loop and the whileflow code = self._blocks_to_code(forever_blk) - self.stacks['stack3' + str(action_name)] = self._readline(code) + self.stacks[self._get_stack_key(action_name)] = self._readline(code) if until_blk and whileflow is not None: # Create a stack from the whileflow to be called from # action_first, but then reconnect it to the ifelse block c = whileflow.connections[0] whileflow.connections[0] = None code = self._blocks_to_code(whileflow) - self.stacks['stack3' + str(action_flow_name)] = \ + self.stacks[self._get_stack_key(action_flow_name)] = \ self._readline(code) whileflow.connections[0] = c |