Skip to content

Commit

Permalink
Rewrite the Actions handling of dec_number (ie Rat and Num constants)…
Browse files Browse the repository at this point in the history
… to work properly if the various components of the number are too long to hold in an Int.

Still needed:
Cleanup.
Porting this solution to Int constants.
Making prefix:<+>(Str) use these methods.
  • Loading branch information
colomon committed Jun 26, 2010
1 parent 6769e19 commit 1424333
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 28 deletions.
39 changes: 11 additions & 28 deletions src/Perl6/Actions.pm
Expand Up @@ -2330,37 +2330,20 @@ method numish($/) {
}

method dec_number($/) {
my $int := $<int> ?? $<int>.ast !! 0;
my $frac := $<frac> ?? $<frac>.ast !! 0;
my $base := Q:PIR {
$P0 = find_lex '$/'
$S0 = $P0['frac']
$I1 = length $S0
$I0 = 0
$I2 = 1
loop:
unless $I0 < $I1 goto done
$S1 = substr $S0, $I0, 1
inc $I0
if $S1 == '_' goto loop
$I2 *= 10
goto loop
done:
%r = box $I2
};
my $int := $<int> ?? ~$<int> !! "0";
my $frac := $<frac> ?? ~$<frac> !! "0";
if $<escale> {
my $exp := $<escale>[0]<decint>.ast;
if $<escale>[0]<sign> eq '-' { $exp := -$exp; }
make PAST::Val.new(
:value(($int * $base + $frac) / $base * 10 ** +$exp ) ,
:returns('Num')
my $exp := ~$<escale>[0]<decint>;
make PAST::Op.new(
:pasttype('call'),
PAST::Var.new(:scope('package'), :name('&str2num-num'), :namespace('Str')),
0, $int, $frac, ($<escale>[0]<sign> eq '-'), $exp
);
}
else {
} else {
make PAST::Op.new(
:pasttype('callmethod'), :name('new'),
PAST::Var.new( :name('Rat'), :namespace(''), :scope('package') ),
$int * $base + $frac, $base, :node($/)
:pasttype('call'),
PAST::Var.new(:scope('package'), :name('&str2num-rat'), :namespace('Str')),
0, $int, $frac
);
}
}
Expand Down
77 changes: 77 additions & 0 deletions src/core/Str.pm
Expand Up @@ -42,4 +42,81 @@ augment class Str does Stringy {
};
return Buf.new(@bytes);
}

our sub str2num-int($src) {
Q:PIR {
.local pmc src
.local string src_s
src = find_lex '$src'
src_s = src
.local int pos, eos
.local num result
pos = 0
eos = length src_s
result = 0
str_loop:
unless pos < eos goto str_done
.local string char
char = substr src_s, pos, 1
if char == '_' goto str_next
.local int digitval
digitval = index "0123456789", char
if digitval < 0 goto err_base
if digitval >= 10 goto err_base
result *= 10
result += digitval
str_next:
inc pos
goto str_loop
err_base:
src.'panic'('Invalid radix conversion of "', char, '"')
str_done:
%r = box result
};
}

our sub str2num-base($src) {
Q:PIR {
.local pmc src
.local string src_s
src = find_lex '$src'
src_s = src
.local int pos, eos
.local num result
pos = 0
eos = length src_s
result = 1
str_loop:
unless pos < eos goto str_done
.local string char
char = substr src_s, pos, 1
if char == '_' goto str_next
result *= 10
str_next:
inc pos
goto str_loop
err_base:
src.'panic'('Invalid radix conversion of "', char, '"')
str_done:
%r = box result
};
}

our sub str2num-rat($negate, $int-part, $frac-part is copy) is export {
$frac-part.=subst(/(\d)0+$/, { ~$_[0] });
my $result = upgrade_to_num_if_needed(str2num-int($int-part))
+ upgrade_to_num_if_needed(str2num-int($frac-part))
/ upgrade_to_num_if_needed(str2num-base($frac-part));
$result = -$result if $negate;
$result;
}

our sub str2num-num($negate, $int-part, $frac-part, $exp-part-negate, $exp-part) is export {
my $exp = str2num-int($exp-part);
$exp = -$exp if $exp-part-negate;
my $result = (str2num-int($int-part) + str2num-int($frac-part) / str2num-base($frac-part))
* 10 ** $exp;
$result = -$result if $negate;
$result;
}
}

0 comments on commit 1424333

Please sign in to comment.