From 6acdbc3db543f2692ee336a99722f5ab0b46c77e Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Wed, 13 Nov 2013 22:42:18 +0000 Subject: convert to new primitive type --- (limited to 'TurtleArt/tabasics.py') diff --git a/TurtleArt/tabasics.py b/TurtleArt/tabasics.py index 3d1eb10..3d88ce4 100644 --- a/TurtleArt/tabasics.py +++ b/TurtleArt/tabasics.py @@ -20,72 +20,94 @@ #THE SOFTWARE. ''' -This file contains the constants that by-in-large determine the -behavior of Turtle Art. Notably, the block palettes are defined -below. If you want to add a new block to Turtle Art, you could -simply add a block of code to this file or to turtle_block_plugin.py, -which contains additional blocks. (Even better, write your own plugin!!) +This file contains the constants that by-in-large determine the +behavior of Turtle Art. Notably, the block palettes are defined +below. If you want to add a new block to Turtle Art, you could +simply add a block of code to this file or to +../plugins/turtle_blocks_extras/turtle_blocks_extras.py , +which contains additional blocks. (Even better, write your own +plugin!!) Adding a new palette is simply a matter of: + palette = make_palette('mypalette', # the name of your palette colors=["#00FF00", "#00A000"], help_string=_('Palette of my custom commands')) -For example, if we want to add a new turtle command, 'uturn', we'd use the -add_block method in the Palette class. +For example, if we want to add a new turtle command, 'uturn', +we'd use the `add_block` method in the Palette class. + palette.add_block('uturn', # the name of your block style='basic-style', # the block style label=_('u turn'), # the label for the block prim_name='uturn', # code reference (see below) help_string=_('turns the turtle 180 degrees')) - # Next, you need to define what your block will do: - # def_prim takes 3 arguments: the primitive name, the number of - # arguments -- 0 in this case -- and the function to call -- in this - # case, we define the _prim_uturn function to set heading += 180. - self.tw.lc.def_prim('uturn', 0, lambda self: self._prim_uturn) - def _prim_uturn(self): - value = self.tw.turtles.get_active_turtle().get_heading() + 180 - self.tw.turtles.get_active_turtle().set_heading(value) +Next, you need to define what your block will do: def_prim takes +3 arguments: the primitive name, the number of arguments --- 0 +in this case --- and a Primitive object. A Primitive object +represents the statement to be executed when the block is +executed in Turtle Art. For the 'uturn' block, we would like the +statement to look roughly like this: + + Turtle.set_heading(plus(Turtle.get_heading(), 180)) + +Formally, a Primitive object consists of a function, its return +type, and descriptions of its arguments and keyword arguments. +The return type is not a Python type, but a type from Turtle +Art's internal type system. All available types are defined as +constants in tatype.py . + +In this case, we know in advance which arguments each function +gets, so we can use ConstantArg objects as argument descrip- +tions. (For examples where the arguments come from other blocks, +please refer to ../doc/primitives-with-arguments.md .) Note that +Primitive objects can be arguments to other Primitive objects. +This leads to the following tree-like structure for our 'uturn' +block: + + prim_uturn = Primitive(Turtle.set_heading, + arg_descs=[ConstantArg(Primitive( + Primitive.plus, return_type=TYPE_NUMBER, + arg_descs=[ConstantArg(Primitive( + Turtle.get_heading, return_type=TYPE_NUMBER)), + ConstantArg(180)]))], + call_afterwards=self.after_uturn) + + self.tw.lc.def_prim('uturn', 0, prim_uturn) + + # somewhere else in the same class: + def after_uturn(self, value): if self.tw.lc.update_values: self.tw.lc.update_label_value('heading', value) -That's it. When you next run Turtle Art, you will have a 'uturn' block -on the 'mypalette' palette. +The `call_afterwards` attribute is a simple function that is +called just after executing the block. It is often used for +updating GUI labels. -You will have to create icons for the palette-selector buttons. These -are kept in the icons subdirectory. You need two icons: -mypaletteoff.svg and mypaletteon.svg, where 'mypalette' is the same -string as the entry you used in instantiating the Palette class. Note -that the icons should be the same size (55x55) as the others. (This is -the default icon size for Sugar toolbars.) -''' +That's it. When you next run Turtle Art, you will have a 'uturn' +block on the 'mypalette' palette. -from time import time, sleep -from math import sqrt -from random import uniform +You will have to create icons for the palette-selector buttons. +These are kept in the 'icons' subdirectory. You need two icons: +mypaletteoff.svg and mypaletteon.svg, where 'mypalette' is the +same string as the entry you used in instantiating the Palette +object. Note that the icons should be the same size (55x55) as +the others. (This is the default icon size for Sugar toolbars.) +''' +from time import time from gettext import gettext as _ from tapalette import (make_palette, define_logo_function) -from talogo import (primitive_dictionary, logoerror) -from tautils import (convert, chr_to_ord, round_int, strtype, debug_output) -from taconstants import (COLORDICT, CONSTANTS) - - -def _color_to_num(c): - if COLORDICT[c][0] is None: - return(COLORDICT[c][1]) - else: - return(COLORDICT[c][0]) - - -def _num_type(x): - ''' Is x a number type? ''' - if isinstance(x, (int, float)): - return True - return False +from talogo import primitive_dictionary +from taconstants import (Color, CONSTANTS) +from taprimitive import (ArgSlot, ConstantArg, or_, Primitive) +from tatype import (TYPE_BOOL, TYPE_BOX, TYPE_CHAR, TYPE_COLOR, TYPE_FLOAT, + TYPE_INT, TYPE_NUMBER, TYPE_NUMERIC_STRING, TYPE_OBJECT, + TYPE_STRING) +from taturtle import Turtle def _millisecond(): @@ -99,6 +121,15 @@ class Palettes(): def __init__(self, turtle_window): self.tw = turtle_window + self.prim_cache = { + "minus": Primitive(Primitive.minus, + return_type=TYPE_NUMBER, + arg_descs=[ArgSlot(TYPE_NUMBER)]), + "ord": Primitive(ord, + return_type=TYPE_INT, + arg_descs=[ArgSlot(TYPE_CHAR)]) + } # avoid several Primitives of the same function + self._turtle_palette() self._pen_palette() @@ -119,13 +150,11 @@ class Palettes(): def _turtle_palette(self): ''' The basic Turtle Art turtle palette ''' - debug_output('creating %s palette' % _('turtle'), - self.tw.running_sugar) palette = make_palette('turtle', colors=["#00FF00", "#00A000"], - help_string=_('Palette of turtle commands')) + help_string=_('Palette of turtle commands'), + translation=_('turtle')) - primitive_dictionary['move'] = self._prim_move palette.add_block('forward', style='basic-style-1arg', label=_('forward'), @@ -134,10 +163,10 @@ class Palettes(): logo_command='forward', help_string=_('moves turtle forward')) self.tw.lc.def_prim( - 'forward', - 1, - lambda self, x: primitive_dictionary['move']( - self.tw.turtles.get_active_turtle().forward, x)) + 'forward', 1, + Primitive(Turtle.forward, + arg_descs=[ArgSlot(TYPE_NUMBER)], + call_afterwards=self.after_move)) palette.add_block('back', style='basic-style-1arg', @@ -146,13 +175,12 @@ class Palettes(): default=100, logo_command='back', help_string=_('moves turtle backward')) - self.tw.lc.def_prim('back', 1, - lambda self, x: - primitive_dictionary['move'] - (self.tw.turtles.get_active_turtle().forward, x, - reverse=True)) + self.tw.lc.def_prim( + 'back', 1, + Primitive(Turtle.backward, + arg_descs=[ArgSlot(TYPE_NUMBER)], + call_afterwards=self.after_move)) - primitive_dictionary['clean'] = self._prim_clear palette.add_block('clean', style='basic-style-extended-vertical', label=_('clean'), @@ -160,12 +188,19 @@ class Palettes(): logo_command='clean', help_string=_('clears the screen and reset the \ turtle')) - self.tw.lc.def_prim( - 'clean', - 0, - lambda self: primitive_dictionary['clean']()) + self.tw.lc.def_prim('clean', 0, + Primitive(Primitive.group, arg_descs=[ + ConstantArg([ + Primitive(self.tw.clear_plugins), + Primitive(self.tw.lc.stop_playing_media), + Primitive(self.tw.lc.reset_scale), + Primitive(self.tw.lc.reset_timer), + Primitive(self.tw.lc.clear_value_blocks), + Primitive(self.tw.lc.reset_internals), + Primitive(self.tw.canvas.clearscreen), + Primitive(self.tw.turtles.reset_turtles) + ])])) - primitive_dictionary['right'] = self._prim_right palette.add_block('left', style='basic-style-1arg', label=_('left'), @@ -175,8 +210,10 @@ turtle')) help_string=_('turns turtle counterclockwise (angle \ in degrees)')) self.tw.lc.def_prim( - 'left', 1, lambda self, - x: primitive_dictionary['right'](x, reverse=True)) + 'left', 1, + Primitive(Turtle.left, + arg_descs=[ArgSlot(TYPE_NUMBER)], + call_afterwards=self.after_right)) palette.add_block('right', style='basic-style-1arg', @@ -187,11 +224,11 @@ in degrees)')) help_string=_('turns turtle clockwise (angle in \ degrees)')) self.tw.lc.def_prim( - 'right', - 1, - lambda self, x: primitive_dictionary['right'](x)) + 'right', 1, + Primitive(Turtle.right, + arg_descs=[ArgSlot(TYPE_NUMBER)], + call_afterwards=self.after_right)) - primitive_dictionary['arc'] = self._prim_arc palette.add_block('arc', style='basic-style-2arg', label=[_('arc'), _('angle'), _('radius')], @@ -200,10 +237,11 @@ degrees)')) logo_command='taarc', help_string=_('moves turtle along an arc')) self.tw.lc.def_prim( - 'arc', - 2, - lambda self, x, y: primitive_dictionary['arc']( - self.tw.turtles.get_active_turtle().arc, x, y)) + 'arc', 2, + Primitive(Turtle.arc, + arg_descs=[ArgSlot(TYPE_NUMBER), + ArgSlot(TYPE_NUMBER)], + call_afterwards=self.after_arc)) define_logo_function('taarc', 'to taarc :a :r\nrepeat round :a \ [right 1 forward (0.0175 * :r)]\nend\n') @@ -216,13 +254,12 @@ degrees)')) help_string=_('moves turtle to position xcor, ycor; \ (0, 0) is in the center of the screen.')) self.tw.lc.def_prim( - 'setxy2', - 2, - lambda self, x, y: primitive_dictionary['move']( - self.tw.turtles.get_active_turtle().set_xy, x, y)) + 'setxy2', 2, + Primitive(Turtle.set_xy, + arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)], + call_afterwards=self.after_move)) define_logo_function('tasetxy', 'to tasetxy :x :y\nsetxy :x :y\nend\n') - primitive_dictionary['set'] = self._prim_set palette.add_block('seth', style='basic-style-1arg', label=_('set heading'), @@ -232,10 +269,11 @@ degrees)')) help_string=_('sets the heading of the turtle (0 is \ towards the top of the screen.)')) self.tw.lc.def_prim( - 'seth', - 1, - lambda self, x: primitive_dictionary['set']( - 'heading', self.tw.turtles.get_active_turtle().set_heading, x)) + 'seth', 1, + Primitive(Turtle.set_heading, + arg_descs=[ArgSlot(TYPE_NUMBER)], + call_afterwards=lambda value: self.after_set( + 'heading', value))) palette.add_block('xcor', style='box-style', @@ -246,10 +284,11 @@ the turtle (can be used in place of a number block)'), prim_name='xcor', logo_command='xcor') self.tw.lc.def_prim( - 'xcor', - 0, - lambda self: self.tw.turtles.get_active_turtle().get_xy()[0] / - self.tw.coord_scale) + 'xcor', 0, + Primitive(Primitive.divide, return_type=TYPE_FLOAT, + arg_descs=[ConstantArg(Primitive(Turtle.get_x)), + ConstantArg(Primitive( + self.tw.get_coord_scale))])) palette.add_block('ycor', style='box-style', @@ -260,10 +299,11 @@ the turtle (can be used in place of a number block)'), prim_name='ycor', logo_command='ycor') self.tw.lc.def_prim( - 'ycor', - 0, - lambda self: self.tw.turtles.get_active_turtle().get_xy()[1] / - self.tw.coord_scale) + 'ycor', 0, + Primitive(Primitive.divide, return_type=TYPE_FLOAT, + arg_descs=[ConstantArg(Primitive(Turtle.get_y)), + ConstantArg(Primitive( + self.tw.get_coord_scale))])) palette.add_block('heading', style='box-style', @@ -273,16 +313,14 @@ turtle (can be used in place of a number block)'), value_block=True, prim_name='heading', logo_command='heading') - self.tw.lc.def_prim( - 'heading', - 0, - lambda self: self.tw.turtles.get_active_turtle().get_heading()) + self.tw.lc.def_prim('heading', 0, + Primitive( + Turtle.get_heading, return_type=TYPE_NUMBER)) - # This block is used for holding the remote turtle name palette.add_block('turtle-label', hidden=True, style='blank-style', - label=['remote turtle name']) + label=['turtle']) # Deprecated palette.add_block('setxy', @@ -295,22 +333,21 @@ turtle (can be used in place of a number block)'), help_string=_('moves turtle to position xcor, ycor; \ (0, 0) is in the center of the screen.')) self.tw.lc.def_prim( - 'setxy', - 2, - lambda self, x, y: primitive_dictionary['move']( - self.tw.turtles.get_active_turtle().set_xy, x, y, - pendown=False)) + 'setxy', 2, + Primitive(Turtle.set_xy, + arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)], + kwarg_descs={'pendown': ConstantArg(False)}, + call_afterwards=self.after_move)) define_logo_function('tasetxypenup', 'to tasetxypenup :x :y\npenup\n\ setxy :x :y\npendown\nend\n') def _pen_palette(self): ''' The basic Turtle Art pen palette ''' - debug_output('creating %s palette' % _('pen'), - self.tw.running_sugar) palette = make_palette('pen', colors=["#00FFFF", "#00A0A0"], - help_string=_('Palette of pen commands')) + help_string=_('Palette of pen commands'), + translation=_('pen')) palette.add_block('fillscreen', hidden=True, @@ -322,9 +359,9 @@ setxy :x :y\npendown\nend\n') help_string=_('fills the background with (color, \ shade)')) self.tw.lc.def_prim( - 'fillscreen', - 2, - lambda self, x, y: self.tw.canvas.fillscreen(x, y)) + 'fillscreen', 2, + Primitive(self.tw.canvas.fillscreen, + arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)])) palette.add_block('fillscreen2', style='basic-style-3arg', @@ -336,9 +373,10 @@ shade)')) help_string=_('fills the background with (color, \ shade)')) self.tw.lc.def_prim( - 'fillscreen2', - 3, - lambda self, x, y, z: self.tw.canvas.fillscreen_with_gray(x, y, z)) + 'fillscreen2', 3, + Primitive(self.tw.canvas.fillscreen_with_gray, + arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER), + ArgSlot(TYPE_NUMBER)])) define_logo_function('tasetbackground', 'to tasetbackground :color \ :shade\ntasetshade :shade\nsetbackground :color\nend\n') @@ -352,10 +390,12 @@ shade)')) help_string=_('sets color of the line drawn by the \ turtle')) self.tw.lc.def_prim( - 'setcolor', - 1, - lambda self, x: primitive_dictionary['set']( - 'color', self.tw.turtles.get_active_turtle().set_color, x)) + 'setcolor', 1, + Primitive(Turtle.set_color, + arg_descs=[or_(ArgSlot(TYPE_COLOR), + ArgSlot(TYPE_NUMBER))], + call_afterwards=lambda value: self.after_set( + 'color', value))) palette.add_block('setshade', style='basic-style-1arg', @@ -366,10 +406,11 @@ turtle')) help_string=_('sets shade of the line drawn by the \ turtle')) self.tw.lc.def_prim( - 'setshade', - 1, - lambda self, x: primitive_dictionary['set']( - 'shade', self.tw.turtles.get_active_turtle().set_shade, x)) + 'setshade', 1, + Primitive(Turtle.set_shade, + arg_descs=[ArgSlot(TYPE_NUMBER)], + call_afterwards=lambda value: self.after_set( + 'shade', value))) palette.add_block('setgray', style='basic-style-1arg', @@ -379,10 +420,11 @@ turtle')) help_string=_('sets gray level of the line drawn by \ the turtle')) self.tw.lc.def_prim( - 'setgray', - 1, - lambda self, x: primitive_dictionary['set']( - 'gray', self.tw.turtles.get_active_turtle().set_gray, x)) + 'setgray', 1, + Primitive(Turtle.set_gray, + arg_descs=[ArgSlot(TYPE_NUMBER)], + call_afterwards=lambda value: self.after_set( + 'gray', value))) palette.add_block('color', style='box-style', @@ -392,10 +434,9 @@ in place of a number block)'), value_block=True, prim_name='color', logo_command='pencolor') - self.tw.lc.def_prim( - 'color', - 0, - lambda self: self.tw.turtles.get_active_turtle().get_color()) + self.tw.lc.def_prim('color', 0, + Primitive( + Turtle.get_color, return_type=TYPE_NUMBER)) palette.add_block('shade', style='box-style', @@ -404,10 +445,7 @@ in place of a number block)'), value_block=True, prim_name='shade', logo_command=':shade') - self.tw.lc.def_prim( - 'shade', - 0, - lambda self: self.tw.turtles.get_active_turtle().get_shade()) + self.tw.lc.def_prim('shade', 0, Primitive(Turtle.get_shade)) palette.add_block('gray', style='box-style', @@ -416,8 +454,9 @@ in place of a number block)'), used in place of a number block)'), value_block=True, prim_name='gray') - self.tw.lc.def_prim('gray', 0, lambda self: - self.tw.turtles.get_active_turtle().get_gray()) + self.tw.lc.def_prim('gray', 0, + Primitive( + Turtle.get_gray, return_type=TYPE_NUMBER)) palette.add_block('penup', style='basic-style-extended-vertical', @@ -426,10 +465,8 @@ used in place of a number block)'), logo_command='penup', help_string=_('Turtle will not draw when moved.')) self.tw.lc.def_prim( - 'penup', - 0, - lambda self: - self.tw.turtles.get_active_turtle().set_pen_state(False)) + 'penup', 0, + Primitive(Turtle.set_pen_state, arg_descs=[ConstantArg(False)])) palette.add_block('pendown', style='basic-style-extended-vertical', @@ -438,10 +475,8 @@ used in place of a number block)'), logo_command='pendown', help_string=_('Turtle will draw when moved.')) self.tw.lc.def_prim( - 'pendown', - 0, - lambda self: - self.tw.turtles.get_active_turtle().set_pen_state(True)) + 'pendown', 0, + Primitive(Turtle.set_pen_state, arg_descs=[ConstantArg(True)])) palette.add_block('penstate', style='boolean-block-style', @@ -449,9 +484,8 @@ used in place of a number block)'), prim_name='penstate', help_string=_('returns True if pen is down')) self.tw.lc.def_prim( - 'penstate', - 0, - lambda self: self.tw.turtles.get_active_turtle().get_pen_state()) + 'penstate', 0, + Primitive(Turtle.get_pen_state, return_type=TYPE_BOOL)) palette.add_block('setpensize', style='basic-style-1arg', @@ -463,8 +497,10 @@ used in place of a number block)'), turtle')) self.tw.lc.def_prim( 'setpensize', 1, - lambda self, x: primitive_dictionary['set'] - ('pensize', self.tw.turtles.get_active_turtle().set_pen_size, x)) + Primitive(Turtle.set_pen_size, + arg_descs=[ArgSlot(TYPE_NUMBER)], + call_afterwards=lambda val: self.after_set( + 'pensize', val))) define_logo_function('tasetpensize', 'to tasetpensize :a\nsetpensize round :a\nend\n') @@ -474,10 +510,7 @@ turtle')) prim_name='startfill', help_string=_('starts filled polygon (used with end \ fill block)')) - self.tw.lc.def_prim( - 'startfill', - 0, - lambda self: self.tw.turtles.get_active_turtle().start_fill()) + self.tw.lc.def_prim('startfill', 0, Primitive(Turtle.start_fill)) palette.add_block('stopfill', style='basic-style-extended-vertical', @@ -485,10 +518,7 @@ fill block)')) prim_name='stopfill', help_string=_('completes filled polygon (used with \ start fill block)')) - self.tw.lc.def_prim( - 'stopfill', - 0, - lambda self: self.tw.turtles.get_active_turtle().stop_fill()) + self.tw.lc.def_prim('stopfill', 0, Primitive(Turtle.stop_fill)) palette.add_block('pensize', style='box-style', @@ -499,33 +529,27 @@ in place of a number block)'), prim_name='pensize', logo_command='pensize') self.tw.lc.def_prim( - 'pensize', - 0, - lambda self: self.tw.turtles.get_active_turtle().get_pen_size()) + 'pensize', 0, + Primitive(Turtle.get_pen_size, return_type=TYPE_NUMBER)) define_logo_function('tapensize', 'to tapensize\noutput first round \ pensize\nend\n') def _color_palette(self): ''' The basic Turtle Art color palette ''' - debug_output('creating %s palette' % _('colors'), - self.tw.running_sugar) palette = make_palette('colors', colors=["#00FFFF", "#00A0A0"], - help_string=_('Palette of pen colors')) - - self._make_constant(palette, 'red', _('red'), CONSTANTS['red']) - self._make_constant(palette, 'orange', _('orange'), - CONSTANTS['orange']) - self._make_constant(palette, 'yellow', _('yellow'), - CONSTANTS['yellow']) - self._make_constant(palette, 'green', _('green'), CONSTANTS['green']) - self._make_constant(palette, 'cyan', _('cyan'), CONSTANTS['cyan']) - self._make_constant(palette, 'blue', _('blue'), CONSTANTS['blue']) - self._make_constant(palette, 'purple', _('purple'), - CONSTANTS['purple']) - self._make_constant(palette, 'white', _('white'), CONSTANTS['white']) - self._make_constant(palette, 'black', _('black'), CONSTANTS['black']) + help_string=_('Palette of pen colors'), + translation=_('colors')) + + color_names = ('red', 'orange', 'yellow', 'green', 'cyan', 'blue', + 'purple', 'white', 'black') + # Need to make sure color names are included in the PO files + color_names_i18n = (_('red'), _('orange'), _('yellow'), _('green'), + _('cyan'), _('blue'), _('purple'), _('white'), + _('black')) + for name in color_names: + self._make_constant(palette, name, _(name), name) # In order to map Turtle Art colors to the standard UCB Logo palette, # we need to define a somewhat complex set of functions. @@ -603,13 +627,11 @@ tasetshade :shade \n') def _numbers_palette(self): ''' The basic Turtle Art numbers palette ''' - debug_output('creating %s palette' % _('numbers'), - self.tw.running_sugar) palette = make_palette('numbers', colors=["#FF00FF", "#A000A0"], - help_string=_('Palette of numeric operators')) + help_string=_('Palette of numeric operators'), + translation=_('numbers')) - primitive_dictionary['plus'] = self._prim_plus palette.add_block('plus2', style='number-style', label='+', @@ -619,9 +641,16 @@ tasetshade :shade \n') logo_command='sum', help_string=_('adds two alphanumeric inputs')) self.tw.lc.def_prim( - 'plus', 2, lambda self, x, y: primitive_dictionary['plus'](x, y)) + 'plus', 2, + # add up two numbers ... + or_(Primitive(Primitive.plus, return_type=TYPE_NUMBER, + arg_descs=[ArgSlot(TYPE_NUMBER), + ArgSlot(TYPE_NUMBER)]), + # ... or concatenate two strings + Primitive(Primitive.plus, return_type=TYPE_STRING, + arg_descs=[ArgSlot(TYPE_STRING), + ArgSlot(TYPE_STRING)]))) - primitive_dictionary['minus'] = self._prim_minus palette.add_block('minus2', style='number-style-porch', label=' –', @@ -631,11 +660,12 @@ tasetshade :shade \n') help_string=_('subtracts bottom numeric input from \ top numeric input')) self.tw.lc.def_prim( - 'minus', 2, lambda self, x, y: primitive_dictionary['minus'](x, y)) + 'minus', 2, + Primitive(Primitive.minus, return_type=TYPE_NUMBER, + arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)])) define_logo_function('taminus', 'to taminus :y :x\noutput sum :x \ minus :y\nend\n') - primitive_dictionary['product'] = self._prim_product palette.add_block('product2', style='number-style', label='×', @@ -645,9 +675,9 @@ minus :y\nend\n') help_string=_('multiplies two numeric inputs')) self.tw.lc.def_prim( 'product', 2, - lambda self, x, y: primitive_dictionary['product'](x, y)) + Primitive(Primitive.multiply, return_type=TYPE_NUMBER, + arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)])) - primitive_dictionary['division'] = self._prim_careful_divide palette.add_block('division2', style='number-style-porch', label=' /', @@ -658,9 +688,9 @@ minus :y\nend\n') (numerator) by bottom numeric input (denominator)')) self.tw.lc.def_prim( 'division', 2, - lambda self, x, y: primitive_dictionary['division'](x, y)) + Primitive(Primitive.divide, return_type=TYPE_NUMBER, + arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)])) - primitive_dictionary['id'] = self._prim_identity palette.add_block('identity2', style='number-style-1arg', label='←', @@ -668,10 +698,26 @@ minus :y\nend\n') prim_name='id', help_string=_('identity operator used for extending \ blocks')) - self.tw.lc.def_prim('id', 1, - lambda self, x: primitive_dictionary['id'](x)) + self.tw.lc.def_prim( + 'id', 1, + # preserve the Type of the argument: try less general types first + or_(Primitive(Primitive.identity, return_type=TYPE_NUMERIC_STRING, + arg_descs=[ArgSlot(TYPE_NUMERIC_STRING)]), + Primitive(Primitive.identity, return_type=TYPE_CHAR, + arg_descs=[ArgSlot(TYPE_CHAR)]), + Primitive(Primitive.identity, return_type=TYPE_COLOR, + arg_descs=[ArgSlot(TYPE_COLOR)]), + Primitive(Primitive.identity, return_type=TYPE_FLOAT, + arg_descs=[ArgSlot(TYPE_FLOAT)]), + Primitive(Primitive.identity, return_type=TYPE_INT, + arg_descs=[ArgSlot(TYPE_INT)]), + Primitive(Primitive.identity, return_type=TYPE_NUMBER, + arg_descs=[ArgSlot(TYPE_NUMBER)]), + Primitive(Primitive.identity, return_type=TYPE_STRING, + arg_descs=[ArgSlot(TYPE_STRING)]), + Primitive(Primitive.identity, return_type=TYPE_OBJECT, + arg_descs=[ArgSlot(TYPE_OBJECT)]))) - primitive_dictionary['remainder'] = self._prim_mod palette.add_block('remainder2', style='number-style-porch', label=_('mod'), @@ -679,11 +725,11 @@ blocks')) prim_name='remainder', logo_command='remainder', help_string=_('modular (remainder) operator')) - self.tw.lc.def_prim('remainder', 2, - lambda self, x, y: - primitive_dictionary['remainder'](x, y)) + self.tw.lc.def_prim( + 'remainder', 2, + Primitive(Primitive.modulo, return_type=TYPE_NUMBER, + arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)])) - primitive_dictionary['sqrt'] = self._prim_sqrt palette.add_block('sqrt', style='number-style-1arg', label=_('√'), @@ -691,10 +737,11 @@ blocks')) prim_name='sqrt', logo_command='tasqrt', help_string=_('calculates square root')) - self.tw.lc.def_prim('sqrt', 1, - lambda self, x: primitive_dictionary['sqrt'](x)) + self.tw.lc.def_prim( + 'sqrt', 1, + Primitive(Primitive.square_root, return_type=TYPE_FLOAT, + arg_descs=[ArgSlot(TYPE_NUMBER)])) - primitive_dictionary['random'] = self._prim_random palette.add_block('random', style='number-style-block', label=[_('random'), _('min'), _('max')], @@ -703,9 +750,19 @@ blocks')) logo_command='tarandom', help_string=_('returns random number between \ minimum (top) and maximum (bottom) values')) + self.tw.lc.def_prim( - 'random', 2, lambda self, x, y: primitive_dictionary['random']( - x, y)) + 'random', 2, + or_( # random character ... + Primitive(Primitive.random_char, return_type=TYPE_CHAR, + arg_descs=[ + ArgSlot(TYPE_INT, + wrapper=self.prim_cache["ord"]), + ArgSlot(TYPE_INT, + wrapper=self.prim_cache["ord"])]), + # ... or random number + Primitive(Primitive.random_int, return_type=TYPE_INT, + arg_descs=[ArgSlot(TYPE_INT), ArgSlot(TYPE_INT)]))) define_logo_function('tarandom', 'to tarandom :min :max\n \ output (random (:max - :min)) + :min\nend\n') @@ -717,7 +774,6 @@ output (random (:max - :min)) + :min\nend\n') help_string=_('used as numeric input in mathematic \ operators')) - primitive_dictionary['more'] = self._prim_more palette.add_block('greater2', style='compare-porch-style', label=' >', @@ -728,9 +784,16 @@ operators')) help_string=_('logical greater-than operator')) self.tw.lc.def_prim( 'greater?', 2, - lambda self, x, y: primitive_dictionary['more'](x, y)) + Primitive(Primitive.greater, return_type=TYPE_BOOL, + arg_descs=or_([ArgSlot(TYPE_COLOR), + ArgSlot(TYPE_COLOR)], + [ArgSlot(TYPE_NUMBER), + ArgSlot(TYPE_NUMBER)], + [ArgSlot(TYPE_STRING), + ArgSlot(TYPE_STRING)], + [ArgSlot(TYPE_OBJECT), + ArgSlot(TYPE_OBJECT)]))) - primitive_dictionary['less'] = self._prim_less palette.add_block('less2', style='compare-porch-style', label=' <', @@ -740,9 +803,17 @@ operators')) logo_command='less?', help_string=_('logical less-than operator')) self.tw.lc.def_prim( - 'less?', 2, lambda self, x, y: primitive_dictionary['less'](x, y)) + 'less?', 2, + Primitive(Primitive.less, return_type=TYPE_BOOL, + arg_descs=or_([ArgSlot(TYPE_COLOR), + ArgSlot(TYPE_COLOR)], + [ArgSlot(TYPE_NUMBER), + ArgSlot(TYPE_NUMBER)], + [ArgSlot(TYPE_STRING), + ArgSlot(TYPE_STRING)], + [ArgSlot(TYPE_OBJECT), + ArgSlot(TYPE_OBJECT)]))) - primitive_dictionary['equal'] = self._prim_equal palette.add_block('equal2', style='compare-style', label='=', @@ -751,9 +822,17 @@ operators')) prim_name='equal?', logo_command='equal?', help_string=_('logical equal-to operator')) - self.tw.lc.def_prim('equal?', 2, - lambda self, x, y: - primitive_dictionary['equal'](x, y)) + self.tw.lc.def_prim( + 'equal?', 2, + Primitive(Primitive.equals, return_type=TYPE_BOOL, + arg_descs=or_([ArgSlot(TYPE_COLOR), + ArgSlot(TYPE_COLOR)], + [ArgSlot(TYPE_NUMBER), + ArgSlot(TYPE_NUMBER)], + [ArgSlot(TYPE_STRING), + ArgSlot(TYPE_STRING)], + [ArgSlot(TYPE_OBJECT), + ArgSlot(TYPE_OBJECT)]))) palette.add_block('not', style='not-style', @@ -761,9 +840,11 @@ operators')) prim_name='not', logo_command='not', help_string=_('logical NOT operator')) - self.tw.lc.def_prim('not', 1, lambda self, x: not x) + self.tw.lc.def_prim( + 'not', 1, + Primitive(Primitive.not_, return_type=TYPE_BOOL, + arg_descs=[ArgSlot(TYPE_BOOL)])) - primitive_dictionary['and'] = self._prim_and palette.add_block('and2', style='boolean-style', label=_('and'), @@ -772,9 +853,10 @@ operators')) special_name=_('and'), help_string=_('logical AND operator')) self.tw.lc.def_prim( - 'and', 2, lambda self, x, y: primitive_dictionary['and'](x, y)) + 'and', 2, + Primitive(Primitive.and_, return_type=TYPE_BOOL, + arg_descs=[ArgSlot(TYPE_BOOL), ArgSlot(TYPE_BOOL)])) - primitive_dictionary['or'] = self._prim_or palette.add_block('or2', style='boolean-style', label=_('or'), @@ -783,18 +865,18 @@ operators')) special_name=_('or'), help_string=_('logical OR operator')) self.tw.lc.def_prim( - 'or', 2, lambda self, x, y: primitive_dictionary['or'](x, y)) + 'or', 2, + Primitive(Primitive.or_, return_type=TYPE_BOOL, + arg_descs=[ArgSlot(TYPE_BOOL), ArgSlot(TYPE_BOOL)])) def _flow_palette(self): ''' The basic Turtle Art flow palette ''' - debug_output('creating %s palette' % _('flow'), - self.tw.running_sugar) palette = make_palette('flow', colors=["#FFC000", "#A08000"], - help_string=_('Palette of flow operators')) + help_string=_('Palette of flow operators'), + translation=_('flow')) - primitive_dictionary['wait'] = self._prim_wait palette.add_block('wait', style='basic-style-1arg', label=_('wait'), @@ -803,9 +885,11 @@ operators')) logo_command='wait', help_string=_('pauses program execution a specified \ number of seconds')) - self.tw.lc.def_prim('wait', 1, primitive_dictionary['wait'], True) + self.tw.lc.def_prim( + 'wait', 1, + Primitive(self.tw.lc.prim_wait, arg_descs=[ArgSlot(TYPE_NUMBER)]), + True) - primitive_dictionary['forever'] = self._prim_forever palette.add_block('forever', style='clamp-style', label=_('forever'), @@ -813,10 +897,13 @@ number of seconds')) default=[None, None], logo_command='forever', help_string=_('loops forever')) - self.tw.lc.def_prim('forever', 1, primitive_dictionary['forever'], - True) + self.tw.lc.def_prim( + 'forever', 1, + Primitive(self.tw.lc.prim_loop, arg_descs=[ConstantArg(Primitive( + Primitive.controller_forever)), ArgSlot(TYPE_OBJECT, + call_arg=False)]), + True) - primitive_dictionary['repeat'] = self._prim_repeat palette.add_block('repeat', style='clamp-style-1arg', label=_('repeat'), @@ -825,9 +912,16 @@ number of seconds')) logo_command='repeat', special_name=_('repeat'), help_string=_('loops specified number of times')) - self.tw.lc.def_prim('repeat', 2, primitive_dictionary['repeat'], True) + self.tw.lc.def_prim( + 'repeat', 2, + Primitive(self.tw.lc.prim_loop, + arg_descs=[ArgSlot( + TYPE_OBJECT, + wrapper=Primitive(Primitive.controller_repeat, + arg_descs=[ArgSlot(TYPE_INT)])), + ArgSlot(TYPE_OBJECT, call_arg=False)]), + True) - primitive_dictionary['if'] = self._prim_if palette.add_block('if', style='clamp-style-boolean', label=[_('if'), _('then'), ''], @@ -837,9 +931,12 @@ number of seconds')) logo_command='if', help_string=_('if-then operator that uses boolean \ operators from Numbers palette')) - self.tw.lc.def_prim('if', 2, primitive_dictionary['if'], True) + self.tw.lc.def_prim( + 'if', 2, + Primitive(self.tw.lc.prim_if, + arg_descs=[ArgSlot(TYPE_BOOL), ArgSlot(TYPE_OBJECT)]), + True) - primitive_dictionary['ifelse'] = self._prim_ifelse palette.add_block('ifelse', hidden=True, # Too big to fit palette style='clamp-style-else', @@ -850,7 +947,12 @@ operators from Numbers palette')) special_name=_('if then else'), help_string=_('if-then-else operator that uses \ boolean operators from Numbers palette')) - self.tw.lc.def_prim('ifelse', 3, primitive_dictionary['ifelse'], True) + self.tw.lc.def_prim( + 'ifelse', 3, + Primitive(self.tw.lc.prim_ifelse, + arg_descs=[ArgSlot(TYPE_BOOL), ArgSlot(TYPE_OBJECT), + ArgSlot(TYPE_OBJECT)]), + True) # macro palette.add_block('ifthenelse', @@ -867,7 +969,9 @@ boolean operators from Numbers palette')) prim_name='nop', special_name=_('horizontal space'), help_string=_('jogs stack right')) - self.tw.lc.def_prim('nop', 0, lambda self: None) + self.tw.lc.def_prim( + 'nop', 0, + Primitive(Primitive.do_nothing, export_me=False)) palette.add_block('vspace', style='basic-style-extended-vertical', @@ -875,28 +979,28 @@ boolean operators from Numbers palette')) prim_name='nop', special_name=_('vertical space'), help_string=_('jogs stack down')) - self.tw.lc.def_prim('nop', 0, lambda self: None) + self.tw.lc.def_prim( + 'nop', 0, + Primitive(Primitive.do_nothing, export_me=False)) - primitive_dictionary['stopstack'] = self._prim_stopstack palette.add_block('stopstack', style='basic-style-tail', label=_('stop action'), prim_name='stopstack', logo_command='stop', help_string=_('stops current action')) - self.tw.lc.def_prim('stopstack', 0, - lambda self: primitive_dictionary['stopstack']()) + self.tw.lc.def_prim( + 'stopstack', 0, + Primitive(self.tw.lc.prim_stop_stack)) def _blocks_palette(self): ''' The basic Turtle Art blocks palette ''' - debug_output('creating %s palette' % _('blocks'), - self.tw.running_sugar) palette = make_palette('blocks', colors=["#FFFF00", "#A0A000"], - help_string=_('Palette of variable blocks')) + help_string=_('Palette of variable blocks'), + translation=_('blocks')) - primitive_dictionary['start'] = self._prim_start palette.add_block('start', style='basic-style-head', label=_('start'), @@ -904,8 +1008,13 @@ boolean operators from Numbers palette')) logo_command='to start\n', help_string=_('connects action to toolbar run \ buttons')) - self.tw.lc.def_prim('start', 0, - lambda self: primitive_dictionary['start']()) + self.tw.lc.def_prim( + 'start', 0, + Primitive(Primitive.group, arg_descs=[ConstantArg([ + Primitive(self.tw.lc.prim_start, + export_me=False), + Primitive(self.tw.lc.prim_define_stack, + arg_descs=[ConstantArg('start')])])])) palette.add_block('string', style='box-style', @@ -922,9 +1031,14 @@ buttons')) default=_('action'), logo_command='to action', help_string=_('top of nameable action stack')) - self.tw.lc.def_prim('nop3', 1, lambda self, x: None) + self.tw.lc.def_prim( + 'nop3', 1, + Primitive(self.tw.lc.prim_define_stack, + arg_descs=[ArgSlot(TYPE_OBJECT)])) - primitive_dictionary['stack'] = self._prim_stack + primitive_dictionary['stack'] = Primitive( + self.tw.lc.prim_invoke_stack, + arg_descs=[ArgSlot(TYPE_OBJECT)]) palette.add_block('stack', style='basic-style-1arg', label=_('action'), @@ -933,9 +1047,9 @@ buttons')) logo_command='action', default=_('action'), help_string=_('invokes named action stack')) - self.tw.lc.def_prim('stack', 1, primitive_dictionary['stack'], True) + self.tw.lc.def_prim('stack', 1, + primitive_dictionary['stack'], True) - primitive_dictionary['setbox'] = self._prim_setbox palette.add_block('storeinbox1', hidden=True, style='basic-style-1arg', @@ -945,10 +1059,10 @@ buttons')) string_or_number=True, logo_command='make "box1', help_string=_('stores numeric value in Variable 1')) - self.tw.lc.def_prim('storeinbox1', 1, - lambda self, x: - primitive_dictionary['setbox'] - ('box1', None, x)) + self.tw.lc.def_prim( + 'storeinbox1', 1, + Primitive(self.tw.lc.prim_set_box, + arg_descs=[ConstantArg('box1'), ArgSlot(TYPE_OBJECT)])) palette.add_block('storeinbox2', hidden=True, @@ -959,10 +1073,10 @@ buttons')) string_or_number=True, logo_command='make "box2', help_string=_('stores numeric value in Variable 2')) - self.tw.lc.def_prim('storeinbox2', 1, - lambda self, x: - primitive_dictionary['setbox'] - ('box2', None, x)) + self.tw.lc.def_prim( + 'storeinbox2', 1, + Primitive(self.tw.lc.prim_set_box, + arg_descs=[ConstantArg('box2'), ArgSlot(TYPE_OBJECT)])) palette.add_block('box1', hidden=True, @@ -972,7 +1086,10 @@ buttons')) logo_command=':box1', help_string=_('Variable 1 (numeric value)'), value_block=True) - self.tw.lc.def_prim('box1', 0, lambda self: self.tw.lc.boxes['box1']) + self.tw.lc.def_prim( + 'box1', 0, + Primitive(self.tw.lc.prim_get_box, return_type=TYPE_BOX, + arg_descs=[ConstantArg('box1')])) palette.add_block('box2', hidden=True, @@ -982,8 +1099,14 @@ buttons')) logo_command=':box2', help_string=_('Variable 2 (numeric value)'), value_block=True) - self.tw.lc.def_prim('box2', 0, lambda self: self.tw.lc.boxes['box2']) + self.tw.lc.def_prim( + 'box2', 0, + Primitive(self.tw.lc.prim_get_box, return_type=TYPE_BOX, + arg_descs=[ConstantArg('box2')])) + primitive_dictionary['setbox'] = Primitive( + self.tw.lc.prim_set_box, + arg_descs=[ArgSlot(TYPE_OBJECT), ArgSlot(TYPE_OBJECT)]) palette.add_block('storein', style='basic-style-2arg', label=[_('store in'), _('box'), _('value')], @@ -993,12 +1116,12 @@ buttons')) default=[_('my box'), 100], help_string=_('stores numeric value in named \ variable')) - self.tw.lc.def_prim('storeinbox', 2, - lambda self, x, y: - primitive_dictionary['setbox'] - ('box3', x, y)) + self.tw.lc.def_prim('storeinbox', 2, primitive_dictionary['setbox']) - primitive_dictionary['box'] = self._prim_box + primitive_dictionary['box'] = Primitive( + self.tw.lc.prim_get_box, + return_type=TYPE_BOX, + arg_descs=[ArgSlot(TYPE_OBJECT)]) palette.add_block('box', style='number-style-1strarg', hidden=True, @@ -1009,8 +1132,7 @@ variable')) logo_command='box', value_block=True, help_string=_('named variable (numeric value)')) - self.tw.lc.def_prim('box', 1, - lambda self, x: primitive_dictionary['box'](x)) + self.tw.lc.def_prim('box', 1, primitive_dictionary['box']) palette.add_block('hat1', hidden=True, @@ -1019,7 +1141,10 @@ variable')) prim_name='nop1', logo_command='to stack1\n', help_string=_('top of Action 1 stack')) - self.tw.lc.def_prim('nop1', 0, lambda self: None) + self.tw.lc.def_prim( + 'nop1', 0, + Primitive(self.tw.lc.prim_define_stack, + arg_descs=[ConstantArg('stack1')])) palette.add_block('hat2', hidden=True, @@ -1028,9 +1153,11 @@ variable')) prim_name='nop2', logo_command='to stack2\n', help_string=_('top of Action 2 stack')) - self.tw.lc.def_prim('nop2', 0, lambda self: None) + self.tw.lc.def_prim( + 'nop2', 0, + Primitive(self.tw.lc.prim_define_stack, + arg_descs=[ConstantArg('stack2')])) - primitive_dictionary['stack1'] = self._prim_stack1 palette.add_block('stack1', hidden=True, style='basic-style-extended-vertical', @@ -1038,9 +1165,12 @@ variable')) prim_name='stack1', logo_command='stack1', help_string=_('invokes Action 1 stack')) - self.tw.lc.def_prim('stack1', 0, primitive_dictionary['stack1'], True) + self.tw.lc.def_prim( + 'stack1', 0, + Primitive(self.tw.lc.prim_invoke_stack, + arg_descs=[ConstantArg('stack1')]), + True) - primitive_dictionary['stack2'] = self._prim_stack2 palette.add_block('stack2', hidden=True, style='basic-style-extended-vertical', @@ -1048,16 +1178,19 @@ variable')) prim_name='stack2', logo_command='stack2', help_string=_('invokes Action 2 stack')) - self.tw.lc.def_prim('stack2', 0, primitive_dictionary['stack2'], True) + self.tw.lc.def_prim( + 'stack2', 0, + Primitive(self.tw.lc.prim_invoke_stack, + arg_descs=[ConstantArg('stack2')]), + True) def _trash_palette(self): ''' The basic Turtle Art turtle palette ''' - debug_output('creating %s palette' % _('trash'), - self.tw.running_sugar) palette = make_palette('trash', colors=["#FFFF00", "#A0A000"], - help_string=_('trash')) + help_string=_('trash'), + translation=_('trash')) palette.add_block('empty', style='blank-style', @@ -1074,19 +1207,9 @@ variable')) label=_('clear all'), help_string=_('move all blocks to trash')) - # Block primitives + # Callbacks to update labels after executing a block - def _prim_clear(self): - self.tw.lc.prim_clear() - self.tw.turtles.reset_turtles() - - def _prim_and(self, x, y): - ''' Logical and ''' - return x & y - - def _prim_arc(self, cmd, value1, value2): - ''' Turtle draws an arc of degree, radius ''' - cmd(float(value1), float(value2)) + def after_arc(self, *ignored_args): if self.tw.lc.update_values: self.tw.lc.update_label_value( 'xcor', @@ -1100,65 +1223,8 @@ variable')) 'heading', self.tw.turtles.get_active_turtle().get_heading()) - def _prim_box(self, x): - ''' Retrieve value from named box ''' - if isinstance(convert(x, float, False), float): - if int(float(x)) == x: - x = int(x) - try: - return self.tw.lc.boxes['box3' + str(x)] - except KeyError: - raise logoerror("#emptybox") - - def _prim_forever(self, blklist): - ''' Do list forever ''' - while True: - self.tw.lc.icall(self.tw.lc.evline, blklist[:]) - yield True - if self.tw.lc.procstop: - break - self.tw.lc.ireturn() - yield True - - def _prim_if(self, boolean, blklist): - ''' If bool, do list ''' - if boolean: - self.tw.lc.icall(self.tw.lc.evline, blklist[:]) - yield True - self.tw.lc.ireturn() - yield True - - def _prim_ifelse(self, boolean, list1, list2): - ''' If bool, do list1, else do list2 ''' - if boolean: - self.tw.lc.ijmp(self.tw.lc.evline, list1[:]) - yield True - else: - self.tw.lc.ijmp(self.tw.lc.evline, list2[:]) - yield True - - def _prim_move(self, cmd, value1, value2=None, pendown=True, - reverse=False): - ''' Turtle moves by method specified in value1 ''' - pos = None - if isinstance(value1, (tuple, list)): - pos = value1 - value1 = pos[0] - value2 = pos[1] - if not _num_type(value1): - raise logoerror("#notanumber") - if value2 is None: - if reverse: - cmd(float(-value1)) - else: - cmd(float(value1)) - else: - if not _num_type(value2): - raise logoerror("#notanumber") - if pos is not None: - cmd((float(value1), float(value2)), pendown=pendown) - else: - cmd(float(value1), float(value2), pendown=pendown) + def after_move(self, *ignored_args, **ignored_kwargs): + ''' Update labels after moving the turtle ''' if self.tw.lc.update_values: self.tw.lc.update_label_value( 'xcor', @@ -1169,323 +1235,38 @@ variable')) self.tw.turtles.get_active_turtle().get_xy()[1] / self.tw.coord_scale) - def _prim_or(self, x, y): - ''' Logical or ''' - return x | y - - def _prim_repeat(self, num, blklist): - ''' Repeat list num times. ''' - if not _num_type(num): - raise logoerror("#notanumber") - num = self.tw.lc.int(num) - for i in range(num): - self.tw.lc.icall(self.tw.lc.evline, blklist[:]) - yield True - if self.tw.lc.procstop: - break - self.tw.lc.ireturn() - yield True - - def _prim_right(self, value, reverse=False): - ''' Turtle rotates clockwise ''' - if not _num_type(value): - raise logoerror("#notanumber") - if reverse: - self.tw.turtles.get_active_turtle().right(float(-value)) - else: - self.tw.turtles.get_active_turtle().right(float(value)) + def after_right(self, *ignored_args): if self.tw.lc.update_values: self.tw.lc.update_label_value( 'heading', self.tw.turtles.get_active_turtle().get_heading()) - def _prim_set(self, name, cmd, value=None): - ''' Set a value and update the associated value blocks ''' + def after_set(self, name, value=None): + ''' Update the associated value blocks ''' if value is not None: - cmd(value) if self.tw.lc.update_values: self.tw.lc.update_label_value(name, value) - def _prim_setbox(self, name, x, val): - ''' Define value of named box ''' - if x is not None: - if isinstance(convert(x, float, False), float): - if int(float(x)) == x: - x = int(x) - self.tw.lc.boxes[name + str(x)] = val - if self.tw.lc.update_values: - self.tw.lc.update_label_value('box', val, label=x) - else: - self.tw.lc.boxes[name] = val - if self.tw.lc.update_values: - self.tw.lc.update_label_value(name, val) - - def _prim_stack(self, x): - ''' Process a named stack ''' - if isinstance(convert(x, float, False), float): - if int(float(x)) == x: - x = int(x) - if 'stack3' + str(x) not in self.tw.lc.stacks or \ - self.tw.lc.stacks['stack3' + str(x)] is None: - raise logoerror("#nostack") - self.tw.lc.icall(self.tw.lc.evline, - self.tw.lc.stacks['stack3' + str(x)][:]) - yield True - self.tw.lc.procstop = False - self.tw.lc.ireturn() - yield True - - def _prim_stack1(self): - ''' Process Stack 1 ''' - if self.tw.lc.stacks['stack1'] is None: - raise logoerror("#nostack") - self.tw.lc.icall(self.tw.lc.evline, - self.tw.lc.stacks['stack1'][:]) - yield True - self.tw.lc.procstop = False - self.tw.lc.ireturn() - yield True - - def _prim_stack2(self): - ''' Process Stack 2 ''' - if self.tw.lc.stacks['stack2'] is None: - raise logoerror("#nostack") - self.tw.lc.icall(self.tw.lc.evline, self.tw.lc.stacks['stack2'][:]) - yield True - self.tw.lc.procstop = False - self.tw.lc.ireturn() - yield True - - def _prim_start(self): - ''' Start block: recenter ''' - if self.tw.running_sugar: - self.tw.activity.recenter() - - def _prim_stopstack(self): - ''' Stop execution of a stack ''' - self.tw.lc.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.tw.lc.ireturn() - yield True - - # Math primitivies - - def _prim_careful_divide(self, x, y): - ''' Raise error on divide by zero ''' - if isinstance(x, list) and _num_type(y): - z = [] - for i in range(len(x)): - try: - z.append(x[i] / y) - except ZeroDivisionError: - raise logoerror("#zerodivide") - return z - try: - return x / y - except ZeroDivisionError: - raise logoerror("#zerodivide") - except TypeError: - try: - return self._string_to_num(x) / self._string_to_num(y) - except ZeroDivisionError: - raise logoerror("#zerodivide") - except ValueError: - raise logoerror("#syntaxerror") - except TypeError: - raise logoerror("#notanumber") - - def _prim_equal(self, x, y): - ''' Numeric and logical equal ''' - if isinstance(x, list) and isinstance(y, list): - for i in range(len(x)): - if x[i] != y[i]: - return False - return True - try: - return float(x) == float(y) - except ValueError: - typex, typey = False, False - if strtype(x): - typex = True - if strtype(y): - typey = True - if typex and typey: - return x == y - try: - return self._string_to_num(x) == self._string_to_num(y) - except TypeError: - raise logoerror("#syntaxerror") - - def _prim_less(self, x, y): - ''' Compare numbers and strings ''' - if isinstance(x, list) or isinstance(y, list): - raise logoerror("#syntaxerror") - try: - return float(x) < float(y) - except ValueError: - typex, typey = False, False - if strtype(x): - typex = True - if strtype(y): - typey = True - if typex and typey: - return x < y - try: - return self._string_to_num(x) < self._string_to_num(y) - except TypeError: - raise logoerror("#notanumber") - - def _prim_more(self, x, y): - ''' Compare numbers and strings ''' - return self._prim_less(y, x) - - def _prim_plus(self, x, y): - ''' Add numbers, concat strings ''' - if x in COLORDICT: - x = _color_to_num(x) - if y in COLORDICT: - y = _color_to_num(y) - if _num_type(x) and _num_type(y): - return(x + y) - elif isinstance(x, list) and isinstance(y, list): - z = [] - for i in range(len(x)): - z.append(x[i] + y[i]) - return(z) - else: - if _num_type(x): - xx = str(round_int(x)) - else: - xx = str(x) - if _num_type(y): - yy = str(round_int(y)) - else: - yy = str(y) - return(xx + yy) - - def _prim_minus(self, x, y): - ''' Numerical subtraction ''' - if _num_type(x) and _num_type(y): - return(x - y) - elif isinstance(x, list) and isinstance(y, list): - z = [] - for i in range(len(x)): - z.append(x[i] - y[i]) - return(z) - try: - return self._string_to_num(x) - self._string_to_num(y) - except TypeError: - raise logoerror("#notanumber") - - def _prim_product(self, x, y): - ''' Numerical multiplication ''' - if _num_type(x) and _num_type(y): - return(x * y) - elif isinstance(x, list) and _num_type(y): - z = [] - for i in range(len(x)): - z.append(x[i] * y) - return(z) - elif isinstance(y, list) and _num_type(x): - z = [] - for i in range(len(y)): - z.append(y[i] * x) - return(z) - try: - return self._string_to_num(x) * self._string_to_num(y) - except TypeError: - raise logoerror("#notanumber") - - def _prim_mod(self, x, y): - ''' Numerical mod ''' - if _num_type(x) and _num_type(y): - return(x % y) - try: - return self._string_to_num(x) % self._string_to_num(y) - except TypeError: - raise logoerror("#notanumber") - except ValueError: - raise logoerror("#syntaxerror") - - def _prim_sqrt(self, x): - ''' Square root ''' - if _num_type(x): - if x < 0: - raise logoerror("#negroot") - return sqrt(x) - try: - return sqrt(self._string_to_num(x)) - except ValueError: - raise logoerror("#negroot") - except TypeError: - raise logoerror("#notanumber") - - def _prim_random(self, x, y): - ''' Random integer ''' - if _num_type(x) and _num_type(y): - return(int(round(uniform(x, y), 0))) - xx, xflag = chr_to_ord(x) - yy, yflag = chr_to_ord(y) - if xflag and yflag: - return chr(int(round(uniform(xx, yy), 0))) - if not xflag: - xx = self._string_to_num(x) - if not yflag: - yy = self._string_to_num(y) - try: - return(int(round(uniform(xx, yy), 0))) - except TypeError: - raise logoerror("#notanumber") - - def _prim_identity(self, x): - ''' Identity function ''' - return(x) - # Utilities - def _string_to_num(self, x): - ''' Try to comvert a string to a number ''' - if isinstance(x, (int, float)): - return(x) - try: - return int(ord(x)) - except TypeError: - pass - if isinstance(x, list): - raise logoerror("#syntaxerror") - if x in COLORDICT: - return _color_to_num(x) - xx = convert(x.replace(self.tw.decimal_point, '.'), float) - if isinstance(xx, float): - return xx - else: - xx, xflag = chr_to_ord(x) - if xflag: - return xx - else: - raise logoerror("#syntaxerror") - - def _make_constant(self, palette, block_name, label, constant): + def _make_constant(self, palette, block_name, label, constant_key): ''' Factory for constant blocks ''' - if constant in COLORDICT: - if COLORDICT[constant][0] is not None: - value = str(COLORDICT[constant][0]) + constant = CONSTANTS[constant_key] + if isinstance(constant, Color): + if constant.color is not None: + logo_command = str(constant.color) else: # Black or White - value = '0 tasetshade %d' % (COLORDICT[constant][1]) + logo_command = '0 tasetshade %d' % (constant.shade) + return_type = TYPE_COLOR else: - value = constant + logo_command = constant + return_type = TYPE_NUMBER palette.add_block(block_name, style='box-style', label=label, prim_name=block_name, - logo_command=value) - self.tw.lc.def_prim(block_name, 0, lambda self: constant) + logo_command=logo_command) + self.tw.lc.def_prim(block_name, 0, + Primitive(CONSTANTS.get, return_type=return_type, + arg_descs=[ConstantArg(constant_key)])) -- cgit v0.9.1