summaryrefslogtreecommitdiffstats
path: root/Python/bltinmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/bltinmodule.c')
-rw-r--r--Python/bltinmodule.c581
1 files changed, 579 insertions, 2 deletions
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 60208a0..b95c351 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -37,6 +37,11 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "compile.h"
#include "eval.h"
+/* Forward */
+static object *filterstring PROTO((object *, object *));
+static object *filtertuple PROTO((object *, object *));
+static object *exec_eval PROTO((object *v, int start));
+
static object *
builtin_abs(self, v)
object *self;
@@ -62,6 +67,132 @@ builtin_apply(self, args)
}
static object *
+builtin_bagof(self, args)
+ object *self;
+ object *args;
+{
+ object *func, *seq, *arg, *result;
+ sequence_methods *sqf;
+ int len, newfunc = 0;
+ register int i,j;
+ static char bagof_err[] = "bagof() requires 1 or 2 args";
+
+ if (args == NULL) {
+ err_setstr(TypeError, bagof_err);
+ return NULL;
+ }
+
+ if (is_tupleobject(args)) {
+ if (gettuplesize(args) != 2) {
+ err_setstr(TypeError, bagof_err);
+ return NULL;
+ }
+
+ func = gettupleitem(args, 0);
+ seq = gettupleitem(args, 1);
+
+ if (is_stringobject(func)) {
+ if ((func = exec_eval(func, lambda_input)) == NULL)
+ return NULL;
+ newfunc = 1;
+ }
+ }
+ else {
+ func = None;
+ seq = args;
+ }
+
+ /* check for special cases; strings and tuples are returned as same */
+ if (is_stringobject(seq)) {
+ object *r = filterstring(func, seq);
+ if (newfunc)
+ DECREF(func);
+ return r;
+ }
+
+ else if (is_tupleobject(seq)) {
+ object *r = filtertuple(func, seq);
+ if (newfunc)
+ DECREF(func);
+ return r;
+ }
+
+ if (! (sqf = seq->ob_type->tp_as_sequence)) {
+ err_setstr(TypeError,
+ "argument to bagof() must be a sequence type");
+ goto Fail_2;
+ }
+
+ if ((len = (*sqf->sq_length)(seq)) < 0)
+ goto Fail_2;
+
+ if (is_listobject(seq) && seq->ob_refcnt == 1) {
+ INCREF(seq);
+ result = seq;
+ }
+ else
+ if ((result = newlistobject(len)) == NULL)
+ goto Fail_2;
+
+ if ((arg = newtupleobject(1)) == NULL)
+ goto Fail_1;
+
+ for (i = j = 0; i < len; ++i) {
+ object *ele, *value;
+
+ if (arg->ob_refcnt > 1) {
+ DECREF(arg);
+ if ((arg = newtupleobject(1)) == NULL)
+ goto Fail_1;
+ }
+
+ if ((ele = (*sqf->sq_item)(seq, i)) == NULL)
+ goto Fail_0;
+
+ if (func == None)
+ value = ele;
+ else {
+ if (settupleitem(arg, 0, ele) < 0)
+ goto Fail_0;
+
+ if ((value = call_object(func, arg)) == NULL)
+ goto Fail_0;
+ }
+
+ if (testbool(value)) {
+ INCREF(ele);
+ if (setlistitem(result, j++, ele) < 0)
+ goto Fail_0;
+ }
+
+ DECREF(value);
+ }
+
+ /* list_ass_slice() expects the rest of the list to be non-null */
+ for (i = j; i < len; ++i) {
+ INCREF(None);
+ if (setlistitem(result, i, None) < 0)
+ goto Fail_0;
+ }
+
+ DECREF(arg);
+ if (newfunc)
+ DECREF(func);
+
+ (*result->ob_type->tp_as_sequence->sq_ass_slice)(result, j, len, NULL);
+ return result;
+
+Fail_0:
+ DECREF(arg);
+Fail_1:
+ DECREF(result);
+Fail_2:
+ if (newfunc)
+ DECREF(func);
+ return NULL;
+}
+
+static object *
builtin_chr(self, args)
object *self;
object *args;
@@ -191,6 +322,7 @@ exec_eval(v, start)
object *str = NULL, *globals = NULL, *locals = NULL;
char *s;
int n;
+ /* XXX This is a bit of a mess. Should make it varargs */
if (v != NULL) {
if (is_tupleobject(v) &&
((n = gettuplesize(v)) == 2 || n == 3)) {
@@ -206,9 +338,10 @@ exec_eval(v, start)
globals != NULL && !is_dictobject(globals) ||
locals != NULL && !is_dictobject(locals)) {
err_setstr(TypeError,
- "exec/eval arguments must be (string|code)[,dict[,dict]]");
+ "eval/lambda arguments must be (string|code)[,dict[,dict]]");
return NULL;
}
+ /* XXX The following is only correct for eval(), not for lambda() */
if (is_codeobject(str))
return eval_code((codeobject *) str, globals, locals,
(object *)NULL, (object *)NULL);
@@ -217,7 +350,7 @@ exec_eval(v, start)
err_setstr(ValueError, "embedded '\\0' in string arg");
return NULL;
}
- if (start == eval_input) {
+ if (start == eval_input || start == lambda_input) {
while (*s == ' ' || *s == '\t')
s++;
}
@@ -336,6 +469,136 @@ builtin_id(self, args)
}
static object *
+builtin_map(self, args)
+ object *self;
+ object *args;
+{
+ typedef struct {
+ object *seq;
+ sequence_methods *sqf;
+ int len;
+ } sequence;
+
+ object *func, *result;
+ sequence *seqs = NULL, *sqp;
+ int n, len, newfunc = 0;
+ register int i, j;
+
+ if (args == NULL || !is_tupleobject(args)) {
+ err_setstr(TypeError, "map() requires at least two args");
+ return NULL;
+ }
+
+ func = gettupleitem(args, 0);
+ n = gettuplesize(args) - 1;
+
+ if (is_stringobject(func)) {
+ if ((func = exec_eval(func, lambda_input)) == NULL)
+ return NULL;
+ newfunc = 1;
+ }
+
+ if ((seqs = (sequence *) malloc(n * sizeof(sequence))) == NULL)
+ return err_nomem();
+
+ for (len = -1, i = 0, sqp = seqs; i < n; ++i, ++sqp) {
+ int curlen;
+
+ if ((sqp->seq = gettupleitem(args, i + 1)) == NULL)
+ goto Fail_2;
+
+ if (! (sqp->sqf = sqp->seq->ob_type->tp_as_sequence)) {
+ static char errmsg[] =
+ "argument %d to map() must be a sequence object";
+ char errbuf[sizeof(errmsg) + 3];
+
+ sprintf(errbuf, errmsg, i+2);
+ err_setstr(TypeError, errbuf);
+ goto Fail_2;
+ }
+
+ if ((curlen = sqp->len = (*sqp->sqf->sq_length)(sqp->seq)) < 0)
+ goto Fail_2;
+
+ if (curlen > len)
+ len = curlen;
+ }
+
+ if ((result = (object *) newlistobject(len)) == NULL)
+ goto Fail_2;
+
+ if ((args = newtupleobject(n)) == NULL)
+ goto Fail_1;
+
+ for (i = 0; i < len; ++i) {
+ object *arg, *value;
+
+ if (args->ob_refcnt > 1) {
+ DECREF(args);
+ if ((args = newtupleobject(n)) == NULL)
+ goto Fail_1;
+ }
+
+ for (j = 0, sqp = seqs; j < n; ++j, ++sqp) {
+ if (i >= sqp->len) {
+ INCREF(None);
+ if (settupleitem(args, j, None) < 0)
+ goto Fail_0;
+ arg = None;
+ }
+
+ else {
+ if ((arg = (*sqp->sqf->sq_item)(sqp->seq, i)) == NULL)
+ goto Fail_0;
+
+ if (settupleitem(args, j, arg) < 0)
+ goto Fail_0;
+ }
+ }
+
+ if (func == None) {
+ if (n == 1) { /* avoid creating singleton */
+ INCREF(arg);
+ if (setlistitem(result, i, arg) < 0)
+ goto Fail_0;
+ }
+ else {
+ INCREF(args);
+ if (setlistitem(result, i, args) < 0)
+ goto Fail_0;
+ }
+ }
+ else {
+ if ((value = call_object(func, args)) == NULL)
+ goto Fail_0;
+
+ if (setlistitem((object *) result, i, value) < 0)
+ goto Fail_0;
+ }
+ }
+
+ if (seqs) free(seqs);
+
+ DECREF(args);
+ if (newfunc)
+ DECREF(func);
+
+ return result;
+
+Fail_0:
+ DECREF(args);
+Fail_1:
+ DECREF(result);
+Fail_2:
+ if (newfunc)
+ DECREF(func);
+
+ if (seqs) free(seqs);
+
+ return NULL;
+}
+
+static object *
builtin_setattr(self, args)
object *self;
object *args;
@@ -414,6 +677,14 @@ builtin_int(self, v)
}
static object *
+builtin_lambda(self, v)
+ object *self;
+ object *v;
+{
+ return exec_eval(v, lambda_input);
+}
+
+static object *
builtin_len(self, v)
object *self;
object *v;
@@ -641,6 +912,58 @@ builtin_range(self, v)
}
static object *
+builtin_xrange(self, v)
+ object *self;
+ object *v;
+{
+ static char *errmsg = "xrange() requires 1-3 int arguments";
+ int i, n;
+ long start, stop, step, len;
+ if (v != NULL && is_intobject(v))
+ start = 0, stop = getintvalue(v), step = 1;
+
+ else if (v == NULL || !is_tupleobject(v)) {
+ err_setstr(TypeError, errmsg);
+ return NULL;
+ }
+ else {
+ n = gettuplesize(v);
+ if (n < 1 || n > 3) {
+ err_setstr(TypeError, errmsg);
+ return NULL;
+ }
+ for (i = 0; i < n; i++) {
+ if (!is_intobject(gettupleitem(v, i))) {
+ err_setstr(TypeError, errmsg);
+ return NULL;
+ }
+ }
+ if (n == 3) {
+ step = getintvalue(gettupleitem(v, 2));
+ --n;
+ }
+ else
+ step = 1;
+ stop = getintvalue(gettupleitem(v, --n));
+ if (n > 0)
+ start = getintvalue(gettupleitem(v, 0));
+ else
+ start = 0;
+ }
+
+ if (step == 0) {
+ err_setstr(ValueError, "zero step for xrange()");
+ return NULL;
+ }
+
+ len = (stop - start + step + ((step > 0) ? -1 : 1)) / step;
+ if (len < 0)
+ len = 0;
+
+ return newrangeobject(start, len, step, 1);
+}
+
+static object *
builtin_raw_input(self, v)
object *self;
object *v;
@@ -659,6 +982,103 @@ builtin_raw_input(self, v)
}
static object *
+builtin_reduce(self, args)
+ object *self;
+ object *args;
+{
+ object *seq, *func, *result;
+ sequence_methods *sqf;
+ static char reduce_err[] = "reduce() requires 2 or 3 args";
+ register int i;
+ int start = 0, newfunc = 0;
+ int len;
+
+ if (args == NULL || !is_tupleobject(args)) {
+ err_setstr(TypeError, reduce_err);
+ return NULL;
+ }
+
+ switch (gettuplesize(args)) {
+ case 2:
+ start = 1; /* fall through */
+ case 3:
+ func = gettupleitem(args, 0);
+ seq = gettupleitem(args, 1);
+ break;
+ default:
+ err_setstr(TypeError, reduce_err);
+ }
+
+ if ((sqf = seq->ob_type->tp_as_sequence) == NULL) {
+ err_setstr(TypeError,
+ "2nd argument to reduce() must be a sequence object");
+ return NULL;
+ }
+
+ if (is_stringobject(func)) {
+ if ((func = exec_eval(func, lambda_input)) == NULL)
+ return NULL;
+ newfunc = 1;
+ }
+
+ if ((len = (*sqf->sq_length)(seq)) < 0)
+ goto Fail_2;
+
+ if (start == 1) {
+ if (len == 0) {
+ err_setstr(TypeError,
+ "reduce of empty sequence with no initial value");
+ goto Fail_2;
+ }
+
+ if ((result = (*sqf->sq_item)(seq, 0)) == NULL)
+ goto Fail_2;
+ }
+ else {
+ result = gettupleitem(args, 2);
+ INCREF(result);
+ }
+
+ if ((args = newtupleobject(2)) == NULL)
+ goto Fail_1;
+
+ for (i = start; i < len; ++i) {
+ object *op2;
+
+ if (args->ob_refcnt > 1) {
+ DECREF(args);
+ if ((args = newtupleobject(2)) == NULL)
+ goto Fail_1;
+ }
+
+ if ((op2 = (*sqf->sq_item)(seq, i)) == NULL)
+ goto Fail_2;
+
+ settupleitem(args, 0, result);
+ settupleitem(args, 1, op2);
+ if ((result = call_object(func, args)) == NULL)
+ goto Fail_0;
+ }
+
+ DECREF(args);
+ if (newfunc)
+ DECREF(func);
+
+ return result;
+
+ /* XXX I hate goto's. I hate goto's. I hate goto's. I hate goto's. */
+Fail_0:
+ DECREF(args);
+ goto Fail_2;
+Fail_1:
+ DECREF(result);
+Fail_2:
+ if (newfunc)
+ DECREF(func);
+ return NULL;
+}
+
+static object *
builtin_reload(self, v)
object *self;
object *v;
@@ -740,6 +1160,7 @@ builtin_type(self, v)
static struct methodlist builtin_methods[] = {
{"abs", builtin_abs},
{"apply", builtin_apply},
+ {"bagof", builtin_bagof},
{"chr", builtin_chr},
{"cmp", builtin_cmp},
{"coerce", builtin_coerce},
@@ -756,8 +1177,10 @@ static struct methodlist builtin_methods[] = {
{"id", builtin_id},
{"input", builtin_input},
{"int", builtin_int},
+ {"lambda", builtin_lambda},
{"len", builtin_len},
{"long", builtin_long},
+ {"map", builtin_map},
{"max", builtin_max},
{"min", builtin_min},
{"oct", builtin_oct},
@@ -766,12 +1189,14 @@ static struct methodlist builtin_methods[] = {
{"pow", builtin_pow},
{"range", builtin_range},
{"raw_input", builtin_raw_input},
+ {"reduce", builtin_reduce},
{"reload", builtin_reload},
{"repr", builtin_repr},
{"round", builtin_round},
{"setattr", builtin_setattr},
{"str", builtin_str},
{"type", builtin_type},
+ {"xrange", builtin_xrange},
{NULL, NULL},
};
@@ -883,3 +1308,155 @@ coerce(pv, pw)
err_setstr(TypeError, "number coercion failed");
return -1;
}
+
+
+/* Filter a tuple through a function */
+
+static object *
+filtertuple(func, tuple)
+ object *func;
+ object *tuple;
+{
+ object *arg, *result;
+ register int i, j;
+ int len = gettuplesize(tuple), shared = 0;
+
+ if (tuple->ob_refcnt == 1) {
+ result = tuple;
+ shared = 1;
+ /* defer INCREF (resizetuple wants it to be one) */
+ }
+ else
+ if ((result = newtupleobject(len)) == NULL)
+ return NULL;
+
+ if ((arg = newtupleobject(1)) == NULL)
+ goto Fail_1;
+
+ for (i = j = 0; i < len; ++i) {
+ object *ele, *value;
+
+ if (arg->ob_refcnt > 1) {
+ DECREF(arg);
+ if ((arg = newtupleobject(1)) == NULL)
+ goto Fail_1;
+ }
+
+ if ((ele = gettupleitem(tuple, i)) == NULL)
+ goto Fail_0;
+ INCREF(ele);
+
+ if (func == None)
+ value = ele;
+ else {
+ if (settupleitem(arg, 0, ele) < 0)
+ goto Fail_0;
+
+ if ((value = call_object(func, arg)) == NULL)
+ goto Fail_0;
+ }
+
+ if (testbool(value)) {
+ INCREF(ele);
+ if (settupleitem(result, j++, ele) < 0)
+ goto Fail_0;
+ }
+
+ DECREF(value);
+ }
+
+ DECREF(arg);
+ if (resizetuple(&result, j) < 0)
+ return NULL;
+
+ if (shared)
+ INCREF(result);
+
+ return result;
+
+Fail_0:
+ DECREF(arg);
+Fail_1:
+ if (!shared)
+ DECREF(result);
+ return NULL;
+}
+
+
+/* Filter a string through a function */
+
+static object *
+filterstring(func, strobj)
+ object *func;
+ object *strobj;
+{
+ object *arg, *result;
+ register int i, j;
+ int len = getstringsize(strobj), shared = 0;
+
+ if (strobj->ob_refcnt == 1) {
+ result = strobj;
+ shared = 1;
+ /* defer INCREF (resizestring wants it to be one) */
+
+ if (func == None) {
+ INCREF(result);
+ return result;
+ }
+ }
+ else {
+ if ((result = newsizedstringobject(NULL, len)) == NULL)
+ return NULL;
+
+ if (func == None) {
+ strcpy(GETSTRINGVALUE((stringobject *)result),
+ GETSTRINGVALUE((stringobject *)strobj));
+ return result;
+ }
+ }
+
+ if ((arg = newtupleobject(1)) == NULL)
+ goto Fail_1;
+
+ for (i = j = 0; i < len; ++i) {
+ object *ele, *value;
+
+ if (arg->ob_refcnt > 1) {
+ DECREF(arg);
+ if ((arg = newtupleobject(1)) == NULL)
+ goto Fail_1;
+ }
+
+ if ((ele = (*strobj->ob_type->tp_as_sequence->sq_item)
+ (strobj, i)) == NULL)
+ goto Fail_0;
+
+ if (settupleitem(arg, 0, ele) < 0)
+ goto Fail_0;
+
+ if ((value = call_object(func, arg)) == NULL)
+ goto Fail_0;
+
+ if (testbool(value))
+ GETSTRINGVALUE((stringobject *)result)[j++] =
+ GETSTRINGVALUE((stringobject *)ele)[0];
+
+ DECREF(value);
+ }
+
+ DECREF(arg);
+ if (resizestring(&result, j) < 0)
+ return NULL;
+
+ if (shared)
+ INCREF(result);
+
+ return result;
+
+Fail_0:
+ DECREF(arg);
+Fail_1:
+ if (!shared)
+ DECREF(result);
+ return NULL;
+}