Exemplo n.º 1
0
    def visit_Compare(self, node):
        # state.log.debug("\ncosts %s", dump(node))

        fqnn = bases.get_fqnn(node.left)
        party_name = fqnn[0]
        if party_name == self.passive_name:
            passive = True
            role = self.passive_role
        else:
            passive = False
            role = self.active_role

        try:
            left_symbol_record = self.symbol_table.identify(fqnn)
            left_kwargs = left_symbol_record["kwargs"]

        except UnknownSymbolError:
            left_kwargs = node.left.return_info[0]

        left_type = left_kwargs["type"]
        left_bitlen = left_kwargs["bitlen"]
        left_dim = left_kwargs["dim"]
        left_signed = left_kwargs["signed"]

        try:
            right_fqnn = bases.get_fqnn(node.comparators[0])
            right_symbol_record = self.symbol_table.identify(right_fqnn)
            right_kwargs = right_symbol_record["kwargs"]
        except FqnnError, e:
            right_kwargs = node.comparators[0].return_info[0]
Exemplo n.º 2
0
    def visit_For(self, node):
        """Creates a symbol_table entry for node.target and visits each
        body node.

        TASK: metatasty: Use stacked symbol_tables to store 'node.target'
        symbol table entry. This would give much more symbol_record accuracy.
        """

        if __debug__:
            state.log.debug("\ninfer %s", dump(node, True, True))
        fqnn = get_fqnn(node.target)

        target_rec = dict()
        if isinstance(node.iter, Call):
            if isinstance(node.iter.func, Name):
                if isinstance(node.iter.args[0], Num):
                    target_rec["type"] = types.Unsigned
                    target_rec["bitlen"] = mpz(
                        node.iter.args[0].n).bit_length()
                    target_rec["dim"] = [1]
                    target_rec["signed"] = False
                else:
                    arg_fqnn = get_fqnn(node.iter.args[0])
                    symbol_record = self.symbol_table.identify(arg_fqnn)
                    target_rec = symbol_record["kwargs"]
            else:
                raise TastySyntaxError(
                    "'for' not handled for iteration node type %s" %
                    type(node.iter.func))
        elif isinstance(node.iter, Attribute):
            arg_fqnn = get_fqnn(node.iter)
            symbol_record = self.symbol_table.identify(arg_fqnn)
            kwargs = symbol_record["kwargs"]
            node.iter.return_info = (kwargs, )

            iter_node_type = kwargs["type"]
            bit_lengths = (kwargs["bitlen"], )
            dims = (kwargs["dim"], )
            signeds = (kwargs["signed"], )
            node.target.return_info = iter_node_type.returns(
                "__getitem__", tuple(), bit_lengths, dims, signeds)
            target_rec = node.target.return_info[0]
        else:
            raise NotImplementedError(
                "'for' not handled for iteration node type %s" %
                type(node.iter))

        self.symbol_table.add_symbol(fqnn,
                                     kwargs=target_rec,
                                     lineno=node.lineno,
                                     colno=node.col_offset)

        #self.symbol_table.dump()
        for i in node.body:
            self.visit(i)
Exemplo n.º 3
0
 def visit_Call(self, node):
     if __debug__:
         state.log.debug("\ntype completion %s", dump(node))
     self.visit(node.func)
     if hasattr(node, "call_type") and node.call_type == CALL_TYPE_CTOR:
         val = node.keywords_map.get("val")
         if val:
             if not isinstance(val.value, Attribute):
                 return node
             fqnn = get_fqnn(val.value)
             if fqnn not in self.symbol_table:
                 symbol_record = self.global_table.identify(fqnn)
                 kwargs = symbol_record["kwargs"]
                 symbol_type = kwargs["type"]
                 node.keywords_map["val"].value = Call(
                     func=Name(id=symbol_type.__name__),
                     args=[],
                     kwargs=None,
                     starargs=None,
                     keywords=[
                         keyword(arg="bitlen",
                                 value=Num(n=kwargs["bitlen"])),
                         keyword(arg="dim", value=Num(n=kwargs["dim"])),
                         keyword(arg="signed",
                                 value=Name(id=str(kwargs["signed"]))),
                         keyword(arg="passive", value=Name(id="True")),
                         keyword(arg="empty", value=Name(id="True"))
                     ])
     return node
Exemplo n.º 4
0
 def check_simple_affects(self, node):
     if isinstance(node, Attribute):
         fqnn = get_fqnn(node)
         symbol_record = self.symbol_table.identify(fqnn)
         return symbol_record["bitmask"]
     else:
         raise NotImplementedError("Not implemented for %r" % type(node))
Exemplo n.º 5
0
    def visit_If(self, node):
        if not bases.has_parent_node(node, bases.TastyCBase.protocol_name):
            return

        if isinstance(node.test, Attribute):
            symbol_record = self.symbol_table.identify(get_fqnn(node.test))
            node.test.return_info = (symbol_record["kwargs"], )
        else:
            self.visit(node.test)
            if not hasattr(node.test, "return_info"):
                raise NotImplementedError(
                    "Inferency of test component of 'if' code not implemented"
                    % type(node.test))

        for i in node.body:
            self.visit(i)
        while True:
            else_ = node.orelse
            num_items = len(else_)
            if num_items == 1:
                if isinstance(else_[0], If):
                    node = else_[0]
                    for i in node.body:
                        self.visit(i)
                else:
                    for i in else_:
                        self.visit(i)
                    break
            else:
                break
Exemplo n.º 6
0
 def visit_Assign_2nd_pass(self, node):
     #state.log.debug("\nconstant propagation 2nd pass %s",
     #dump(node, True, True))
     target = node.targets[0]
     if isinstance(target, Name):
         fqnn = get_fqnn(target)
         if fqnn in self.propagated_symbols:
             return
     return node
Exemplo n.º 7
0
 def visit_BinOp(self, node):
     if isinstance(node.left, Attribute):
         fqnn = get_fqnn(node.left)
         if fqnn not in self.symbol_table:
             symbol_record = self.global_table.identify(fqnn)
             kwargs = symbol_record["kwargs"]
             symbol_type = kwargs["type"]
             node.left = Call(func=Name(id=symbol_type.__name__),
                              args=[],
                              kwargs=None,
                              starargs=None,
                              keywords=[
                                  keyword(arg="bitlen",
                                          value=Num(n=kwargs["bitlen"])),
                                  keyword(arg="dim",
                                          value=Num(n=kwargs["dim"])),
                                  keyword(
                                      arg="signed",
                                      value=Name(id=str(kwargs["signed"]))),
                                  keyword(arg="passive",
                                          value=Name(id="True")),
                                  keyword(arg="empty",
                                          value=Name(id="True"))
                              ])
     if isinstance(node.right, Attribute):
         fqnn = get_fqnn(node.right)
         if fqnn not in self.symbol_table:
             symbol_record = self.global_table.identify(fqnn)
             symbol_type = symbol_record["node_type"]
             kwargs = symbol_record["kwargs"]
             node.right = Call(
                 func=Name(id=symbol_type.__name__),
                 args=[],
                 kwargs=None,
                 starargs=None,
                 keywords=[
                     keyword(arg="bitlen", value=Num(n=kwargs["bitlen"])),
                     keyword(arg="dim", value=Num(n=kwargs["dim"])),
                     keyword(arg="signed",
                             value=Name(id=str(kwargs["signed"]))),
                     keyword(arg="passive", value=Name(id="True")),
                     keyword(arg="empty", value=Name(id="True"))
                 ])
     return node
Exemplo n.º 8
0
    def visit_Assign(self, node):
        """Only assignments of global aka party unbounded symbol/variable nodes
        gets analyzed, stored and annotated"""

        if isinstance(node.value, Num):
            #state.log.debug("symbolize constant %s", dump(node, True, True))
            for target in node.targets:
                self.symbol_table.add_symbol(get_fqnn(target),
                                             kwargs=eval_num_arg(node.value),
                                             lineno=target.lineno,
                                             colno=target.col_offset)
Exemplo n.º 9
0
 def visit_Attribute(self, node):
     try:
         fqnn = get_fqnn(node)
         if fqnn[0] == self.active_name:
             node.role = self.active_role
             node.passive = False
         else:
             node.role = self.passive_role
             node.passive = True
     except Exception:
         pass
Exemplo n.º 10
0
 def visit_Subscript(self, node):
     self.visit(node.value)
     if hasattr(node.value, "role"):
         node.role = node.value.role
         node.passive = node.value.passive
     else:
         fqnn = get_fqnn(node)
         if fqnn[0] == self.active_name:
             node.role = self.active_role
             node.passive = False
         else:
             node.role = self.passive_role
             node.passive = True
Exemplo n.º 11
0
    def visit_Expr(self, node):
        #state.log.debug("\nattribute propagator %s", dump(node, True, True))
        if (isinstance(node.value, Call)
                and isinstance(node.value.func, Attribute)):
            fqnn = get_fqnn(node.value.func)
            if fqnn[0] == self.active_name:
                node.role = self.active_role
                node.passive = False
            else:
                node.role = self.passive_role
                node.passive = True

        set_inherited_attributes(node, ("role", "passive"))
Exemplo n.º 12
0
    def visit_Assign(self, node):
        if not has_parent_node(node, bases.TastyCBase.protocol_name):
            return node
        if __debug__:
            state.log.debug("prune %s", dump(node, True, True))

        node.value = self.visit(node.value)
        if not node.value or self.check_remove(node):
            for target in node.targets:
                if (isinstance(target, Attribute)
                        or isinstance(target, Subscript)):
                    self.symbol_table.remove_symbol(get_fqnn(target))
                elif isinstance(target, Tuple):
                    for item in target.elts:
                        self.symbol_table.remove_symbol(get_fqnn(item))
                elif isinstance(target, Name):
                    self.symbol_table.remove_symbol(get_fqnn(target))
                else:
                    raise NotImplementedError("pruning of assign " \
                        "for node %r not yet implemented" % type(target))
            return
        return node
Exemplo n.º 13
0
    def visit_tasty_func_call(self, node):
        if __debug__:
            state.log.debug("\ninfer tasty func call %d %s", id(node),
                            dump(node, True, True))

        if isinstance(node.func, Name):
            fqnn = get_fqnn(node.func)
            symbol_record = self.symbol_table.identify(fqnn)
            # checking for tasty function
            kwargs = symbol_record["kwargs"]
            node.tasty_function = kwargs["tasty_function"]
            kwargs = symbol_record["kwargs"]
            node_type = kwargs["type"]
            node.initial_info = kwargs
        elif isinstance(node.func, Call):
            self.visit(node.func)
            node.tasty_function = node.func.tasty_function
        else:
            raise UnknownSymbolError()  # than this is not a tasty func

        for i in node.args:
            self.visit(i)

        retrieve_node_args(node)

        node.methodname = "__call__"
        node.call_type = CALL_TYPE_TASTY_FUNC_CALL

        node.input_types = list()
        node.bit_lengths = list()
        node.dims = list()
        node.signeds = list()
        for arg in node.args:
            ri = arg.return_info[0]
            node.input_types.append(ri["type"])
            node.bit_lengths.append(ri["bitlen"])
            node.dims.append(ri["dim"])
            node.signeds.append(ri["signed"])

        node.return_info = node.tasty_function.returns(node.methodname,
                                                       node.input_types,
                                                       node.bit_lengths,
                                                       node.dims, node.signeds)

        if isinstance(node.parent, Attribute):
            copy_type_info(node.parent, node)
        elif isinstance(node.func, Call):
            # directly called tasty functions after instantiation
            node.initial_info = node.func.return_info[0]
Exemplo n.º 14
0
    def visit_Name(self, node):
        #state.log.debug("\nconstant propagation %s", dump(node, True, True))

        if (isinstance(node.parent, Attribute)
                or node.id in tasty.tastyc.analyzation._cost_class_names
                or node.id in (self.active_name, self.passive_name)):
            return node

        try:
            fqnn = get_fqnn(node)
            symbol_record = self.symbol_table.identify(fqnn)
            node_kwargs = symbol_record["kwargs"]
        except Exception, e:
            #if state.config.verbose >= 2:
            #state.log.exception(e)
            pass
Exemplo n.º 15
0
    def visit_Assign(self, node):
        if __debug__:
            state.log.debug("\npass dispatch pre %s", dump(node, True, True))
        if not has_parent_node(node, bases.TastyCBase.protocol_name):
            return

        self.visit(node.value)

        if isinstance(node.value, Attribute):
            symbol_record = self.symbol_table.identify(get_fqnn(node.value))
            symbol_record[
                "bitmask"] = node.bitmask = Value.S_ONLINE if node.role else Value.C_ONLINE
        elif isinstance(node.value, Num):
            node.bitmask = 15
        else:
            node.bitmask = node.value.bitmask

        assert hasattr(node, "bitmask")
Exemplo n.º 16
0
    def visit_Subscript(self, node):
        if not has_parent_node(node, self.protocol_name):
            return
        if __debug__:
            state.log.debug("\ninfer %d %s", id(node), dump(node, True, True))

        fqnn = get_fqnn(node.value)
        symbol_record = self.symbol_table.identify(fqnn)
        kwargs = symbol_record["kwargs"]
        node_type = kwargs["type"]
        node.initial_info = kwargs
        node.input_types = tuple()
        node.bit_lengths = (kwargs["bitlen"], )
        node.dims = (kwargs["dim"], )
        node.signeds = (kwargs["signed"], )
        node.methodname = "__getitem__"
        node.return_info = node_type.returns(node.methodname, node.input_types,
                                             node.bit_lengths, node.dims,
                                             node.signeds)
