Skip to content

Commit 87b85ef

Browse files
committed
Update the chr_at primitive to return characters with the base string's actual encoding.
Over time we've veered away from what Rubinius's `chr_at` primitive does; it may make sense to just rename it. Given the big change in semantics I removed the pointer to the original Rubinius method because it'd just confuse any reader at this point. Attribution still appears in the copyright header. The change in semantics was necessary to get `String#inspect` to properly format strings with dummy encodings.
1 parent 9a843bc commit 87b85ef

File tree

1 file changed

+11
-10
lines changed

1 file changed

+11
-10
lines changed

src/main/java/org/truffleruby/core/string/StringNodes.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3200,42 +3200,43 @@ public Object stringByteSubstring(Object string, Object range, Object length) {
32003200
@ImportStatic(StringGuards.class)
32013201
public static abstract class StringChrAtPrimitiveNode extends CoreMethodArrayArgumentsNode {
32023202

3203-
@Child private StringByteSubstringPrimitiveNode stringByteSubstringNode = StringByteSubstringPrimitiveNode.create();
3204-
32053203
@Specialization(guards = "indexOutOfBounds(string, byteIndex)")
32063204
public Object stringChrAtOutOfBounds(DynamicObject string, int byteIndex) {
32073205
return nil();
32083206
}
32093207

32103208
@Specialization(guards = { "!indexOutOfBounds(string, byteIndex)", "isSingleByteOptimizable(string, singleByteOptimizableNode)" })
32113209
public Object stringChrAtSingleByte(DynamicObject string, int byteIndex,
3210+
@Cached("create()") StringByteSubstringPrimitiveNode stringByteSubstringNode,
32123211
@Cached("create()") RopeNodes.SingleByteOptimizableNode singleByteOptimizableNode) {
32133212
return stringByteSubstringNode.executeStringByteSubstring(string, byteIndex, 1);
32143213
}
32153214

32163215
@Specialization(guards = { "!indexOutOfBounds(string, byteIndex)", "!isSingleByteOptimizable(string, singleByteOptimizableNode)" })
32173216
public Object stringChrAt(DynamicObject string, int byteIndex,
3217+
@Cached("create()") EncodingNodes.GetActualEncodingNode getActualEncodingNode,
32183218
@Cached("create()") RopeNodes.BytesNode bytesNode,
32193219
@Cached("create()") RopeNodes.CalculateCharacterLengthNode calculateCharacterLengthNode,
32203220
@Cached("create()") RopeNodes.CodeRangeNode codeRangeNode,
3221-
@Cached("create()") RopeNodes.SingleByteOptimizableNode singleByteOptimizableNode) {
3222-
// Taken from Rubinius's Character::create_from.
3223-
3221+
@Cached("create()") RopeNodes.SingleByteOptimizableNode singleByteOptimizableNode,
3222+
@Cached("create()") MakeStringNode makeStringNode) {
32243223
final Rope rope = rope(string);
3224+
final Encoding encoding = getActualEncodingNode.execute(rope);
32253225
final int end = rope.byteLength();
3226-
final int c = calculateCharacterLengthNode.characterLength(rope.getEncoding(), codeRangeNode.execute(rope),
3227-
bytesNode.execute(rope), byteIndex, end);
3226+
final byte[] bytes = bytesNode.execute(rope);
3227+
final int c = calculateCharacterLengthNode.characterLength(encoding, codeRangeNode.execute(rope),
3228+
bytes, byteIndex, end);
32283229

32293230
if (!StringSupport.MBCLEN_CHARFOUND_P(c)) {
32303231
return nil();
32313232
}
32323233

3233-
final int n = StringSupport.MBCLEN_CHARFOUND_LEN(c);
3234-
if (n + byteIndex > end) {
3234+
if (c + byteIndex > end) {
32353235
return nil();
32363236
}
32373237

3238-
return stringByteSubstringNode.executeStringByteSubstring(string, byteIndex, n);
3238+
return makeStringNode.executeMake(
3239+
ArrayUtils.extractRange(bytes, byteIndex, byteIndex + c), encoding, CR_UNKNOWN);
32393240
}
32403241

32413242
protected static boolean indexOutOfBounds(DynamicObject string, int byteIndex) {

0 commit comments

Comments
 (0)