diff --git a/src/builtin_functions.h b/src/builtin_functions.h index 8fc30a5cfe5b6fb0ae3ecc50e03aaea570d5b690..0764d3e0f895c006874a970660194339195ec48b 100644 --- a/src/builtin_functions.h +++ b/src/builtin_functions.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: builtin_functions.h,v 1.26 2003/07/21 23:34:01 mast Exp $ +|| $Id: builtin_functions.h,v 1.27 2003/09/05 15:19:20 mast Exp $ */ #ifndef BUILTIN_EFUNS_H @@ -107,9 +107,12 @@ PMOD_EXPORT void f_transpose(INT32 args); PMOD_EXPORT void f__reset_dmalloc(INT32 args); PMOD_EXPORT void f__locate_references(INT32 args); PMOD_EXPORT void f_map_array(INT32 args); -PMOD_EXPORT void f_get_iterator(INT32 args); void init_builtin_efuns(void); +/* From iterators.cmod. */ +PMOD_EXPORT void f_get_iterator(INT32 args); +int foreach_iterate(struct object *o, int do_step); + /* From builtin.cmod. */ PMOD_EXPORT void f_column(INT32 args); PMOD_EXPORT void f_trace(INT32 args); diff --git a/src/docode.c b/src/docode.c index 0bb3dfae841eb5b9e3ef115c81270e73ceb07f31..86d5fb75cf48b4e9bc6e24e95e3b012176ee365e 100644 --- a/src/docode.c +++ b/src/docode.c @@ -2,11 +2,11 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: docode.c,v 1.165 2003/08/03 00:52:42 mast Exp $ +|| $Id: docode.c,v 1.166 2003/09/05 15:19:20 mast Exp $ */ #include "global.h" -RCSID("$Id: docode.c,v 1.165 2003/08/03 00:52:42 mast Exp $"); +RCSID("$Id: docode.c,v 1.166 2003/09/05 15:19:20 mast Exp $"); #include "las.h" #include "program.h" #include "pike_types.h" @@ -1254,15 +1254,18 @@ static int do_docode2(node *n, int flags) current_switch.jumptable=0; current_label->break_label=alloc_label(); current_label->continue_label=alloc_label(); - - tmp3=do_branch(-1); + + /* Doubt it's necessary to use a label separate from + * current_label->break_label, but I'm playing safe. /mast */ + tmp3 = alloc_label(); + do_jump(F_FOREACH_START, DO_NOT_WARN((INT32) tmp3)); tmp1=ins_label(-1); DO_CODE_BLOCK(CDR(n)); ins_label(current_label->continue_label); - low_insert_label( DO_NOT_WARN((INT32)tmp3)); - do_jump(F_NEW_FOREACH, DO_NOT_WARN((INT32)tmp1)); + do_jump(F_FOREACH_LOOP, DO_NOT_WARN((INT32)tmp1)); ins_label(current_label->break_label); - + low_insert_label( DO_NOT_WARN((INT32)tmp3)); + current_switch.jumptable = prev_switch_jumptable; POP_STATEMENT_LABEL; POP_AND_DO_CLEANUP; @@ -1279,6 +1282,7 @@ static int do_docode2(node *n, int flags) node **a2=my_get_arg(&_CAR(arr),1); if(a1 && a2 && a2[0]->token==F_CONSTANT && a2[0]->u.sval.type==T_INT && + /* FIXME: The following can never be true! */ a2[0]->u.sval.type==0x7fffffff && a1[0]->type == int_type_string) { diff --git a/src/interpret_functions.h b/src/interpret_functions.h index 4ad878f5940b36de6bd4ff8ca4d2adc625d63e2a..4c7f193a96a82b76c95c95fdd639c8421f6edcdb 100644 --- a/src/interpret_functions.h +++ b/src/interpret_functions.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: interpret_functions.h,v 1.155 2003/08/13 15:58:04 grubba Exp $ +|| $Id: interpret_functions.h,v 1.156 2003/09/05 15:19:20 mast Exp $ */ /* @@ -1407,16 +1407,29 @@ OPCODE0(F_MAKE_ITERATOR, "get_iterator", 0, { f_get_iterator(1); }); -OPCODE0_BRANCH(F_NEW_FOREACH, "foreach++", 0, { /* iterator, lvalue, lvalue */ - extern int foreach_iterate(struct object *o); +/* Stack is: iterator, index lvalue, value lvalue. */ +OPCODE0_BRANCH (F_FOREACH_START, "foreach start", 0, { + DO_IF_DEBUG ( + if(Pike_sp[-5].type != PIKE_T_OBJECT) + Pike_fatal ("Iterator gone from stack.\n"); + ); + if (foreach_iterate (Pike_sp[-5].u.object, 0)) + DONT_BRANCH(); + else { + DO_BRANCH(); + } +}); - if(Pike_sp[-5].type != PIKE_T_OBJECT) - PIKE_ERROR("foreach", "Bad argument 1.\n", Pike_sp-3, 1); - if(foreach_iterate(Pike_sp[-5].u.object)) +/* Stack is: iterator, index lvalue, value lvalue. */ +OPCODE0_BRANCH(F_FOREACH_LOOP, "foreach loop", 0, { + DO_IF_DEBUG ( + if(Pike_sp[-5].type != PIKE_T_OBJECT) + Pike_fatal ("Iterator gone from stack.\n"); + ); + if(foreach_iterate(Pike_sp[-5].u.object, 1)) { DO_BRANCH(); }else{ - /* write_to_stderr("foreach\n", 8); */ DONT_BRANCH(); } }); diff --git a/src/iterators.cmod b/src/iterators.cmod index 1160e431b3807e2d55c5fe20e17de33674eefc22..5810e28b0d4481679d2ee56dd54bf132e9c3ffd7 100644 --- a/src/iterators.cmod +++ b/src/iterators.cmod @@ -2,11 +2,11 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: iterators.cmod,v 1.46 2003/09/04 17:03:04 grubba Exp $ +|| $Id: iterators.cmod,v 1.47 2003/09/05 15:19:20 mast Exp $ */ #include "global.h" -RCSID("$Id: iterators.cmod,v 1.46 2003/09/04 17:03:04 grubba Exp $"); +RCSID("$Id: iterators.cmod,v 1.47 2003/09/05 15:19:20 mast Exp $"); #include "main.h" #include "object.h" #include "mapping.h" @@ -269,8 +269,7 @@ PIKECLASS mapping_iterator push_svalue(& THIS->current->val); else { - push_int(0); - Pike_sp[-1].subtype=NUMBER_UNDEFINED; + push_undefined(); } } @@ -280,8 +279,7 @@ PIKECLASS mapping_iterator push_svalue(& THIS->current->ind); else { - push_int(0); - Pike_sp[-1].subtype=NUMBER_UNDEFINED; + push_undefined(); } } @@ -530,7 +528,6 @@ PIKECLASS multiset_iterator { CVAR struct multiset *l; CVAR int lock_index; - CVAR int prestepped; /* Ugly special flag to work correctly in foreach_iterate. */ CVAR ptrdiff_t nodepos; PIKEFUN int value() @@ -690,7 +687,6 @@ PIKECLASS multiset_iterator add_ref (THIS->l = l); THIS->lock_index = 0; THIS->nodepos = multiset_first (THIS->l); - THIS->prestepped = (THIS->nodepos >= 0); } INIT @@ -825,8 +821,7 @@ PIKECLASS string_iterator { if(!THIS->s || THIS->pos < 0 || THIS->pos >= THIS->s->len) { - push_int(0); - Pike_sp[-1].subtype=NUMBER_UNDEFINED; + push_undefined(); }else{ RETURN index_shared_string(THIS->s, THIS->pos); } @@ -836,8 +831,7 @@ PIKECLASS string_iterator { if(!THIS->s || THIS->pos < 0 || THIS->pos >= THIS->s->len) { - push_int(0); - Pike_sp[-1].subtype=NUMBER_UNDEFINED; + push_undefined(); }else{ RETURN THIS->pos; } @@ -1026,16 +1020,14 @@ PIKECLASS file_line_iterator if (THIS->current) { ref_push_string(THIS->current); } else { - push_int(0); - Pike_sp[-1].subtype = NUMBER_UNDEFINED; + push_undefined(); } } PIKEFUN int index() { if (!THIS->current) { - push_int(0); - Pike_sp[-1].subtype = NUMBER_UNDEFINED; + push_undefined(); }else{ RETURN THIS->index; } @@ -1386,16 +1378,14 @@ PIKECLASS string_split_iterator if (THIS->current) { ref_push_string(THIS->current); } else { - push_int(0); - Pike_sp[-1].subtype = NUMBER_UNDEFINED; + push_undefined(); } } PIKEFUN int index() { if (!THIS->current) { - push_int(0); - Pike_sp[-1].subtype = NUMBER_UNDEFINED; + push_undefined(); }else{ RETURN THIS->index; } @@ -1842,19 +1832,29 @@ PIKEFUN object(Iterator) get_iterator(object|array|mapping|multiset|string data) return; - case PIKE_T_OBJECT: + case PIKE_T_OBJECT: { + int fun; + if(!data->u.object->prog) SIMPLE_ARG_ERROR ("get_iterator", 1, "Got a destructed object.\n"); - if(FIND_LFUN(data->u.object->prog, LFUN__GET_ITERATOR) != -1) + fun = FIND_LFUN(data->u.object->prog, LFUN__GET_ITERATOR); + if (fun != -1) { - apply_lfun(data->u.object, LFUN__GET_ITERATOR, 0); + apply_low (data->u.object, fun, 0); + if (sp[-1].type != T_OBJECT) { + /* FIXME: Ought to include what we got in the error message. */ + pop_stack(); + SIMPLE_ARG_ERROR ("get_iterator", 1, + "_get_iterator() didn't return an object.\n"); + } stack_pop_keep_top(); return; } /* Assume it already is an iterator... */ return; + } default: SIMPLE_ARG_TYPE_ERROR("get_iterator", 1, "multiset|array|string|mapping|object"); @@ -1862,105 +1862,117 @@ PIKEFUN object(Iterator) get_iterator(object|array|mapping|multiset|string data) } /* sp[-4] = index; sp[-2] = value */ -int foreach_iterate(struct object *o) +int foreach_iterate(struct object *o, int do_step) { + struct program *prog = o->prog; int fun; - if(!o->prog) + if(!prog) Pike_error("foreach on destructed iterator.\n"); - if(o->prog->flags & PROGRAM_HAS_C_METHODS) + + if(prog->flags & PROGRAM_HAS_C_METHODS) { - if(o->prog == mapping_iterator_program) + if(prog == mapping_iterator_program) { struct mapping_iterator_struct *i=OBJ2_MAPPING_ITERATOR(o); - if(i->current) - { - if(Pike_sp[-4].type != T_INT) - assign_lvalue(Pike_sp-4, & i->current->ind); - - if(Pike_sp[-2].type != T_INT) - assign_lvalue(Pike_sp-2, & i->current->val); - mi_step(i); - return 1; - }else{ - return 0; + if (!i->current) return 0; + if (do_step) { + mi_step (i); + if (!i->current) return 0; } - } else if(o->prog == string_split_iterator_program) + + if(Pike_sp[-4].type != T_INT) + assign_lvalue(Pike_sp-4, & i->current->ind); + + if(Pike_sp[-2].type != T_INT) + assign_lvalue(Pike_sp-2, & i->current->val); + + return 1; + } + + else if(prog == string_split_iterator_program) { struct string_split_iterator_struct *i=OBJ2_STRING_SPLIT_ITERATOR(o); - if(i->current) - { - if(Pike_sp[-4].type != T_INT) - { - /* Black Magic... */ - push_int(i->index); - Pike_sp--; - assign_lvalue(Pike_sp-4, Pike_sp); - } - if(Pike_sp[-2].type != T_INT) - { - /* Black Magic... */ - push_string(i->current); - dmalloc_touch_svalue(Pike_sp-1); - Pike_sp--; - assign_lvalue(Pike_sp-2, Pike_sp); - } + if (!i->current) return 0; + if (do_step) { + find_next (i); + if (!i->current) return 0; + } - find_next(i); - return 1; - }else{ - return 0; + if(Pike_sp[-4].type != T_INT) + { + /* Black Magic... */ + push_int(i->index); + Pike_sp--; + assign_lvalue(Pike_sp-4, Pike_sp); } - } else if(o->prog == file_line_iterator_program) + + if(Pike_sp[-2].type != T_INT) + { + /* Black Magic... */ + push_string(i->current); + dmalloc_touch_svalue(Pike_sp-1); + Pike_sp--; + assign_lvalue(Pike_sp-2, Pike_sp); + } + + return 1; + } + + else if(prog == file_line_iterator_program) { struct file_line_iterator_struct *i=OBJ2_FILE_LINE_ITERATOR(o); - if(i->current) - { - if(Pike_sp[-4].type != T_INT) - { - /* Black Magic... */ - push_int(i->index); - Pike_sp--; - assign_lvalue(Pike_sp-4, Pike_sp); - } - if(Pike_sp[-2].type != T_INT) - { - /* Black Magic... */ - push_string(i->current); - dmalloc_touch_svalue(Pike_sp-1); - Pike_sp--; - assign_lvalue(Pike_sp-2, Pike_sp); - } + if (!i->current) return 0; + if (do_step) { + fl_find_next (i); + if (!i->current) return 0; + } - fl_find_next(i); - return 1; - }else{ - return 0; + if(Pike_sp[-4].type != T_INT) + { + /* Black Magic... */ + push_int(i->index); + Pike_sp--; + assign_lvalue(Pike_sp-4, Pike_sp); } - } else if(o->prog == array_iterator_program) + + if(Pike_sp[-2].type != T_INT) + { + /* Black Magic... */ + push_string(i->current); + dmalloc_touch_svalue(Pike_sp-1); + Pike_sp--; + assign_lvalue(Pike_sp-2, Pike_sp); + } + + return 1; + } + + else if(prog == array_iterator_program) { struct array_iterator_struct *i=OBJ2_ARRAY_ITERATOR(o); - if(i->pos >= 0 && i->pos < i->a->size) - { - if(Pike_sp[-4].type != T_INT) - { - push_int(i->pos); - assign_lvalue(Pike_sp-5, Pike_sp-1); - pop_stack(); - } - if(Pike_sp[-2].type != T_INT) - assign_lvalue(Pike_sp-2, i->a->item + i->pos); + if (i->pos < 0 || i->pos >= i->a->size) return 0; + if (do_step) + if (++i->pos == i->a->size) return 0; - i->pos++; - return 1; - }else{ - return 0; + if(Pike_sp[-4].type != T_INT) + { + push_int(i->pos); + assign_lvalue(Pike_sp-5, Pike_sp-1); + pop_stack(); } - } else if(o->prog == multiset_iterator_program) + + if(Pike_sp[-2].type != T_INT) + assign_lvalue(Pike_sp-2, i->a->item + i->pos); + + return 1; + } + + else if(prog == multiset_iterator_program) { struct multiset_iterator_struct *i=OBJ2_MULTISET_ITERATOR(o); @@ -1968,13 +1980,7 @@ int foreach_iterate(struct object *o) struct svalue ind; if (i->nodepos < 0) return 0; - - /* Step before getting the values, to behave better if the - * multiset is changed during the iteration. Since the iterator - * got to be initialized to the first element in its create(), - * we need an ugly special flag to get it right. */ - if ((i->prestepped ? (i->prestepped = 0) : 1) || - msnode_is_deleted (i->l, i->nodepos)) { + if (do_step) { i->nodepos = multiset_next (i->l, i->nodepos); if (i->nodepos < 0) { sub_msnode_ref (i->l); @@ -1990,53 +1996,110 @@ int foreach_iterate(struct object *o) return 1; #else /* PIKE_NEW_MULTISETS */ - if(i->pos >= 0 && i->pos < i->a->size) - { - if(Pike_sp[-4].type != T_INT) - assign_lvalue(Pike_sp-4, i->a->item + i->pos); + if (i->pos < 0 || i->pos >= i->a->size) return 0; + if (do_step) + if (++i->pos == i->a->size) return 0; - if(Pike_sp[-2].type != T_INT) - { - push_int(1); - assign_lvalue(Pike_sp-3, Pike_sp-1); - pop_stack(); - } + if(Pike_sp[-4].type != T_INT) + assign_lvalue(Pike_sp-4, i->a->item + i->pos); - i->pos++; - return 1; - }else{ - return 0; + if(Pike_sp[-2].type != T_INT) + { + push_int(1); + assign_lvalue(Pike_sp-3, Pike_sp-1); + pop_stack(); } + + return 1; + #endif /* PIKE_NEW_MULTISETS */ + } - } else if(o->prog == string_iterator_program) + else if(prog == string_iterator_program) { struct string_iterator_struct *i=OBJ2_STRING_ITERATOR(o); - if(i->pos >= 0 && i->pos < i->s->len) - { - if(Pike_sp[-4].type != T_INT) - { - push_int(i->pos); - assign_lvalue(Pike_sp-5, Pike_sp-1); - pop_stack(); - } - if(Pike_sp[-2].type != T_INT) - { - push_int(index_shared_string(i->s, i->pos)); - assign_lvalue(Pike_sp-3, Pike_sp-1); - pop_stack(); - } + if (i->pos < 0 || i->pos >= i->s->len) return 0; + if (do_step) + if (++i->pos == i->s->len) return 0; - i->pos++; - return 1; - }else{ - return 0; + if(Pike_sp[-4].type != T_INT) + { + push_int(i->pos); + assign_lvalue(Pike_sp-5, Pike_sp-1); + pop_stack(); + } + + if(Pike_sp[-2].type != T_INT) + { + push_int(index_shared_string(i->s, i->pos)); + assign_lvalue(Pike_sp-3, Pike_sp-1); + pop_stack(); } + + return 1; } } /* Generic iteration */ + + if (do_step) { + fun = FIND_LFUN (prog, LFUN_ADD_EQ); + if (fun < 0) Pike_error ("Iterator object lacks `+=.\n"); + push_int(1); + apply_low(o, fun, 1); + pop_stack(); + } + +#if 0 + /* We should be able to save calls to `! this way, but there are + * iterators where index() and value() don't return UNDEFINED as + * stipulated by the interface. */ + + fun = -1; + + if(Pike_sp[-4].type != T_INT) + { + fun = find_identifier ("index", prog); + if (fun < 0) Pike_error ("Iterator object lacks index().\n"); + apply_low(o, fun, 0); + if (IS_UNDEFINED (Pike_sp - 1)) { + Pike_sp--; + return 0; + } + assign_lvalue(Pike_sp-5,Pike_sp-1); + pop_stack(); + } + + if(Pike_sp[-2].type != T_INT) + { + fun = find_identifier ("value", prog); + if (fun < 0) Pike_error ("Iterator object lacks value().\n"); + apply_low(o, fun, 0); + if (IS_UNDEFINED (Pike_sp - 1)) { + Pike_sp--; + return 0; + } + assign_lvalue(Pike_sp-3,Pike_sp-1); + pop_stack(); + } + + if (fun >= 0) + /* index() and/or value() has returned a value so we know we can + * iterate without calling `!. */ + return 1; + else { + int res; + fun = FIND_LFUN (prog, LFUN_NOT); + if (fun < 0) Pike_error ("Iterator object lacks `!.\n"); + apply_low(o, fun, 0); + res = UNSAFE_IS_ZERO(Pike_sp-1); + pop_stack(); + return res; + } + +#else + fun = FIND_LFUN (o->prog, LFUN_NOT); if (fun < 0) Pike_error ("Iterator object lacks `!.\n"); apply_low(o, fun, 0); @@ -2062,16 +2125,13 @@ int foreach_iterate(struct object *o) pop_stack(); } - push_int(1); - fun = FIND_LFUN (o->prog, LFUN_ADD_EQ); - if (fun < 0) Pike_error ("Iterator object lacks `+=.\n"); - apply_lfun(o,LFUN_ADD_EQ,1); - pop_stack(); return 1; }else{ pop_stack(); return 0; } + +#endif } diff --git a/src/testsuite.in b/src/testsuite.in index 07d0bb29af19d74c7312d0525ed7a685c2086052..f89d33e4fee2dfb93c08212b7bbda7a3fac8a107 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -1,4 +1,4 @@ -test_true([["$Id: testsuite.in,v 1.672 2003/08/26 18:33:20 mast Exp $"]]); +test_true([["$Id: testsuite.in,v 1.673 2003/09/05 15:19:20 mast Exp $"]]); // This triggered a bug only if run sufficiently early. test_compile_any([[#pike 7.2]]) @@ -6840,6 +6840,13 @@ test_eval_error([[ return i; ]]) +test_any([[ + String.Iterator iter = String.Iterator ("foo"); + foreach (iter; int idx;) + if (idx != iter->index()) return 1; + return 0; +]], 0) + // do-while test_any(int e;string t=""; e=0; do{ t+=e; }while(++e<6); return t,"012345";)