* compile.[ch]: support for lambda()

* PROTO.h, mymalloc.h: added #ifdefs for TURBOC and GNUC.
* allobjects.h: added #include "rangeobject.h"
* Grammar: added lambda_input; relaxed syntax for exec.
* bltinmodule.c: added bagof, map, reduce, lambda, xrange.
* tupleobject.[ch]: added resizetuple().
* rangeobject.[ch]: new object type to speed up range operations (not
  convinced this is needed!!!)
This commit is contained in:
Guido van Rossum 1993-10-26 17:58:25 +00:00
parent 444fc7c90c
commit 12d12c5faf
12 changed files with 1683 additions and 750 deletions

View File

@ -2,6 +2,9 @@
# Change log: # Change log:
# 25-Oct-93:
# Added lambda_input
# 18-Oct-93: # 18-Oct-93:
# Use testlist instead of exprlist in expr_stmt # Use testlist instead of exprlist in expr_stmt
# Add exec statement # Add exec statement
@ -75,13 +78,14 @@
# single_input is a single interactive statement; # single_input is a single interactive statement;
# file_input is a module or sequence of commands read from an input file; # file_input is a module or sequence of commands read from an input file;
# expr_input is the input for the input() function; # expr_input is the input for the input() function;
# eval_input is the input for the eval() function. # eval_input is the input for the eval() function;
# lambda_input is the input for the proposed lambda() function.
# NB: compound_stmt in single_input is followed by extra NEWLINE! # NB: compound_stmt in single_input is followed by extra NEWLINE!
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
file_input: (NEWLINE | stmt)* ENDMARKER file_input: (NEWLINE | stmt)* ENDMARKER
expr_input: testlist NEWLINE
eval_input: testlist NEWLINE* ENDMARKER eval_input: testlist NEWLINE* ENDMARKER
lambda_input: varargslist ':' testlist NEWLINE* ENDMARKER
funcdef: 'def' NAME parameters ':' suite funcdef: 'def' NAME parameters ':' suite
parameters: '(' [varargslist] ')' parameters: '(' [varargslist] ')'
@ -108,7 +112,7 @@ access_stmt: 'access' ('*' | NAME (',' NAME)*) ':' accesstype (',' accesstype)*
accesstype: NAME+ accesstype: NAME+
# accesstype should be ('public' | 'protected' | 'private') ['read'] ['write'] # accesstype should be ('public' | 'protected' | 'private') ['read'] ['write']
# but can't be because that would create undesirable reserved words! # but can't be because that would create undesirable reserved words!
exec_stmt: 'exec' expr ['in' expr [',' expr]] exec_stmt: 'exec' expr ['in' test [',' test]]
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]

View File

@ -46,6 +46,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "intobject.h" #include "intobject.h"
#include "longobject.h" #include "longobject.h"
#include "floatobject.h" #include "floatobject.h"
#include "rangeobject.h"
#include "stringobject.h" #include "stringobject.h"
#include "tupleobject.h" #include "tupleobject.h"
#include "listobject.h" #include "listobject.h"

View File

@ -54,10 +54,12 @@ extern typeobject Codetype;
/* Public interface */ /* Public interface */
struct _node; /* Declare the existence of this type */ struct _node; /* Declare the existence of this type */
codeobject *compile PROTO((struct _node *, char *)); codeobject *_compile PROTO((struct _node *, char *, int));
codeobject *newcodeobject codeobject *newcodeobject
PROTO((object *, object *, object *, object *, object *)); PROTO((object *, object *, object *, object *, object *));
#define compile(n,f) (_compile((n),(f),0))
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,7 +1,7 @@
#define single_input 256 #define single_input 256
#define file_input 257 #define file_input 257
#define expr_input 258 #define eval_input 258
#define eval_input 259 #define lambda_input 259
#define funcdef 260 #define funcdef 260
#define parameters 261 #define parameters 261
#define varargslist 262 #define varargslist 262

View File

