Exemplo n.º 1
0
    def visit_For(self, node: ast.For) -> None:
        # create list to iterate over
        lst_name = self.context.get_temp_name()
        assign_node = ast.Assign(
            targets=[ast.Name(id=lst_name, ctx=ast.Store())], value=node.iter)
        self.visit(assign_node)

        lst = self.context[lst_name]
        index = self.context.get_temp_var(TypeDB.get_type_by_name("int"))
        length = lst.tp.get_method("len")
        length_code = length.get_code(self.context, lst).code

        # construct for statement
        self.start_line(
            f"for({index.code}=0; {index.code} < {length_code}; {index.code}++) {{\n"
        )
        self.indent += 4
        assign_node = ast.Assign(
            targets=[node.target],
            value=ast.Subscript(
                value=ast.Name(id=lst_name, ctx=ast.Load()),
                slice=ast.Index(value=ast.Name(id=index.code, ctx=ast.Load())),
                ctx=ast.Load()))
        self.visit(assign_node)
        for statement in node.body:
            self.visit(statement)
        self.indent -= 4
        self.start_line("}\n")
        self.all_paths_return = False
Exemplo n.º 2
0
    def visit_Compare(self, node: ast3.Compare) -> VisitorOutput:
        "Transforms a comparision into a function call. E.g. `ABC == MNO` into `ABC.eq(MNO)`"

        assert len(
            node.ops
        ) == 1, "Pytropos only supports comparisions of two values at the time"
        self.generic_visit(node)

        op_type = type(node.ops[0])
        if op_type not in compopt:
            raise AstTransformerError(
                f"Pytropos doesn't support the comparison {type(op_type)} yet, sorry :("
            )

        op_str = compopt[op_type]

        new_v = ast3.Call(func=ast3.Attribute(value=node.left,
                                              attr=op_str,
                                              ctx=ast3.Load()),
                          args=[node.comparators[0]],
                          keywords=[
                              ast3.keyword(arg='pos',
                                           value=pos_as_tuple(node),
                                           ctx=ast3.Load())
                          ])
        return new_v
Exemplo n.º 3
0
    def visit_Attribute(self, node: ast3.Attribute) -> VisitorOutput:
        """Transforms accessing to an attribute to be handled as PythonValues do

        For example, it converts::

            expr.val

        into::

            expr.attr['val']

        or::

            expr.attr[('val', pos)]"""

        self.generic_visit(node)

        pos = pos_as_tuple(node)
        if pos is not None:
            varname = ast3.Tuple(elts=[ast3.Str(s=node.attr), pos],
                                 ctx=ast3.Load())  # type: ast3.expr
        else:
            varname = ast3.Str(s=node.attr)

        return ast3.Subscript(
            value=ast3.Attribute(
                value=node.value,
                attr='attr',
                ctx=ast3.Load(),
            ),
            slice=ast3.Index(value=varname, ),
            ctx=node.ctx,
        )
Exemplo n.º 4
0
 def visit_ArrayDecl(  # pylint: disable=invalid-name
         self, node) -> t.Tuple[str, typed_ast3.Subscript]:
     """Return tuple of: name, st.ndarray[..., ...] for given array type information."""
     name, type_ = self.visit(node.type)
     assert isinstance(name, str)
     assert isinstance(type_, typed_ast3.AST)
     dim = self.visit(node.dim)
     if dim is not None:
         raise NotImplementedError(_node_debug(node.dim), str(dim))
     dim_quals = [self.visit(subnode) for subnode in node.dim_quals]
     if dim_quals:
         raise NotImplementedError(_node_debug(node.dim_quals),
                                   str(dim_quals))
     _ = self.visit(node.coord)
     return name, typed_ast3.Subscript(
         value=typed_ast3.Attribute(value=typed_ast3.Name(
             id='st', ctx=typed_ast3.Load()),
                                    attr='ndarray',
                                    ctx=typed_ast3.Load()),
         slice=typed_ast3.ExtSlice(dims=[
             typed_ast3.Index(value=typed_ast3.Ellipsis()),
             typed_ast3.Index(value=type_)  # ,
             # typed_ast3.Index(value=typed_ast3.Tuple(n=-1))
         ]),
         ctx=typed_ast3.Load())
