2 Copyright (C) 2004-2008, The Perl Foundation.
7 src/pmc/slice.pmc - Slice PMC
11 These are the vtable functions for the slice PMC class.
13 A Slice PMC isa Key PMC, holding a chain of start and/or end values
14 for slice ranges. Private flags define the meaning of the values:
16 [ s .. e ] s .. KEY_start_slice_FLAG; e .. KEY_end_slice_FLAG
17 [ x, ] KEY_start_slice_FLAG | KEY_end_slice_FLAG
18 [ .. e ] KEY_inf_slice_FLAG | KEY_end_slice_FLAG
19 [ s .. ] KEY_start_slice_FLAG | KEY_inf_slice_FLAG
21 Infinite ranges are currently implemented for Array and PerlString only.
25 $ parrot -d2000 slice.pasm
27 to see slice constant flags.
29 During initialization above key chain gets converted to parrot_range_t
40 #include "parrot/parrot.h"
42 #define VALID_RANGE(r) ((r) && ((INTVAL)(r) != -1))
43 #define RVal_int(u) (u).i
44 #define RVal_str(u) (u).s
48 * create range_t structure
50 * set the Slice iter state to initial, first position
51 * no backwards iterations for now
53 * XXX self is a key chain (PMC constant), which shouldn't be modified
54 * finally this stuff should be call from packfiles thaw
58 set_slice_start(PARROT_INTERP, PMC *self, PMC *key, PMC *agg)
60 parrot_range_t *range = mem_allocate_typed(parrot_range_t);
63 * when this PMC gets created with init(), this flag should get set if and
64 * only if there's a slice range allocated for it -- that is, if this
65 * function gets called
67 PObj_custom_mark_destroy_SETALL(self);
69 PMC_struct_val(self) = range;
73 RVal_int(range->step) = 1;
75 if (key_type(interp, key) & KEY_integer_FLAG) {
76 range->type = enum_type_INTVAL;
79 if ((PObj_get_FLAGS(key) &
80 (KEY_start_slice_FLAG | KEY_end_slice_FLAG)) ==
81 (KEY_start_slice_FLAG | KEY_end_slice_FLAG)) {
83 RVal_int(range->start) =
84 RVal_int(range->end) = key_integer(interp, key);
86 else if ((PObj_get_FLAGS(key) &
87 (KEY_inf_slice_FLAG | KEY_end_slice_FLAG)) ==
88 (KEY_inf_slice_FLAG | KEY_end_slice_FLAG)) {
90 * first range is ".. end"
93 RVal_int(range->start) = 0;
94 RVal_int(range->end) = key_integer(interp, key);
98 * else start at range value
100 RVal_int(range->start) = key_integer(interp, key);
101 if ((PObj_get_FLAGS(key) &
102 (KEY_inf_slice_FLAG | KEY_start_slice_FLAG)) ==
103 (KEY_inf_slice_FLAG | KEY_start_slice_FLAG)) {
104 /* last range "start .." */
105 RVal_int(range->end) = VTABLE_elements(interp, agg) - 1;
107 real_exception(interp, NULL, 1, "Illegal range after start..");
110 /* must have end in next key */
111 key = PMC_data_typed(key, PMC *);
114 real_exception(interp, NULL, 1, "no end range specified");
116 RVal_int(range->end) = key_integer(interp, key);
120 if (agg->vtable->base_type == enum_class_Slice)
121 --RVal_int(range->end);
122 RVal_int(range->cur) = RVal_int(range->start);
125 key = PMC_data_typed(key, PMC *);
128 parrot_range_t * const n = mem_allocate_typed(parrot_range_t);
136 if (PObj_get_FLAGS(key) & KEY_inf_slice_FLAG) {
137 real_exception(interp, NULL, 1,
138 "unlimited slice range for hash "
141 range->type = enum_type_STRING;
147 RVal_str(range->start) =
148 RVal_str(range->cur) =
149 key_string(interp, key);
151 if ((PObj_get_FLAGS(key) &
152 (KEY_start_slice_FLAG | KEY_end_slice_FLAG)) ==
153 (KEY_start_slice_FLAG | KEY_end_slice_FLAG)) {
155 RVal_str(range->end) = RVal_str(range->start);
158 /* must have end in next key */
159 key = PMC_data_typed(key, PMC *);
162 real_exception(interp, NULL, 1, "no end range specified");
164 RVal_str(range->end) = key_string(interp, key);
171 * increment Slice value according to range and/or advance to
172 * next range PMC in Key chain
175 set_slice_next(PARROT_INTERP, PMC *self, PMC *agg)
177 parrot_range_t * const r = (parrot_range_t *)PMC_struct_val(self);
180 real_exception(interp, NULL, E_StopIteration, "StopIteration");
182 if (r->type == enum_type_INTVAL) {
183 RVal_int(r->cur) += RVal_int(r->step);
184 if (RVal_int(r->step) > 0) {
185 if (RVal_int(r->cur) > RVal_int(r->end)) {
191 PMC_struct_val(self) = n;
194 PMC_int_val(self) = -1;
198 if (RVal_int(r->cur) < RVal_int(r->end))
203 STRING * const cur = RVal_str(r->cur);
204 STRING * const end = RVal_str(r->end);
206 if (string_compare(interp, cur, end) < 0)
207 RVal_str(r->cur) = string_increment(interp, cur);
213 pmclass Slice need_ext extends Key {
216 PMC_struct_val(SELF) = NULL;
217 PMC_pmc_val(SELF) = NULL;
221 parrot_range_t * const r = (parrot_range_t *)PMC_struct_val(SELF);
223 if (PMC_pmc_val(SELF))
224 pobject_lives(INTERP, (PObj *)PMC_pmc_val(SELF));
227 * the pointer must not be null, or at the end of iteration and it must
228 * point to STRINGs. Note that r->step is always the integer value 1.
230 if (VALID_RANGE(r) && r->type == enum_type_STRING) {
231 if (RVal_str(r->start))
232 pobject_lives(INTERP, (PObj *)RVal_str(r->start));
233 if (RVal_str(r->end))
234 pobject_lives(INTERP, (PObj *)RVal_str(r->end));
235 if (RVal_str(r->cur))
236 pobject_lives(INTERP, (PObj *)RVal_str(r->cur));
240 VTABLE void init_pmc(PMC *key) {
244 * that's actually the KEY_number_FLAG - but I can't hardly
245 * imagine that we get keyed by FLOATVAL slices on
248 PObj_get_FLAGS(SELF) |= PObj_private1_FLAG;
249 PObj_custom_mark_destroy_SETALL(SELF);
250 set_slice_start(INTERP, SELF, key, SELF);
253 VTABLE void destroy() {
254 parrot_range_t *r = (parrot_range_t *)PMC_struct_val(SELF);
256 /* iteration ended - all is freed */
261 parrot_range_t * const n = r->next;
267 VTABLE PMC *clone() {
268 real_exception(INTERP, NULL, E_NotImplementedError, "Unimplemented");
273 =item C<INTVAL get_integer()>
275 Get the next integer key from the current slice range.
277 =item C<STRING *get_string()>
279 Get the next string key from the current slice range.
285 VTABLE INTVAL get_integer() {
286 const parrot_range_t * const r = (parrot_range_t *)PMC_struct_val(SELF);
289 real_exception(INTERP, NULL, E_StopIteration, "StopIteration");
291 return RVal_int(r->cur);
294 VTABLE STRING *get_string() {
295 const parrot_range_t * const r = (parrot_range_t *)PMC_struct_val(SELF);
297 return RVal_str(r->cur);
302 =item C<PMC *slice(PMC *key)>
304 =item C<PMC *get_iter()>
306 A slice can serve as its own iterator, yielding values [start .. end-1].
307 This is used for implementing Pythons xrange()
313 VTABLE PMC *slice(PMC *key, INTVAL f) {
317 real_exception(INTERP, NULL, E_ValueError,
318 "Slice: Unknown slice type");
320 iter = pmc_new_init(INTERP, enum_class_Iterator, SELF);
321 PMC_struct_val(iter) = key;
325 VTABLE PMC *get_iter() {
326 PMC * const iter = pmc_new_init(INTERP, enum_class_Iterator, SELF);
327 PMC_struct_val(iter) = SELF;
331 VTABLE INTVAL elements() {
332 const parrot_range_t * const r = (parrot_range_t *)PMC_struct_val(SELF);
333 /* only start .. end supported so:
334 * TODO check flags somewhere
336 return RVal_int(r->start) - RVal_int(r->end);
339 VTABLE INTVAL get_integer_keyed(PMC *key) {
340 const parrot_range_t * const r = (parrot_range_t *)PMC_struct_val(key);
341 return RVal_int(r->cur);
344 VTABLE STRING *get_string_keyed(PMC *key) {
345 const INTVAL v = VTABLE_get_integer(INTERP, key);
346 return string_from_int(INTERP, v);
349 VTABLE PMC *get_pmc_keyed(PMC *key) {
350 const parrot_range_t * const r = (parrot_range_t *)PMC_struct_val(key);
351 PMC * const res = PMC_pmc_val(SELF);
352 PMC_int_val(res) = RVal_int(r->cur);
358 =item C<PMC *nextkey_keyed(PMC *agg, INTVAL what)>
360 Prepare slice PMC SELF for iteration over the passed aggregate or
361 advance to next position in the range, depending on what.
366 VTABLE PMC *nextkey_keyed(PMC *agg, INTVAL what) {
370 case ITERATE_FROM_START:
371 case ITERATE_FROM_START_KEYS: /* reset key */
373 /* xrange implementation - the slice PMC itself serves as the
374 * aggregate. It's already initialized. */
379 * need a new Slice PMC that holds the state
380 * especially PMC_data() must be zero
382 * aggregate call get_integer/get_string on this
383 * PMC, because it's marked being a Key PMC
385 ret = pmc_new(INTERP, enum_class_Slice);
386 PObj_get_FLAGS(ret) |= KEY_pmc_FLAG;
388 /* set start value */
389 set_slice_start(INTERP, ret, SELF, agg);
392 /* we are passed now the new PMC we created above */
393 case ITERATE_GET_NEXT:
394 set_slice_next(INTERP, SELF, agg);
397 real_exception(INTERP, NULL, E_NotImplementedError,
398 "No backward iteration on slices yet");
416 * c-file-style: "parrot"
418 * vim: expandtab shiftwidth=4: