/* Copyright (C) 2004-2007, The Perl Foundation. $Id: matchrange.pmc 23493 2007-12-05 12:55:03Z paultcochrane $ =head1 NAME src/dynpmc/matchrange.pmc - MatchRange Numbers PMC Class =head1 DESCRIPTION C provides a representation of regular expression matches, by describing the starting and ending offsets within the input string. This PMC only provides the start and end values; the Match PMC is responsible for interpreting these values appropriately (namely, as a substring within the input string.) This really probably shouldn't be a top-level class; it probably ought to inherit from "IntPair" or something like that. (But it can't just *be* "IntPair", because the Match PMC uses the type to figure out whether it has a regular variable or something that it needs to interpret as a string given its value and the input string.) This PMC is used by the languages/regex rule compiler, together with the Match PMC. =head2 Functions =over 4 =cut */ #include "parrot/parrot.h" #define RANGE_START(pmc) PMC_int_val(pmc) #define RANGE_END(pmc) PMC_int_val2(pmc) int MatchRange_type_id = -1; /* =item C Interpret the string C; valid keys are C and C, representing the offsets of the first and last characters of the matching range. =cut */ static INTVAL* matchrange_locate_keyed_int(Interp* interp, PMC* self, STRING *key) { STRING *start = string_from_cstring(interp, "start", 5); STRING *end; if (0 == string_equal(interp, key, start)) return &RANGE_START(self); end = string_from_cstring(interp, "end", 3); if (0 == string_equal(interp, key, end)) return &RANGE_END(self); real_exception(interp, NULL, KEY_NOT_FOUND, "MatchRange: key is neither 'start' nor 'end'"); return NULL; } pmclass MatchRange dynpmc group match_group { /* =back =head2 Methods =over 4 =item C Class initialization. Caches the type id of the MatchRange PMC, because it will be used frequently here. */ void class_init() { /* class_init_code */ if (pass) { MatchRange_type_id = entry; } } /* =item C Initializes the matchrange with [-2,-2]. =item C Initializes the matchrange number with the specified values. (not implemented) =item C Cleans up. =item C Creates an identical copy of the matchrange number. =cut */ void init() { RANGE_START(SELF) = RANGE_END(SELF) = -2; } void init_pmc(PMC* initializer) { /* RT#48168 not implemented */ DYNSELF.init(); } void destroy() { } void morph(INTVAL type) { if (SELF->vtable->base_type == type) return; SUPER(type); } PMC* clone() { PMC* dest = pmc_new_noinit(interp, SELF->vtable->base_type); PObj_active_destroy_SET(dest); RANGE_START(dest) = RANGE_START(SELF); RANGE_END(dest) = RANGE_END(SELF); return dest; } /* =item C Returns true if the match range is defined. =cut */ INTVAL get_bool() { return (INTVAL)(RANGE_START(SELF) != -2 && RANGE_END(SELF) != -2); } /* =item C =item C =item C =item C =item C =item C Returns the requested number (real part for C and imaginary for C). =cut */ INTVAL get_integer_keyed(PMC* key) { if (key_type(interp, key) == KEY_integer_FLAG) { return SELF.get_integer_keyed_int(PMC_int_val(key)); } else { STRING* s = VTABLE_get_string(interp, key); return DYNSELF.get_integer_keyed_str(s); } } INTVAL get_integer_keyed_str(STRING* key) { FLOATVAL f = DYNSELF.get_number_keyed_str(key); return (INTVAL)f; } FLOATVAL get_number_keyed(PMC* key) { STRING* s = VTABLE_get_string(interp, key); return DYNSELF.get_number_keyed_str(s); } FLOATVAL get_number_keyed_str(STRING* key) { INTVAL *num = matchrange_locate_keyed_int(interp, SELF, key); if (num) return *num; return 0.0; } PMC* get_pmc_keyed(PMC* key) { STRING* s = VTABLE_get_string(interp, key); return DYNSELF.get_pmc_keyed_str(s); } PMC* get_pmc_keyed_str(STRING* key) { PMC *ret; FLOATVAL val; ret = pmc_new(interp, enum_class_Float); val = DYNSELF.get_number_keyed_str(key); VTABLE_set_number_native(interp, ret, val); return ret; } /* =item C Quick hack to emulate get_start() and get_end(): key = 0 ... get start offset key = 1 ... get end offset =item C Set start or end depending on key */ INTVAL get_integer_keyed_int(INTVAL key) { switch (key) { case 0: return RANGE_START(SELF); case 1: return RANGE_END(SELF); default: real_exception(interp, NULL, 1, "MatchRange: key must be 0 or 1"); } return -2; } void set_integer_keyed_int(INTVAL key, INTVAL v) { switch (key) { case 0: RANGE_START(SELF) = v; break; case 1: RANGE_END(SELF) = v; break; default: real_exception(interp, NULL, 1, "MatchRange: key must be 0 or 1"); } } /* =item C if C is a MatchRange PMC then the set the range indices to the same values; otherwise throw an exception. This really only makes sense if you're using a MatchRange from the same Match, or at least for the same input string, but I won't worry about that for now. =cut */ void set_pmc(PMC* value) { if (value->vtable->base_type == MatchRange_type_id) { RANGE_START(SELF) = RANGE_START(value); RANGE_END(SELF) = RANGE_END(value); } else { real_exception(interp, NULL, 1, "MatchRange: cannot set from pmc"); } } /* =item C =item C =item C =item C =item C =item C =item C Sets the requested number(start offset for C and end offset for C) to C. For the keyed_int variants, 0 means RANGE_START, 1 means RANGE_END. =cut */ void set_integer_keyed(PMC* key, INTVAL value) { if (key_type(interp, key) == KEY_integer_FLAG) { SELF.set_integer_keyed_int(PMC_int_val(key), value); } else { STRING* s = VTABLE_get_string(interp, key); DYNSELF.set_integer_keyed_str(s, value); } } void set_integer_keyed_str(STRING* key, INTVAL value) { INTVAL *num = matchrange_locate_keyed_int(interp, SELF, key); if (num) *num = value; } void set_number_keyed(PMC* key, FLOATVAL value) { DYNSELF.set_integer_keyed(key, (INTVAL) value); } void set_number_keyed_str(STRING* key, FLOATVAL value) { DYNSELF.set_integer_keyed_str(key, (INTVAL) value); } void set_number_keyed_int(INTVAL key, FLOATVAL value) { DYNSELF.set_integer_keyed_int(key, (INTVAL) value); } void set_pmc_keyed(PMC* key, PMC* value) { INTVAL f = VTABLE_get_integer(interp, value); DYNSELF.set_integer_keyed(key, f); } void set_pmc_keyed_str(STRING* key, PMC* value) { INTVAL f = VTABLE_get_integer(interp, value); DYNSELF.set_integer_keyed_str(key, f); } /* =item C =item C =item C Adds C to the ending offset of the match range, placing the result in C. =cut */ PMC* add(PMC* value, PMC* dest) { INTVAL v = VTABLE_get_integer(interp, dest); return SELF.add_int(v, dest); } PMC* add_int(INTVAL value, PMC* dest) { if (dest) VTABLE_morph(interp, dest, MatchRange_type_id); else dest = pmc_new(interp, MatchRange_type_id); if (RANGE_END(SELF) == -2) { if (RANGE_START(SELF) == -2) { real_exception(interp, NULL, 1, "MatchRange: cannot add to nonexistent range"); return NULL; } RANGE_END(SELF) = RANGE_START(SELF); } RANGE_END(dest) = RANGE_END(SELF) + value; return dest; } PMC* add_float(FLOATVAL value, PMC* dest) { return SELF.add_int((INTVAL) value, dest); } /* =item C =item C =item C Subtracts C from the ending offset of the match range, placing the result in C. =cut */ PMC* subtract(PMC* value, PMC* dest) { INTVAL v = VTABLE_get_integer(interp, dest); return SELF.subtract_int(v, dest); } PMC* subtract_int(INTVAL value, PMC* dest) { if (dest) VTABLE_morph(interp, dest, MatchRange_type_id); else dest = pmc_new(interp, MatchRange_type_id); RANGE_END(dest) = RANGE_END(SELF) - value; if (RANGE_END(dest) <= -2 || RANGE_END(dest) < RANGE_START(dest) - 1) RANGE_END(dest) = -2; return dest; } PMC* subtract_float(FLOATVAL value, PMC* dest) { return SELF.subtract_int((INTVAL) value, dest); } /* =item C Compares the matchrange number with C and returs true if they are equal. =cut */ INTVAL is_equal(PMC* value) { if (value->vtable->base_type == MatchRange_type_id) return (INTVAL)( RANGE_START(SELF) == RANGE_START(value) && RANGE_END(SELF) == RANGE_END(value)); return (INTVAL)0; } } /* =back =cut */ /* * Local variables: * c-file-style: "parrot" * End: * vim: expandtab shiftwidth=4: */