Exemplo n.º 17
0
    def visit_constructor(self, node):
        """here we inspect constructor invocations."""

        if __debug__:
            state.log.debug("\ninfer ctor %s", dump(node, True, True))

        node.call_type = CALL_TYPE_CTOR
        node.methodname = node.node_type.__name__

        self.visit(node.func)
        for i in node.keywords:
            self.visit(i)

        if hasattr(node, "keywords_data"):
            raise InternalError(
                "trying to overwrite keywords_data attribute twice")

        # keyword name -> object
        # real objects of ast representation
        node.keywords_data = dict()

        # keyword name -> keyword node
        # used for fast access to keyword nodes
        node.keywords_map = dict()

        if node.args:
            raise TastySyntaxError(
                "Tasty type constructors must not use positional arguments")

        for ix, kw in enumerate(node.keywords):
            value = kw.value
            key = kw.arg
            node.keywords_map[key] = kw
            node.keywords_data[key] = value

            if isinstance(value, Num):
                evaled = eval_num_arg(value)
                node.keywords_data[key] = evaled["val"]
                evaled["type"] = node.node_type
                kw.return_info = (evaled, )
            elif isinstance(value, Attribute):
                symbol_record = self.symbol_table.identify(get_fqnn(value))
                kwargs = copy.deepcopy(symbol_record["kwargs"])
                kw.return_info = (kwargs, )
            elif isinstance(value, List):
                eval_value = eval_arg(value)
                node.keywords_data[key] = eval_value["val"]
                kw.return_info = (eval_value, )
            elif isinstance(value, Tuple):
                eval_value = eval_arg(value)
                node.keywords_data[key] = eval_value["val"]
                kw.return_info = (eval_value, )
            elif isinstance(value, Name):
                if value.id == "None":
                    raise TastySyntaxError(
                        "'None' not allowed as constructor argument")
                elif value.id == "True":
                    kw.return_info = ({
                        "type": bool,
                        "bitlen": None,
                        "dim": None,
                        "signed": None
                    }, )
                    node.keywords_data[key] = True
                elif value.id == "False":
                    kw.return_info = ({
                        "type": bool,
                        "bitlen": None,
                        "dim": None,
                        "signed": None
                    }, )
                    node.keywords_data[key] = False
                else:
                    raise NotImplementedError("argument %r not handled" %
                                              value.id)
            elif (isinstance(value, UnaryOp) or isinstance(value, BinOp)
                  or isinstance(value, BoolOp)
                  or isinstance(value, Subscript)):
                kw.return_info = kw.value.return_info
            else:
                raise NotImplementedError("unhandled node type %s" %
                                          type(value))

        val = node.keywords_map.get("val")
        if val:
            kwargs = val.return_info[0]
            for k, v in kwargs.iteritems():
                if (k not in node.keywords_data
                        and k not in ("force_signed", "force_bitlen")):
                    node.keywords_data[k] = v

        if "dim" not in node.keywords_data:
            if (issubclass(node.node_type, types.PlainType)
                    or issubclass(node.node_type, types.GarbledType)
                    or issubclass(node.node_type, types.HomomorphicType)):
                node.keywords_data["dim"] = [1]
            elif issubclass(node.node_type, types.Vec):
                # otherwise inspect val kwargs for dims
                val_node = node.keywords_data["val"]
                if isinstance(val, Attribute):
                    symbol_record = self.symbol_table.identify(
                        get_fqnn(val_node))
                    kwargs = symbol_record["kwargs"]
                    node.keywords_data["dim"] = kwargs["dim"]
                else:
                    raise NotImplementedError("not implemented for %s" %
                                              type(val))

        dim = node.keywords_data["dim"]
        try:
            iter(dim)
        except TypeError:
            node.keywords_data["dim"] = dim = [dim]
        except KeyError:
            raise

        if "force_bitlen" in node.keywords_data:
            node.keywords_data["bitlen"] = node.keywords_data["force_bitlen"]

        if "force_signed" in node.keywords_data:
            node.keywords_data["signed"] = node.keywords_data["force_signed"]

        if not "signed" in node.keywords_data:
            try:
                val = node.keywords_data["val"]
                node.keywords_data["signed"] = val.return_info[0]["signed"]
            except KeyError:
                node.signed_not_finished = True

        if "bitlen" not in node.keywords_data:
            if node.node_type in (types.Modular, types.ModularVec):
                node.keywords_data["bitlen"] = \
                    state.config.asymmetric_security_parameter
            elif issubclass(node.node_type, types.TastyFunction):
                pass
            else:
                #node.keywords_data["bitlen"] = e
                # the type declaration is not yet completed. Later we must
                # ensure correct tasty type initialization and set in node
                # and symbol table if present
                node.bitlen_not_finished = True
                if __debug__:
                    state.log.debug("bitlen_not_finished")

        force_bitlen = node.keywords_data.get("force_bitlen")
        if force_bitlen:
            node.keywords_data["bitlen"] = force_bitlen

        force_signed = node.keywords_data.get("force_signed")
        if force_signed:
            node.keywords_data["signed"] = True

        val_return_rec = None
        bit_lengths = None
        dims = None

        if val:
            #propagate_kwargs(node)
            val_return_rec = val.return_info[0]
            input_types = (val_return_rec["type"], )
            bit_lengths = (node.keywords_data["bitlen"],
                           val_return_rec["bitlen"])
            dims = (node.keywords_data["dim"], val_return_rec["dim"])
            signeds = (node.keywords_data.get("signed"),
                       val_return_rec["signed"])
        else:
            input_types = tuple()
            bit_lengths = (node.keywords_data.get("bitlen"), )
            dims = (node.keywords_data["dim"], )
            signeds = (node.keywords_data.get("signed"), None)

        # in this special case we must populate input_types, bit_lengths, dims
        # and signeds after calling returns()
        node.return_info = node.node_type.returns(node.methodname, input_types,
                                                  bit_lengths, dims, signeds)
        return_rec = node.return_info[0]

        if val:
            node.input_types = (val_return_rec["type"], )
            node.bit_lengths = (return_rec["bitlen"], val_return_rec["bitlen"])
            node.dims = (return_rec["dim"], val_return_rec["dim"])
            node.signeds = (return_rec["signed"], val_return_rec["signed"])
        else:
            node.input_types = tuple()
            node.bit_lengths = (return_rec["bitlen"], )
            node.dims = (return_rec["dim"], )
            node.signeds = (return_rec["signed"], )

        if isinstance(node.parent, Attribute):
            copy_type_info(node.parent, node)

        assert hasattr(node, "return_info")
        assert hasattr(node, "node_type")
        assert (isinstance(node.keywords_data, dict))
        assert "dim" in node.keywords_data
        assert type(node.return_info[0]["dim"]) != dict

        node.initial_info = node.return_info[0]
