Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarion <marion.zepf@gmail.com>2013-08-29 13:30:34 (GMT)
committer Marion <marion.zepf@gmail.com>2013-08-29 13:30:34 (GMT)
commita0e0b5a769f95e995e04c58f270cfa953b34f901 (patch)
tree99824ffbb8bcea0016f55e124456d14c862c2224
parent376521086f2263cbd7270b99b36a06f023942824 (diff)
introduce PrimitiveDisjunctions and TypeDisjunctions
-rw-r--r--TurtleArt/taprimitive.py177
-rw-r--r--TurtleArt/tatype.py6
2 files changed, 112 insertions, 71 deletions
diff --git a/TurtleArt/taprimitive.py b/TurtleArt/taprimitive.py
index fbc9c2d..b7bca61 100644
--- a/TurtleArt/taprimitive.py
+++ b/TurtleArt/taprimitive.py
@@ -20,7 +20,6 @@
import ast
from gettext import gettext as _
-import traceback
#from ast_pprint import * # only used for debugging, safe to comment out
@@ -30,7 +29,7 @@ from talogo import (LogoCode, logoerror)
from taturtle import (Turtle, Turtles)
from tatype import (convert, get_call_ast, get_converter, get_type,
is_bound_instancemethod, is_instancemethod,
- is_staticmethod, TATypeError, TYPE_OBJECT)
+ is_staticmethod, TATypeError, TypeDisjunction, TYPE_OBJECT)
from tautils import debug_output
from tawindow import (global_objects, TurtleArtWindow)
@@ -947,12 +946,23 @@ class Disjunction(tuple):
return "".join(s)
def get_alternatives(self):
- """ Return a tuple of slot alternatives, i.e. self """
+ """ Return a tuple of alternatives, i.e. self """
return self
+# make TypeDisjunction 'inherit' the methods of the abstract Disjunction class
+TypeDisjunction.__repr__ = Disjunction.__repr__
+TypeDisjunction.get_alternatives = Disjunction.get_alternatives
+
+
class PrimitiveDisjunction(Disjunction,Primitive):
- """ Disjunction of two or more Primitives """
+ """ Disjunction of two or more Primitives. PrimitiveDisjunctions may not
+ be nested. """
+
+ @property
+ def return_type(self):
+ """ Tuple of the return_types of all disjuncts """
+ return TypeDisjunction((prim.return_type for prim in self))
def __call__(self, *runtime_args, **runtime_kwargs):
""" TODO doc """
@@ -1017,84 +1027,109 @@ class ArgSlot(object):
elif convert_to_ast:
argument = value_to_ast(argument)
+ # 1. can the argument be called?
+ (func_disjunction, args) = (None, [])
+ if (isinstance(argument, tuple) and argument
+ and callable(argument[0])):
+ func_disjunction = argument[0]
+ args = argument[1:]
+ elif callable(argument):
+ func_disjunction = argument
+
+ # make sure we can loop over func_disjunction
+ if not isinstance(func_disjunction, PrimitiveDisjunction):
+ func_disjunction = PrimitiveDisjunction((func_disjunction, ))
+
error = None
- for slot in self.get_alternatives():
-
- # 1. Call the argument?
- called_argument = argument
- (func, args) = (None, [])
- if (isinstance(argument, tuple) and argument
- and callable(argument[0])):
- func = argument[0]
- args = argument[1:]
- elif callable(argument):
- func = argument
-
- # check if the argument can fill this slot (type-wise)
- if slot.wrapper is not None:
- arg_type = get_type(slot.wrapper)[0]
- elif func is not None:
- arg_type = get_type(func)[0]
- else:
- arg_type = get_type(argument)[0]
- converter = get_converter(arg_type, slot.type)
- if converter is None:
- continue
+ for func in func_disjunction:
+ for slot in self.get_alternatives():
- # 1. (cont'd) call the argument
- if func is not None:
- if convert_to_ast:
- call_ast = get_call_ast(func.__name__,
- [value_to_ast(arg) for arg in args])
- if slot.call_arg:
- was_argument_called = True
- if convert_to_ast:
- called_argument = call_ast
- else:
- called_argument = func(*args)
+ if isinstance(slot.wrapper, PrimitiveDisjunction):
+ wrapper_disjunction = slot.wrapper
else:
- if convert_to_ast:
- was_argument_called = True
- called_argument = ast.Lambda(args=[], vararg=None,
- kwarg=None, defaults=[], body=call_ast)
- elif args:
- was_argument_called = True
- if isinstance(func, Primitive):
- called_argument = func.fill_slots(*args)
- else:
- called_argument = Primitive(func,
- [ConstantArg(arg) for arg in args])
+ wrapper_disjunction = PrimitiveDisjunction((slot.wrapper, ))
- # 2. apply any wrappers
- wrapped_argument = called_argument
- if slot.wrapper is not None:
- if convert_to_ast:
- if hasattr(slot.wrapper, "get_ast"):
- wrapped_argument = slot.wrapper.get_ast(
- called_argument)
- else:
- raise PyExportError(("cannot convert callable %s to "
- "an AST") % (repr(slot.wrapper)))
- elif callable(slot.wrapper):
- wrapped_argument = slot.wrapper(called_argument)
+ for wrapper in wrapper_disjunction:
- # 3. check the type and convert the argument if necessary
- try:
- converted_argument = convert(wrapped_argument, slot.type,
- converter=converter)
- except TATypeError as error:
- # on failure, try the next slot
- continue
- else:
- # on success, return the result
- return converted_argument
+ # check if the argument can fill this slot (type-wise)
+ if wrapper is not None:
+ arg_type = get_type(wrapper)[0]
+ elif func is not None:
+ arg_type = get_type(func)[0]
+ else:
+ arg_type = get_type(argument)[0]
+ converter = None
+ if isinstance(slot.type, TypeDisjunction):
+ for type_ in slot.type:
+ converter = get_converter(arg_type, type_)
+ if converter is not None:
+ break
+ else:
+ type_ = slot.type
+ converter = get_converter(arg_type, type_)
+ # unable to convert, try next wrapper/ slot/ func
+ if converter is None:
+ continue
+
+ # 1. (cont'd) call the argument or pass it on as a callable
+ called_argument = argument
+ if func is not None:
+ if convert_to_ast:
+ call_ast = get_call_ast(func.__name__,
+ [value_to_ast(arg) for arg in args])
+ if slot.call_arg:
+ # call and pass on the return value
+ was_argument_called = True
+ if convert_to_ast:
+ called_argument = call_ast
+ else:
+ called_argument = func(*args)
+ else:
+ # don't call and pass on the callable
+ if convert_to_ast:
+ was_argument_called = True
+ called_argument = ast.Lambda(body=call_ast,
+ args=[], vararg=None, kwarg=None,
+ defaults=[])
+ elif args:
+ was_argument_called = True
+ if isinstance(func, Primitive):
+ called_argument = func.fill_slots(*args)
+ else:
+ called_argument = Primitive(func,
+ [ConstantArg(arg) for arg in args])
+
+ # 2. apply any wrappers
+ wrapped_argument = called_argument
+ if wrapper is not None:
+ if convert_to_ast:
+ if hasattr(wrapper, "get_ast"):
+ wrapped_argument = wrapper.get_ast(
+ called_argument)
+ else:
+ raise PyExportError(("cannot convert callable"
+ " %s to an AST") % (repr(wrapper)))
+ elif callable(wrapper):
+ wrapped_argument = wrapper(called_argument)
+
+ # 3. check the type and convert the argument if necessary
+ try:
+ converted_argument = convert(wrapped_argument, type_,
+ converter=converter)
+ except TATypeError as error:
+ # on failure, try next wrapper/ slot/ func
+ continue
+ else:
+ # on success, return the result
+ return converted_argument
# if we haven't returned anything yet, then all alternatives failed
if error is not None:
raise error
else:
raise TATypeError(bad_value=argument, bad_type=arg_type,
- req_type=self.type)
+ req_type=type_,
+ message="filling slot " + repr(self))
class ArgSlotDisjunction(Disjunction,ArgSlot):
diff --git a/TurtleArt/tatype.py b/TurtleArt/tatype.py
index 2c78c92..e6ffbb9 100644
--- a/TurtleArt/tatype.py
+++ b/TurtleArt/tatype.py
@@ -46,6 +46,12 @@ class Type(object):
def __str__(self):
return str(self.name)
+
+class TypeDisjunction(tuple,Type):
+ """ Disjunction of two or more Types (from the type hierarchy) """
+ pass
+
+
TYPE_OBJECT = Type('object', 0)
TYPE_CHAR = Type('char', 1)
TYPE_COLOR = Type('color', 2)