type : term
                | array_type opt_order
                | pointer_type
                | type LIST
                | type SET
                | type LPAREN opt_types RPAREN
                | type COLUMN type DICT
                | LPAREN types RPAREN
                | LARRAY type RARRAY
                | type OR type

def p_type(self, p):
        '''type : term
                | array_type opt_order
                | pointer_type
                | type LIST
                | type SET
                | type LPAREN opt_types RPAREN
                | type COLUMN type DICT
                | LPAREN types RPAREN
                | LARRAY type RARRAY
                | type OR type
                '''
        if len(p) == 2:
            p[0] = p[1],
        elif len(p) == 3 and p[2] == 'list':
            p[0] = tuple(List[t] for t in p[1])
        elif len(p) == 3 and p[2] == 'set':
            p[0] = tuple(Set[t] for t in p[1])
        elif len(p) == 3:
            if p[2] is None:
                expanded = []
                for nd in p[1]:
                    expanded.append(nd)
                    if isinstance(nd, NDArray) and len(nd.__args__) == 3:
                        expanded.append(NDArray[nd.__args__[0], -1::, -1::])
                p[0] = tuple(expanded)
            elif p[2] == "F":
                for nd in p[1]:
                    if len(nd.__args__) != 3:
                        raise PythranSyntaxError("Invalid Pythran spec. "
                                                 "F order is only valid for 2D arrays")
                p[0] = tuple(NDArray[nd.__args__[0], -1::, -1::] for nd in p[1])
            else:
                p[0] = p[1]
        elif len(p) == 5 and p[4] == ')':
            p[0] = tuple(Fun[args, r]
                         for r in p[1]
                         for args in (product(*p[3])
                                      if len(p[3]) > 1 else p[3]))
        elif len(p) == 5:
            p[0] = tuple(Dict[k, v] for k in p[1] for v in p[3])
        elif len(p) == 4 and p[2] == 'or':
            p[0] = p[1] + p[3]
        elif len(p) == 4 and p[3] == ')':
            p[0] = tuple(Tuple[t] for t in p[2])
        elif len(p) == 4 and p[3] == ']':
            p[0] = p[2]
        else:
            raise PythranSyntaxError("Invalid Pythran spec. "
                                     "Unknown text '{0}'".format(p.value))