diff Python/compile.c @ 32888:c7e03cf8333e legacy-trunk

PEP-0318, @decorator-style. In Guido's words: "@ seems the syntax that everybody can hate equally" Implementation by Mark Russell, from SF #979728.
author Anthony Baxter <anthonybaxter@gmail.com>
date Mon, 02 Aug 2004 06:10:11 +0000
parents efca55bbba0a
children 685a948b3bc9
line wrap: on
line diff
--- a/Python/compile.c	Mon Aug 02 04:30:37 2004 +0000
+++ b/Python/compile.c	Mon Aug 02 06:10:11 2004 +0000
@@ -1876,6 +1876,7 @@
 	else com_list(c, n, 0);
 }
 
+
 static void
 com_dictmaker(struct compiling *c, node *n)
 {
@@ -3963,8 +3964,9 @@
 		n = CHILD(n, 1);
 	}
 	else {
-		REQ(n, funcdef); /* funcdef: 'def' NAME parameters ... */
-		n = CHILD(n, 2);
+		REQ(n, funcdef);
+		/* funcdef: [decorators] 'def' NAME parameters ':' suite */
+		n = RCHILD(n, -3);
 		REQ(n, parameters); /* parameters: '(' [varargslist] ')' */
 		n = CHILD(n, 1);
 	}
@@ -4009,15 +4011,89 @@
 }
 
 static void
