From f10570b9eb556b015a4a068377cf6cadf380a39d Mon Sep 17 00:00:00 2001
From: Guido van Rossum <guido@python.org>
Date: Fri, 7 Jul 1995 22:53:21 +0000
Subject: 3rd arg for raise; INCOMPLETE keyword parameter passing (currently
 f(kw=value) is seen as f('kw', value))

---
 Python/ceval.c   | 181 ++++++++++++++++++++++++++++++++++++++++++++++---------
 Python/compile.c | 100 +++++++++++++++++++++++-------
 2 files changed, 229 insertions(+), 52 deletions(-)

diff --git a/Python/ceval.c b/Python/ceval.c
index 3fa03c0..a55451c 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -775,43 +775,88 @@ eval_code(co, globals, locals, owner, arg)
 		case BREAK_LOOP:
 			why = WHY_BREAK;
 			break;
-		
+
 		case RAISE_EXCEPTION:
-			v = POP();
-			w = POP();
+			oparg = 2;
+			/* Fallthrough */
+		case RAISE_VARARGS:
+			u = v = w = NULL;
+			switch (oparg) {
+			case 3:
+				u = POP(); /* traceback */
+				if (u == None) {
+					DECREF(u);
+					u = NULL;
+				}
+				else if (strcmp(u->ob_type->tp_name,
+						"traceback") != 0) {
+					/* XXX traceback.h needs to define
+					   is_traceback() */
+					err_setstr(TypeError,
+				    "raise 3rd arg must be traceback or None");
+					goto raise_error;
+				}
+				/* Fallthrough */
+			case 2:
+				v = POP(); /* value */
+				/* Fallthrough */
+			case 1:
+				w = POP(); /* exc */
+				break;
+			default:
+				err_setstr(SystemError,
+					   "bad RAISE_VARARGS oparg");
+				goto raise_error;
+			}
+			if (v == NULL) {
+				v = None;
+				INCREF(v);
+			}
 			/* A tuple is equivalent to its first element here */
 			while (is_tupleobject(w) && gettuplesize(w) > 0) {
-				u = w;
-				w = GETTUPLEITEM(u, 0);
+				object *t = w;
+				w = GETTUPLEITEM(t, 0);
 				INCREF(w);
-				DECREF(u);
+				DECREF(t);
 			}
 			if (is_stringobject(w)) {
-				err_setval(w, v);
+				;
 			} else if (is_classobject(w)) {
 				if (!is_instanceobject(v)
 				    || !issubclass((object*)((instanceobject*)v)->in_class,
-						   w))
+						   w)) {
 					err_setstr(TypeError,
 						   "a class exception must have a value that is an instance of the class");
-				else
-					err_setval(w,v);
+					goto raise_error;
+				}
 			} else if (is_instanceobject(w)) {
-				if (v != None)
+				if (v != None) {
 					err_setstr(TypeError,
 						   "an instance exception may not have a separate value");
+					goto raise_error;
+				}
 				else {
 					DECREF(v);
 					v = w;
 					w = (object*) ((instanceobject*)w)->in_class;
 					INCREF(w);
-					err_setval(w, v);
 				}
-			} else
+			}
+			else {
 				err_setstr(TypeError,
 					"exceptions must be strings, classes, or instances");
-			DECREF(v);
-			DECREF(w);
+				goto raise_error;
+			}
+			err_restore(w, v, u);
+			if (u == NULL)
+				why = WHY_EXCEPTION;
+			else
+				why = WHY_RERAISE;
+			break;
+		raise_error:
+			XDECREF(v);
+			XDECREF(w);
+			XDECREF(u);
 			why = WHY_EXCEPTION;
 			break;
 		
@@ -876,11 +921,8 @@ eval_code(co, globals, locals, owner, arg)
 			}
 			else if (is_stringobject(v) || is_classobject(v)) {
 				w = POP();
-				err_setval(v, w);
-				DECREF(w);
-				w = POP();
-				tb_store(w);
-				DECREF(w);
+				u = POP();
+				err_restore(v, w, u);
 				why = WHY_RERAISE;
 			}
 			else if (v != None) {
@@ -1000,6 +1042,7 @@ eval_code(co, globals, locals, owner, arg)
 					err_setstr(TypeError,
 						   "bad argument list");
 					why = WHY_EXCEPTION;
+					DECREF(v);
 					break;
 				}
 				n = gettuplesize(v);
@@ -1308,8 +1351,7 @@ eval_code(co, globals, locals, owner, arg)
 			}
 			x = call_object(x, w);
 			DECREF(w);