@ -51,6 +51,16 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define HAVE_STDLIB #define HAVE_STDLIB
#endif #endif
#ifdef __TURBOC__
#define ANY void
#define HAVE_STDLIB
#endif
#ifdef __GNUC__
#define ANY void
#define HAVE_STDLIB
#endif
#ifndef ANY #ifndef ANY
#define ANY char #define ANY char
#endif #endif

41
Include/rangeobject.h Normal file
View File

@ -0,0 +1,41 @@
/***********************************************************
Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
Amsterdam, The Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
/* Range object interface */
/*
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
rangeobject represents an integer range. This is an immutable object;
a range cannot change its value after creation.
Range objects behave like the corresponding tuple objects except that
they are represented by a start, stop, and step datamembers.
*/
extern typeobject Rangetype;
#define is_rangeobject(op) ((op)->ob_type == &Rangetype)
extern object *newrangeobject PROTO((long, long, long, int));

View File

@ -58,6 +58,7 @@ extern int gettuplesize PROTO((object *));
extern object *gettupleitem PROTO((object *, int)); extern object *gettupleitem PROTO((object *, int));
extern int settupleitem PROTO((object *, int, object *)); extern int settupleitem PROTO((object *, int, object *));
extern object *gettupleslice PROTO((object *, int, int)); extern object *gettupleslice PROTO((object *, int, int));
extern int resizetuple PROTO((object **, int));
/* Macro, trading safety for speed */ /* Macro, trading safety for speed */
#define GETTUPLEITEM(op, i) ((op)->ob_item[i]) #define GETTUPLEITEM(op, i) ((op)->ob_item[i])

205
Objects/rangeobject.c Normal file
View File

@ -0,0 +1,205 @@
/***********************************************************
Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
Amsterdam, The Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
/* Range object implementation */
#include "allobjects.h"
typedef struct {
OB_HEAD
long start;
long step;
long len;
int reps;
} rangeobject;
object *
newrangeobject(start, len, step, reps)
long start, len, step;
int reps;
{
rangeobject *obj = (rangeobject *) newobject(&Rangetype);
obj->start = start;
obj->len = len;
obj->step = step;
obj->reps = reps;
return (object *) obj;
}
static void
range_dealloc(r)
rangeobject *r;
{
DEL(r);
}
static object *
range_item(r, i)
rangeobject *r;
int i;
{
if (i < 0 || i >= r->len * r->reps) {
err_setstr(IndexError, "range object index out of range");
return NULL;
}
return newintobject(r->start + (i % r->len) * r->step);
}
static int
range_length(r)
rangeobject *r;
{
return r->len * r->reps;
}
static object *
range_repr(r)
rangeobject *r;
{
char buf[80];
if (r->reps != 1)
sprintf(buf, "(xrange(%ld, %ld, %ld) * %d)",
r->start,
r->start + r->len * r->step,
r->step,
r->reps);
else
sprintf(buf, "xrange(%ld, %ld, %ld)",
r->start,
r->start + r->len * r->step,
r->step);
return newstringobject(buf);
}
object *
range_concat(r, obj)
rangeobject *r;
object *obj;
{
if (is_rangeobject(obj)) {
rangeobject *s = (rangeobject *)obj;
if (r->start == s->start && r->len == s->len &&
r->step == s->step)
return newrangeobject(r->start, r->len, r->step,
r->reps + s->reps);
}
err_setstr(TypeError, "cannot concatenate different range objects");
return NULL;
}
object *
range_repeat(r, n)
rangeobject *r;
int n;
{
if (n < 0)
return (object *) newrangeobject(0, 0, 1, 1);
else if (n == 1) {
INCREF(r);
return (object *) r;
}
else
return (object *) newrangeobject(
r->start,
r->len,
r->step,
r->reps * n);
}
static int
range_compare(r1, r2)
rangeobject *r1, *r2;
{
if (r1->start != r2->start)
return r1->start - r2->start;
else if (r1->step != r2->step)
return r1->step - r2->step;
else if (r1->len != r2->len)
return r1->len - r2->len;
else
return r1->reps - r2->reps;
}
static object *
range_slice(r, low, high)
rangeobject *r;
int low, high;
{
if (r->reps != 1) {
err_setstr(TypeError, "cannot slice a replicated range");
return NULL;
}
if (low < 0)
low = 0;
else if (low > r->len)
low = r->len;
if (high < 0)
high = 0;
if (high < low)
high = low;
else if (high > r->len)
high = r->len;
return (object *) newrangeobject(
low * r->step + r->start,
high - low,
r->step,
1);
}
static sequence_methods range_as_sequence = {
range_length, /*sq_length*/
range_concat, /*sq_concat*/
range_repeat, /*sq_repeat*/
range_item, /*sq_item*/
range_slice, /*sq_slice*/
0, /*sq_ass_item*/
0, /*sq_ass_slice*/
};
typeobject Rangetype = {
OB_HEAD_INIT(&Typetype)
0, /* Number of items for varobject */
"range", /* Name of this type */
sizeof(rangeobject), /* Basic object size */
0, /* Item size for varobject */
range_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
range_compare, /*tp_compare*/
range_repr, /*tp_repr*/
0, /*tp_as_number*/
&range_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
};

