diff options
author | Marion Zepf <marion.zepf@gmail.com> | 2013-10-29 21:25:26 (GMT) |
---|---|---|
committer | Walter Bender <walter@sugarlabs.org> | 2013-10-29 21:25:26 (GMT) |
commit | db8c29ce3204b79aed7b9679c91f7abf3f6f2102 (patch) | |
tree | 287d0eed75c47669ab27ec708b0b2c24f7390d3b /TurtleArt/talogo.py | |
parent | 671ee68af425063395e9f2248f93bb723b158406 (diff) |
convert to type branch of python export code
Diffstat (limited to 'TurtleArt/talogo.py')
-rw-r--r-- | TurtleArt/talogo.py | 260 |
1 files changed, 233 insertions, 27 deletions
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py index ef482a1..25d316c 100644 --- a/TurtleArt/talogo.py +++ b/TurtleArt/talogo.py @@ -25,6 +25,7 @@ import gtk from time import time, sleep from operator import isNumberType +from os.path import exists as os_path_exists from UserDict import UserDict try: @@ -35,12 +36,13 @@ except ImportError: import traceback -from tablock import (Block, media_blocks_dictionary) +from tablock import (Block, Media, media_blocks_dictionary) from taconstants import (TAB_LAYER, DEFAULT_SCALE) +from tajail import myfunc 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, - get_stack_name) +from tatype import (TATypeError, TYPES_NUMERIC) +from tautils import (get_pixbuf_from_journal, data_from_file, get_stack_name, + text_media_type, round_int, debug_output, find_group) try: from util.RtfParser import RtfTextOnly @@ -82,6 +84,20 @@ class logoerror(Exception): return str(self.value) +class NegativeRootError(BaseException): + """ Similar to the ZeroDivisionError, this error is raised at runtime + when trying to computer the square root of a negative number. """ + + DEFAULT_MESSAGE = 'square root of negative number' + + def __init__(self, neg_value=None, message=DEFAULT_MESSAGE): + self.neg_value = neg_value + self.message = message + + def __str__(self): + return str(self.message) + + class HiddenBlock(Block): def __init__(self, name, value=None): @@ -193,7 +209,11 @@ class LogoCode: def get_prim_callable(self, name): """ Return the callable primitive associated with the given name """ - return self.oblist[name].fcn + sym = self.oblist.get(name) + if sym is not None: + return sym.fcn + else: + return None def run_blocks(self, code): """Run code generated by generate_code(). @@ -227,6 +247,7 @@ class LogoCode: for b in blocks: b.unhighlight() + ''' # Hidden macro expansions for b in blocks: if b.name in ['while', 'until']: @@ -240,6 +261,7 @@ class LogoCode: blocks = new_blocks[:] if b == blk: blk = action_blk + ''' for b in blocks: if b.name in ('hat', 'hat1', 'hat2'): @@ -276,7 +298,8 @@ class LogoCode: return ['%nothing%', '%nothing%'] code = [] dock = blk.docks[0] - if len(dock) > 4 and dock[4] in ('[', ']', ']['): # There could be a '(', ')', '[' or ']'. + # There could be a '(', ')', '[' or ']'. + if len(dock) > 4 and dock[4] in ('[', ']', ']['): code.append(dock[4]) if blk.primitive is not None: # make a tuple (prim, blk) if blk in self.tw.block_list.list: @@ -296,7 +319,8 @@ class LogoCode: for i in range(1, len(blk.connections)): b = blk.connections[i] dock = blk.docks[i] - if len(dock) > 4 and dock[4] in ('[', ']', ']['): # There could be a '(', ')', '[' or ']'. + # There could be a '(', ')', '[' or ']'. + if len(dock) > 4 and dock[4] in ('[', ']', ']['): for c in dock[4]: code.append(c) if b is not None: @@ -326,7 +350,9 @@ class LogoCode: bindex = None if isinstance(token, tuple): (token, bindex) = token - if isNumberType(token): + if isinstance(token, Media): + res.append(token) + elif isNumberType(token): res.append(token) elif token.isdigit(): res.append(float(token)) @@ -374,6 +400,7 @@ 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. """ @@ -468,7 +495,10 @@ class LogoCode: self.tw.showblocks() self.tw.display_coordinates() raise logoerror("#noinput") - call_args = type(self.cfun.fcn).__name__ != 'Primitive' + is_Primitive = type(self.cfun.fcn).__name__ == 'Primitive' + is_PrimitiveDisjunction = type(self.cfun.fcn).__name__ == \ + 'PrimitiveDisjunction' + call_args = not (is_Primitive or is_PrimitiveDisjunction) for i in range(token.nargs): self._no_args_check() self.icall(self._eval, call_args) @@ -520,21 +550,48 @@ class LogoCode: try: while (_millisecond() - starttime) < 120: try: - if self.step is not None: + if self.step is None: + return False + if self.tw.running_turtleart: try: self.step.next() 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)) + debug_output('generator already executing', + self.tw.running_sugar) + self.tw.running_blocks = False return False + except TATypeError as tte: + # TODO insert the correct block name + # (self.cfun.name is only the name of the + # outermost block in this statement/ line of code) + # use logoerror("#notanumber") when possible + if (tte.req_type in TYPES_NUMERIC and + tte.bad_type not in TYPES_NUMERIC): + raise logoerror("#notanumber") + else: + raise logoerror( + "%s %s %s %s" % + (self.cfun.name, _("doesn't like"), + str(tte.bad_value), _("as input"))) + except ZeroDivisionError: + raise logoerror("#zerodivide") + except NegativeRootError: + raise logoerror("#negroot") + except IndexError: + raise logoerror("#emptyheap") else: - return False + try: + self.step.next() + except BaseException as error: + if isinstance(error, (StopIteration, + logoerror)): + raise error + else: + traceback.print_exc() + self.tw.showlabel( + 'status', '%s: %s' % + (type(error).__name__, str(error))) + return False except StopIteration: if self.tw.running_turtleart: # self.tw.turtles.show_all() @@ -611,18 +668,30 @@ class LogoCode: def prim_clear(self): """ Clear screen """ self.tw.clear_plugins() - self.prim_clear_helper() + self.stop_playing_media() + self.reset_scale() + self.reset_timer() + self.clear_value_blocks() + self.reset_internals() self.tw.canvas.clearscreen() self.tw.turtles.reset_turtles() - def prim_clear_helper(self): + def stop_playing_media(self): if self.tw.gst_available: from tagplay import stop_media stop_media(self) + + def reset_scale(self): self.scale = DEFAULT_SCALE - self.hidden_turtle = None + + def reset_timer(self): self.start_time = time() - self.clear_value_blocks() + + def get_start_time(self): + return self.start_time + + def reset_internals(self): + self.hidden_turtle = None if self.tw.running_turtleart: self.tw.activity.restore_state() @@ -645,6 +714,29 @@ class LogoCode: self.ireturn() yield True + def prim_clamp(self, blklist): + """ Run clamp blklist """ + self.icall(self.evline, blklist[:]) + yield True + self.procstop = False + self.ireturn() + yield True + + def prim_stop_stack(self): + """ Stop execution of a stack """ + self.procstop = True + + def prim_wait(self, wait_time): + """ Show the turtle while we wait """ + self.tw.turtles.get_active_turtle().show() + endtime = _millisecond() + wait_time * 1000. + while _millisecond() < endtime: + sleep(wait_time / 10.) + yield True + self.tw.turtles.get_active_turtle().hide() + self.ireturn() + yield True + def prim_if(self, boolean, blklist): """ If bool, do list """ if boolean: @@ -679,6 +771,7 @@ class LogoCode: try: return self.boxes[key] except KeyError: + # FIXME this looks like a syntax error in the GUI raise logoerror("#emptybox") def _get_box_key(self, name): @@ -688,9 +781,12 @@ class LogoCode: 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) + if isinstance(name, (basestring, int, long)): + try: + name = float(name) + except ValueError: + pass + return ('box3_' + str(name), False) def prim_define_stack(self, name): """ Top of a named stack """ @@ -717,6 +813,47 @@ class LogoCode: name = float(name) return 'stack3' + str(name) + def get_heap(self): + return self.heap + + def reset_heap(self): + """ Reset heap to an empty list """ + # empty the list rather than setting it to a new empty list object, + # so the object references are preserved + while self.heap: + self.heap.pop() + + def prim_myfunction(self, f, *args): + """ Programmable block (Call tajail.myfunc and convert any errors to + logoerrors) """ + try: + y = myfunc(f, args) + if str(y) == 'nan': + debug_output('Python function returned NAN', + self.tw.running_sugar) + self.stop_logo() + raise logoerror("#notanumber") + else: + return y + except ZeroDivisionError: + self.stop_logo() + raise logoerror("#zerodivide") + except ValueError, e: + self.stop_logo() + raise logoerror('#' + str(e)) + except SyntaxError, e: + self.stop_logo() + raise logoerror('#' + str(e)) + except NameError, e: + self.stop_logo() + raise logoerror('#' + str(e)) + except OverflowError: + self.stop_logo() + raise logoerror("#overflowerror") + except TypeError: + self.stop_logo() + raise logoerror("#notanumber") + def clear_value_blocks(self): if not hasattr(self, 'value_blocks_to_update'): return @@ -792,6 +929,75 @@ class LogoCode: for blk in drag_group: blk.spr.move_relative((dx, 0)) + def show(self, obj, center=False): + """ Show is the general-purpose media-rendering block. """ + # media + if isinstance(obj, Media) and obj.value: + self.filepath = None + self.pixbuf = None # Camera writes directly to pixbuf + self.dsobject = None + + # camera snapshot + if obj.value.lower() in media_blocks_dictionary: + media_blocks_dictionary[obj.value.lower()]() + # file path + elif os_path_exists(obj.value): + self.filepath = obj.value + # datastore object + elif self.tw.running_sugar: + from sugar.datastore import datastore + try: + self.dsobject = datastore.get(obj.value) + except: + debug_output("Couldn't find dsobject %s" % + (obj.value), self.tw.running_sugar) + if self.dsobject is not None: + self.filepath = self.dsobject.file_path + + if self.pixbuf is not None: + self.insert_image(center=center, pixbuf=True) + elif self.filepath is None: + if self.dsobject is not None: + self.tw.showlabel( + 'nojournal', + self.dsobject.metadata['title']) + else: + self.tw.showlabel('nojournal', obj.value) + debug_output("Couldn't open %s" % (obj.value), + self.tw.running_sugar) + elif obj.type == 'media': + self.insert_image(center=center) + elif obj.type == 'descr': + mimetype = None + if self.dsobject is not None and \ + 'mime_type' in self.dsobject.metadata: + mimetype = self.dsobject.metadata['mime_type'] + description = None + if self.dsobject is not None and \ + 'description' in self.dsobject.metadata: + description = self.dsobject.metadata[ + 'description'] + self.insert_desc(mimetype, description) + elif obj.type == 'audio': + self.play_sound() + elif obj.type == 'video': + self.play_video() + + if self.dsobject is not None: + self.dsobject.destroy() + + # text or number + elif isinstance(obj, (basestring, float, int)): + if isinstance(obj, (float, int)): + obj = round_int(obj) + x, y = self.x2tx(), self.y2ty() + if center: + y -= self.tw.canvas.textsize + self.tw.turtles.get_active_turtle().draw_text( + obj, x, y, + int(self.tw.canvas.textsize * self.scale / 100.), + self.tw.canvas.width - x) + def push_file_data_to_heap(self, dsobject): """ push contents of a data store object (assuming json encoding) """ data = data_from_file(dsobject.file_path) @@ -967,7 +1173,7 @@ class LogoCode: def _expand_forever(self, b, blk, blocks): """ Expand a while or until block into: forever, ifelse, stopstack - Expand a forever block to run in a separate stack + Expand a forever block to run in a separate stack Parameters: the loop block, the top block, all blocks. Return the start block of the expanded loop, and all blocks.""" |