Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9f98c9e62021
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 7b526f131c98
Choose a head ref
  • 5 commits
  • 9 files changed
  • 1 contributor

Commits on Mar 16, 2015

  1. Copy the full SHA
    369d2fe View commit details
  2. Copy the full SHA
    08a1cfb View commit details
  3. Copy the full SHA
    4ff3c8e View commit details
  4. Copy the full SHA
    87df296 View commit details
  5. Copy the full SHA
    7b526f1 View commit details
18 changes: 0 additions & 18 deletions spec/truffle/tags/core/string/chomp_tags.txt

This file was deleted.

118 changes: 38 additions & 80 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/StringNodes.java
Original file line number Diff line number Diff line change
@@ -666,50 +666,6 @@ public int byteSize(RubyString string) {

}

@CoreMethod(names = "chomp!", optional = 1, raiseIfFrozenSelf = true)
public abstract static class ChompBangNode extends CoreMethodNode {

@Child private ToStrNode toStrNode;

public ChompBangNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public ChompBangNode(ChompBangNode prev) {
super(prev);
}

@Specialization
public Object chompBang(RubyString string, UndefinedPlaceholder undefined) {
notDesignedForCompilation();

if (string.length() == 0) {
return nil();
}

string.set(StringNodesHelper.chomp(string));
return string;
}

@Specialization
public RubyNilClass chompBangWithNil(RubyString string, RubyNilClass stringToChomp) {
return nil();
}

@Specialization(guards = { "!isUndefinedPlaceholder(arguments[1])", "!isRubyNilClass(arguments[1])" })
public RubyString chompBangWithString(VirtualFrame frame, RubyString string, Object stringToChomp) {
notDesignedForCompilation();

if (toStrNode == null) {
CompilerDirectives.transferToInterpreter();
toStrNode = insert(ToStrNodeFactory.create(getContext(), getSourceSection(), null));
}

string.set(StringNodesHelper.chompWithString(string, toStrNode.executeRubyString(frame, stringToChomp)));
return string;
}
}

@CoreMethod(names = "chop!", raiseIfFrozenSelf = true)
public abstract static class ChopBangNode extends CoreMethodNode {

@@ -1419,6 +1375,44 @@ public Object match(VirtualFrame frame, RubyString string, RubyRegexp regexp) {
}
}

@RubiniusOnly
@CoreMethod(names = "modify!")
public abstract static class ModifyBangNode extends CoreMethodNode {

public ModifyBangNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public ModifyBangNode(ModifyBangNode prev) {
super(prev);
}

@Specialization
public RubyString modifyBang(RubyString string) {
string.modify();
return string;
}
}

@RubiniusOnly
@CoreMethod(names = "num_bytes=", required = 1)
public abstract static class SetNumBytesNode extends CoreMethodNode {

public SetNumBytesNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public SetNumBytesNode(SetNumBytesNode prev) {
super(prev);
}

@Specialization
public RubyString setNumBytes(RubyString string, int count) {
string.getByteList().view(0, count);
return string;
}
}

