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: c3ad29072fe9
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 256c8ce61cad
Choose a head ref
  • 2 commits
  • 8 files changed
  • 1 contributor

Commits on Oct 13, 2015

  1. Copy the full SHA
    b546429 View commit details
  2. Copy the full SHA
    256c8ce View commit details
6 changes: 0 additions & 6 deletions spec/truffle/tags/core/string/modulo_tags.txt
Original file line number Diff line number Diff line change
@@ -80,9 +80,3 @@ fails:String#% behaves as if calling Kernel#Float for %g arguments, when the pas
fails:String#% behaves as if calling Kernel#Float for %g arguments, when the passed argument is hexadecimal string
fails:String#% behaves as if calling Kernel#Float for %G arguments, when the passed argument does not respond to #to_ary
fails:String#% behaves as if calling Kernel#Float for %G arguments, when the passed argument is hexadecimal string
fails:String#% when format string contains %{} sections replaces %{} sections with values from passed-in hash
fails:String#% when format string contains %{} sections raises KeyError if key is missing from passed-in hash
fails:String#% when format string contains %{} sections should raise ArgumentError if no hash given
fails:String#% when format string contains %<> formats uses the named argument for the format's value
fails:String#% when format string contains %<> formats raises KeyError if key is missing from passed-in hash
fails:String#% when format string contains %<> formats should raise ArgumentError if no hash given
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.format.nodes.read;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.format.nodes.PackNode;
import org.jruby.truffle.format.nodes.SourceNode;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.hash.HashNodes;
import org.jruby.truffle.nodes.core.hash.HashNodesFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;

@NodeChildren({
@NodeChild(value = "source", type = SourceNode.class),
})
public abstract class ReadHashValueNode extends PackNode {

private final Object key;

public ReadHashValueNode(RubyContext context, Object key) {
super(context);
this.key = key;
}

@Specialization
@CompilerDirectives.TruffleBoundary
public Object read(Object[] source) {
if (source.length != 1 || !RubyGuards.isRubyHash(source[0])) {
throw new RaiseException(getContext().getCoreLibrary().argumentError("one hash required", this));
}

// We're not in a Ruby frame here, so we can't run arbitrary Ruby nodes like Hash#[]. Instead use a slow send.

return getContext().send(source[0], "fetch", null, key);
}

}
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ public ReadStringNode(RubyContext context, boolean convertNumbersToStrings,
}

