Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TurtleArt/talogo.py
diff options
context:
space:
mode:
authorMarion 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)
commitdb8c29ce3204b79aed7b9679c91f7abf3f6f2102 (patch)
tree287d0eed75c47669ab27ec708b0b2c24f7390d3b /TurtleArt/talogo.py
parent671ee68af425063395e9f2248f93bb723b158406 (diff)
convert to type branch of python export code
Diffstat (limited to 'TurtleArt/talogo.py')
-rw-r--r--TurtleArt/talogo.py260
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."""