Exemplo n.º 18
0
    def visit_method(self, node):
        """here we inspect function and method calls"""

        if __debug__:
            state.log.debug("\ninfer method %d %s", id(node),
                            dump(node, True, True))
        node.call_type = CALL_TYPE_METHOD

        # handling method of party attribute
        if (isinstance(node.func, Attribute)
                and isinstance(node.func.value, Attribute)):
            attribute_symbol_record = self.symbol_table.identify(
                get_fqnn(node.func.value))
            node.func.return_info = node.func.value.return_info = \
                (attribute_symbol_record["kwargs"],)

        self.visit(node.func)
        for i in node.args:
            self.visit(i)

        if hasattr(node, "attr"):
            if node.attr == "input":
                node.methodname = "input"
            elif node.attr == "output":
                node.methodname = "output"
            else:
                raise NotImplementedError()
            assert hasattr(node, "methodname")
            return

        if hasattr(node.func, "attr"):
            if node.func.attr == "input":
                cnode = node.func.value
                node.methodname = "input"
                if (hasattr(cnode, "call_type")
                        and cnode.call_type == CALL_TYPE_CTOR):
                    add_keyword(cnode, "empty", True)
                copy_type_info(node, node.func)
                node.initial_info = cnode.return_info[0]
                node.input_types = tuple()
                node.dims = tuple()
                return
            elif node.func.attr in ("output", "setup_output"):
                node.methodname = node.func.attr
                return

        retrieve_node_args(node)

        symbol_table = self.symbol_table

        # handles methods of bounded party attributes
        if isinstance(node.func, Attribute):
            if hasattr(node.func.value, "call_type"
                       ) and node.func.value.call_type == CALL_TYPE_CTOR:
                attribute_node_type = node.func.value.node_type
                attribute_kwargs = node.func.value.return_info[0]
            elif (isinstance(node.func.value, Attribute)
                  or isinstance(node.func.value, Call)):
                fqnn = find_fqnn(node.func.value)
                attribute_symbol_record = symbol_table.identify(fqnn)
                attribute_kwargs = attribute_symbol_record["kwargs"]
                attribute_node_type = attribute_kwargs["type"]
            elif isinstance(node.func.value, Subscript):
                attribute_kwargs = node.func.value.return_info[0]
                attribute_node_type = attribute_kwargs["type"]
            node.methodname = methodname = node.func.attr
            node.input_types = list()
            node.bit_lengths = [attribute_kwargs["bitlen"]]
            node.dims = [attribute_kwargs["dim"]]
            node.signeds = [attribute_kwargs["signed"]]
            node.input_types.extend(
                [arg.return_info[0]["type"] for arg in node.args])
            node.dims.extend([arg.return_info[0]["dim"] for arg in node.args])
            node.bit_lengths.extend(
                [arg.return_info[0]["bitlen"] for arg in node.args])
            node.return_info = attribute_node_type.returns(
                node.methodname, node.input_types, node.bit_lengths, node.dims,
                node.signeds)
            node.initial_info = attribute_kwargs
        else:
            raise TastySyntaxError(
                "expected a method of a subclass of Value or Vec, got '%s'" %
                type(node.func))

        if isinstance(node.parent, Attribute):
            copy_type_info(node.parent, node)
        assert hasattr(node, "return_info")
        assert hasattr(node, "initial_info")
        assert hasattr(node, "methodname")
        assert type(node.return_info[0]) == dict
        assert type(node.initial_info) == dict
