diff options
author | Marion <marion.zepf@gmail.com> | 2013-09-04 15:08:07 (GMT) |
---|---|---|
committer | Marion <marion.zepf@gmail.com> | 2013-09-04 15:08:07 (GMT) |
commit | 97b945e1e088c2e51d9a6233be49c401040883e9 (patch) | |
tree | b9ae9cb56638f9bf7291b5b762f7ce942e7cc32b /TurtleArt/tatype.py | |
parent | cc420f0e37c82275bb5d6b46d85aef9cb9fdae91 (diff) | |
parent | e0fcb7656caf8d35e3e4bfa9ce99729328f35b1d (diff) |
Merge branch 'type-system' into type-system-while-until
Conflicts:
TurtleArt/taprimitive.py -- preserve the semantics of both changes
Diffstat (limited to 'TurtleArt/tatype.py')
-rw-r--r-- | TurtleArt/tatype.py | 100 |
1 files changed, 76 insertions, 24 deletions
diff --git a/TurtleArt/tatype.py b/TurtleArt/tatype.py index 164ba2a..9cb5433 100644 --- a/TurtleArt/tatype.py +++ b/TurtleArt/tatype.py @@ -49,7 +49,19 @@ class Type(object): class TypeDisjunction(tuple,Type): """ Disjunction of two or more Types (from the type hierarchy) """ - pass + + def __init__(self, iterable): + self = tuple(iterable) + + + def __str__(self): + s = ["("] + for disj in self: + s.append(str(disj)) + s.append(" or ") + s.pop() + s.append(")") + return "".join(s) TYPE_OBJECT = Type('object', 0) @@ -65,6 +77,9 @@ TYPE_STRING = Type('string', 9) # TODO add list types +BOX_AST = ast.Name(id='BOX', ctx=ast.Load) +ACTION_AST = ast.Name(id='ACTION', ctx=ast.Load) + def get_type(x): """ Return the most specific type in the type hierarchy that applies to x and a boolean indicating whether x is an AST. If the type cannot be @@ -101,6 +116,11 @@ def get_type(x): return (TYPE_OBJECT, True) else: return (get_type(value)[0], True) + elif isinstance(x, ast.Subscript): + if x.value == BOX_AST: + return (TypeDisjunction((TYPE_OBJECT, TYPE_STRING, TYPE_NUMBER, + TYPE_FLOAT, TYPE_INT, TYPE_NUMERIC_STRING, TYPE_CHAR, + TYPE_COLOR)), True) elif isinstance(x, ast.Call): if isinstance(x.func, ast.Name): if x.func.id == 'float': @@ -163,24 +183,6 @@ TYPE_CONVERTERS = { } -def get_call_ast(func_name, args=None, kwargs=None): - """ Return an AST representing the call to a function with the name - func_name, passing it the arguments args (given as a list) and the - keyword arguments kwargs (given as a dictionary). """ - if args is None: - args = [] - keywords = [] - if kwargs is not None: - for (key, value) in kwargs.iteritems(): - keywords.append(ast.keyword(arg=key, value=value)) - return ast.Call(func=ast.Name(id=func_name, - ctx=ast.Load), - args=args, - keywords=keywords, - starargs=None, - kwargs=None) - - class TATypeError(BaseException): """ TypeError with the types from the hierarchy, not with Python types """ @@ -299,11 +301,7 @@ def convert(x, new_type, old_type=None, converter=None): func = ast.Attribute(value=y, attr=converter.im_func.__name__, ctx=ast.Load) - return ast.Call(func=func, - args=[], - keywords={}, - starargs=None, - kwargs=None) + return get_call_ast(func) else: func_name = converter.__name__ return get_call_ast(func_name, [y]) @@ -320,3 +318,57 @@ def convert(x, new_type, old_type=None, converter=None): return _apply_converter(converter, x) +class TypedCall(ast.Call): + """ Like a Call AST, but with a return type """ + + def __init__(self, func, args=None, keywords=None, starargs=None, + kwargs=None, return_type=None): + + if args is None: + args = [] + if keywords is None: + keywords = [] + + ast.Call.__init__(self, func=func, args=args, keywords=keywords, + starargs=starargs, kwargs=kwargs) + + self._return_type = return_type + + @property + def return_type(self): + if self._return_type is None: + return get_type(self.func) + else: + return self._return_type + + +def get_call_ast(func_name, args=None, kwargs=None, return_type=None): + """ Return an AST representing the call to a function with the name + func_name, passing it the arguments args (given as a list) and the + keyword arguments kwargs (given as a dictionary). + func_name -- either the name of a callable as a string, or an AST + representing a callable expression + return_type -- if this is not None, return a TypedCall object with this + return type instead """ + if args is None: + args = [] + # convert keyword argument dict to a list of (key, value) pairs + keywords = [] + if kwargs is not None: + for (key, value) in kwargs.iteritems(): + keywords.append(ast.keyword(arg=key, value=value)) + # get or generate the AST representing the callable + if isinstance(func_name, ast.AST): + func_ast = func_name + else: + func_ast = ast.Name(id=func_name, ctx=ast.Load) + # if no return type is given, return a simple Call AST + if return_type is None: + return ast.Call(func=func_ast, args=args, keywords=keywords, + starargs=None, kwargs=None) + # if a return type is given, return a TypedCall AST + else: + return TypedCall(func=func_ast, args=args, keywords=keywords, + return_type=return_type) + + |