-			if (x)
-				PUSH(x);
+			PUSH(x);
 			break;
 		
 		case IMPORT_FROM:
@@ -1402,6 +1444,85 @@ eval_code(co, globals, locals, owner, arg)
 						 f, "line", None);
 			}
 			break;
+
+		case CALL_FUNCTION:
+		{
+			/* XXX To do:
+			   - fill in default arguments here
+			   - proper handling of keyword parameters
+			   - change eval_code interface to take an
+			     array of arguments instead of a tuple
+			   */
+			int na = oparg & 0xff;
+			int nk = (oparg>>8) & 0xff;
+			int n = na + 2*nk;
+			object **pfunc = stack_pointer - n - 1;
+			object *func = *pfunc;
+			object *self = NULL;
+			object *class = NULL;
+			object *args;
+			f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */
+			INCREF(func);
+			if (is_instancemethodobject(func)) {
+				self = instancemethodgetself(func);
+				if (self != NULL) {
+					class = instancemethodgetclass(func);
+					DECREF(func);
+					func = instancemethodgetfunc(func);
+					INCREF(func);
+					INCREF(self);
+					DECREF(*pfunc);
+					*pfunc = self;
+					na++;
+					n++;
+				}
+			}
+			args = newtupleobject(n);
+			if (args == NULL)
+				x = NULL;
+			else {
+				while (--n >= 0) {
+					w = POP();
+					SETTUPLEITEM(args, n, w);
+				}
+				if (self == NULL)
+					 POP();
+				if (is_funcobject(func)) {
+					int argcount;
+					object *argdefs =
+					    getfuncargstuff(func, &argcount);
+					if (argdefs == NULL) { /* Fast path */
+						object *co, *loc, *glob;
+						co = getfunccode(func);
+						loc = newdictobject();
+						if (loc == NULL) {
+							x = NULL;
+							DECREF(func);
+							break;
+						}
+						glob = getfuncglobals(func);
+						INCREF(glob);
+						x = eval_code(
+							(codeobject *)co,
+							glob,
+							loc,
+							class,
+							args);
+						DECREF(glob);
+						DECREF(loc);
+						DECREF(args);
+						DECREF(func);
+						PUSH(x);
+						break;
+					}
+				}
+				x = call_object(func, args);
+				DECREF(args);
+				PUSH(x);
+			}
+			DECREF(func);
+			break;
+		}
 		
 		default:
 			fprintf(stderr,
@@ -1613,7 +1734,7 @@ call_trace(p_trace, p_newtrace, f, msg, arg)
 	char *msg;
 	object *arg;
 {
-	object *arglist, *what;
+	object *args, *what;
 	object *res = NULL;
 	static int tracing = 0;
 	
@@ -1626,26 +1747,26 @@ call_trace(p_trace, p_newtrace, f, msg, arg)
 		return 0;
 	}
 	
-	arglist = newtupleobject(3);
-	if (arglist == NULL)
+	args = newtupleobject(3);
+	if (args == NULL)
 		goto cleanup;
 	what = newstringobject(msg);
 	if (what == NULL)
 		goto cleanup;
 	INCREF(f);
-	SETTUPLEITEM(arglist, 0, (object *)f);
-	SETTUPLEITEM(arglist, 1, what);
+	SETTUPLEITEM(args, 0, (object *)f);
+	SETTUPLEITEM(args, 1, what);
 	if (arg == NULL)
 		arg = None;
 	INCREF(arg);
-	SETTUPLEITEM(arglist, 2, arg);
+	SETTUPLEITEM(args, 2, arg);
 	tracing++;
 	fast_2_locals(f);
-	res = call_object(*p_trace, arglist); /* May clear *p_trace! */
+	res = call_object(*p_trace, args); /* May clear *p_trace! */
 	locals_2_fast(f, 1);
 	tracing--;
  cleanup:
-	XDECREF(arglist);
+	XDECREF(args);
 	if (res == NULL) {
 		/* The trace proc raised an exception */
 		tb_here(f);
diff --git a/Python/compile.c b/Python/compile.c
index a178bdb..df81f8f 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -782,19 +782,72 @@ com_apply_subscript(c, n)
 	}
 }
 