Exemplo n.º 19
0
    def visit_AugAssign(self, node):
        """ checking for tasty operators with previously undefined targets and
        annotates them with the type information of the source"""

        if __debug__:
            state.log.debug("\ninfer %s", dump(node, True, True))

        left_node = node.target
        right_node = node.value
        fqnn = get_fqnn(left_node)

        if isinstance(node.op, LShift):
            # special treatment, since semantic redefined as sending operator
            # with optional type conversion

            if not isinstance(node.target, Attribute):
                raise TastySyntaxError("Can only send to a party")

            if node.value.passive:
                direction = "receive"
            else:
                direction = "send"

            try:
                # processing bound party attribute, both sides have same type
                right_fqnn = get_fqnn(right_node)
                symbol_record = self.symbol_table.identify(right_fqnn)
                dest_return_rec = symbol_record["kwargs"]
                dest_type = dest_return_rec["type"]
                dest_bitlen = dest_return_rec["bitlen"]
                dest_dim = dest_return_rec["dim"]
                dest_signed = dest_return_rec["signed"]
                node.input_types = (dest_type, dest_type)
                node.bit_lengths = (dest_bitlen, dest_bitlen)
                node.dims = (dest_dim, dest_dim)
                node.signeds = (dest_signed, dest_signed)
                node.return_info = ((dest_type, dest_bitlen, dest_dim,
                                     dest_signed), )
                node.methodname = "%s_%s_%s" % (dest_type.__name__,
                                                dest_type.__name__, direction)
            except (FqnnError, UnknownSymbolError):
                if not isinstance(right_node, Call):
                    raise TastySyntaxError("value of tasty operator must be " \
                    "a constructor call of a type of TASTY or a " \
                    "bound PartyAttribute, got %r" %
                    type(right_node))

                # tasty operator including type conversion

                self.visit(right_node)

                node.return_info = right_node.return_info
                dest_return_rec = right_node.return_info[0]

                src_node = right_node.keywords_map["val"]
                src_return_rec = src_node.return_info[0]
                src_type = src_return_rec["type"]
                dest_type = dest_return_rec["type"]

                node.input_types = (dest_return_rec["type"],
                                    src_return_rec["type"])
                node.bit_lengths = (dest_return_rec["bitlen"],
                                    src_return_rec["bitlen"])
                node.dims = (dest_return_rec["dim"], src_return_rec["dim"])
                node.signeds = (dest_return_rec["signed"],
                                src_return_rec["signed"])
                node.methodname = "%s_%s_%s" % (src_type.__name__,
                                                dest_type.__name__, direction)

            try_finish_bitlenless(self, fqnn, dest_return_rec["bitlen"])
            try_finish_signed(self, fqnn, dest_return_rec["signed"])

            node.initial_info = node.return_info[0]

            self.symbol_table.add_symbol(fqnn,
                                         kwargs=dest_return_rec,
                                         lineno=node.lineno,
                                         colno=node.col_offset)
        else:
            # normal pythonic operator behaviour

            fqnn = get_fqnn(left_node)

            node.dims = list()
            node.bit_lengths = list()
            node.input_types = list()
            node.signeds = list()

            annotate_item_of_node(self, left_node, node, False)
            annotate_item_of_node(self, right_node, node)

            node.methodname = bases.AUGASSIGN_METHODS[type(node.op)]

            node.return_info = left_node.return_info[0]["type"].returns(
                node.methodname, node.input_types, node.bit_lengths, node.dims,
                node.signeds)

            kwargs = node.return_info[0]

            self.symbol_table.add_symbol(fqnn,
                                         kwargs=kwargs,
                                         lineno=node.lineno,
                                         colno=node.col_offset)