New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Report the number of elements in an infinite range correctly #525
Comments
From @cspencerThe attatched patch lets an infinite Range (ie. (1..Inf)) report its It also adds temporary !FAIL cases when an infinite range is converted |
From @cspencerinfinite-range.patchIndex: src/classes/Range.pir
===================================================================
--- src/classes/Range.pir (revision 34246)
+++ src/classes/Range.pir (working copy)
@@ -72,7 +72,21 @@
.return ($P0)
.end
+=item elems()
+Returns in the number of elements in the Range.
+
+=cut
+
+.sub 'elems' :method
+ # TODO: Returning a Num for the moment, so Inf gets reported correctly.
+ # TODO: Should be returning an Int.
+ $N0 = self
+
+ .return ($N0)
+.end
+
+
=item from()
=item to()
@@ -114,16 +128,27 @@
=cut
.sub 'list' :method
- .local pmc range_it, result
- range_it = self.'iterator'()
- result = new 'List'
- range_loop:
- unless range_it goto range_end
- $P0 = shift range_it
- push result, $P0
- goto range_loop
- range_end:
- .return (result)
+ .local int test
+ .local pmc it
+ .local pmc rv
+
+ test = self.'!infinite'()
+ if test goto infinite
+
+ it = self.'iterator'()
+ rv = new 'List'
+
+ loop:
+ unless it goto end
+ $P0 = shift it
+ push rv, $P0
+ goto loop
+
+ infinite:
+ rv = '!FAIL'("Can't convert an infinite range to a list (yet)")
+
+ end:
+ .return (rv)
.end
@@ -242,7 +267,6 @@
.return ($I0)
.end
-
=back
=head2 Operators
@@ -381,6 +405,22 @@
.return ($I0)
.end
+.sub '!infinite' :method
+ .local pmc val
+
+ val = self.'from'()
+ if val == "-inf" goto infinite
+
+ val = self.'to'()
+ if val == "inf" goto infinite
+
+ finite:
+ .return (0)
+
+ infinite:
+ .return (1)
+.end
+
=back
=head2 Vtable functions
@@ -396,21 +436,65 @@
=cut
.sub 'VTABLE_get_integer' :method :vtable('get_integer')
+ .local int test
+ .local int rv
+
+ test = self.'!infinite'()
+ if test goto infinite
+
+ finite:
$P0 = self.'list'()
- $I0 = $P0
- .return ($I0)
+ rv = $P0.'elems'()
+ goto done
+
+ infinite:
+ # TODO: This isn't returning the correct value yet, should be Inf but isn't
+ rv = "inf"
+ goto done
+
+ done:
+ .return (rv)
.end
.sub 'VTABLE_get_number' :method :vtable('get_number')
+ .local int test
+ .local num rv
+
+ test = self.'!infinite'()
+ if test goto infinite
+
+ finite:
$P0 = self.'list'()
- $N0 = $P0
- .return ($N0)
+ rv = $P0.'elems'()
+ goto done
+
+ infinite:
+ rv = "inf"
+ goto done
+
+ done:
+ .return (rv)
.end
.sub 'VTABLE_get_string' :method :vtable('get_string')
+ .local int test
+ .local string rv
+
+ rv = ""
+ test = self.'!infinite'()
+ if test goto infinite
+
+ finite:
$P0 = self.'list'()
- $S0 = $P0
- .return ($S0)
+ rv = $P0
+ goto done
+
+ infinite:
+ rv = '!FAIL'("Can't convert an infinite range to a string (yet)")
+ goto done
+
+ done:
+ .return (rv)
.end
=back
|
From @pmichaudOn Mon Dec 22 09:46:43 2008, cspencer wrote:
The patch needs some rework before it can be accepted. First, I'd prefer to avoid the duplication of code between the Second, I'd like .elems to be able to figure out the size of the range Third, note that the get_string vtable function can't really return a So, work on those a bit and resubmit. Thanks! Pm |
The RT System itself - Status changed from 'new' to 'open' |
From @cspencerHere's take two which should handle things a bit better for many cases. It also adds a reverse() method which returns another Range object. Please let me know if there any problems! Cory On Mon Dec 22 12:08:55 2008, pmichaud wrote:
|
From @cspencerinfinite-range.patchIndex: src/classes/Range.pir
===================================================================
--- src/classes/Range.pir (revision 34313)
+++ src/classes/Range.pir (working copy)
@@ -61,24 +61,64 @@
.end
-=item clone() (vtable method)
+=item elems()
-Create a clone of the Range.
+Returns in the number of elements in the Range.
=cut
-.sub 'clone' :method :vtable
- $P0 = self.'!cloneattr'('$!from $!to $!from_exclusive $!to_exclusive')
- .return ($P0)
+.sub 'elems' :method
+ .local num elems
+ .local pmc from
+ .local pmc to
+
+ $P0 = self.'from'()
+ $P1 = self.'to'()
+
+ from = $P0.'clone'()
+ to = $P1.'clone'()
+
+ # Check if it's a null Range, returning 0 if so
+ $I0 = 'infix:cmp'(from, to)
+ if $I0 == 1 goto null_range
+
+ # Check if any of the end points are Inf, returning Inf if so
+ $I0 = self.'!infinite'()
+ if $I0 goto infinite_range
+
+ elems = 0
+
+ # If the start point is excluded in the Range, skip to the next
+ $I0 = self.'!from_test'(from)
+ if $I0 goto loop
+ $P0 = 'postfix:++'(from)
+
+ loop:
+ $P0 = 'postfix:++'(from)
+
+ $I0 = self.'!to_test'($P0)
+ unless $I0 goto done
+
+ inc elems
+ goto loop
+
+ null_range:
+ elems = 0
+ goto done
+
+ done:
+ .return (elems)
+
+ infinite_range:
+ $N0 = 'Inf'()
+ .return ($N0)
.end
=item from()
-=item to()
+Returns the beginning of the range.
-Gets the beginning or end of the range.
-
=cut
.sub 'from' :method
@@ -86,21 +126,39 @@
.return ($P0)
.end
-.sub 'to' :method
- $P0 = getattribute self, '$!to'
- .return ($P0)
+
+=item reverse()
+
+Returns a new Range with the to and from reversed.
+
+=cut
+
+.sub 'reverse' :method
+ .local pmc from
+ .local pmc fromexc
+ .local pmc to
+ .local pmc toexc
+ .local pmc proto
+
+ fromexc = getattribute self, '$!from_exclusive'
+ toexc = getattribute self, '$!to_exclusive'
+
+ from = self.'from'()
+ to = self.'to'()
+
+ proto = get_hll_global 'Range'
+ .tailcall proto.'new'('from'=>to, 'to'=>from, 'from_exclusive'=>toexc, 'to_exclusive'=>fromexc)
.end
-=item iterator() (vtable function)
+=item to()
-Return an iterator for the Range. Since Ranges are already
-iterators, we can just return a clone.
+Gets the beginning or end of the range.
=cut
-.sub 'iterator' :method :vtable('get_iter')
- $P0 = clone self
+.sub 'to' :method
+ $P0 = getattribute self, '$!to'
.return ($P0)
.end
@@ -113,38 +171,54 @@
=cut
+.namespace ['Range']
.sub 'list' :method
- .local pmc range_it, result
- range_it = self.'iterator'()
- result = new 'List'
- range_loop:
- unless range_it goto range_end
- $P0 = shift range_it
- push result, $P0
- goto range_loop
- range_end:
- .return (result)
+ .local int test
+ .local pmc it
+ .local pmc rv
+
+ test = self.'!infinite'()
+ if test goto infinite
+
+ it = self.'iterator'()
+ rv = new 'List'
+
+ loop:
+ unless it goto end
+ $P0 = shift it
+ push rv, $P0
+ goto loop
+
+ infinite:
+ rv = '!FAIL'("Can't convert an infinite range to a list (yet)")
+
+ end:
+ .return (rv)
.end
=item max()
-=item min()
-
-=item minmax()
-
=cut
-.namespace ['Range']
-
.sub 'max' :method
.tailcall self.'to'()
.end
+
+=item min()
+
+=cut
+
.sub 'min' :method
.tailcall self.'from'()
.end
+
+=item minmax()
+
+=cut
+
.sub 'minmax' :method
$P0 = self.'from'()
$P1 = self.'to'()
@@ -180,69 +254,6 @@
.end
-=item pop() (vtable_method)
-
-Generate the next element at the end of the Range.
-
-=cut
-
-.sub 'pop' :method :vtable('pop_pmc')
- .local pmc to, toexc, value
- to = getattribute self, '$!to'
- toexc = getattribute self, '$!to_exclusive'
- value = 'postfix:--'(to)
- unless toexc goto have_value
- value = clone to
- have_value:
- $I0 = self.'!from_test'(value)
- if $I0 goto success
- value = '!FAIL'('Undefined value popped from empty range')
- success:
- .return (value)
-.end
-
-
-=item shift() (vtable_method)
-
-Generate the next element at the front of the Range.
-
-=cut
-
-.sub 'shift' :method :vtable('shift_pmc')
- .local pmc from, fromexc, value
- from = getattribute self, '$!from'
- fromexc = getattribute self, '$!from_exclusive'
- value = 'postfix:++'(from)
- unless fromexc goto have_value
- value = clone from
- have_value:
- $I0 = self.'!to_test'(value)
- if $I0 goto success
- value = '!FAIL'('Undefined value shifted from empty range')
- success:
- .return (value)
-.end
-
-
-=item true()
-
-Return true if there are any more values to iterate over.
-
-=cut
-
-.sub 'true' :method :vtable('get_bool')
- .local pmc from, fromexc
- from = getattribute self, '$!from'
- fromexc = getattribute self, '$!from_exclusive'
- unless fromexc goto have_value
- from = clone from
- 'postfix:++'(from)
- have_value:
- $I0 = self.'!to_test'(from)
- .return ($I0)
-.end
-
-
=back
=head2 Operators
@@ -297,18 +308,19 @@
.tailcall proto.'new'('from'=>from, 'to'=>to, 'from_exclusive'=>true, 'to_exclusive'=>true)
.end
+
=item prefix:<^>(Any $to)
Construct a Range from C< 0 ..^ $to >.
=cut
-.namespace[]
.sub 'prefix:^' :multi(_)
.param num to
.tailcall 'infix:..^'(0, to)
.end
+
=item prefix:<^>(Type $x)
Return $x.HOW.
@@ -320,6 +332,7 @@
.tailcall proto.'HOW'()
.end
+
=back
=head2 Private methods
@@ -328,6 +341,8 @@
=item !flatten()
+Flattens the Range into a List.
+
=cut
.namespace ['Range']
@@ -335,34 +350,70 @@
.tailcall self.'list'()
.end
+
=item !from_test(topic)
-=item !to_test(topic)
+Returns true if C<topic> is greater than C<.from>, honoring exclusive flags.
-Returns true if C<topic> is greater than C<.from> / less than C<.to>,
-honoring exclusive flags.
-
=cut
-.namespace ['Range']
.sub '!from_test' :method
.param pmc topic
.local pmc from, fromexc
+
from = getattribute self, '$!from'
fromexc = getattribute self, '$!from_exclusive'
+
if fromexc goto exclusive_test
+
$I0 = isge topic, from
.return ($I0)
+
exclusive_test:
$I0 = isgt topic, from
.return ($I0)
.end
+
+=item !to_test(topic)
+
+Returns true if C<topic> is less than C<.to>, honoring exclusive flags.
+
+=cut
+
+.sub '!infinite' :method
+ .local int test
+ .local num inf
+
+ inf = 'Inf'()
+
+ $P0 = self.'from'()
+ $N0 = $P0
+ test = iseq $N0, inf
+ if test goto done
+
+ $P0 = self.'to'()
+ $N0 = $P0
+ test = iseq $N0, inf
+
+ done:
+ .return (test)
+.end
+
+
+=item !to_test(topic)
+
+Returns true if C<topic> is less than C<.to>, honoring exclusive flags.
+
+=cut
+
.sub '!to_test' :method
.param pmc topic
.local pmc to, toexc
+
to = getattribute self, '$!to'
$I0 = isa to, 'String'
+
unless $I0 goto test_value
$S0 = topic
$I0 = length $S0
@@ -371,46 +422,164 @@
eq $I0, $I1, test_value
$I0 = islt $I0, $I1
.return ($I0)
+
test_value:
toexc = getattribute self, '$!to_exclusive'
if toexc goto exclusive_test
$I0 = isle topic, to
.return ($I0)
+
exclusive_test:
$I0 = islt topic, to
.return ($I0)
.end
+
=back
=head2 Vtable functions
=over
-=item VTABLE_get integer (vtable method)
+=item clone() (vtable method)
-=item VTABLE_get_number (vtable method)
+=cut
-=item VTABLE_get_string (vtable method)
+.namespace ['Range']
+.sub 'clone' :method :vtable
+ $P0 = self.'!cloneattr'('$!from $!to $!from_exclusive $!to_exclusive')
+ .return ($P0)
+.end
+
+=item iterator() (vtable function)
+
+Return an iterator for the Range. Since Ranges are already
+iterators, we can just return a clone.
+
=cut
+.sub 'iterator' :method :vtable('get_iter')
+ $P0 = clone self
+ .return ($P0)
+.end
+
+
+=item pop() (vtable_method)
+
+Generate the next element at the end of the Range.
+
+=cut
+
+.sub 'pop' :method :vtable('pop_pmc')
+ .local pmc to, toexc, value
+ to = getattribute self, '$!to'
+ toexc = getattribute self, '$!to_exclusive'
+ value = 'postfix:--'(to)
+ unless toexc goto have_value
+ value = clone to
+ have_value:
+ $I0 = self.'!from_test'(value)
+ if $I0 goto success
+ value = '!FAIL'('Undefined value popped from empty range')
+ success:
+ .return (value)
+.end
+
+
+=item shift() (vtable_method)
+
+Generate the next element at the front of the Range.
+
+=cut
+
+.sub 'shift' :method :vtable('shift_pmc')
+ .local pmc from, fromexc, value
+ from = getattribute self, '$!from'
+ fromexc = getattribute self, '$!from_exclusive'
+ value = 'postfix:++'(from)
+ unless fromexc goto have_value
+ value = clone from
+ have_value:
+ $I0 = self.'!to_test'(value)
+ if $I0 goto success
+ value = '!FAIL'('Undefined value shifted from empty range')
+ success:
+ .return (value)
+.end
+
+
+=item true()
+
+Return true if there are any more values to iterate over.
+
+=cut
+
+.sub 'true' :method :vtable('get_bool')
+ .local pmc from, fromexc
+ from = getattribute self, '$!from'
+ fromexc = getattribute self, '$!from_exclusive'
+ unless fromexc goto have_value
+ from = clone from
+ 'postfix:++'(from)
+ have_value:
+ $I0 = self.'!to_test'(from)
+ .return ($I0)
+.end
+
+
+=item VTABLE_get integer (vtable method)
+
+=cut
+
.sub 'VTABLE_get_integer' :method :vtable('get_integer')
- $P0 = self.'list'()
- $I0 = $P0
+ $I0 = self.'elems'()
.return ($I0)
.end
+
+=item VTABLE_get_number (vtable method)
+
+=cut
+
.sub 'VTABLE_get_number' :method :vtable('get_number')
- $P0 = self.'list'()
- $N0 = $P0
+ $N0 = self.'elems'()
.return ($N0)
.end
+
+=item VTABLE_get_string (vtable method)
+
+=cut
+
.sub 'VTABLE_get_string' :method :vtable('get_string')
+ .local string rv
+ .local int test
+
+ rv = ""
+ test = self.'!infinite'()
+ if test goto infinite
+
+ finite:
$P0 = self.'list'()
- $S0 = $P0
- .return ($S0)
+ rv = $P0
+ goto done
+
+ infinite:
+ $P0 = self.'from'()
+ $S0 = $P0.'perl'()
+
+ $P1 = self.'to'()
+ $S1 = $P0.'perl'()
+
+ rv .= $S0
+ rv .= ".."
+ rv .= $S1
+
+ goto done
+
+ done:
+ .return (rv)
.end
=back
|
From @cspencerAn updated version of the patch is attached that fixes a bug in the On Tue Dec 23 21:39:03 2008, cspencer wrote:
|
From @cspencerinfinite-range.patchIndex: src/classes/Range.pir
===================================================================
--- src/classes/Range.pir (revision 34313)
+++ src/classes/Range.pir (working copy)
@@ -61,24 +61,64 @@
.end
-=item clone() (vtable method)
+=item elems()
-Create a clone of the Range.
+Returns in the number of elements in the Range.
=cut
-.sub 'clone' :method :vtable
- $P0 = self.'!cloneattr'('$!from $!to $!from_exclusive $!to_exclusive')
- .return ($P0)
+.sub 'elems' :method
+ .local num elems
+ .local pmc from
+ .local pmc to
+
+ $P0 = self.'from'()
+ $P1 = self.'to'()
+
+ from = $P0.'clone'()
+ to = $P1.'clone'()
+
+ # Check if it's a null Range, returning 0 if so
+ $I0 = 'infix:cmp'(from, to)
+ if $I0 == 1 goto null_range
+
+ # Check if any of the end points are Inf, returning Inf if so
+ $I0 = self.'!infinite'()
+ if $I0 goto infinite_range
+
+ elems = 0
+
+ # If the start point is excluded in the Range, skip to the next
+ $I0 = self.'!from_test'(from)
+ if $I0 goto loop
+ $P0 = 'postfix:++'(from)
+
+ loop:
+ $P0 = 'postfix:++'(from)
+
+ $I0 = self.'!to_test'($P0)
+ unless $I0 goto done
+
+ inc elems
+ goto loop
+
+ null_range:
+ elems = 0
+ goto done
+
+ done:
+ .return (elems)
+
+ infinite_range:
+ $N0 = 'Inf'()
+ .return ($N0)
.end
=item from()
-=item to()
+Returns the beginning of the range.
-Gets the beginning or end of the range.
-
=cut
.sub 'from' :method
@@ -86,21 +126,39 @@
.return ($P0)
.end
-.sub 'to' :method
- $P0 = getattribute self, '$!to'
- .return ($P0)
+
+=item reverse()
+
+Returns a new Range with the to and from reversed.
+
+=cut
+
+.sub 'reverse' :method
+ .local pmc from
+ .local pmc fromexc
+ .local pmc to
+ .local pmc toexc
+ .local pmc proto
+
+ fromexc = getattribute self, '$!from_exclusive'
+ toexc = getattribute self, '$!to_exclusive'
+
+ from = self.'from'()
+ to = self.'to'()
+
+ proto = get_hll_global 'Range'
+ .tailcall proto.'new'('from'=>to, 'to'=>from, 'from_exclusive'=>toexc, 'to_exclusive'=>fromexc)
.end
-=item iterator() (vtable function)
+=item to()
-Return an iterator for the Range. Since Ranges are already
-iterators, we can just return a clone.
+Gets the beginning or end of the range.
=cut
-.sub 'iterator' :method :vtable('get_iter')
- $P0 = clone self
+.sub 'to' :method
+ $P0 = getattribute self, '$!to'
.return ($P0)
.end
@@ -113,38 +171,54 @@
=cut
+.namespace ['Range']
.sub 'list' :method
- .local pmc range_it, result
- range_it = self.'iterator'()
- result = new 'List'
- range_loop:
- unless range_it goto range_end
- $P0 = shift range_it
- push result, $P0
- goto range_loop
- range_end:
- .return (result)
+ .local int test
+ .local pmc it
+ .local pmc rv
+
+ test = self.'!infinite'()
+ if test goto infinite
+
+ it = self.'iterator'()
+ rv = new 'List'
+
+ loop:
+ unless it goto end
+ $P0 = shift it
+ push rv, $P0
+ goto loop
+
+ infinite:
+ rv = '!FAIL'("Can't convert an infinite range to a list (yet)")
+
+ end:
+ .return (rv)
.end
=item max()
-=item min()
-
-=item minmax()
-
=cut
-.namespace ['Range']
-
.sub 'max' :method
.tailcall self.'to'()
.end
+
+=item min()
+
+=cut
+
.sub 'min' :method
.tailcall self.'from'()
.end
+
+=item minmax()
+
+=cut
+
.sub 'minmax' :method
$P0 = self.'from'()
$P1 = self.'to'()
@@ -180,69 +254,6 @@
.end
-=item pop() (vtable_method)
-
-Generate the next element at the end of the Range.
-
-=cut
-
-.sub 'pop' :method :vtable('pop_pmc')
- .local pmc to, toexc, value
- to = getattribute self, '$!to'
- toexc = getattribute self, '$!to_exclusive'
- value = 'postfix:--'(to)
- unless toexc goto have_value
- value = clone to
- have_value:
- $I0 = self.'!from_test'(value)
- if $I0 goto success
- value = '!FAIL'('Undefined value popped from empty range')
- success:
- .return (value)
-.end
-
-
-=item shift() (vtable_method)
-
-Generate the next element at the front of the Range.
-
-=cut
-
-.sub 'shift' :method :vtable('shift_pmc')
- .local pmc from, fromexc, value
- from = getattribute self, '$!from'
- fromexc = getattribute self, '$!from_exclusive'
- value = 'postfix:++'(from)
- unless fromexc goto have_value
- value = clone from
- have_value:
- $I0 = self.'!to_test'(value)
- if $I0 goto success
- value = '!FAIL'('Undefined value shifted from empty range')
- success:
- .return (value)
-.end
-
-
-=item true()
-
-Return true if there are any more values to iterate over.
-
-=cut
-
-.sub 'true' :method :vtable('get_bool')
- .local pmc from, fromexc
- from = getattribute self, '$!from'
- fromexc = getattribute self, '$!from_exclusive'
- unless fromexc goto have_value
- from = clone from
- 'postfix:++'(from)
- have_value:
- $I0 = self.'!to_test'(from)
- .return ($I0)
-.end
-
-
=back
=head2 Operators
@@ -297,18 +308,19 @@
.tailcall proto.'new'('from'=>from, 'to'=>to, 'from_exclusive'=>true, 'to_exclusive'=>true)
.end
+
=item prefix:<^>(Any $to)
Construct a Range from C< 0 ..^ $to >.
=cut
-.namespace[]
.sub 'prefix:^' :multi(_)
.param num to
.tailcall 'infix:..^'(0, to)
.end
+
=item prefix:<^>(Type $x)
Return $x.HOW.
@@ -320,6 +332,7 @@
.tailcall proto.'HOW'()
.end
+
=back
=head2 Private methods
@@ -328,6 +341,8 @@
=item !flatten()
+Flattens the Range into a List.
+
=cut
.namespace ['Range']
@@ -335,34 +350,70 @@
.tailcall self.'list'()
.end
+
=item !from_test(topic)
-=item !to_test(topic)
+Returns true if C<topic> is greater than C<.from>, honoring exclusive flags.
-Returns true if C<topic> is greater than C<.from> / less than C<.to>,
-honoring exclusive flags.
-
=cut
-.namespace ['Range']
.sub '!from_test' :method
.param pmc topic
.local pmc from, fromexc
+
from = getattribute self, '$!from'
fromexc = getattribute self, '$!from_exclusive'
+
if fromexc goto exclusive_test
+
$I0 = isge topic, from
.return ($I0)
+
exclusive_test:
$I0 = isgt topic, from
.return ($I0)
.end
+
+=item !to_test(topic)
+
+Returns true if C<topic> is less than C<.to>, honoring exclusive flags.
+
+=cut
+
+.sub '!infinite' :method
+ .local int test
+ .local num inf
+
+ inf = 'Inf'()
+
+ $P0 = self.'from'()
+ $N0 = $P0
+ test = iseq $N0, inf
+ if test goto done
+
+ $P0 = self.'to'()
+ $N0 = $P0
+ test = iseq $N0, inf
+
+ done:
+ .return (test)
+.end
+
+
+=item !to_test(topic)
+
+Returns true if C<topic> is less than C<.to>, honoring exclusive flags.
+
+=cut
+
.sub '!to_test' :method
.param pmc topic
.local pmc to, toexc
+
to = getattribute self, '$!to'
$I0 = isa to, 'String'
+
unless $I0 goto test_value
$S0 = topic
$I0 = length $S0
@@ -371,46 +422,164 @@
eq $I0, $I1, test_value
$I0 = islt $I0, $I1
.return ($I0)
+
test_value:
toexc = getattribute self, '$!to_exclusive'
if toexc goto exclusive_test
$I0 = isle topic, to
.return ($I0)
+
exclusive_test:
$I0 = islt topic, to
.return ($I0)
.end
+
=back
=head2 Vtable functions
=over
-=item VTABLE_get integer (vtable method)
+=item clone() (vtable method)
-=item VTABLE_get_number (vtable method)
+=cut
-=item VTABLE_get_string (vtable method)
+.namespace ['Range']
+.sub 'clone' :method :vtable
+ $P0 = self.'!cloneattr'('$!from $!to $!from_exclusive $!to_exclusive')
+ .return ($P0)
+.end
+
+=item iterator() (vtable function)
+
+Return an iterator for the Range. Since Ranges are already
+iterators, we can just return a clone.
+
=cut
+.sub 'iterator' :method :vtable('get_iter')
+ $P0 = clone self
+ .return ($P0)
+.end
+
+
+=item pop() (vtable_method)
+
+Generate the next element at the end of the Range.
+
+=cut
+
+.sub 'pop' :method :vtable('pop_pmc')
+ .local pmc to, toexc, value
+ to = getattribute self, '$!to'
+ toexc = getattribute self, '$!to_exclusive'
+ value = 'postfix:--'(to)
+ unless toexc goto have_value
+ value = clone to
+ have_value:
+ $I0 = self.'!from_test'(value)
+ if $I0 goto success
+ value = '!FAIL'('Undefined value popped from empty range')
+ success:
+ .return (value)
+.end
+
+
+=item shift() (vtable_method)
+
+Generate the next element at the front of the Range.
+
+=cut
+
+.sub 'shift' :method :vtable('shift_pmc')
+ .local pmc from, fromexc, value
+ from = getattribute self, '$!from'
+ fromexc = getattribute self, '$!from_exclusive'
+ value = 'postfix:++'(from)
+ unless fromexc goto have_value
+ value = clone from
+ have_value:
+ $I0 = self.'!to_test'(value)
+ if $I0 goto success
+ value = '!FAIL'('Undefined value shifted from empty range')
+ success:
+ .return (value)
+.end
+
+
+=item true()
+
+Return true if there are any more values to iterate over.
+
+=cut
+
+.sub 'true' :method :vtable('get_bool')
+ .local pmc from, fromexc
+ from = getattribute self, '$!from'
+ fromexc = getattribute self, '$!from_exclusive'
+ unless fromexc goto have_value
+ from = clone from
+ 'postfix:++'(from)
+ have_value:
+ $I0 = self.'!to_test'(from)
+ .return ($I0)
+.end
+
+
+=item VTABLE_get integer (vtable method)
+
+=cut
+
.sub 'VTABLE_get_integer' :method :vtable('get_integer')
- $P0 = self.'list'()
- $I0 = $P0
+ $I0 = self.'elems'()
.return ($I0)
.end
+
+=item VTABLE_get_number (vtable method)
+
+=cut
+
.sub 'VTABLE_get_number' :method :vtable('get_number')
- $P0 = self.'list'()
- $N0 = $P0
+ $N0 = self.'elems'()
.return ($N0)
.end
+
+=item VTABLE_get_string (vtable method)
+
+=cut
+
.sub 'VTABLE_get_string' :method :vtable('get_string')
+ .local string rv
+ .local int test
+
+ rv = ""
+ test = self.'!infinite'()
+ if test goto infinite
+
+ finite:
$P0 = self.'list'()
- $S0 = $P0
- .return ($S0)
+ rv = $P0
+ goto done
+
+ infinite:
+ $P0 = self.'from'()
+ $S0 = $P0.'perl'()
+
+ $P1 = self.'to'()
+ $S1 = $P1.'perl'()
+
+ rv .= $S0
+ rv .= ".."
+ rv .= $S1
+
+ goto done
+
+ done:
+ .return (rv)
.end
=back
|
From @cspencerThis update to the patch adds support for Whatever objects in ranges. On Mon Dec 22 12:08:55 2008, pmichaud wrote:
|
From @cspencerinfinite-range.patchIndex: src/classes/Range.pir
===================================================================
--- src/classes/Range.pir (revision 34360)
+++ src/classes/Range.pir (working copy)
@@ -61,46 +61,126 @@
.end
-=item clone() (vtable method)
+=item elems()
-Create a clone of the Range.
+Returns in the number of elements in the Range.
=cut
-.sub 'clone' :method :vtable
- $P0 = self.'!cloneattr'('$!from $!to $!from_exclusive $!to_exclusive')
- .return ($P0)
+.sub 'elems' :method
+ .local num elems
+ .local pmc from
+ .local pmc to
+
+ $P0 = self.'from'()
+ $P1 = self.'to'()
+
+ from = $P0.'clone'()
+ to = $P1.'clone'()
+
+ # Check if it's a null Range, returning 0 if so
+ $I0 = 'infix:cmp'(from, to)
+ if $I0 == 1 goto null_range
+
+ # Check if any of the end points are Inf, returning Inf if so
+ $I0 = self.'!infinite'()
+ if $I0 goto infinite_range
+
+ elems = 0
+
+ # If the start point is excluded in the Range, skip to the next
+ $I0 = self.'!from_test'(from)
+ if $I0 goto loop
+ $P0 = 'postfix:++'(from)
+
+ loop:
+ $P0 = 'postfix:++'(from)
+
+ $I0 = self.'!to_test'($P0)
+ unless $I0 goto done
+
+ inc elems
+ goto loop
+
+ null_range:
+ elems = 0
+ goto done
+
+ done:
+ .return (elems)
+
+ infinite_range:
+ $N0 = 'Inf'()
+ .return ($N0)
.end
=item from()
-=item to()
+Returns the beginning of the range.
-Gets the beginning or end of the range.
-
=cut
.sub 'from' :method
$P0 = getattribute self, '$!from'
+
+ $I0 = isa $P0, "Whatever"
+ if $I0 goto whatever
+ goto done
+
+ whatever:
+ $N0 = "-Inf"
+ $P0 = new 'Num'
+ $P0 = $N0
+
+ done:
.return ($P0)
.end
-.sub 'to' :method
- $P0 = getattribute self, '$!to'
- .return ($P0)
+
+=item reverse()
+
+Returns a new Range with the to and from reversed.
+
+=cut
+
+.sub 'reverse' :method
+ .local pmc from
+ .local pmc fromexc
+ .local pmc to
+ .local pmc toexc
+ .local pmc proto
+
+ fromexc = getattribute self, '$!from_exclusive'
+ toexc = getattribute self, '$!to_exclusive'
+
+ from = self.'from'()
+ to = self.'to'()
+
+ proto = get_hll_global 'Range'
+ .tailcall proto.'new'('from'=>to, 'to'=>from, 'from_exclusive'=>toexc, 'to_exclusive'=>fromexc)
.end
-=item iterator() (vtable function)
+=item to()
-Return an iterator for the Range. Since Ranges are already
-iterators, we can just return a clone.
+Gets the beginning or end of the range.
=cut
-.sub 'iterator' :method :vtable('get_iter')
- $P0 = clone self
+.sub 'to' :method
+ $P0 = getattribute self, '$!to'
+
+ $I0 = isa $P0, "Whatever"
+ if $I0 goto whatever
+ goto done
+
+ whatever:
+ $N0 = "Inf"
+ $P0 = new 'Num'
+ $P0 = $N0
+
+ done:
.return ($P0)
.end
@@ -113,38 +193,54 @@
=cut
+.namespace ['Range']
.sub 'list' :method
- .local pmc range_it, result
- range_it = self.'iterator'()
- result = new 'List'
- range_loop:
- unless range_it goto range_end
- $P0 = shift range_it
- push result, $P0
- goto range_loop
- range_end:
- .return (result)
+ .local int test
+ .local pmc it
+ .local pmc rv
+
+ test = self.'!infinite'()
+ if test goto infinite
+
+ it = self.'iterator'()
+ rv = new 'List'
+
+ loop:
+ unless it goto end
+ $P0 = shift it
+ push rv, $P0
+ goto loop
+
+ infinite:
+ rv = '!FAIL'("Can't convert an infinite range to a list (yet)")
+
+ end:
+ .return (rv)
.end
=item max()
-=item min()
-
-=item minmax()
-
=cut
-.namespace ['Range']
-
.sub 'max' :method
.tailcall self.'to'()
.end
+
+=item min()
+
+=cut
+
.sub 'min' :method
.tailcall self.'from'()
.end
+
+=item minmax()
+
+=cut
+
.sub 'minmax' :method
$P0 = self.'from'()
$P1 = self.'to'()
@@ -162,87 +258,31 @@
.sub 'perl' :method
.local string result, tmp
.local pmc from, fromexc, toexc, to
+
from = getattribute self, '$!from'
fromexc = getattribute self, '$!from_exclusive'
toexc = getattribute self, '$!to_exclusive'
to = getattribute self, '$!to'
+
+ range_from:
result = from.'perl'()
- unless fromexc goto dots
+ unless fromexc goto range_dots
result .= '^'
- dots:
+
+ range_dots:
result .= '..'
- unless toexc goto end
+ unless toexc goto range_to
result .= '^'
- end:
+
+ range_to:
tmp = to.'perl'()
result .= tmp
+
+ done:
.return (result)
.end
-=item pop() (vtable_method)
-
-Generate the next element at the end of the Range.
-
-=cut
-
-.sub 'pop' :method :vtable('pop_pmc')
- .local pmc to, toexc, value
- to = getattribute self, '$!to'
- toexc = getattribute self, '$!to_exclusive'
- value = 'postfix:--'(to)
- unless toexc goto have_value
- value = clone to
- have_value:
- $I0 = self.'!from_test'(value)
- if $I0 goto success
- value = '!FAIL'('Undefined value popped from empty range')
- success:
- .return (value)
-.end
-
-
-=item shift() (vtable_method)
-
-Generate the next element at the front of the Range.
-
-=cut
-
-.sub 'shift' :method :vtable('shift_pmc')
- .local pmc from, fromexc, value
- from = getattribute self, '$!from'
- fromexc = getattribute self, '$!from_exclusive'
- value = 'postfix:++'(from)
- unless fromexc goto have_value
- value = clone from
- have_value:
- $I0 = self.'!to_test'(value)
- if $I0 goto success
- value = '!FAIL'('Undefined value shifted from empty range')
- success:
- .return (value)
-.end
-
-
-=item true()
-
-Return true if there are any more values to iterate over.
-
-=cut
-
-.sub 'true' :method :vtable('get_bool')
- .local pmc from, fromexc
- from = getattribute self, '$!from'
- fromexc = getattribute self, '$!from_exclusive'
- unless fromexc goto have_value
- from = clone from
- 'postfix:++'(from)
- have_value:
- $I0 = self.'!to_test'(from)
- .return ($I0)
-.end
-
-
=back
=head2 Operators
@@ -297,18 +337,19 @@
.tailcall proto.'new'('from'=>from, 'to'=>to, 'from_exclusive'=>true, 'to_exclusive'=>true)
.end
+
=item prefix:<^>(Any $to)
Construct a Range from C< 0 ..^ $to >.
=cut
-.namespace[]
.sub 'prefix:^' :multi(_)
.param num to
.tailcall 'infix:..^'(0, to)
.end
+
=item prefix:<^>(Type $x)
Return $x.HOW.
@@ -320,6 +361,7 @@
.tailcall proto.'HOW'()
.end
+
=back
=head2 Private methods
@@ -328,6 +370,8 @@
=item !flatten()
+Flattens the Range into a List.
+
=cut
.namespace ['Range']
@@ -335,34 +379,72 @@
.tailcall self.'list'()
.end
+
=item !from_test(topic)
-=item !to_test(topic)
+Returns true if C<topic> is greater than C<.from>, honoring exclusive flags.
-Returns true if C<topic> is greater than C<.from> / less than C<.to>,
-honoring exclusive flags.
-
=cut
-.namespace ['Range']
.sub '!from_test' :method
.param pmc topic
.local pmc from, fromexc
- from = getattribute self, '$!from'
+
+ from = self.'from'()
fromexc = getattribute self, '$!from_exclusive'
+
if fromexc goto exclusive_test
+
$I0 = isge topic, from
.return ($I0)
+
exclusive_test:
$I0 = isgt topic, from
.return ($I0)
.end
+
+=item !to_test(topic)
+
+Returns true if C<topic> is less than C<.to>, honoring exclusive flags.
+
+=cut
+
+.sub '!infinite' :method
+ .local int test
+ .local num inf
+
+ inf = 'Inf'()
+
+ $P0 = self.'from'()
+
+ $N0 = $P0
+ test = iseq $N0, inf
+ if test goto done
+
+ $P0 = self.'to'()
+
+ $N0 = $P0
+ test = iseq $N0, inf
+
+ done:
+ .return (test)
+.end
+
+
+=item !to_test(topic)
+
+Returns true if C<topic> is less than C<.to>, honoring exclusive flags.
+
+=cut
+
.sub '!to_test' :method
.param pmc topic
.local pmc to, toexc
- to = getattribute self, '$!to'
+
+ to = self.'to'()
$I0 = isa to, 'String'
+
unless $I0 goto test_value
$S0 = topic
$I0 = length $S0
@@ -371,46 +453,172 @@
eq $I0, $I1, test_value
$I0 = islt $I0, $I1
.return ($I0)
+
test_value:
toexc = getattribute self, '$!to_exclusive'
if toexc goto exclusive_test
$I0 = isle topic, to
.return ($I0)
+
exclusive_test:
$I0 = islt topic, to
.return ($I0)
.end
+
=back
=head2 Vtable functions
=over
-=item VTABLE_get integer (vtable method)
+=item clone() (vtable method)
-=item VTABLE_get_number (vtable method)
+=cut
-=item VTABLE_get_string (vtable method)
+.namespace ['Range']
+.sub 'clone' :method :vtable
+ $P0 = self.'!cloneattr'('$!from $!to $!from_exclusive $!to_exclusive')
+ .return ($P0)
+.end
+
+=item iterator() (vtable function)
+
+Return an iterator for the Range. Since Ranges are already
+iterators, we can just return a clone.
+
=cut
+.sub 'iterator' :method :vtable('get_iter')
+ $P0 = clone self
+ .return ($P0)
+.end
+
+
+=item pop() (vtable_method)
+
+Generate the next element at the end of the Range.
+
+=cut
+
+.sub 'pop' :method :vtable('pop_pmc')
+ .local pmc to, toexc, value
+ to = self.'to'()
+ toexc = getattribute self, '$!to_exclusive'
+ value = 'postfix:--'(to)
+ unless toexc goto have_value
+ value = clone to
+ have_value:
+ $I0 = self.'!from_test'(value)
+ if $I0 goto success
+ value = '!FAIL'('Undefined value popped from empty range')
+ success:
+ .return (value)
+.end
+
+
+=item shift() (vtable_method)
+
+Generate the next element at the front of the Range.
+
+=cut
+
+.sub 'shift' :method :vtable('shift_pmc')
+ .local pmc from
+ .local pmc fromexc
+ .local pmc value
+
+ from = self.'from'()
+ fromexc = getattribute self, '$!from_exclusive'
+
+ value = 'postfix:++'(from)
+ unless fromexc goto have_value
+ value = clone from
+
+ have_value:
+ $I0 = self.'!to_test'(value)
+ if $I0 goto success
+ value = '!FAIL'('Undefined value shifted from empty range')
+
+ success:
+ .return (value)
+.end
+
+
+=item true()
+
+Return true if there are any more values to iterate over.
+
+=cut
+
+.sub 'true' :method :vtable('get_bool')
+ .local pmc from, fromexc
+
+ from = self.'from'()
+ fromexc = getattribute self, '$!from_exclusive'
+ unless fromexc goto have_value
+
+ from = clone from
+ 'postfix:++'(from)
+
+ have_value:
+ $I0 = self.'!to_test'(from)
+ .return ($I0)
+.end
+
+
+=item VTABLE_get integer (vtable method)
+
+=cut
+
.sub 'VTABLE_get_integer' :method :vtable('get_integer')
- $P0 = self.'list'()
- $I0 = $P0
+ $I0 = self.'elems'()
.return ($I0)
.end
+
+=item VTABLE_get_number (vtable method)
+
+=cut
+
.sub 'VTABLE_get_number' :method :vtable('get_number')
- $P0 = self.'list'()
- $N0 = $P0
+ $N0 = self.'elems'()
.return ($N0)
.end
+
+=item VTABLE_get_string (vtable method)
+
+=cut
+
.sub 'VTABLE_get_string' :method :vtable('get_string')
+ .local string rv
+ .local int test
+
+ rv = ""
+ test = self.'!infinite'()
+ if test goto infinite
+
+ finite:
$P0 = self.'list'()
- $S0 = $P0
- .return ($S0)
+ rv = $P0
+ goto done
+
+ infinite:
+ $P0 = self.'from'()
+ $S0 = $P0.'perl'()
+
+ $P1 = self.'to'()
+ $S1 = $P1.'perl'()
+
+ rv .= $S0
+ rv .= ".."
+ rv .= $S1
+ goto done
+
+ done:
+ .return (rv)
.end
=back
|
From @pmichaudThank you very much for the patch contribution; since the time of the Thanks! Pm |
@pmichaud - Status changed from 'open' to 'resolved' |
Migrated from rt.perl.org#61618 (status was 'resolved')
Searchable as RT61618$
The text was updated successfully, but these errors were encountered: