Skip to content

Commit

Permalink
[Truffle] Implement String.new encoding argument
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon Fish committed Dec 8, 2016
1 parent 1cc597d commit e8cbcd7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 7 deletions.
1 change: 0 additions & 1 deletion spec/truffle/tags/core/string/new_tags.txt

This file was deleted.

Expand Up @@ -1271,41 +1271,66 @@ public int hash(DynamicObject string) {

}

@CoreMethod(names = "initialize", optional = 1, taintFrom = 1)
@CoreMethod(names = "initialize_internal", optional = 2, taintFrom = 1)

This comment has been minimized.

Copy link
@nirvdrum

nirvdrum Dec 8, 2016

Contributor

This should be marked @NonStandard.

This comment has been minimized.

Copy link
@eregon

eregon Dec 8, 2016

Member

and private if possible, to avoid exposing it to Ruby code (you need to remove the self. below).

This comment has been minimized.

Copy link
@bjfish

bjfish Dec 8, 2016

Contributor

@eregon Could you clarify what it means to "remove self below self" ?

This comment has been minimized.

Copy link
@eregon

eregon Dec 8, 2016

Member

I made it a primitive in efb62cd

This comment has been minimized.

Copy link
@eregon

eregon Dec 8, 2016

Member

@bjfish I was thinking private methods can only be called without the leading self.meth (just meth), but I think this changed in Ruby so it does not matter anymore.
The primitive seems cleaner here, do most of the logic in Ruby and just the part that needs access to Java code in Java.

public abstract static class InitializeNode extends CoreMethodArrayArgumentsNode {

@Child private IsFrozenNode isFrozenNode;
@Child private ToStrNode toStrNode;
@Child private CallDispatchHeadNode forceEncodingNode;

@Specialization
public DynamicObject initialize(DynamicObject self, NotProvided from) {
public DynamicObject initialize(DynamicObject self, NotProvided from, NotProvided encoding) {
return self;
}

@Specialization
public DynamicObject initializeJavaString(DynamicObject self, String from) {
public DynamicObject initializeJavaString(DynamicObject self, String from, NotProvided encoding) {
raiseIfFrozen(self);
StringOperations.setRope(self, StringOperations.encodeRope(from, ASCIIEncoding.INSTANCE));
return self;
}

@Specialization(guards = "isRubyString(from)")
public DynamicObject initialize(DynamicObject self, DynamicObject from) {
public DynamicObject initialize(DynamicObject self, DynamicObject from, NotProvided encoding) {
raiseIfFrozen(self);

StringOperations.setRope(self, rope(from));

return self;
}

@Specialization(guards = {"isRubyString(from)"})
public DynamicObject initialize(VirtualFrame frame, DynamicObject self, DynamicObject from, DynamicObject encoding) {
raiseIfFrozen(self);

StringOperations.setRope(self, rope(from));

if (forceEncodingNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
forceEncodingNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

return (DynamicObject) forceEncodingNode.call(frame, self, "force_encoding", encoding);
}

@Specialization(guards = { "!isRubyString(from)", "!isString(from)", "wasProvided(from)" })
public DynamicObject initialize(VirtualFrame frame, DynamicObject self, Object from, NotProvided encoding) {
if (toStrNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toStrNode = insert(ToStrNodeGen.create(getContext(), null, null));
}

return initialize(self, toStrNode.executeToStr(frame, from), NotProvided.INSTANCE);
}

@Specialization(guards = { "!isRubyString(from)", "!isString(from)", "wasProvided(from)" })
public DynamicObject initialize(VirtualFrame frame, DynamicObject self, Object from) {
public DynamicObject initialize(VirtualFrame frame, DynamicObject self, Object from, DynamicObject encoding) {
if (toStrNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toStrNode = insert(ToStrNodeGen.create(getContext(), null, null));
}

return initialize(self, toStrNode.executeToStr(frame, from));
return initialize(frame, self, toStrNode.executeToStr(frame, from), encoding);
}

protected void raiseIfFrozen(Object object) {
Expand Down
12 changes: 12 additions & 0 deletions truffle/src/main/ruby/core/string.rb
Expand Up @@ -1555,6 +1555,18 @@ def index(str, start=undefined)
m.character_index str, start
end

def initialize(other = undefined, encoding: undefined)

This comment has been minimized.

Copy link
@eregon

eregon Dec 8, 2016

Member

for this case it seems we should really have a way to have NotProvided.INSTANCE as a default value.

This comment has been minimized.

Copy link
@bjfish

bjfish Dec 8, 2016

Contributor

That could be nice, would it look something like this then?

def initialize(other = Truffle.not_provided, encoding: Truffle.not_provided)
  self.initialize_internal(other, encoding)
end

This comment has been minimized.

Copy link
@eregon

eregon Dec 8, 2016

Member

Yes, that was my thinking. Maybe even just not_provided.

if !undefined.equal?(other) && !undefined.equal?(encoding)
return self.initialize_internal(other, encoding)
elsif !undefined.equal?(other)
return self.initialize_internal(other)
elsif !undefined.equal?(encoding)
return self.initialize_internal("", encoding)
end

self.initialize_internal
end

def rindex(sub, finish=undefined)
if undefined.equal?(finish)
finish = size
Expand Down

0 comments on commit e8cbcd7

Please sign in to comment.