3
augment class Str does Stringy {
5
multi method Bool { ?(pir::istrue__IP(self)); }
9
my @KNOWN_ENCODINGS = <utf-8 iso-8859-1 ascii>;
11
# XXX: We have no $?ENC or $?NF compile-time constants yet.
12
multi method encode($encoding is copy = 'utf-8', $nf = '') {
13
if $encoding eq 'latin-1' {
14
$encoding = 'iso-8859-1';
16
die "Unknown encoding $encoding"
17
unless $encoding.lc eq any @KNOWN_ENCODINGS;
21
.local pmc bytebuffer, it, result
24
$P1 = find_lex '$encoding'
26
if $S1 == 'ascii' goto transcode_ascii
27
if $S1 == 'iso-8859-1' goto transcode_iso_8859_1
28
# NOTE: There's an assumption here, that all strings coming in
29
# from the rest of Rakudo are always in UTF-8 form. Don't
30
# know if this assumption always holds; to be on the safe
31
# side, we might transcode even to UTF-8.
32
goto finished_transcoding
34
$I0 = find_encoding 'ascii'
35
$S0 = trans_encoding $S0, $I0
36
goto finished_transcoding
38
$I0 = find_encoding 'iso-8859-1'
39
$S0 = trans_encoding $S0, $I0
41
bytebuffer = new ['ByteBuffer']
44
result = new ['Parcel']
54
return Buf.new(@bytes);
57
# Zero indent does nothing
58
multi method indent($steps as Int where { $_ == 0 }) {
62
# Positive indent does indent
63
multi method indent($steps as Int where { $_ > 0 }) {
64
# We want to keep trailing \n so we have to .comb explicitly instead of .lines
65
return self.comb(/:r ^^ \N* \n?/).map({
67
# Use the existing space character if they're all the same
68
# (but tabs are done slightly differently)
69
when /^(\t+) ([ \S .* | $ ])/ {
70
$0 ~ "\t" x ($steps div $?TABSTOP) ~
71
' ' x ($steps mod $?TABSTOP) ~ $1
73
when /^(\h) $0* [ \S | $ ]/ {
77
# Otherwise we just insert spaces after the existing leading space
79
($_ ~~ /^(\h*) (.*)$/).join(' ' x $steps)
85
# Negative values and Whatever-* do outdent
86
multi method indent($steps) {
87
# Loop through all lines to get as much info out of them as possible
88
my @lines = self.comb(/:r ^^ \N* \n?/).map({
89
# Split the line into indent and content
90
my ($indent, $rest) = @($_ ~~ /^(\h*) (.*)$/);
92
# Split the indent into characters and annotate them
93
# with their visual size
95
my @indent-chars = $indent.comb.map(-> $char {
96
my $width = $char eq "\t"
97
?? $?TABSTOP - ($indent-size mod $?TABSTOP)
99
$indent-size += $width;
103
{ :$indent-size, :@indent-chars, :$rest };
106
# Figure out the amount * should outdent by, we also use this for warnings
107
my $common-prefix = [min] @lines.map({ $_<indent-size> });
109
# Set the actual outdent amount here
110
my Int $outdent = $steps ~~ Whatever ?? $common-prefix
113
warn sprintf('Asked to remove %d spaces, ' ~
114
'but the shortest indent is %d spaces',
115
$outdent, $common-prefix) if $outdent > $common-prefix;
117
# Work backwards from the right end of the indent whitespace, removing
118
# array elements up to # (or over, in the case of tab-explosion)
119
# the specified outdent amount.
122
while $_<indent-chars> and $pos < $outdent {
123
$pos += $_<indent-chars>.pop.value;
125
$_<indent-chars>».key.join ~ ' ' x ($pos - $outdent) ~ $_<rest>;
129
our sub str2num-int($src) {
133
src = find_lex '$src'
141
unless pos < eos goto str_done
143
char = substr src_s, pos, 1
144
if char == '_' goto str_next
146
digitval = index "0123456789", char
147
if digitval < 0 goto err_base
148
if digitval >= 10 goto err_base
155
src.'panic'('Invalid radix conversion of "', char, '"')
161
our sub str2num-base($src) {
165
src = find_lex '$src'
173
unless pos < eos goto str_done
175
char = substr src_s, pos, 1
176
if char == '_' goto str_next
182
src.'panic'('Invalid radix conversion of "', char, '"')
188
sub chop-trailing-zeros($i) {
195
if idx == 0 goto done
197
$S1 = substr $S0, idx, 1
198
if $S1 == '0' goto repl_loop
201
$S0 = substr $S0, 0, idx
207
our sub str2num-rat($negate, $int-part, $frac-part is copy) is export {
208
$frac-part = chop-trailing-zeros($frac-part);
209
my $result = upgrade_to_num_if_needed(str2num-int($int-part))
210
+ upgrade_to_num_if_needed(str2num-int($frac-part))
211
/ upgrade_to_num_if_needed(str2num-base($frac-part));
212
$result = -$result if $negate;
216
our sub str2num-num($negate, $int-part, $frac-part, $exp-part-negate, $exp-part) is export {
217
my $exp = str2num-int($exp-part);
218
$exp = -$exp if $exp-part-negate;
219
my $result = (str2num-int($int-part) + str2num-int($frac-part) / str2num-base($frac-part))
221
$result = -$result if $negate;