@Specialization(guards = "isNull(source)")
public long read(VirtualFrame frame, Object source) {
public Object read(VirtualFrame frame, Object source) {
CompilerDirectives.transferToInterpreter();

// Advance will handle the error
Original file line number Diff line number Diff line change
@@ -23,13 +23,15 @@ public class FormatDirective {
private final boolean leftJustified;
private final int precision;
private final char type;
private final Object key;

public FormatDirective(int spacePadding, int zeroPadding, boolean leftJustified, int precision, char type) {
public FormatDirective(int spacePadding, int zeroPadding, boolean leftJustified, int precision, char type, Object key) {
this.spacePadding = spacePadding;
this.zeroPadding = zeroPadding;
this.leftJustified = leftJustified;
this.precision = precision;
this.type = type;
this.key = key;
}

public int getSpacePadding() {
@@ -52,4 +54,7 @@ public char getType() {
return type;
}

public Object getKey() {
return key;
}
}
Original file line number Diff line number Diff line change
@@ -18,10 +18,12 @@
import org.jruby.truffle.format.nodes.format.FormatFloatNodeGen;
import org.jruby.truffle.format.nodes.format.FormatIntegerNodeGen;
import org.jruby.truffle.format.nodes.read.LiteralBytesNode;
import org.jruby.truffle.format.nodes.read.ReadHashValueNodeGen;
import org.jruby.truffle.format.nodes.read.ReadStringNodeGen;
import org.jruby.truffle.format.nodes.read.ReadValueNodeGen;
import org.jruby.truffle.format.nodes.type.ToDoubleWithCoercionNodeGen;
import org.jruby.truffle.format.nodes.type.ToIntegerNodeGen;
import org.jruby.truffle.format.nodes.type.ToStringNodeGen;
import org.jruby.truffle.format.nodes.write.WriteByteNode;
import org.jruby.truffle.format.nodes.write.WriteBytesNodeGen;
import org.jruby.truffle.format.nodes.write.WritePaddedBytesNodeGen;
@@ -46,7 +48,7 @@ public FormatParser(RubyContext context) {
}

public CallTarget parse(ByteList format) {
final FormatTokenizer tokenizer = new FormatTokenizer(format);
final FormatTokenizer tokenizer = new FormatTokenizer(context, format);
final PackNode body = parse(tokenizer);
return Truffle.getRuntime().createCallTarget(new PackRootNode(PackParser.describe(format.toString()), encoding, body));
}
@@ -74,17 +76,40 @@ public PackNode parse(FormatTokenizer tokenizer) {
} else if (token instanceof FormatDirective) {
final FormatDirective directive = (FormatDirective) token;

final PackNode valueNode;

if (directive.getKey() == null) {
valueNode = ReadValueNodeGen.create(context, new SourceNode());
} else {
valueNode = ReadHashValueNodeGen.create(context, directive.getKey(), new SourceNode());
}

switch (directive.getType()) {
case '%':
node = new WriteByteNode(context, (byte) '%');
break;
case '{':
node = WriteBytesNodeGen.create(context,
ToStringNodeGen.create(context, true, "to_s", false, new ByteList(),
valueNode));
break;
case 's':
if (directive.getSpacePadding() == FormatDirective.DEFAULT) {
node = WriteBytesNodeGen.create(context, ReadStringNodeGen.create(
context, true, "to_s", false, new ByteList(), new SourceNode()));
if (directive.getKey() == null) {
if (directive.getSpacePadding() == FormatDirective.DEFAULT) {
node = WriteBytesNodeGen.create(context, ReadStringNodeGen.create(
context, true, "to_s", false, new ByteList(), new SourceNode()));
} else {
node = WritePaddedBytesNodeGen.create(context, directive.getSpacePadding(), directive.getLeftJustified(),
ReadStringNodeGen.create(context, true, "to_s", false, new ByteList(), new SourceNode()));
}
} else {
node = WritePaddedBytesNodeGen.create(context, directive.getSpacePadding(), directive.getLeftJustified(),
ReadStringNodeGen.create(context, true, "to_s", false, new ByteList(), new SourceNode()));
if (directive.getSpacePadding() == FormatDirective.DEFAULT) {
node = WriteBytesNodeGen.create(context, ToStringNodeGen.create(
context, true, "to_s", false, new ByteList(), valueNode));
} else {
node = WritePaddedBytesNodeGen.create(context, directive.getSpacePadding(), directive.getLeftJustified(),
ToStringNodeGen.create(context, true, "to_s", false, new ByteList(), valueNode));
}
}
break;
case 'd':
@@ -127,7 +152,7 @@ public PackNode parse(FormatTokenizer tokenizer) {
node = WriteBytesNodeGen.create(context,
FormatIntegerNodeGen.create(context, spacePadding, zeroPadding, format,
ToIntegerNodeGen.create(context,
ReadValueNodeGen.create(context, new SourceNode()))));
valueNode)));
break;
case 'f':
case 'g':
@@ -139,7 +164,7 @@ public PackNode parse(FormatTokenizer tokenizer) {
directive.getZeroPadding(), directive.getPrecision(),
directive.getType(),
ToDoubleWithCoercionNodeGen.create(context,
ReadValueNodeGen.create(context, new SourceNode()))));
valueNode)));
break;
default:
throw new UnsupportedOperationException();
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.format.parser;

import org.jruby.truffle.runtime.RubyContext;
import org.jruby.util.ByteList;

/**
@@ -19,6 +20,7 @@ public class FormatTokenizer {

private static final String TYPE_CHARS = "%-sdiuxXfgGeE";

private final RubyContext context;
private final ByteList format;
private int position;
private Object peek;
@@ -27,18 +29,11 @@ public class FormatTokenizer {
* Construct a tokenizer.
* @param format the pack expression
*/
public FormatTokenizer(ByteList format) {
public FormatTokenizer(RubyContext context, ByteList format) {
this.context = context;
this.format = format;
}

public Object peek() {
if (peek == null) {
peek = next();
}

return peek;
}

public Object next() {
if (peek != null) {
final Object token = peek;
@@ -66,30 +61,43 @@ public Object next() {

position++;

Object key = null;

if (format.charAt(position) == '{') {
position++;
key = readUntil('}');
position++;
return new FormatDirective(0, 0, false, 0, '{', key);
} else if (format.charAt(position) == '<') {
position++;
key = readUntil('>');
position++;
}

boolean leftJustified = false;

if (format.charAt(position) == '-') {
if (position < format.length() && format.charAt(position) == '-') {
leftJustified = true;
position++;
}

int spacePadding;
int zeroPadding;

if (format.charAt(position) == ' ') {
if (position < format.length() && format.charAt(position) == ' ') {
position++;
spacePadding = readInt();
zeroPadding = FormatDirective.DEFAULT;
} else if (format.charAt(position) == '0') {
} else if (position < format.length() && format.charAt(position) == '0') {
spacePadding = FormatDirective.DEFAULT;
zeroPadding = readInt();
} else if (Character.isDigit(format.charAt(position))) {
} else if (position < format.length() && Character.isDigit(format.charAt(position))) {
spacePadding = readInt();
zeroPadding = FormatDirective.DEFAULT;
} else {
spacePadding = FormatDirective.DEFAULT;

if (format.charAt(position) == '0') {
if (position < format.length() && format.charAt(position) == '0') {
position++;
zeroPadding = readInt();
} else {
@@ -99,26 +107,37 @@ public Object next() {

final int precision;

if (format.charAt(position) == '.') {
if (position < format.length() && format.charAt(position) == '.') {
position++;
precision = readInt();
} else {
precision = FormatDirective.DEFAULT;
}

if (Character.isDigit(format.charAt(position))) {
if (position < format.length() && Character.isDigit(format.charAt(position))) {
spacePadding = readInt();
}

final char type = format.charAt(position);
char type;

if (key != null && position >= format.length()) {
type = 's';
} else {
type = format.charAt(position);

if (TYPE_CHARS.indexOf(type) == -1) {
throw new UnsupportedOperationException("Unknown format type '" + format.charAt(position) + "'");
if (key != null && Character.isWhitespace(type)) {
type = 's';
} else {
if (TYPE_CHARS.indexOf(type) == -1) {
throw new UnsupportedOperationException("Unknown format type '" + format.charAt(position) + "'");
}
}

position++;
}

position++;

return new FormatDirective(spacePadding, zeroPadding, leftJustified, precision, type);
return new FormatDirective(spacePadding, zeroPadding, leftJustified, precision, type, key);
}

private int readInt() {
@@ -131,4 +150,14 @@ private int readInt() {
return Integer.parseInt(format.subSequence(start, position).toString());
}

private Object readUntil(char end) {
final int start = position;

while (format.charAt(position) != end) {
position++;
}

return context.getSymbol((ByteList) format.subSequence(start, position));
}

}
Original file line number Diff line number Diff line change
@@ -40,8 +40,6 @@ public final class UnresolvedDispatchNode extends DispatchNode {
private final boolean ignoreVisibility;
private final MissingBehavior missingBehavior;

@Child private SingletonClassNode singletonClassNode;

public UnresolvedDispatchNode(
RubyContext context,
boolean ignoreVisibility,
6 changes: 5 additions & 1 deletion truffle/src/main/ruby/core/string.rb
Original file line number Diff line number Diff line change
@@ -9,7 +9,11 @@
class String

def %(args)
sprintf(self, *args)
if args.is_a? Hash
sprintf(self, args)
else
sprintf(self, *args)
end
end

def downcase