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: 62645daf8ad7
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5187aacfd92c
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Feb 27, 2015

  1. Copy the full SHA
    eb75ad4 View commit details
  2. Copy the full SHA
    975b9b7 View commit details
  3. Copy the full SHA
    5187aac View commit details
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/string/encode_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:String#encode when passed no options transcodes to Encoding.default_internal when set
fails:String#encode when passed no options transcodes a 7-bit String despite no generic converting being available
fails:String#encode when passed no options raises an Encoding::ConverterNotFoundError when no conversion is possible
fails:String#encode when passed to encoding transcodes a 7-bit String despite no generic converting being available
@@ -21,16 +20,13 @@ fails:String#encode when passed to, from, options calls #to_hash to convert the
fails:String#encode given the :xml => :text option replaces all instances of '&' with '&'
fails:String#encode given the :xml => :text option replaces all instances of '<' with '&lt;'
fails:String#encode given the :xml => :text option replaces all instances of '>' with '&gt;'
fails:String#encode given the :xml => :text option does not replace '"'
fails:String#encode given the :xml => :text option replaces undefined characters with their upper-case hexadecimal numeric character references
fails:String#encode given the :xml => :attr option surrounds the encoded text with double-quotes
fails:String#encode given the :xml => :attr option replaces all instances of '&' with '&amp;'
fails:String#encode given the :xml => :attr option replaces all instances of '<' with '&lt;'
fails:String#encode given the :xml => :attr option replaces all instances of '>' with '&gt;'
fails:String#encode given the :xml => :attr option replaces all instances of '"' with '&quot;'
fails:String#encode given the :xml => :attr option replaces undefined characters with their upper-case hexadecimal numeric character references
fails:String#encode when passed no options returns a copy when Encoding.default_internal is nil
fails:String#encode when passed no options returns a copy for a ASCII-only String when Encoding.default_internal is nil
fails:String#encode when passed options returns a copy when Encoding.default_internal is nil
fails:String#encode when passed options normalizes newlines
fails:String#encode when passed to, from returns a copy when both encodings are the same
53 changes: 0 additions & 53 deletions spec/truffle/tags/core/string/sub_tags.txt
Original file line number Diff line number Diff line change
@@ -1,72 +1,19 @@
fails:String#sub with pattern, replacement returns a copy of self with all occurrences of pattern replaced with replacement
fails:String#sub with pattern, replacement ignores a block if supplied
fails:String#sub with pattern, replacement supports \G which matches at the beginning of the string
fails:String#sub with pattern, replacement supports /i for ignoring case
fails:String#sub with pattern, replacement doesn't interpret regexp metacharacters if pattern is a string
fails:String#sub with pattern, replacement replaces \1 sequences with the regexp's corresponding capture
fails:String#sub with pattern, replacement treats \1 sequences without corresponding captures as empty strings
fails:String#sub with pattern, replacement replaces \& and \0 with the complete match
fails:String#sub with pattern, replacement replaces \` with everything before the current match
fails:String#sub with pattern, replacement replaces \' with everything after the current match
fails:String#sub with pattern, replacement replaces \\\+ with \\+
fails:String#sub with pattern, replacement replaces \+ with the last paren that actually matched
fails:String#sub with pattern, replacement treats \+ as an empty string if there was no captures
fails:String#sub with pattern, replacement maps \\ in replacement to \
fails:String#sub with pattern, replacement leaves unknown \x escapes in replacement untouched
fails:String#sub with pattern, replacement leaves \ at the end of replacement untouched
fails:String#sub with pattern, replacement taints the result if the original string or replacement is tainted
fails:String#sub with pattern, replacement tries to convert pattern to a string using to_str
fails:String#sub with pattern, replacement raises a TypeError when pattern can't be converted to a string
fails:String#sub with pattern, replacement tries to convert replacement to a string using to_str
fails:String#sub with pattern, replacement raises a TypeError when replacement can't be converted to a string
fails:String#sub with pattern, replacement returns subclass instances when called on a subclass
fails:String#sub with pattern, replacement sets $~ to MatchData of match and nil when there's none
fails:String#sub with pattern, replacement replaces \ with 
fails:String#sub with pattern, replacement replaces \\1 with \1
fails:String#sub with pattern, replacement replaces \\ with \
fails:String#sub with pattern and block returns a copy of self with the first occurrences of pattern replaced with the block's return value
fails:String#sub with pattern and block sets $~ for access from the block
fails:String#sub with pattern and block sets $~ to MatchData of last match and nil when there's none for access from outside
fails:String#sub with pattern and block doesn't raise a RuntimeError if the string is modified while substituting
fails:String#sub with pattern and block doesn't interpolate special sequences like \1 for the block's return value
fails:String#sub with pattern and block converts the block's return value to a string using to_s
fails:String#sub with pattern and block taints the result if the original string or replacement is tainted
fails:String#sub! with pattern, replacement modifies self in place and returns self
fails:String#sub! with pattern, replacement taints self if replacement is tainted
fails:String#sub! with pattern, replacement returns nil if no modifications were made
fails:String#sub! with pattern, replacement raises a RuntimeError when self is frozen
fails:String#sub! with pattern and block modifies self in place and returns self
fails:String#sub! with pattern and block sets $~ for access from the block
fails:String#sub! with pattern and block taints self if block's result is tainted
fails:String#sub! with pattern and block returns nil if no modifications were made
fails:String#sub! with pattern and block raises a RuntimeError if the string is modified while substituting
fails:String#sub! with pattern and block raises a RuntimeError when self is frozen
fails:String#sub with pattern and Hash returns a copy of self with the first occurrence of pattern replaced with the value of the corresponding hash key
fails:String#sub with pattern and Hash removes keys that don't correspond to matches
fails:String#sub with pattern and Hash ignores non-String keys
fails:String#sub with pattern and Hash uses a key's value only a single time
fails:String#sub with pattern and Hash uses the hash's default value for missing keys
fails:String#sub with pattern and Hash coerces the hash values with #to_s
fails:String#sub with pattern and Hash uses the hash's value set from default_proc for missing keys
fails:String#sub with pattern and Hash sets $~ to MatchData of first match and nil when there's none for access from outside
fails:String#sub with pattern and Hash doesn't interpolate special sequences like \1 for the block's return value
fails:String#sub with pattern and Hash untrusts the result if the original string is untrusted
fails:String#sub with pattern and Hash untrusts the result if a hash value is untrusted
fails:String#sub with pattern and Hash taints the result if the original string is tainted
fails:String#sub with pattern and Hash taints the result if a hash value is tainted
fails:String#sub! with pattern and Hash returns self with the first occurrence of pattern replaced with the value of the corresponding hash key
fails:String#sub! with pattern and Hash removes keys that don't correspond to matches
fails:String#sub! with pattern and Hash ignores non-String keys
fails:String#sub! with pattern and Hash uses a key's value only a single time
fails:String#sub! with pattern and Hash uses the hash's default value for missing keys
fails:String#sub! with pattern and Hash coerces the hash values with #to_s
fails:String#sub! with pattern and Hash uses the hash's value set from default_proc for missing keys
fails:String#sub! with pattern and Hash sets $~ to MatchData of first match and nil when there's none for access from outside
fails:String#sub! with pattern and Hash doesn't interpolate special sequences like \1 for the block's return value
fails:String#sub! with pattern and Hash keeps untrusted state
fails:String#sub! with pattern and Hash untrusts self if a hash value is untrusted
fails:String#sub! with pattern and Hash keeps tainted state
fails:String#sub! with pattern and Hash taints self if a hash value is tainted
fails:String#sub with pattern, replacement raises a TypeError when pattern is a Symbol
fails:String#sub with pattern, replacement raises a TypeError when pattern is an Array
fails:String#sub with pattern, replacement replaces \ with 
51 changes: 22 additions & 29 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/StringNodes.java
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@