View File

@ -123,21 +123,18 @@ settupleitem(op, i, newitem)
{ {
register object *olditem; register object *olditem;
if (!is_tupleobject(op)) { if (!is_tupleobject(op)) {
if (newitem != NULL) XDECREF(newitem);
DECREF(newitem);
err_badcall(); err_badcall();
return -1; return -1;
} }
if (i < 0 || i >= ((tupleobject *)op) -> ob_size) { if (i < 0 || i >= ((tupleobject *)op) -> ob_size) {
if (newitem != NULL) XDECREF(newitem);
DECREF(newitem);
err_setstr(IndexError, "tuple assignment index out of range"); err_setstr(IndexError, "tuple assignment index out of range");
return -1; return -1;
} }
olditem = ((tupleobject *)op) -> ob_item[i]; olditem = ((tupleobject *)op) -> ob_item[i];
((tupleobject *)op) -> ob_item[i] = newitem; ((tupleobject *)op) -> ob_item[i] = newitem;
if (olditem != NULL) XDECREF(olditem);
DECREF(olditem);
return 0; return 0;
} }
@ -148,10 +145,8 @@ tupledealloc(op)
register tupleobject *op; register tupleobject *op;
{ {
register int i; register int i;
for (i = 0; i < op->ob_size; i++) { for (i = 0; i < op->ob_size; i++)
if (op->ob_item[i] != NULL) XDECREF(op->ob_item[i]);
DECREF(op->ob_item[i]);
}
#if MAXSAVESIZE > 0 #if MAXSAVESIZE > 0
if (0 < op->ob_size && op->ob_size < MAXSAVESIZE) { if (0 < op->ob_size && op->ob_size < MAXSAVESIZE) {
op->ob_item[0] = (object *) free_list[op->ob_size]; op->ob_item[0] = (object *) free_list[op->ob_size];
@ -194,8 +189,7 @@ tuplerepr(v)
joinstring(&s, comma); joinstring(&s, comma);
t = reprobject(v->ob_item[i]); t = reprobject(v->ob_item[i]);
joinstring(&s, t); joinstring(&s, t);
if (t != NULL) XDECREF(t);
DECREF(t);
} }
DECREF(comma); DECREF(comma);
if (v->ob_size == 1) { if (v->ob_size == 1) {
@ -397,3 +391,42 @@ typeobject Tupletype = {
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
tuplehash, /*tp_hash*/ tuplehash, /*tp_hash*/
}; };
/* The following function breaks the notion that tuples are immutable:
it changes the size of a tuple. We get away with this only if there
is only one module referencing the object. You can also think of it
as creating a new tuple object and destroying the old one, only
more efficiently. In any case, don't use this if the tuple may
already be known to some other part of the code... */
int
resizetuple(pv, newsize)
object **pv;
int newsize;
{
register object *v;
register tupleobject *sv;
v = *pv;
if (!is_tupleobject(v) || v->ob_refcnt != 1) {
*pv = 0;
DECREF(v);
err_badcall();
return -1;
}
/* XXX UNREF/NEWREF interface should be more symmetrical */
#ifdef REF_DEBUG
--ref_total;
#endif
UNREF(v);
*pv = (object *)
realloc((char *)v,
sizeof(tupleobject) + newsize * sizeof(object *));
if (*pv == NULL) {
DEL(v);
err_nomem();
return -1;
}
NEWREF(*pv);
((tupleobject *) *pv)->ob_size = newsize;
return 0;
}

View File

@ -37,6 +37,11 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "compile.h" #include "compile.h"
#include "eval.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 * static object *
builtin_abs(self, v) builtin_abs(self, v)
object *self; object *self;
@ -61,6 +66,132 @@ builtin_apply(self, args)
return call_object(func, arglist); return call_object(func, arglist);
} }
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 * static object *
builtin_chr(self, args) builtin_chr(self, args)
object *self; object *self;
@ -191,6 +322,7 @@ exec_eval(v, start)
object *str = NULL, *globals = NULL, *locals = NULL; object *str = NULL, *globals = NULL, *locals = NULL;
char *s; char *s;
int n; int n;
/* XXX This is a bit of a mess. Should make it varargs */
if (v != NULL) { if (v != NULL) {
if (is_tupleobject(v) && if (is_tupleobject(v) &&
((n = gettuplesize(v)) == 2 || n == 3)) { ((n = gettuplesize(v)) == 2 || n == 3)) {
@ -206,9 +338,10 @@ exec_eval(v, start)
globals != NULL && !is_dictobject(globals) || globals != NULL && !is_dictobject(globals) ||
locals != NULL && !is_dictobject(locals)) { locals != NULL && !is_dictobject(locals)) {
err_setstr(TypeError, err_setstr(TypeError,
"exec/eval arguments must be (string|code)[,dict[,dict]]"); "eval/lambda arguments must be (string|code)[,dict[,dict]]");
return NULL; return NULL;
} }
/* XXX The following is only correct for eval(), not for lambda() */
if (is_codeobject(str)) if (is_codeobject(str))
return eval_code((codeobject *) str, globals, locals, return eval_code((codeobject *) str, globals, locals,
(object *)NULL, (object *)NULL); (object *)NULL, (object *)NULL);
@ -217,7 +350,7 @@ exec_eval(v, start)
err_setstr(ValueError, "embedded '\\0' in string arg"); err_setstr(ValueError, "embedded '\\0' in string arg");
return NULL; return NULL;
} }
if (start == eval_input) { if (start == eval_input || start == lambda_input) {
while (*s == ' ' || *s == '\t') while (*s == ' ' || *s == '\t')
s++; s++;
} }
@ -335,6 +468,136 @@ builtin_id(self, args)
return newintobject((long)v); return newintobject((long)v);
} }
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 * static object *
builtin_setattr(self, args) builtin_setattr(self, args)
object *self; object *self;
@ -413,6 +676,14 @@ builtin_int(self, v)
return (*nb->nb_int)(v); return (*nb->nb_int)(v);
} }
static object *
builtin_lambda(self, v)
object *self;
object *v;
{
return exec_eval(v, lambda_input);
}
static object * static object *
builtin_len(self, v) builtin_len(self, v)
object *self; object *self;
@ -640,6 +911,58 @@ builtin_range(self, v)
return v; return 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 * static object *
builtin_raw_input(self, v) builtin_raw_input(self, v)
object *self; object *self;
@ -658,6 +981,103 @@ builtin_raw_input(self, v)
return filegetline(sysget("stdin"), -1); return filegetline(sysget("stdin"), -1);
} }
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 * static object *
builtin_reload(self, v) builtin_reload(self, v)
object *self; object *self;
@ -740,6 +1160,7 @@ builtin_type(self, v)
static struct methodlist builtin_methods[] = { static struct methodlist builtin_methods[] = {
{"abs", builtin_abs}, {"abs", builtin_abs},
{"apply", builtin_apply}, {"apply", builtin_apply},
{"bagof", builtin_bagof},
{"chr", builtin_chr}, {"chr", builtin_chr},
{"cmp", builtin_cmp}, {"cmp", builtin_cmp},
{"coerce", builtin_coerce}, {"coerce", builtin_coerce},
@ -756,8 +1177,10 @@ static struct methodlist builtin_methods[] = {
{"id", builtin_id}, {"id", builtin_id},
{"input", builtin_input}, {"input", builtin_input},
{"int", builtin_int}, {"int", builtin_int},
{"lambda", builtin_lambda},
{"len", builtin_len}, {"len", builtin_len},
{"long", builtin_long}, {"long", builtin_long},
{"map", builtin_map},
{"max", builtin_max}, {"max", builtin_max},
{"min", builtin_min}, {"min", builtin_min},
{"oct", builtin_oct}, {"oct", builtin_oct},
@ -766,12 +1189,14 @@ static struct methodlist builtin_methods[] = {
{"pow", builtin_pow}, {"pow", builtin_pow},
{"range", builtin_range}, {"range", builtin_range},
{"raw_input", builtin_raw_input}, {"raw_input", builtin_raw_input},
{"reduce", builtin_reduce},
{"reload", builtin_reload}, {"reload", builtin_reload},
{"repr", builtin_repr}, {"repr", builtin_repr},
{"round", builtin_round}, {"round", builtin_round},
{"setattr", builtin_setattr}, {"setattr", builtin_setattr},
{"str", builtin_str}, {"str", builtin_str},
{"type", builtin_type}, {"type", builtin_type},
{"xrange", builtin_xrange},
{NULL, NULL}, {NULL, NULL},
}; };
@ -883,3 +1308,155 @@ coerce(pv, pw)
err_setstr(TypeError, "number coercion failed"); err_setstr(TypeError, "number coercion failed");
return -1; 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;
}

View File

@ -164,6 +164,7 @@ struct compiling {
int c_nexti; /* index into c_code */ int c_nexti; /* index into c_code */
int c_errors; /* counts errors occurred */ int c_errors; /* counts errors occurred */
int c_infunction; /* set when compiling a function */ int c_infunction; /* set when compiling a function */
int c_inlambda; /* set when compiling an expression */
int c_loops; /* counts nested loops */ int c_loops; /* counts nested loops */
int c_begin; /* begin of current loop, for 'continue' */ int c_begin; /* begin of current loop, for 'continue' */
int c_block[MAXBLOCKS]; /* stack of block types */ int c_block[MAXBLOCKS]; /* stack of block types */
@ -205,7 +206,7 @@ block_pop(c, type)
/* Prototypes */ /* Prototypes */
static int com_init PROTO((struct compiling *, char *)); static int com_init PROTO((struct compiling *, char *, int));
static void com_free PROTO((struct compiling *)); static void com_free PROTO((struct compiling *));
static void com_done PROTO((struct compiling *)); static void com_done PROTO((struct compiling *));
static void com_node PROTO((struct compiling *, struct _node *)); static void com_node PROTO((struct compiling *, struct _node *));
@ -221,9 +222,10 @@ static void com_addopname PROTO((struct compiling *, int, node *));
static void com_list PROTO((struct compiling *, node *, int)); static void com_list PROTO((struct compiling *, node *, int));
static int static int
com_init(c, filename) com_init(c, filename, inlambda)
struct compiling *c; struct compiling *c;
char *filename; char *filename;
int inlambda;
{ {
if ((c->c_code = newsizedstringobject((char *)NULL, 1000)) == NULL) if ((c->c_code = newsizedstringobject((char *)NULL, 1000)) == NULL)
goto fail_3; goto fail_3;
@ -236,6 +238,7 @@ com_init(c, filename)
c->c_nexti = 0; c->c_nexti = 0;
c->c_errors = 0; c->c_errors = 0;
c->c_infunction = 0; c->c_infunction = 0;
c->c_inlambda = inlambda;
c->c_loops = 0; c->c_loops = 0;
c->c_begin = 0; c->c_begin = 0;
c->c_nblocks = 0; c->c_nblocks = 0;
@ -1792,7 +1795,7 @@ com_funcdef(c, n)
{ {
object *v; object *v;
REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */
v = (object *)compile(n, c->c_filename); v = (object *)_compile(n, c->c_filename, 0);
if (v == NULL) if (v == NULL)
c->c_errors++; c->c_errors++;
else { else {
@ -1804,6 +1807,25 @@ com_funcdef(c, n)
} }
} }
static void
com_lambda(c, n)
struct compiling *c;
node *n;
{
object *v;
REQ(n, lambda_input);
v = (object *)_compile(n, c->c_filename, 1);
if (v == NULL)
c->c_errors++;
else {
int i = com_addconst(c, v);
DECREF(v);
com_addoparg(c, LOAD_CONST, i);
com_addbyte(c, BUILD_FUNCTION);
com_addbyte(c, RETURN_VALUE);
}
}
static void static void
com_bases(c, n) com_bases(c, n)
struct compiling *c; struct compiling *c;
@ -1839,7 +1861,7 @@ com_classdef(c, n)
com_addoparg(c, BUILD_TUPLE, 0); com_addoparg(c, BUILD_TUPLE, 0);
else else
com_bases(c, CHILD(n, 3)); com_bases(c, CHILD(n, 3));
v = (object *)compile(n, c->c_filename); v = (object *)_compile(n, c->c_filename, 0);
if (v == NULL) if (v == NULL)
c->c_errors++; c->c_errors++;
else { else {
@ -2096,6 +2118,17 @@ compile_funcdef(c, n)
com_addbyte(c, RETURN_VALUE); com_addbyte(c, RETURN_VALUE);
} }
static void
compile_lambda(c, n)
struct compiling *c;
node *n;
{
REQ(n, lambda_input)
com_arglist(c, CHILD(n, 0));
com_node(c, CHILD(n, 2));
com_addbyte(c, RETURN_VALUE);
}
static void static void
compile_node(c, n) compile_node(c, n)
struct compiling *c; struct compiling *c;
@ -2120,12 +2153,11 @@ compile_node(c, n)
com_addbyte(c, RETURN_VALUE); com_addbyte(c, RETURN_VALUE);
break; break;
case expr_input: /* Built-in function eval() */ case lambda_input: /* Built-in function lambda() */
com_node(c, CHILD(n, 0)); (c->c_inlambda ? compile_lambda : com_lambda)(c, n);
com_addbyte(c, RETURN_VALUE);
break; break;
case eval_input: /* Built-in function input() */ case eval_input: /* Built-in functions eval() and input() */
com_node(c, CHILD(n, 0)); com_node(c, CHILD(n, 0));
com_addbyte(c, RETURN_VALUE); com_addbyte(c, RETURN_VALUE);
break; break;
@ -2285,13 +2317,14 @@ optimize(c)
} }
codeobject * codeobject *
compile(n, filename) _compile(n, filename, inlambda)
node *n; node *n;
char *filename; char *filename;
int inlambda;
{ {
struct compiling sc; struct compiling sc;
codeobject *co; codeobject *co;
if (!com_init(&sc, filename)) if (!com_init(&sc, filename, inlambda))
return NULL; return NULL;
compile_node(&sc, n); compile_node(&sc, n);
com_done(&sc); com_done(&sc);

File diff suppressed because it is too large Load Diff