Exemplo n.º 5
0
 def _Attribute(self, t):
     if isinstance(t.value, typed_ast3.Name) and t.value.id == 'Fortran':
         raise NotImplementedError(
             'Fortran.{} can be handled only when subscripted.'.format(
                 t.attr))
     if isinstance(t.value, typed_ast3.Name) and t.attr == 'size':
         call = typed_ast3.Call(func=typed_ast3.Name(id='size',
                                                     ctx=typed_ast3.Load()),
                                args=[t.value],
                                keywords=[])
         self._Call(call)
         return
     if syntax_matches(
             t,
             typed_ast3.Attribute(value=typed_ast3.Attribute(
                 value=typed_ast3.Name(id='st', ctx=typed_ast3.Load()),
                 attr='generic',
                 ctx=typed_ast3.Load()),
                                  attr='GenericVar',
                                  ctx=typed_ast3.Load())):
         # t._fortran_metadata = {'is_generic_var': True}
         # self._generic_vars.append()
         return
     self._unsupported_syntax(t)
     '''
Exemplo n.º 6
0
def make_numpy_constructor(function: str, arg: typed_ast3.AST,
                           data_type: typed_ast3.AST) -> typed_ast3.Call:
    return typed_ast3.Call(
        func=typed_ast3.Attribute(
            value=typed_ast3.Name(id='np', ctx=typed_ast3.Load()),
            attr=function, ctx=typed_ast3.Load()),
        args=[arg],
        keywords=[typed_ast3.keyword(arg='dtype', value=data_type)])
Exemplo n.º 7
0
 def _show_store_contents_expr(self) -> ast3.Expr:
     """Returns an ast3.Expr which prints the value of the store in the screen. Useful
     for debugging.
     """
     # print(st)
     return ast3.Expr(value=ast3.Call(
         func=ast3.Name(id='print', ctx=ast3.Load()),
         args=[ast3.Name(id='st', ctx=ast3.Load())],
         keywords=[],
     ), )
Exemplo n.º 8
0
def pos_as_tuple(node: Union[ast3.expr, ast3.stmt]) -> Optional[ast3.Tuple]:
    if not hasattr(node, 'lineno'):
        return None

    return ast3.Tuple(elts=[
        ast3.Tuple(elts=[ast3.Num(node.lineno),
                         ast3.Num(node.col_offset)],
                   ctx=ast3.Load()),
        ast3.Name(id='fn', ctx=ast3.Load())
    ],
                      ctx=ast3.Load())
    def visit_Exec(self, n):
        new_globals = self.maybe_visit(n.globals)
        if new_globals is None:
            new_globals = ast3.Name("None", ast3.Load(), lineno=-1, col_offset=-1)
        new_locals = self.maybe_visit(n.locals)
        if new_locals is None:
            new_locals = ast3.Name("None", ast3.Load(), lineno=-1, col_offset=-1)

        return ast3.Expr(ast3.Call(ast3.Name("exec", ast3.Load(), lineno=n.lineno, col_offset=-1),
                                   [self.visit(n.body), new_globals, new_locals],
                                   [],
                                   lineno=n.lineno, col_offset=-1))
Exemplo n.º 10
0
 def visit_PtrDecl(self, node):  # pylint: disable=invalid-name
     """Return st.Pointer[...] for given pointer type."""
     quals = node.quals
     if quals:
         _LOG.warning('ignoring unsupported C grammar: %s', quals)
     name, type_ = self.visit(node.type)
     assert name is None or isinstance(name, str)
     assert isinstance(type_, typed_ast3.AST), type(type_)
     _ = self.visit(node.coord)
     # assert type_ is not None, _node_str(node)
     return name, typed_ast3.Subscript(
         value=typed_ast3.Attribute(value=typed_ast3.Name(id='st', ctx=typed_ast3.Load()),
                                    attr='Pointer', ctx=typed_ast3.Load()),
         slice=typed_ast3.Index(value=type_), ctx=typed_ast3.Load())
Exemplo n.º 11
0
    def visit_ListComp(self, node):
        from parser.functions import FunctionImplementation

        # calculate result type
        if len(node.generators) > 1:
            raise InvalidOperation(
                "Only one for statement permitted in comprehensions")
        comp = node.generators[0]
        if len(comp.ifs) > 1:
            raise InvalidOperation(
                "Only one if statement allowed in List Comprehension")
        assign_node = ast.Assign(targets=[comp.target],
                                 value=ast.Subscript(value=comp.iter,
                                                     slice=ast.Index(
                                                         ast.Num(0))))
        return_node = ast.Return(value=node.elt)
        function_node = ast.FunctionDef(name="temp",
                                        args=ast.arguments(args=[],
                                                           vararg=None,
                                                           kwonlyargs=[],
                                                           kw_defaults=[],
                                                           kwarg=None,
                                                           defaults=[]),
                                        body=[assign_node, return_node])
        function_interpreter = FunctionImplementation(function_node, (),
                                                      self.context)
        result_type = TypeDB.get_list([function_interpreter.retval.tp])

        # create temp list to hold values
        result = self.context.get_temp_var(result_type)
        self.prepends.append(
            f"{result.code} = {result_type.as_literal([])};\n")
        # create for expression
        append_node = ast.Expr(
            ast.Call(func=ast.Attribute(value=ast.Name(id=result.code,
                                                       ctx=ast.Load()),
                                        attr="append",
                                        ctx=ast.Load()),
                     args=[node.elt],
                     keywords=[]))
        if comp.ifs:
            body = ast.If(test=comp.ifs[0], body=[append_node], orelse=[])
        else:
            body = append_node
        for_node = ast.For(target=comp.target,
                           iter=comp.iter,
                           body=[body],
                           orelse=[])
        self.prepends.append(for_node)
        return result
Exemplo n.º 12
0
 def visit_TypeDecl(self, node) -> t.Tuple[str, typed_ast3.Name]:  # pylint: disable=invalid-name
     """Return a tuple: identifier and its type."""
     declname = node.declname
     assert declname is None or isinstance(declname, str)
     quals = node.quals
     type_ = self.visit(node.type)
     assert isinstance(type_, typed_ast3.Name), type(type_)
     for qual in quals:
         assert isinstance(qual, str)
         type_ = typed_ast3.Subscript(
             value=typed_ast3.Attribute(value=typed_ast3.Name(id='st', ctx=typed_ast3.Load()),
                                        attr=qual.title(), ctx=typed_ast3.Load()),
             slice=typed_ast3.Index(value=type_), ctx=typed_ast3.Load())
     _ = self.visit(node.coord)
     return declname, type_
Exemplo n.º 13
0
def evaluate_call(node: ast3.Call,
                  *,
                  scope: Scope,
                  module_path: catalog.Path) -> Node:
    if not is_named_tuple_definition(node,
                                     scope=scope,
                                     module_path=module_path):
        return node
    class_name_node, fields_node = node.args

    def field_to_parameter(field_node: ast3.expr) -> ast3.arg:
        name_node, annotation_node = field_node.elts
        return ast3.arg(ast3.literal_eval(name_node), annotation_node)

    initializer_node = ast3.FunctionDef(
            '__init__',
            ast3.arguments([ast3.arg('self', None)]
                           + list(map(field_to_parameter,
                                      fields_node.elts)),
                           None, [], [], None, []),
            [ast3.Pass()], [], None)
    function_path = evaluate_node(node.func,
                                  scope=scope,
                                  module_path=module_path)
    class_def = ast3.ClassDef(ast3.literal_eval(class_name_node),
                              [ast3.Name(str(function_path), ast3.Load())],
                              [], [initializer_node], [])
    return ast3.fix_missing_locations(ast3.copy_location(class_def, node))
Exemplo n.º 14
0
 def visit_ArrayRef(self, node):  # pylint: disable=invalid-name
     name = self.visit(node.name)
     subscript = self.visit(node.subscript)
     _ = self.visit(node.coord)
     return typed_ast3.Subscript(value=name,
                                 slice=typed_ast3.Index(subscript),
                                 ctx=typed_ast3.Load())
Exemplo n.º 15
0
 def visit_Cast(self, node):  # pylint: disable=invalid-name
     """Transform C cast into cast() function call."""
     to_type = self.visit(node.to_type)
     expr = self.visit(node.expr)
     _ = self.visit(node.coord)
     return typed_ast3.Call(func=typed_ast3.Name(id='cast', ctx=typed_ast3.Load()), args=[expr],
                            keywords=[typed_ast3.keyword(arg='type', value=to_type)])
Exemplo n.º 16
0
 def visit_Struct(self, node):  # pylint: disable=invalid-name
     """Transform Struct."""
     name = node.name
     assert isinstance(name, str), type(name)
     assert node.decls is None, node.decls
     _ = self.visit(node.coord)
     return typed_ast3.Name(name, typed_ast3.Load())
Exemplo n.º 17
0
 def visit_IdentifierType(self, node) -> typed_ast3.Name:  # pylint: disable=invalid-name
     """Transform IdentifierType(names: t.List[str], coord: t.Optional[Coord])."""
     names = node.names
     assert len(names) == 1, names
     name = names[0]
     assert isinstance(name, str)
     _ = self.visit(node.coord)
     return typed_ast3.Name(id=name, ctx=typed_ast3.Load())
Exemplo n.º 18
0
    def _Class(self, node: ET.Element):  # pylint: disable=invalid-name
        context = node.attrib['context']
        assert context in self.namespaces, context

        cls_name = node.attrib['name']
        if '<' in cls_name:
            _LOG.warning('processing template class %s', cls_name)
            assert '>' in cls_name
            cls_name, _, rest = cls_name.partition('<')
            rest = rest[:-1]
            generic_args = [_.strip() for _ in rest.split(',')]
            _LOG.warning('found generic args: %s', generic_args)

        full_name = '{}::{}'.format(self.namespaces[context], cls_name)
        is_stl_class = full_name in CPP_STL_CLASSES and generic_args
        value_type = None

        body = []
        for member_id in node.attrib['members'].split():
            if not is_stl_class:
                # TODO: handle non-STL classes too
                break
            if member_id not in self.all_types:
                continue
            member_type = self.all_types[member_id]
            if member_type.tag == 'Typedef' and member_type.attrib[
                    'name'] == 'value_type':
                referenced_id = member_type.attrib['type']
                assert referenced_id in self.all_types
                if referenced_id not in self.relevant_types \
                        and referenced_id not in self._new_relevant_types:
                    self._new_relevant_types[referenced_id] = self.all_types[
                        referenced_id]
                    _LOG.debug(
                        'type marked as relevant due to being container value type %s',
                        ET.tostring(
                            self.all_types[referenced_id]).decode().rstrip())
                body.append(typed_ast3.Expr(typed_ast3.Str(referenced_id, '')))
                value_type = referenced_id
            '''
            if member_id not in self.relevant_types and member_id not in self._new_relevant_types:
                self._new_relevant_types[member_id] = member_type
                _LOG.warning('marked %s as relevant type',
                             ET.tostring(member_type).decode().rstrip())
            body.append(typed_ast3.Expr(typed_ast3.Str(member_id, '')))
            '''

        base_class = typed_ast3.parse(CPP_PYTHON_CLASS_PAIRS[full_name],
                                      mode='eval').body

        if is_stl_class:
            assert value_type is not None
            base_class = typed_ast3.Subscript(
                value=base_class,
                slice=typed_ast3.Index(typed_ast3.Str(value_type, '')),
                ctx=typed_ast3.Load())

        return base_class
Exemplo n.º 19
0
    def dispatch_var_type(self, tree):
        code = horast.unparse(tree)
        stripped_code = code.strip()
        if stripped_code in PYTHON_FORTRAN_TYPE_PAIRS:
            type_name, precision = PYTHON_FORTRAN_TYPE_PAIRS[stripped_code]
            self.write(type_name)
            if precision is not None:
                self.write('*')
                self.write(str(precision))
        elif _match_array(tree):
            sli = tree.slice
            assert isinstance(sli,
                              typed_ast3.Index), typed_astunparse.dump(tree)
            assert isinstance(sli.value, typed_ast3.Tuple)
            assert len(sli.value.elts) in (2, 3), sli.value.elts
            elts = sli.value.elts
            self.dispatch_var_type(elts[1])
            self.write(', ')
            self.write('dimension(')

            if len(sli.value.elts) == 2:
                self.write(':')
            else:
                if not self._context_input_args:
                    self.dispatch(elts[2])
                else:
                    assert isinstance(elts[2], typed_ast3.Tuple)
                    _LOG.warning('coercing indices of %i dims to 0-based',
                                 len(elts[2].elts))
                    # _LOG.warning('coercing indices of %s in %s to 0-based', arg.arg, t.name)
                    tup_elts = []
                    for elt in elts[2].elts:
                        if isinstance(elt, typed_ast3.Num):
                            assert isinstance(elt.n, int)
                            upper = typed_ast3.Num(n=elt.n - 1)
                        else:
                            assert isinstance(elt, typed_ast3.Name)
                            upper = typed_ast3.BinOp(left=elt,
                                                     op=typed_ast3.Sub(),
                                                     right=typed_ast3.Num(n=1))
                        tup_elts.append(
                            typed_ast3.Slice(lower=typed_ast3.Num(n=0),
                                             upper=upper,
                                             step=None))
                    tup = typed_ast3.Tuple(elts=tup_elts,
                                           ctx=typed_ast3.Load())
                    self.dispatch(tup)

            self.write(')')
        elif _match_io(tree):
            self.write('integer')
        elif isinstance(tree, typed_ast3.Call) and isinstance(tree.func, typed_ast3.Name) \
                and tree.func.id == 'type':
            self.dispatch(tree)
        else:
            raise NotImplementedError('not yet implemented: {}'.format(
                typed_astunparse.dump(tree)))
Exemplo n.º 20
0
def make_st_ndarray(data_type: typed_ast3.AST,
                    dimensions_or_sizes: t.Union[int, list]) -> typed_ast3.Subscript:
    """Create a typed_ast node equivalent to: st.ndarray[dimensions, data_type, sizes]."""
    if isinstance(dimensions_or_sizes, int):
        dimensions = dimensions_or_sizes
        sizes = None
    else:
        dimensions = len(dimensions_or_sizes)
        sizes = [make_expression_from_slice(size) for size in dimensions_or_sizes]
    return typed_ast3.Subscript(
        value=typed_ast3.Attribute(
            value=typed_ast3.Name(id='st', ctx=typed_ast3.Load()),
            attr='ndarray', ctx=typed_ast3.Load()),
        slice=typed_ast3.Index(value=typed_ast3.Tuple(
            elts=[typed_ast3.Num(n=dimensions), data_type] + [
                typed_ast3.Tuple(elts=sizes, ctx=typed_ast3.Load())] if sizes else [],
            ctx=typed_ast3.Load())),
        ctx=typed_ast3.Load())
Exemplo n.º 21
0
    def visit_Num(self, node: ast3.Num) -> VisitorOutput:
        """Wraps a number into a Pytropos type.

        Example: given the number `3` returns `pt.int(3)`
        """
        if isinstance(node.n, (int, float)):
            attr = 'int' if isinstance(node.n, int) else 'float'
            new_v = ast3.Call(func=ast3.Attribute(value=ast3.Name(
                id='pt', ctx=ast3.Load()),
                                                  attr=attr,
                                                  ctx=ast3.Load()),
                              args=[ast3.Num(n=node.n)],
                              keywords=[])
            return new_v
        else:
            raise AstTransformerError(
                f"Number of type {type(node.n)} isn't supported by pytropos. Sorry :S"
            )
Exemplo n.º 22
0
 def _PointerType(self, node: ET.Element):  # pylint: disable=invalid-name
     id_ = node.attrib['id']
     type_ = node.attrib['type']
     is_const = type_.endswith('c')
     if is_const:
         type_ = type_[:-1]
     try:
         base_type = self.fundamental_types[type_]
     except KeyError:
         # _LOG.debug()
         base_type = typed_ast3.Str(type_, '')
     type_info = typed_ast3.Subscript(value=typed_ast3.Name(
         id='Pointer', ctx=typed_ast3.Load()),
                                      slice=typed_ast3.Index(base_type),
                                      ctx=typed_ast3.Load())
     if is_const:
         type_info = typed_ast3.Subscript(value=typed_ast3.Name(
             id='Const', ctx=typed_ast3.Load()),
                                          slice=typed_ast3.Index(type_info),
                                          ctx=typed_ast3.Load())
     return (id_, type_info)
Exemplo n.º 23
0
    def visit_Tuple(self, node: ast3.Tuple) -> VisitorOutput:
        """Transforms a tuple into a Pytropos value.

        For example, it converts::

            (a, 5, 21)

        into::

            pt.tuple(st['a'], pt.int(5), pt.int(21))"""
        self.generic_visit(node)

        return ast3.Call(
            func=ast3.Attribute(
                value=ast3.Name(id='pt', ctx=ast3.Load()),
                attr='tuple',
                ctx=ast3.Load(),
            ),
            args=node.elts,
            keywords=[],
        )
Exemplo n.º 24
0
 def visit_UnaryOp(self, node):  # pylint: disable=invalid-name
     """Transform UnaryOp."""
     op_type, op_ = C_UNARY_OPERATORS_TO_PYTHON[node.op]
     expr = self.visit(node.expr)
     _ = self.visit(node.coord)
     if op_type is typed_ast3.Call:
         return op_type(func=typed_ast3.Name(id=op_, ctx=typed_ast3.Load()), args=[expr],
                        keywords=[])
     if op_type is typed_ast3.AugAssign:
         return op_type(target=expr, op=op_(), value=typed_ast3.Num(n=1))
         # raise NotImplementedError()
     return op_type(op=op_(), operand=expr)
Exemplo n.º 25
0
    def visit_Call(self, n):
        args = self.visit(n.args)
        if n.starargs is not None:
            args.append(ast3.Starred(self.visit(n.starargs), ast3.Load(), lineno=n.starargs.lineno, col_offset=n.starargs.col_offset))

        keywords = self.visit(n.keywords)
        if n.kwargs is not None:
            keywords.append(ast3.keyword(None, self.visit(n.kwargs)))

        return ast3.Call(self.visit(n.func),
                         args,
                         keywords)
Exemplo n.º 26
0
    def visit_List(self, node: ast3.List) -> VisitorOutput:
        """Transforms a list into a Pytropos value.

        For example, it converts::

            [a, 5, 21]

        into::

            pt.list([st['a'], pt.int(5), pt.int(21)])"""
        self.generic_visit(node)

        return ast3.Call(
            func=ast3.Attribute(
                value=ast3.Name(id='pt', ctx=ast3.Load()),
                attr='list',
                ctx=ast3.Load(),
            ),
            args=[node],
            keywords=[],
        )
Exemplo n.º 27
0
    def visit_Print(self, n):
        keywords = []
        if n.dest is not None:
            keywords.append(ast3.keyword("file", self.visit(n.dest)))

        if not n.nl:
            keywords.append(ast3.keyword("end", ast3.Str(" ", lineno=n.lineno, col_offset=-1)))

        return ast3.Expr(ast3.Call(ast3.Name("print", ast3.Load(), lineno=n.lineno, col_offset=-1),
                                   self.visit(n.values),
                                   keywords,
                                   lineno=n.lineno, col_offset=-1))
Exemplo n.º 28
0
    def visit_Name(self, node: ast3.Name) -> VisitorOutput:
        """Transforms a name lookup into a dictionary lookup.

        For example, it converts::

            var

        into::

            st[('var', ...)]
        """

        pos = pos_as_tuple(node)
        if pos is not None:
            varname = ast3.Tuple(elts=[ast3.Str(s=node.id), pos],
                                 ctx=ast3.Load())  # type: ast3.expr
        else:
            varname = ast3.Str(s=node.id)

        return ast3.Subscript(value=ast3.Name(id='st', ctx=ast3.Load()),
                              slice=ast3.Index(value=varname),
                              ctx=node.ctx)
Exemplo n.º 29
0
    def visit_BinOp(self, node: ast3.BinOp) -> VisitorOutput:
        "Transforms a binary operation into a function call. E.g. `ABC == MNO` into `ABC.eq(MNO)`"

        self.generic_visit(node)
        op_type = type(node.op)
        if op_type not in operations:
            raise AstTransformerError(
                f"Pytropos doesn't support the operation {type(op_type)} yet, sorry :("
            )

        op_str = operations[op_type]

        new_v = ast3.Call(func=ast3.Attribute(value=node.left,
                                              attr=op_str,
                                              ctx=ast3.Load()),
                          args=[node.right],
                          keywords=[
                              ast3.keyword(arg='pos',
                                           value=pos_as_tuple(node),
                                           ctx=ast3.Load())
                          ])
        return new_v
Exemplo n.º 30
0
 def visit_Typedef(self, node):  # pylint: disable=invalid-name
     """Transform Typedef."""
     name = node.name
     assert isinstance(name, str), type(name)
     quals = node.quals
     if quals:
         _LOG.warning('ignoring unsupported C grammar: %s', quals)
     assert node.storage == ['typedef'], node.storage
     name_, type_ = self.visit(node.type)
     assert name == name_, (name, name_)
     _ = self.visit(node.coord)
     return typed_ast3.AnnAssign(target=typed_ast3.Name(name, typed_ast3.Store()), value=type_,
                                 annotation=typed_ast3.Name('type', typed_ast3.Load()), simple=1)