@CoreMethod(names = "ord")
public abstract static class OrdNode extends CoreMethodNode {

@@ -2163,24 +2157,6 @@ public static ByteList downcase(RubyString string) {
return newByteList;
}

@TruffleBoundary
public static ByteList chomp(RubyString string) {
String javaString = string.toString();
if (javaString.endsWith("\r")) {
String newString = javaString.substring(0, javaString.length()-1);
ByteList byteListString = ByteList.create(newString);
byteListString.setEncoding(string.getBytes().getEncoding());

return byteListString;
} else {
ByteList byteListString = ByteList.create(javaString.trim());
byteListString.setEncoding(string.getBytes().getEncoding());

return byteListString;
}

}

@TruffleBoundary
public static ByteList chompWithString(RubyString string, RubyString stringToChomp) {

@@ -2227,22 +2203,4 @@ public static ByteList swapcase(RubyString string) {
}
}

@CoreMethod(names = "_set_num_bytes", required = 1)
public abstract static class SetNumBytesNode extends CoreMethodNode {

public SetNumBytesNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public SetNumBytesNode(SetNumBytesNode prev) {
super(prev);
}

@Specialization
public RubyString setNumBytes(RubyString string, int count) {
string.getByteList().view(0, count);
return string;
}
}

}
Original file line number Diff line number Diff line change
@@ -84,6 +84,23 @@
*/
public abstract class StringPrimitiveNodes {

@RubiniusPrimitive(name = "character_ascii_p")
public static abstract class CharacterAsciiPrimitiveNode extends RubiniusPrimitiveNode {

public CharacterAsciiPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public CharacterAsciiPrimitiveNode(CharacterAsciiPrimitiveNode prev) {
super(prev);
}

@Specialization
public boolean isCharacterAscii(RubyString character) {
return StringSupport.isAsciiOnly(character);
}
}

@RubiniusPrimitive(name = "string_awk_split")
public static abstract class StringAwkSplitPrimitiveNode extends RubiniusPrimitiveNode {

@@ -285,6 +302,112 @@ public boolean stringCheckNullSafe(RubyString string) {

}

@RubiniusPrimitive(name = "string_chr_at")
public static abstract class StringChrAtPrimitiveNode extends RubiniusPrimitiveNode {

@Child private StringByteSubstringPrimitiveNode stringByteSubstringNode;

public StringChrAtPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public StringChrAtPrimitiveNode(StringChrAtPrimitiveNode prev) {
super(prev);
stringByteSubstringNode = prev.stringByteSubstringNode;
}

@CompilerDirectives.TruffleBoundary
@Specialization
public Object stringChrAt(RubyString string, int byteIndex) {
if (stringByteSubstringNode == null) {
CompilerDirectives.transferToInterpreter();

stringByteSubstringNode = insert(
StringPrimitiveNodesFactory.StringByteSubstringPrimitiveNodeFactory.create(
getContext(),
getSourceSection(),
new RubyNode[]{})
);
}

final ByteList bytes = string.getByteList();
final int p = bytes.getBegin();
final int end = p + bytes.getRealSize();
final int c = StringSupport.preciseLength(bytes.getEncoding(), bytes.getUnsafeBytes(), p, end);

if (! StringSupport.MBCLEN_CHARFOUND_P(c)) {
return getContext().getCoreLibrary().getNilObject();
}

final int n = StringSupport.MBCLEN_CHARFOUND_LEN(c);
if (n + byteIndex > end) {
return getContext().getCoreLibrary().getNilObject();
}

return stringByteSubstringNode.stringByteSubstring(string, byteIndex, n);
}

}

@RubiniusPrimitive(name = "string_compare_substring")
public static abstract class StringCompareSubstringPrimitiveNode extends RubiniusPrimitiveNode {

private final ConditionProfile startTooLargeProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile startTooSmallProfile = ConditionProfile.createBinaryProfile();

public StringCompareSubstringPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public StringCompareSubstringPrimitiveNode(StringCompareSubstringPrimitiveNode prev) {
super(prev);
}

@Specialization
public int stringCompareSubstring(RubyString string, RubyString other, int start, int size) {
// Transliterated from Rubinius C++.

if (start < 0) {
start += other.length();
}

if (startTooLargeProfile.profile(start > other.length())) {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(
getContext().getCoreLibrary().indexError(
String.format("index %d out of string", start),
this
));
}

if (startTooSmallProfile.profile(start < 0)) {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(
getContext().getCoreLibrary().indexError(
String.format("index %d out of string", start),
this
));
}

if (start + size > other.length()) {
size = other.length() - start;
}

if (size > string.length()) {
size = string.length();
}

final ByteList bytes = string.getByteList();
final ByteList otherBytes = other.getByteList();

return ByteList.memcmp(bytes.getUnsafeBytes(), bytes.getBegin(), size,
otherBytes.getUnsafeBytes(), otherBytes.getBegin() + start, size);
}

}

@RubiniusPrimitive(name = "string_equal", needsSelf = true)
public static abstract class StringEqualPrimitiveNode extends RubiniusPrimitiveNode {

@@ -559,7 +682,7 @@ public Object stringByteIndex(RubyString string, int characters, int start) {

}

@RubiniusPrimitive(name = "string_previous_byte_index", needsSelf = false)
@RubiniusPrimitive(name = "string_previous_byte_index")
public static abstract class StringPreviousByteIndexPrimitiveNode extends RubiniusPrimitiveNode {

public StringPreviousByteIndexPrimitiveNode(RubyContext context, SourceSection sourceSection) {
@@ -571,8 +694,27 @@ public StringPreviousByteIndexPrimitiveNode(StringPreviousByteIndexPrimitiveNode
}

@Specialization
public Object stringPreviousByteIndex(RubyString string, Object indexedString, Object start) {
throw new UnsupportedOperationException("string_previous_byte_index");
public Object stringPreviousByteIndex(RubyString string, int index) {
if (index < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("negative index given", this));
}

final ByteList bytes = string.getByteList();
final int p = bytes.getBegin();
final int end = p + bytes.getRealSize();

if (p > end) {
return 0;
}

final int s = bytes.getEncoding().prevCharHead(bytes.getUnsafeBytes(), p, p + index, end);

if (s == -1) {
return 0;
}

return s - p;
}

}
Original file line number Diff line number Diff line change
@@ -1538,6 +1538,15 @@ public RubyNode visitInstAsgnNode(org.jruby.ast.InstAsgnNode node) {
}
}

if (sourceSection.getSource().getPath().equals("core:/core/rubinius/bootstrap/string.rb") ||
sourceSection.getSource().getPath().equals("core:/core/rubinius/common/string.rb")) {

if (name.equals("@hash")) {
return StringNodesFactory.ModifyBangNodeFactory.create(context, sourceSection, new RubyNode[]{});
}
}


return new WriteInstanceVariableNode(context, sourceSection, name, self, rhs, false);
}

1 change: 1 addition & 0 deletions truffle/src/main/ruby/core.rb
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
# Load bootstrap (ordered according to Rubinius' load_order.txt)
require_relative 'core/rubinius/bootstrap/basic_object'
require_relative 'core/rubinius/bootstrap/mirror'
require_relative 'core/rubinius/bootstrap/character'
require_relative 'core/rubinius/bootstrap/false'
require_relative 'core/rubinius/bootstrap/gc'
require_relative 'core/rubinius/bootstrap/kernel'
40 changes: 40 additions & 0 deletions truffle/src/main/ruby/core/rubinius/bootstrap/character.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright (c) 2007-2014, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Only part of Rubinius's character.rb

# We use String throughout, rather than Rubinius::Character. As such, we're adding the Rubinius::Character methods
# to String for simplicity. However, the Rubinius::Character methods are being added here to better match the
# Rubinius code layout.

class String

def ascii?
Rubinius.primitive :character_ascii_p
raise PrimitiveFailure, "Rubinius::Character#ascii? primitive failed"
end

end
7 changes: 6 additions & 1 deletion truffle/src/main/ruby/core/rubinius/bootstrap/string.rb
Original file line number Diff line number Diff line change
@@ -43,6 +43,11 @@ def find_string(pattern, start)
raise PrimitiveFailure, "String#find_string primitive failed"
end

def chr_at(byte)
Rubinius.primitive :string_chr_at
raise ArgumentError, "String#chr_at primitive failed"
end

def byteslice(index_or_range, length=undefined)
Rubinius.primitive :string_byte_substring

@@ -90,4 +95,4 @@ def byte_append(str)
raise TypeError, "String#byte_append primitive only accepts Strings"
end

end
end
82 changes: 82 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/string.rb
Original file line number Diff line number Diff line change
@@ -26,6 +26,10 @@

# Only part of Rubinius' string.rb

# Default Ruby Record Separator
# Used in this file and by various methods that need to ignore $/
DEFAULT_RECORD_SEPARATOR = "\n"

class String

def include?(needle)
@@ -62,6 +66,75 @@ def chars
end
end


def chomp!(sep=undefined)
Rubinius.check_frozen

if undefined.equal?(sep)
sep = $/
elsif sep
sep = StringValue(sep)
end

return if sep.nil?

m = Rubinius::Mirror.reflect self

if sep == DEFAULT_RECORD_SEPARATOR
return unless bytes = m.previous_byte_index(@num_bytes)

chr = chr_at bytes
return unless chr.ascii?

case chr.ord
when 13
# do nothing
when 10
if j = m.previous_byte_index(bytes)
chr = chr_at j

if chr.ord == 13 and chr.ascii?
bytes = j
end
end
else
return
end
elsif sep.size == 0
return if @num_bytes == 0
bytes = @num_bytes

while i = m.previous_byte_index(bytes)
chr = chr_at i
break unless chr.ord == 10 and chr.ascii?

bytes = i

if j = m.previous_byte_index(i)
chr = chr_at j
if chr.ord == 13 and chr.ascii?
bytes = j
end
end
end

return if bytes == @num_bytes
else
size = sep.size
return if size > @num_bytes

# TODO: Move #compare_substring to mirror.
return unless sep.compare_substring(self, -size, size) == 0
bytes = @num_bytes - size
end

# We do not need to dup the data, so don't use #modify!
@hash_value = nil
self.num_bytes = bytes

self
end

def chomp(separator=$/)
str = dup
str.chomp!(separator) || str
@@ -658,6 +731,15 @@ def to_inum(base, check)
raise ArgumentError, "invalid value for Integer"
end

def compare_substring(other, start, size)
Rubinius.primitive :string_compare_substring

if start > @num_bytes || start + @num_bytes < 0
raise IndexError, "index #{start} out of string"
end
raise PrimitiveFailure, "String#compare_substring primitive failed"
end

def self.try_convert(obj)
Rubinius::Type.try_convert obj, String, :to_str
end
12 changes: 0 additions & 12 deletions truffle/src/main/ruby/core/shims.rb
Original file line number Diff line number Diff line change
@@ -193,18 +193,6 @@ def [](index)
end
end

class String

def modify!
# TODO CS 14-Mar-15 what does this do?
end

def num_bytes=(count)
_set_num_bytes count
end

end

class IO

RDONLY = 0