+static int
+com_argument(c, n, inkeywords)
+	struct compiling *c;
+	node *n; /* argument */
+	int inkeywords;
+{
+	node *m;
+	REQ(n, argument); /* [test '='] test; really [ keyword '='] keyword */
+	if (NCH(n) == 1) {
+		if (inkeywords) {
+			err_setstr(SyntaxError,
+				   "non-keyword arg after keyword arg");
+			c->c_errors++;
+		}
+		else {
+			com_node(c, CHILD(n, 0));
+		}
+		return 0;
+	}
+	m = n;
+	do {
+		m = CHILD(m, 0);
+	} while (NCH(m) == 1);
+	if (TYPE(m) != NAME) {
+		err_setstr(SyntaxError, "keyword can't be an expression");
+		c->c_errors++;
+	}
+	else {
+		object *v = newstringobject(STR(m));
+		if (v == NULL)
+			c->c_errors++;
+		else {
+			com_addoparg(c, LOAD_CONST, com_addconst(c, v));
+			DECREF(v);
+		}
+	}
+	com_node(c, CHILD(n, 2));
+	return 1;
+}
+
 static void
 com_call_function(c, n)
 	struct compiling *c;
-	node *n; /* EITHER testlist OR ')' */
+	node *n; /* EITHER arglist OR ')' */
 {
 	if (TYPE(n) == RPAR) {
-		com_addoparg(c, BUILD_TUPLE, 0);
-		com_addbyte(c, BINARY_CALL);
+		com_addoparg(c, CALL_FUNCTION, 0);
 	}
 	else {
-		REQ(n, testlist);
-		com_list(c, n, 1);
-		com_addbyte(c, BINARY_CALL);
+		int inkeywords, i, na, nk;
+		REQ(n, arglist);
+		inkeywords = 0;
+		na = 0;
+		nk = 0;
+		for (i = 0; i < NCH(n); i += 2) {
+			inkeywords = com_argument(c, CHILD(n, i), inkeywords);
+			if (!inkeywords)
+				na++;
+			else
+				nk++;
+		}
+		if (na > 255 || nk > 255) {
+			err_setstr(SyntaxError, "more than 255 arguments");
+			c->c_errors++;
+		}
+		com_addoparg(c, CALL_FUNCTION, na | (nk << 8));
 	}
 }
 
@@ -1482,13 +1535,18 @@ com_raise_stmt(c, n)
 	struct compiling *c;
 	node *n;
 {
-	REQ(n, raise_stmt); /* 'raise' test [',' test] */
+	REQ(n, raise_stmt); /* 'raise' test [',' test [',' test]] */
 	com_node(c, CHILD(n, 1));
 	if (NCH(n) > 3)
 		com_node(c, CHILD(n, 3));
 	else
 		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
-	com_addbyte(c, RAISE_EXCEPTION);
+	if (NCH(n) > 5) {
+		com_node(c, CHILD(n, 5));
+		com_addoparg(c, RAISE_VARARGS, 3);
+	}
+	else
+		com_addbyte(c, RAISE_EXCEPTION);
 }
 
 static void
@@ -1980,19 +2038,16 @@ com_argdefs(c, n, argcount_return)
 	if (TYPE(n) != varargslist)
 		    return -1;
 	/* varargslist:
-		(fpdef ['=' test] ',')* '*' NAME |
+		(fpdef ['=' test] ',')* '*' NAME ....... |
 		fpdef ['=' test] (',' fpdef ['=' test])* [','] */
 	nch = NCH(n);
-	if (nch >= 2 && TYPE(CHILD(n, nch-2)) == STAR) {
-		star = 1;
-		nch -= 2;
-	}
-	else
-		star = 0;
 	nargs = 0;
 	ndefs = 0;
+	star = 0;
 	for (i = 0; i < nch; i++) {
 		int t;
+		if (TYPE(CHILD(n, i)) == STAR)
+			break;
 		nargs++;
 		i++;
 		if (i >= nch)
@@ -2285,17 +2340,18 @@ com_arglist(c, n)
 	int nch, op, nargs, i, t;
 	REQ(n, varargslist);
 	/* varargslist:
-		(fpdef ['=' test] ',')* '*' NAME |
+		(fpdef ['=' test] ',')* '*' NAME ..... |
 		fpdef ['=' test] (',' fpdef ['=' test])* [','] */
 	nch = NCH(n);
-	if (nch >= 2 && TYPE(CHILD(n, nch-2)) == STAR) {
-		op = UNPACK_VARARG;
-		nch -= 2;
-	}
-	else
-		op = UNPACK_ARG;
+	op = UNPACK_ARG;
 	nargs = 0;
 	for (i = 0; i < nch; i++) {
+		if (TYPE(CHILD(n, i)) == STAR) {
+			nch = i;
+			if (TYPE(CHILD(n, i+1)) != STAR)
+				op = UNPACK_VARARG;
+			break;
+		}
 		nargs++;
 		i++;
 		if (i >= nch)
-- 
cgit v0.12

