Index: Python/ceval.c =================================================================== --- Python/ceval.c (Revision 51629) +++ Python/ceval.c (Arbeitskopie) @@ -1945,6 +1945,24 @@ } break; + case BUILD_SET: + x = PySet_New(NULL); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + if (err == 0) + err = PySet_Add(x, w); + Py_DECREF(w); + } + if (err != 0) { + Py_DECREF(x); + break; + } + PUSH(x); + continue; + } + break; + case BUILD_MAP: x = PyDict_New(); PUSH(x); Index: Python/graminit.c =================================================================== --- Python/graminit.c (Revision 51629) +++ Python/graminit.c (Arbeitskopie) @@ -1500,26 +1500,42 @@ static arc arcs_71_0[1] = { {26, 1}, }; -static arc arcs_71_1[1] = { +static arc arcs_71_1[3] = { {21, 2}, + {27, 3}, + {0, 1}, }; static arc arcs_71_2[1] = { - {26, 3}, + {26, 4}, }; static arc arcs_71_3[2] = { - {27, 4}, + {26, 5}, {0, 3}, }; static arc arcs_71_4[2] = { - {26, 1}, + {27, 6}, {0, 4}, }; -static state states_71[5] = { +static arc arcs_71_5[2] = { + {27, 3}, + {0, 5}, +}; +static arc arcs_71_6[2] = { + {26, 7}, + {0, 6}, +}; +static arc arcs_71_7[1] = { + {21, 2}, +}; +static state states_71[8] = { {1, arcs_71_0}, - {1, arcs_71_1}, + {3, arcs_71_1}, {1, arcs_71_2}, {2, arcs_71_3}, {2, arcs_71_4}, + {2, arcs_71_5}, + {2, arcs_71_6}, + {1, arcs_71_7}, }; static arc arcs_72_0[1] = { {157, 1}, @@ -1911,7 +1927,7 @@ "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\140\010\311\000\000"}, {326, "testlist", 0, 3, states_70, "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\140\010\311\000\000"}, - {327, "dictmaker", 0, 5, states_71, + {327, "dictsetmaker", 0, 8, states_71, "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\140\010\311\000\000"}, {328, "classdef", 0, 8, states_72, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000"}, Index: Python/ast.c =================================================================== --- Python/ast.c (Revision 51629) +++ Python/ast.c (Arbeitskopie) @@ -394,6 +394,7 @@ expr_name = "list comprehension"; break; case Dict_kind: + case Set_kind: case Num_kind: case Str_kind: expr_name = "literal"; @@ -1187,7 +1188,7 @@ ast_for_atom(struct compiling *c, const node *n) { /* atom: '(' [yield_expr|testlist_gexp] ')' | '[' [listmaker] ']' - | '{' [dictmaker] '}' | NAME | NUMBER | STRING+ + | '{' [dictsetmaker] '}' | NAME | NUMBER | STRING+ */ node *ch = CHILD(n, 0); @@ -1242,36 +1243,55 @@ else return ast_for_listcomp(c, ch); case LBRACE: { - /* dictmaker: test ':' test (',' test ':' test)* [','] */ + /* dictsetmaker: test ':' test (',' test ':' test)* [','] | + * test (',' test)* [','] */ int i, size; asdl_seq *keys, *values; ch = CHILD(n, 1); - size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ - keys = asdl_seq_new(size, c->c_arena); - if (!keys) - return NULL; - - values = asdl_seq_new(size, c->c_arena); - if (!values) - return NULL; - - for (i = 0; i < NCH(ch); i += 4) { - expr_ty expression; - - expression = ast_for_expr(c, CHILD(ch, i)); - if (!expression) - return NULL; + if (NCH(ch) == 1 || (NCH(ch) > 0 && STR(CHILD(ch, 1))[0] == ',')) { + /* it's a set */ + size = (NCH(ch) + 1) / 2; /* +1 in case no trailing comma */ + keys = asdl_seq_new(size, c->c_arena); + if (!keys) + return NULL; - asdl_seq_SET(keys, i / 4, expression); + for (i = 0; i < NCH(ch); i += 2) { + expr_ty expression; + expression = ast_for_expr(c, CHILD(ch, i)); + if (!expression) + return NULL; + asdl_seq_SET(keys, i / 2, expression); + } + return Set(keys, LINENO(n), n->n_col_offset, c->c_arena); + } else { + /* it's a dict */ + size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ + keys = asdl_seq_new(size, c->c_arena); + if (!keys) + return NULL; + + values = asdl_seq_new(size, c->c_arena); + if (!values) + return NULL; + + for (i = 0; i < NCH(ch); i += 4) { + expr_ty expression; + + expression = ast_for_expr(c, CHILD(ch, i)); + if (!expression) + return NULL; - expression = ast_for_expr(c, CHILD(ch, i + 2)); - if (!expression) - return NULL; + asdl_seq_SET(keys, i / 4, expression); - asdl_seq_SET(values, i / 4, expression); - } - return Dict(keys, values, LINENO(n), n->n_col_offset, c->c_arena); + expression = ast_for_expr(c, CHILD(ch, i + 2)); + if (!expression) + return NULL; + + asdl_seq_SET(values, i / 4, expression); + } + return Dict(keys, values, LINENO(n), n->n_col_offset, c->c_arena); + } } default: PyErr_Format(PyExc_SystemError, "unhandled atom %d", TYPE(ch)); Index: Python/import.c =================================================================== --- Python/import.c (Revision 51629) +++ Python/import.c (Arbeitskopie) @@ -66,9 +66,10 @@ storing constants that should have been removed) Python 3000: 3000 3010 (removed UNARY_CONVERT) + 3020 (added BUILD_SET) . */ -#define MAGIC (3010 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define MAGIC (3020 | ((long)'\r'<<16) | ((long)'\n'<<24)) /* Magic word as global; note that _PyImport_Init() can change the value of this global to accommodate for alterations of how the Index: Python/compile.c =================================================================== --- Python/compile.c (Revision 51629) +++ Python/compile.c (Arbeitskopie) @@ -851,6 +851,7 @@ return 1; case BUILD_TUPLE: case BUILD_LIST: + case BUILD_SET: return 1-oparg; case BUILD_MAP: return 1; @@ -2955,6 +2956,11 @@ ADDOP(c, STORE_SUBSCR); } break; + case Set_kind: + n = asdl_seq_LEN(e->v.Set.elts); + VISIT_SEQ(c, expr, e->v.Set.elts); + ADDOP_I(c, BUILD_SET, n); + break; case ListComp_kind: return compiler_listcomp(c, e); case GeneratorExp_kind: Index: Python/Python-ast.c =================================================================== --- Python/Python-ast.c (Revision 51629) +++ Python/Python-ast.c (Arbeitskopie) @@ -178,6 +178,10 @@ "keys", "values", }; +static PyTypeObject *Set_type; +static char *Set_fields[]={ + "elts", +}; static PyTypeObject *ListComp_type; static char *ListComp_fields[]={ "elt", @@ -517,6 +521,8 @@ if (!IfExp_type) return 0; Dict_type = make_type("Dict", expr_type, Dict_fields, 2); if (!Dict_type) return 0; + Set_type = make_type("Set", expr_type, Set_fields, 1); + if (!Set_type) return 0; ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2); if (!ListComp_type) return 0; GeneratorExp_type = make_type("GeneratorExp", expr_type, @@ -1435,6 +1441,22 @@ } expr_ty +Set(asdl_seq * elts, int lineno, int col_offset, PyArena *arena) +{ + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Set_kind; + p->v.Set.elts = elts; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty ListComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena) { @@ -2424,6 +2446,15 @@ goto failed; Py_DECREF(value); break; + case Set_kind: + result = PyType_GenericNew(Set_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Set.elts, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "elts", value) == -1) + goto failed; + Py_DECREF(value); + break; case ListComp_kind: result = PyType_GenericNew(ListComp_type, NULL, NULL); if (!result) goto failed; @@ -3069,6 +3100,7 @@ return; if (PyDict_SetItemString(d, "IfExp", (PyObject*)IfExp_type) < 0) return; if (PyDict_SetItemString(d, "Dict", (PyObject*)Dict_type) < 0) return; + if (PyDict_SetItemString(d, "Set", (PyObject*)Set_type) < 0) return; if (PyDict_SetItemString(d, "ListComp", (PyObject*)ListComp_type) < 0) return; if (PyDict_SetItemString(d, "GeneratorExp", Index: Include/opcode.h =================================================================== --- Include/opcode.h (Revision 51629) +++ Include/opcode.h (Arbeitskopie) @@ -97,11 +97,12 @@ #define LOAD_NAME 101 /* Index in name list */ #define BUILD_TUPLE 102 /* Number of tuple items */ #define BUILD_LIST 103 /* Number of list items */ -#define BUILD_MAP 104 /* Always zero for now */ -#define LOAD_ATTR 105 /* Index in name list */ -#define COMPARE_OP 106 /* Comparison operator */ -#define IMPORT_NAME 107 /* Index in name list */ -#define IMPORT_FROM 108 /* Index in name list */ +#define BUILD_SET 104 /* Number of set items */ +#define BUILD_MAP 105 /* Always zero for now */ +#define LOAD_ATTR 106 /* Index in name list */ +#define COMPARE_OP 107 /* Comparison operator */ +#define IMPORT_NAME 108 /* Index in name list */ +#define IMPORT_FROM 109 /* Index in name list */ #define JUMP_FORWARD 110 /* Number of bytes to skip */ #define JUMP_IF_FALSE 111 /* "" */ Index: Include/graminit.h =================================================================== --- Include/graminit.h (Revision 51629) +++ Include/graminit.h (Arbeitskopie) @@ -69,7 +69,7 @@ #define sliceop 324 #define exprlist 325 #define testlist 326 -#define dictmaker 327 +#define dictsetmaker 327 #define classdef 328 #define arglist 329 #define argument 330 Index: Include/Python-ast.h =================================================================== --- Include/Python-ast.h (Revision 51629) +++ Include/Python-ast.h (Arbeitskopie) @@ -184,10 +184,10 @@ }; enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, - IfExp_kind=5, Dict_kind=6, ListComp_kind=7, - GeneratorExp_kind=8, Yield_kind=9, Compare_kind=10, - Call_kind=11, Num_kind=12, Str_kind=13, Attribute_kind=14, - Subscript_kind=15, Name_kind=16, List_kind=17, Tuple_kind=18}; + IfExp_kind=5, Dict_kind=6, Set_kind=7, ListComp_kind=8, + GeneratorExp_kind=9, Yield_kind=10, Compare_kind=11, + Call_kind=12, Num_kind=13, Str_kind=14, Attribute_kind=15, + Subscript_kind=16, Name_kind=17, List_kind=18, Tuple_kind=19}; struct _expr { enum _expr_kind kind; union { @@ -224,6 +224,10 @@ } Dict; struct { + asdl_seq *elts; + } Set; + + struct { expr_ty elt; asdl_seq *generators; } ListComp; @@ -399,6 +403,7 @@ col_offset, PyArena *arena); expr_ty Dict(asdl_seq * keys, asdl_seq * values, int lineno, int col_offset, PyArena *arena); +expr_ty Set(asdl_seq * elts, int lineno, int col_offset, PyArena *arena); expr_ty ListComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, PyArena *arena); expr_ty GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int Index: Grammar/Grammar =================================================================== --- Grammar/Grammar (Revision 51629) +++ Grammar/Grammar (Arbeitskopie) @@ -101,7 +101,7 @@ power: atom trailer* ['**' factor] atom: ('(' [yield_expr|testlist_gexp] ')' | '[' [listmaker] ']' | - '{' [dictmaker] '}' | + '{' [dictsetmaker] '}' | NAME | NUMBER | STRING+) listmaker: test ( list_for | (',' test)* [','] ) testlist_gexp: test ( gen_for | (',' test)* [','] ) @@ -112,7 +112,7 @@ sliceop: ':' [test] exprlist: expr (',' expr)* [','] testlist: test (',' test)* [','] -dictmaker: test ':' test (',' test ':' test)* [','] +dictsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [',']) classdef: 'class' NAME ['(' [testlist] ')'] ':' suite Index: Objects/setobject.c =================================================================== --- Objects/setobject.c (Revision 51629) +++ Objects/setobject.c (Arbeitskopie) @@ -530,14 +530,20 @@ char *emit = ""; /* No separator emitted on first pass */ char *separator = ", "; - fprintf(fp, "%s([", so->ob_type->tp_name); + if (so->ob_type == &PySet_Type) + fprintf(fp, "{"); + else + fprintf(fp, "%s([", so->ob_type->tp_name); while (set_next(so, &pos, &entry)) { fputs(emit, fp); emit = separator; if (PyObject_Print(entry->key, fp, 0) != 0) return -1; } - fputs("])", fp); + if (so->ob_type == &PySet_Type) + fputs("}", fp); + else + fputs("])", fp); return 0; } @@ -554,8 +560,15 @@ if (listrepr == NULL) return NULL; - result = PyString_FromFormat("%s(%s)", so->ob_type->tp_name, - PyString_AS_STRING(listrepr)); + if (so->ob_type == &PySet_Type) { + char *s = PyString_AS_STRING(listrepr); + s += 1; + s[strlen(s)-1] = 0; + result = PyString_FromFormat("{%s}", s); + } else { + result = PyString_FromFormat("%s(%s)", so->ob_type->tp_name, + PyString_AS_STRING(listrepr)); + } Py_DECREF(listrepr); return result; } Index: Parser/Python.asdl =================================================================== --- Parser/Python.asdl (Revision 51629) +++ Parser/Python.asdl (Arbeitskopie) @@ -56,6 +56,7 @@ | Lambda(arguments args, expr body) | IfExp(expr test, expr body, expr orelse) | Dict(expr* keys, expr* values) + | Set(expr* elts) | ListComp(expr elt, comprehension* generators) | GeneratorExp(expr elt, comprehension* generators) -- the grammar constrains where yield expressions can occur Index: Tools/compiler/ast.txt =================================================================== --- Tools/compiler/ast.txt (Revision 51629) +++ Tools/compiler/ast.txt (Arbeitskopie) @@ -50,11 +50,11 @@ GenExprIf: test List: nodes! Dict: items! +Set: items! Not: expr Compare: expr, ops! Name: name* Global: names* -Backquote: expr Getattr: expr, attrname* CallFunc: node, args!, star_args& = None, dstar_args& = None Keyword: name*, expr @@ -97,7 +97,7 @@ self.kwargs = 1 init(GenExpr): - self.argnames = ['[outmost-iterable]'] + self.argnames = ['.0'] self.varargs = self.kwargs = None init(GenExprFor): Index: Tools/compiler/astgen.py =================================================================== --- Tools/compiler/astgen.py (Revision 51629) +++ Tools/compiler/astgen.py (Arbeitskopie) @@ -235,7 +235,7 @@ This file is automatically generated by Tools/compiler/astgen.py """ -from consts import CO_VARARGS, CO_VARKEYWORDS +from compiler.consts import CO_VARARGS, CO_VARKEYWORDS def flatten(seq): l = [] Index: Doc/lib/libdis.tex =================================================================== --- Doc/lib/libdis.tex (Revision 51629) +++ Doc/lib/libdis.tex (Arbeitskopie) @@ -501,6 +501,10 @@ Works as \code{BUILD_TUPLE}, but creates a list. \end{opcodedesc} +\begin{opcodedesc}{BUILD_SET}{count} +Works as \code{BUILD_TUPLE}, but creates a set. +\end{opcodedesc} + \begin{opcodedesc}{BUILD_MAP}{zero} Pushes a new empty dictionary object onto the stack. The argument is ignored and set to zero by the compiler. Index: Lib/compiler/pycodegen.py =================================================================== --- Lib/compiler/pycodegen.py (Revision 51629) +++ Lib/compiler/pycodegen.py (Arbeitskopie) @@ -1241,6 +1241,12 @@ self.visit(elt) self.emit('BUILD_LIST', len(node.nodes)) + def visitSet(self, node): + self.set_lineno(node) + for elt in node.items: + self.visit(elt) + self.emit('BUILD_SET', len(node.items)) + def visitSliceobj(self, node): for child in node.nodes: self.visit(child) Index: Lib/compiler/pyassem.py =================================================================== --- Lib/compiler/pyassem.py (Revision 51629) +++ Lib/compiler/pyassem.py (Arbeitskopie) @@ -793,6 +793,8 @@ return -count+1 def BUILD_LIST(self, count): return -count+1 + def BUILD_SET(self, count): + return -count+1 def CALL_FUNCTION(self, argc): hi, lo = divmod(argc, 256) return -(lo + hi * 2) Index: Lib/compiler/transformer.py =================================================================== --- Lib/compiler/transformer.py (Revision 51629) +++ Lib/compiler/transformer.py (Arbeitskopie) @@ -738,7 +738,7 @@ def atom_lbrace(self, nodelist): if nodelist[1][0] == token.RBRACE: return Dict((), lineno=nodelist[0][2]) - return self.com_dictmaker(nodelist[1]) + return self.com_dictsetmaker(nodelist[1]) def atom_backquote(self, nodelist): return Backquote(self.com_node(nodelist[1])) @@ -1182,13 +1182,20 @@ assert node[0] == symbol.gen_iter return node[1] - def com_dictmaker(self, nodelist): - # dictmaker: test ':' test (',' test ':' value)* [','] + def com_dictsetmaker(self, nodelist): + # dictsetmaker: (test ':' test (',' test ':' value)* [',']) | (test (',' test)* [',']) items = [] - for i in range(1, len(nodelist), 4): - items.append((self.com_node(nodelist[i]), - self.com_node(nodelist[i+2]))) - return Dict(items, lineno=items[0][0].lineno) + if nodelist[2] != ':': + # it's a set + for i in range(1, len(nodelist), 2): + items.append(self.com_node(nodelist[i])) + return Set(items, lineno=items[0].lineno) + else: + # it's a dict + for i in range(1, len(nodelist), 4): + items.append((self.com_node(nodelist[i]), + self.com_node(nodelist[i+2]))) + return Dict(items, lineno=items[0][0].lineno) def com_apply_trailer(self, primaryNode, nodelist): t = nodelist[1][0] Index: Lib/compiler/ast.py =================================================================== --- Lib/compiler/ast.py (Revision 51629) +++ Lib/compiler/ast.py (Arbeitskopie) @@ -542,7 +542,6 @@ self.kwargs = 1 - def getChildren(self): children = [] children.append(self.decorators) @@ -572,6 +571,7 @@ self.argnames = ['.0'] self.varargs = self.kwargs = None + def getChildren(self): return self.code, @@ -589,7 +589,6 @@ self.lineno = lineno self.is_outmost = False - def getChildren(self): children = [] children.append(self.assign) @@ -766,7 +765,6 @@ self.kwargs = 1 - def getChildren(self): children = [] children.append(self.argnames) @@ -1091,6 +1089,22 @@ def __repr__(self): return "RightShift((%s, %s))" % (repr(self.left), repr(self.right)) +class Set(Node): + def __init__(self, items, lineno=None): + self.items = items + self.lineno = lineno + + def getChildren(self): + return tuple(flatten(self.items)) + + def getChildNodes(self): + nodelist = [] + nodelist.extend(flatten_nodes(self.items)) + return tuple(nodelist) + + def __repr__(self): + return "Set(%s)" % (repr(self.items),) + class Slice(Node): def __init__(self, expr, flags, lower, upper, lineno=None): self.expr = expr Index: Lib/opcode.py =================================================================== --- Lib/opcode.py (Revision 51629) +++ Lib/opcode.py (Arbeitskopie) @@ -137,12 +137,13 @@ name_op('LOAD_NAME', 101) # Index in name list def_op('BUILD_TUPLE', 102) # Number of tuple items def_op('BUILD_LIST', 103) # Number of list items -def_op('BUILD_MAP', 104) # Always zero for now -name_op('LOAD_ATTR', 105) # Index in name list -def_op('COMPARE_OP', 106) # Comparison operator -hascompare.append(106) -name_op('IMPORT_NAME', 107) # Index in name list -name_op('IMPORT_FROM', 108) # Index in name list +def_op('BUILD_SET', 104) # Number of set items +def_op('BUILD_MAP', 105) # Always zero for now +name_op('LOAD_ATTR', 106) # Index in name list +def_op('COMPARE_OP', 107) # Comparison operator +hascompare.append(107) +name_op('IMPORT_NAME', 108) # Index in name list +name_op('IMPORT_FROM', 109) # Index in name list jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip jrel_op('JUMP_IF_FALSE', 111) # "" Index: Lib/test/test_set.py =================================================================== --- Lib/test/test_set.py (Revision 51629) +++ Lib/test/test_set.py (Arbeitskopie) @@ -261,6 +261,11 @@ t = self.thetype(s) self.assertNotEqual(id(s), id(t)) + def test_set_literal(self): + s = set([1,2,3]) + t = {1,2,3} + self.assertEqual(s, t) + def test_hash(self): self.assertRaises(TypeError, hash, self.s) @@ -626,7 +631,7 @@ self.set = set(self.values) self.dup = set(self.values) self.length = 0 - self.repr = "set([])" + self.repr = "{}" #------------------------------------------------------------------------------ @@ -637,7 +642,7 @@ self.set = set(self.values) self.dup = set(self.values) self.length = 1 - self.repr = "set([3])" + self.repr = "{3}" def test_in(self): self.failUnless(3 in self.set) @@ -654,7 +659,7 @@ self.set = set(self.values) self.dup = set(self.values) self.length = 1 - self.repr = "set([(0, 'zero')])" + self.repr = "{(0, 'zero')}" def test_in(self): self.failUnless((0, "zero") in self.set) Index: Lib/test/test_grammar.py =================================================================== --- Lib/test/test_grammar.py (Revision 51629) +++ Lib/test/test_grammar.py (Arbeitskopie) @@ -685,8 +685,8 @@ print 'atoms' -### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | NAME | NUMBER | STRING -### dictmaker: test ':' test (',' test ':' test)* [','] +### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictsetmaker] '}' | NAME | NUMBER | STRING +### dictsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [',']) x = (1) x = (1 or 2 or 3) @@ -706,6 +706,11 @@ x = {'one': 1, 'two': 2,} x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6} +x = {'one'} +x = {'one', 1,} +x = {'one', 'two', 'three'} +x = {2, 3, 4,} + x = x x = 'x' x = 123