import org.jcodings.Encoding;
import org.jcodings.specific.ASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
import org.joni.Matcher;
import org.joni.Option;
import org.joni.Region;
@@ -808,10 +809,11 @@ public boolean empty(RubyString string) {
}
}

@CoreMethod(names = "encode", required = 1, optional = 1)
@CoreMethod(names = "encode", optional = 2)
public abstract static class EncodeNode extends CoreMethodNode {

@Child private ToStrNode toStrNode;
@Child private EncodingNodes.DefaultInternalNode defaultInternalNode;

public EncodeNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
@@ -851,7 +853,7 @@ public RubyString encode(RubyString string, RubyEncoding encoding, @SuppressWarn
return getContext().toTruffle(jrubyTranscoded);
}

@Specialization(guards = { "!isRubyString(arguments[1])", "!isRubyEncoding(arguments[1])" })
@Specialization(guards = { "!isRubyString(arguments[1])", "!isRubyEncoding(arguments[1])", "!isUndefinedPlaceholder(arguments[1])" })
public RubyString encode(VirtualFrame frame, RubyString string, Object encoding, UndefinedPlaceholder options) {
notDesignedForCompilation();

@@ -862,6 +864,24 @@ public RubyString encode(VirtualFrame frame, RubyString string, Object encoding,

return encode(string, toStrNode.executeRubyString(frame, encoding), options);
}

@Specialization
public RubyString encode(RubyString string, @SuppressWarnings("unused") UndefinedPlaceholder encoding, @SuppressWarnings("unused") UndefinedPlaceholder options) {
notDesignedForCompilation();

if (defaultInternalNode == null) {
CompilerDirectives.transferToInterpreter();
defaultInternalNode = insert(EncodingNodesFactory.DefaultInternalNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{}));
}

final Object defaultInternalEncoding = defaultInternalNode.defaultInternal();

if (defaultInternalEncoding == getContext().getCoreLibrary().getNilObject()) {
return encode(string, RubyEncoding.getEncoding("UTF-8"), UndefinedPlaceholder.INSTANCE);
}

return encode(string, (RubyEncoding) defaultInternalEncoding, UndefinedPlaceholder.INSTANCE);
}
}