+com_decorator_name(struct compiling *c, node *n)
+{
+	/* dotted_name: NAME ('.' NAME)* */
+	
+	int i, nch;
+	node *varname;
+
+	REQ(n, dotted_name);
+	nch = NCH(n);
+	assert(nch >= 1 && nch % 2 == 1);
+
+	varname = CHILD(n, 0);
+	REQ(varname, NAME);
+	com_addop_varname(c, VAR_LOAD, STR(varname));
+		
+	for (i = 1; i < nch; i += 2) {
+		node *attrname;
+		
+		REQ(CHILD(n, i), DOT);
+
+		attrname = CHILD(n, i + 1);
+		REQ(attrname, NAME);
+		com_addop_name(c, LOAD_ATTR, STR(attrname));
+	}
+}
+
+static void
+com_decorator(struct compiling *c, node *n)
+{
+	/* decorator: '@' dotted_name [ '(' [arglist] ')' ] */
+	int nch = NCH(n);
+	assert(nch >= 2);
+	REQ(CHILD(n, 0), AT);
+	com_decorator_name(c, CHILD(n, 1));
+
+	if (nch > 2) {
+		assert(nch == 4 || nch == 5);
+		REQ(CHILD(n, 2), LPAR);
+		REQ(CHILD(n, nch - 1), RPAR);
+		com_call_function(c, CHILD(n, 3));
+	}
+}
+
+static int
+com_decorators(struct compiling *c, node *n)
+{
+	int i, nch, ndecorators;
+	
+	/* decorator ([NEWLINE] decorator)* NEWLINE */
+	nch = NCH(n);
+	assert(nch >= 2);
+	REQ(CHILD(n, nch - 1), NEWLINE);
+
+	ndecorators = 0;
+	for (i = NCH(n) - 1; i >= 0; --i) {
+		node *ch = CHILD(n, i);
+		if (TYPE(ch) != NEWLINE) {
+			com_decorator(c, ch);
+			++ndecorators;
+		}
+	}
+
+	return ndecorators;
+}
+
+static void
 com_funcdef(struct compiling *c, node *n)
 {
 	PyObject *co;
-	int ndefs;
-	REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
+	int ndefs, ndecorators;
+	REQ(n, funcdef);
+	/*          -6            -5   -4   -3         -2  -1
+	   funcdef: [decorators] 'def' NAME parameters ':' suite */
+
+	if (NCH(n) == 6)
+		ndecorators = com_decorators(c, CHILD(n, 0));
+	else
+		ndecorators = 0;
+	
 	ndefs = com_argdefs(c, n);
 	if (ndefs < 0)
 		return;
-	symtable_enter_scope(c->c_symtable, STR(CHILD(n, 1)), TYPE(n),
+	symtable_enter_scope(c->c_symtable, STR(RCHILD(n, -4)), TYPE(n),
 			     n->n_lineno);
 	co = (PyObject *)icompile(n, c);
 	symtable_exit_scope(c->c_symtable);
@@ -4033,7 +4109,12 @@
 		else
 			com_addoparg(c, MAKE_FUNCTION, ndefs);
 		com_pop(c, ndefs);
-		com_addop_varname(c, VAR_STORE, STR(CHILD(n, 1)));
+		while (ndecorators > 0) {
+			com_addoparg(c, CALL_FUNCTION, 1);
+			com_pop(c, 1);
+			ndecorators--;
+		}
+		com_addop_varname(c, VAR_STORE, STR(RCHILD(n, -4)));
 		com_pop(c, 1);
 		Py_DECREF(co);
 	}
@@ -4112,7 +4193,7 @@
 	switch (TYPE(n)) {
 	
 	/* Definition nodes */
-	
+
 	case funcdef:
 		com_funcdef(c, n);
 		break;
@@ -4377,21 +4458,23 @@
 {
 	PyObject *doc;
 	node *ch;
-	REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
-	c->c_name = STR(CHILD(n, 1));
-	doc = get_docstring(c, CHILD(n, 4));
+	REQ(n, funcdef);
+	/*          -6            -5   -4   -3         -2  -1
+	   funcdef: [decorators] 'def' NAME parameters ':' suite */
+	c->c_name = STR(RCHILD(n, -4));
+	doc = get_docstring(c, RCHILD(n, -1));
 	if (doc != NULL) {
 		(void) com_addconst(c, doc);
 		Py_DECREF(doc);
 	}
 	else
 		(void) com_addconst(c, Py_None); /* No docstring */
-	ch = CHILD(n, 2); /* parameters: '(' [varargslist] ')' */
+	ch = RCHILD(n, -3); /* parameters: '(' [varargslist] ')' */
 	ch = CHILD(ch, 1); /* ')' | varargslist */
 	if (TYPE(ch) == varargslist)
 		com_arglist(c, ch);
 	c->c_infunction = 1;
-	com_node(c, CHILD(n, 4));
+	com_node(c, RCHILD(n, -1));
 	c->c_infunction = 0;
 	com_strip_lnotab(c);
 	com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
@@ -5587,9 +5670,12 @@
  loop:
 	switch (TYPE(n)) {
 	case funcdef: {
-		char *func_name = STR(CHILD(n, 1));
+		char *func_name;
+		if (NCH(n) == 6)
+			symtable_node(st, CHILD(n, 0));
+		func_name = STR(RCHILD(n, -4));
 		symtable_add_def(st, func_name, DEF_LOCAL);
-		symtable_default_args(st, CHILD(n, 2));
+		symtable_default_args(st, RCHILD(n, -3));
 		symtable_enter_scope(st, func_name, TYPE(n), n->n_lineno);
 		symtable_funcdef(st, n);
 		symtable_exit_scope(st);
@@ -5734,6 +5820,17 @@
 	   to be coded with great care, even though they look like
 	   rather innocuous.  Each case must double-check TYPE(n).
 	*/
+	case decorator:
+		if (TYPE(n) == decorator) {
+			/* decorator: '@' dotted_name [ '(' [arglist] ')' ] */
+			node *name, *varname;
+			name = CHILD(n, 1);
+			REQ(name, dotted_name);
+			varname = CHILD(name, 0);
+			REQ(varname, NAME);
+			symtable_add_use(st, STR(varname));
+		}
+		/* fall through */
 	case argument:
 		if (TYPE(n) == argument && NCH(n) == 3) {
 			n = CHILD(n, 2);
@@ -5787,7 +5884,7 @@
 		if (NCH(n) == 4)
 			symtable_params(st, CHILD(n, 1));
 	} else
-		symtable_params(st, CHILD(n, 2));
+		symtable_params(st, RCHILD(n, -3));
 	body = CHILD(n, NCH(n) - 1);
 	symtable_node(st, body);
 }