@CoreMethod(names = "encoding")
@@ -1535,33 +1555,6 @@ private RubyArray splitHelper(RubyString string, String sep) {
}
}

@CoreMethod(names = "sub", required = 2)
public abstract static class SubNode extends RegexpNodes.EscapingNode {

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

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

@Specialization
public RubyString sub(VirtualFrame frame, RubyString string, RubyString regexpString, RubyString replacement) {
notDesignedForCompilation();

final RubyRegexp regexp = new RubyRegexp(this, getContext().getCoreLibrary().getRegexpClass(), escape(frame, regexpString).getBytes(), Option.DEFAULT);
return sub(string, regexp, replacement);
}

@Specialization
public RubyString sub(RubyString string, RubyRegexp regexp, RubyString replacement) {
notDesignedForCompilation();

return regexp.sub(string.toString(), replacement.toString());
}
}

@CoreMethod(names = "succ")
public abstract static class SuccNode extends CoreMethodNode {

137 changes: 137 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/string.rb
Original file line number Diff line number Diff line change
@@ -410,6 +410,143 @@ def to_sub_replacement(result, match)
end
end

def sub(pattern, replacement=undefined)
# Because of the behavior of $~, this is duplicated from sub! because
# if we call sub! from sub, the last_match can't be updated properly.

unless valid_encoding?
raise ArgumentError, "invalid byte sequence in #{encoding}"
end

if undefined.equal? replacement
unless block_given?
return to_enum(:sub, pattern, replacement)
end
use_yield = true
tainted = false
else
tainted = replacement.tainted?
untrusted = replacement.untrusted?

unless replacement.kind_of?(String)
hash = Rubinius::Type.check_convert_type(replacement, Hash, :to_hash)
replacement = StringValue(replacement) unless hash
tainted ||= replacement.tainted?
untrusted ||= replacement.untrusted?
end
use_yield = false
end

pattern = Rubinius::Type.coerce_to_regexp(pattern, true) unless pattern.kind_of? Regexp
match = pattern.match_from(self, 0)

Regexp.last_match = match

ret = byteslice(0, 0) # Empty string and string subclass

if match
ret.append match.pre_match

if use_yield || hash
Regexp.last_match = match

if use_yield
val = yield match.to_s
else
val = hash[match.to_s]
end
untrusted = true if val.untrusted?
val = val.to_s unless val.kind_of?(String)

tainted ||= val.tainted?

ret.append val
else
replacement.to_sub_replacement(ret, match)
end

ret.append(match.post_match)
tainted ||= val.tainted?
else
return self
end

ret.taint if tainted
ret.untrust if untrusted

ret
end

def sub!(pattern, replacement=undefined)
# Because of the behavior of $~, this is duplicated from sub! because
# if we call sub! from sub, the last_match can't be updated properly.

unless valid_encoding?
raise ArgumentError, "invalid byte sequence in #{encoding}"
end

if undefined.equal? replacement
unless block_given?
return to_enum(:sub, pattern, replacement)
end
Rubinius.check_frozen
use_yield = true
tainted = false
else
Rubinius.check_frozen
tainted = replacement.tainted?
untrusted = replacement.untrusted?

unless replacement.kind_of?(String)
hash = Rubinius::Type.check_convert_type(replacement, Hash, :to_hash)
replacement = StringValue(replacement) unless hash
tainted ||= replacement.tainted?
untrusted ||= replacement.untrusted?
end
use_yield = false
end

pattern = Rubinius::Type.coerce_to_regexp(pattern, true) unless pattern.kind_of? Regexp
match = pattern.match_from(self, 0)

Regexp.last_match = match

ret = byteslice(0, 0) # Empty string and string subclass

if match
ret.append match.pre_match

if use_yield || hash
Regexp.last_match = match

if use_yield
val = yield match.to_s
else
val = hash[match.to_s]
end
untrusted = true if val.untrusted?
val = val.to_s unless val.kind_of?(String)

tainted ||= val.tainted?

ret.append val
else
replacement.to_sub_replacement(ret, match)
end

ret.append(match.post_match)
tainted ||= val.tainted?
else
return nil
end

ret.taint if tainted
ret.untrust if untrusted

replace(ret)
self
end

def start_with?(*prefixes)
prefixes.each do |original_prefix|
prefix = Rubinius::Type.check_convert_type original_prefix, String, :to_str