Skip to content

Commit

Permalink
Showing 8 changed files with 280 additions and 239 deletions.
Original file line number Diff line number Diff line change
@@ -71,6 +71,10 @@ public DynamicObject argumentErrorNegativeArraySize(Node currentNode) {
return argumentError(coreStrings().NEGATIVE_ARRAY_SIZE.getRope(), currentNode, null);
}

public DynamicObject argumentErrorCharacterRequired(Node currentNode) {
return argumentError("%c requires a character", currentNode);
}

public DynamicObject argumentErrorCantOmitPrecision(Node currentNode) {
return argumentError("can't omit precision for a Float.", currentNode);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright (c) 2016 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.core.format.format;

import com.oracle.truffle.api.CompilerDirectives;
@@ -35,7 +44,6 @@ public FormatCharacterNode(RubyContext context, boolean hasMinusFlag) {
this.hasMinusFlag = hasMinusFlag;
}

// @TruffleBoundary
@Specialization
protected byte[] format(VirtualFrame frame, int width, Object value) {
if (toStringNode == null) {
@@ -67,19 +75,22 @@ protected byte[] format(VirtualFrame frame, int width, Object value) {
final String resultString = new String((byte[]) toStrResult);
final int size = resultString.length();
if (size > 1) {
throw new RaiseException(getContext().getCoreExceptions().argumentError("%c requires a character", this));
throw new RaiseException(getContext().getCoreExceptions().argumentErrorCharacterRequired(this));
}
charString = resultString;
}


final boolean leftJustified = hasMinusFlag || width < 0;
if (width < 0) {
width = -width;
}

final String result = String.format("%" + (leftJustified ? "-" : "") + width + "." + width + "s", charString);
return result.getBytes(StandardCharsets.US_ASCII);
return doFormat(charString, width, leftJustified).getBytes(StandardCharsets.US_ASCII);
}

@TruffleBoundary
private String doFormat(final String charString, final int width, final boolean leftJustified) {
return String.format("%" + (leftJustified ? "-" : "") + width + "." + width + "s", charString);
}

}
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ public FormatFloatNode(RubyContext context, char format, boolean hasSpaceFlag, b
@Specialization(guards = "isInfinite(value)")
public byte[] formatInfinite(int width, int precision, double value) {
final String infinityString = String.format(getInfiniteFormatString(width), value);
return mapInifityResult(infinityString).getBytes(StandardCharsets.US_ASCII);
return mapInfiniteResult(infinityString).getBytes(StandardCharsets.US_ASCII);
}

@TruffleBoundary
@@ -60,13 +60,15 @@ protected boolean isInfinite(double value) {
}

private static String mapFiniteResult(String input){
// Map java finite strings to the Ruby style NaN
if(input.contains("NAN")){
return input.replaceFirst("NAN", "NaN");
}
return input;
}

private static String mapInifityResult(String input){
private static String mapInfiniteResult(String input){
// Map java infinite strings to the Ruby style Inf
if(input.contains("-Infinity")) {
return input.replaceFirst("-Infinity", "-Inf");
} else if(input.contains("-INFINITY")){
@@ -120,31 +122,30 @@ private String getFiniteFormatString(final int width, final int precision){
}

private String getInfiniteFormatString(final int width){
final StringBuilder inifiniteFormatBuilder = new StringBuilder();
inifiniteFormatBuilder.append("%");
final StringBuilder infiniteFormatBuilder = new StringBuilder();
infiniteFormatBuilder.append("%");
if(hasMinusFlag){
inifiniteFormatBuilder.append("-");
infiniteFormatBuilder.append("-");
}
if(hasPlusFlag){
inifiniteFormatBuilder.append("+");
infiniteFormatBuilder.append("+");
}

if (hasSpaceFlag) {
inifiniteFormatBuilder.append(" ");
inifiniteFormatBuilder.append(width + 5);
infiniteFormatBuilder.append(" ");
infiniteFormatBuilder.append(width + 5);
}
if (hasZeroFlag && width != 0) {
inifiniteFormatBuilder.append("0");
inifiniteFormatBuilder.append(width + 5);
infiniteFormatBuilder.append("0");
infiniteFormatBuilder.append(width + 5);
}
if(!hasSpaceFlag && !hasZeroFlag){
inifiniteFormatBuilder.append(width + 5);
infiniteFormatBuilder.append(width + 5);
}

infiniteFormatBuilder.append(format);

inifiniteFormatBuilder.append(format);

return inifiniteFormatBuilder.toString();
return infiniteFormatBuilder.toString();
}

}
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ public FormatIntegerNode(RubyContext context, char format, boolean hasSpaceFlag,
this.hasFSharp = hasFSharp;
}

@TruffleBoundary
@Specialization
public byte[] format(int width, int precision, int value) {
String formatted;
@@ -96,6 +97,7 @@ public byte[] format(int width, int precision, int value) {
return formatStart(width, precision, formatted, value < 0);
}

@TruffleBoundary
@Specialization
public byte[] format(int width, int precision, long value) {
String formatted;
@@ -143,12 +145,11 @@ public byte[] format(int width, int precision, long value) {
}

private static byte[] elide(byte[] bytes, char format, int precision) {
// TODO BJF need to implement the skipping of bytes per format type when value is negative
return bytes;
}


private byte[] formatStart(int width, int precision, String formatted, boolean isNegative) {

boolean leftJustified = hasMinusFlag;
if (width < 0 && width != PrintfSimpleTreeBuilder.DEFAULT) { // TODO handle default width better
width = -width;
@@ -198,7 +199,6 @@ private byte[] formatStart(int width, int precision, String formatted, boolean i
}

return formatted.getBytes(StandardCharsets.US_ASCII);

}

@TruffleBoundary
@@ -207,7 +207,6 @@ public byte[] format(int width, int precision, DynamicObject value) {
final BigInteger bigInteger = Layouts.BIGNUM.getValue(value);

String formatted;

switch (format) {
case 'd':
case 'i':
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ public PrintfCompiler(RubyContext context, RubyNode currentNode) {

public CallTarget compile(String formatString, byte[] format) {
final PrintfSimpleParser parser = new PrintfSimpleParser(bytesToChars(format));
final List<PrintfSimpleParser.SprintfConfig> configs = parser.parse();
final List<SprintfConfig> configs = parser.parse();
final PrintfSimpleTreeBuilder builder = new PrintfSimpleTreeBuilder(context, configs);

return Truffle.getRuntime().createCallTarget(
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright (c) 2016 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.core.format.printf;

import org.jruby.truffle.core.format.exceptions.InvalidFormatException;
@@ -362,214 +371,6 @@ public static boolean isDigit(char c) {
return c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9';
}

public static class SprintfConfig {

public enum FormatType {
INTEGER, FLOAT, OTHER
}

private boolean literal = false;
private byte[] literalBytes;

private byte[] namesBytes;
private boolean argWidth = false;

private Integer absoluteArgumentIndex;
private Integer precision;
private boolean precisionArg = false;
private boolean precisionVisited = false;
private Integer width;
private boolean hasSpace = false;
private boolean fsharp = false; // #
private boolean plus = false;
private boolean minus = false;
private boolean zero = false;
private boolean widthStar = false;
private boolean precisionStar = false;
private char format;
private FormatType formatType;


public void checkForFlags() {
if (hasWidth()) {
throw new InvalidFormatException("flag after width");
}
if (hasPrecision()) {
throw new InvalidFormatException("flag after precision");
}
}

public void checkForWidth() {
if (hasWidth()) {
throw new InvalidFormatException("width given twice");
}
if (hasPrecision()) {
throw new InvalidFormatException("width after precision");
}
}

public boolean isHasSpace() {
return hasSpace;
}

public void setHasSpace(boolean hasSpace) {
this.hasSpace = hasSpace;
}

public Integer getPrecision() {
return precision;
}

public void setPrecision(int precision) {
this.precision = precision;
}

public void setPrecision(Integer precision) {
this.precision = precision;
}

public Integer getWidth() {
return width;
}

public void setWidth(Integer width) {
this.width = width;
}

public boolean isFsharp() {
return fsharp;
}

public void setFsharp(boolean fsharp) {
this.fsharp = fsharp;
}

public boolean isPlus() {
return plus;
}

public void setPlus(boolean plus) {
this.plus = plus;
}

public boolean isMinus() {
return minus;
}

public void setMinus(boolean minus) {
this.minus = minus;
}

public boolean isZero() {
return zero;
}

public void setZero(boolean zero) {
this.zero = zero;
}

public FormatType getFormatType() {
return formatType;
}

public void setFormatType(FormatType formatType) {
this.formatType = formatType;
}

public char getFormat() {
return format;
}

public void setFormat(char format) {
this.format = format;
}

public boolean isWidthStar() {
return widthStar;
}

public void setWidthStar(boolean widthStar) {
this.widthStar = widthStar;
}

public boolean isPrecisionStar() {
return precisionStar;
}

public void setPrecisionStar(boolean precisionStar) {
this.precisionStar = precisionStar;
}

public boolean hasPrecision() {
return precision != null || precisionStar || precisionVisited;
}

public boolean hasWidth() {
return width != null || widthStar;
}

public boolean isLiteral() {
return literal;
}

public void setLiteral(boolean literal) {
this.literal = literal;
}

public byte[] getLiteralBytes() {
return literalBytes;
}

public void setLiteralBytes(byte[] literalBytes) {
this.literalBytes = literalBytes;
}

public Integer getAbsoluteArgumentIndex() {
return absoluteArgumentIndex;
}

public void setAbsoluteArgumentIndex(Integer absoluteArgumentIndex) {
this.absoluteArgumentIndex = absoluteArgumentIndex;
}

public boolean isArgWidth() {
return argWidth;
}

public void setArgWidth(boolean argWidth) {
this.argWidth = argWidth;
}


public boolean isPrecisionVisited() {
return precisionVisited;
}

public void setPrecisionVisited(boolean precisionVisited) {
this.precisionVisited = precisionVisited;
}

public byte[] getNamesBytes() {
return namesBytes;
}

public void setNamesBytes(byte[] namesBytes) {
this.namesBytes = namesBytes;
}

public boolean isPrecisionArg() {
return precisionArg;
}

public void setPrecisionArg(boolean precisionArg) {
this.precisionArg = precisionArg;
}

public boolean hasFlags() {
return literal || precision != null || precisionVisited || width != null || hasSpace || fsharp || plus || minus || zero || precisionStar || widthStar || formatType != null;
}
}

public Character valueAt(int index) {
assert index >= 0;
if (index < this.source.length) {
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright (c) 2016 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.core.format.printf;

import com.oracle.truffle.api.object.DynamicObject;
@@ -29,22 +38,21 @@

public class PrintfSimpleTreeBuilder {


private final RubyContext context;
private final List<FormatNode> sequence = new ArrayList<>();
private final List<PrintfSimpleParser.SprintfConfig> configs;
private final List<SprintfConfig> configs;

public static int DEFAULT = -1;

private static final byte[] EMPTY_BYTES = new byte[]{};

public PrintfSimpleTreeBuilder(RubyContext context, List<PrintfSimpleParser.SprintfConfig> configs) {
public PrintfSimpleTreeBuilder(RubyContext context, List<SprintfConfig> configs) {
this.context = context;
this.configs = configs;
}

private void buildTree() {
for (PrintfSimpleParser.SprintfConfig config : configs) {
for (SprintfConfig config : configs) {
final FormatNode node;
if (config.isLiteral()) {
node = WriteBytesNodeGen.create(context, new LiteralFormatNode(context, config.getLiteralBytes()));
@@ -175,9 +183,6 @@ private void buildTree() {
break;
default:
throw new UnsupportedOperationException("unsupported type: " + config.getFormatType().toString());



}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* Copyright (c) 2016 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.core.format.printf;

import org.jruby.truffle.core.format.exceptions.InvalidFormatException;

public class SprintfConfig {

public enum FormatType {
INTEGER, FLOAT, OTHER
}

private boolean literal = false;
private byte[] literalBytes;

private byte[] namesBytes;
private boolean argWidth = false;

private Integer absoluteArgumentIndex;
private Integer precision;
private boolean precisionArg = false;
private boolean precisionVisited = false;
private Integer width;
private boolean hasSpace = false;
private boolean fsharp = false; // #
private boolean plus = false;
private boolean minus = false;
private boolean zero = false;
private boolean widthStar = false;
private boolean precisionStar = false;
private char format;
private FormatType formatType;


public void checkForFlags() {
if (hasWidth()) {
throw new InvalidFormatException("flag after width");
}
if (hasPrecision()) {
throw new InvalidFormatException("flag after precision");
}
}

public void checkForWidth() {
if (hasWidth()) {
throw new InvalidFormatException("width given twice");
}
if (hasPrecision()) {
throw new InvalidFormatException("width after precision");
}
}

public boolean isHasSpace() {
return hasSpace;
}

public void setHasSpace(boolean hasSpace) {
this.hasSpace = hasSpace;
}

public Integer getPrecision() {
return precision;
}

public void setPrecision(int precision) {
this.precision = precision;
}

public void setPrecision(Integer precision) {
this.precision = precision;
}

public Integer getWidth() {
return width;
}

public void setWidth(Integer width) {
this.width = width;
}

public boolean isFsharp() {
return fsharp;
}

public void setFsharp(boolean fsharp) {
this.fsharp = fsharp;
}

public boolean isPlus() {
return plus;
}

public void setPlus(boolean plus) {
this.plus = plus;
}

public boolean isMinus() {
return minus;
}

public void setMinus(boolean minus) {
this.minus = minus;
}

public boolean isZero() {
return zero;
}

public void setZero(boolean zero) {
this.zero = zero;
}

public FormatType getFormatType() {
return formatType;
}

public void setFormatType(FormatType formatType) {
this.formatType = formatType;
}

public char getFormat() {
return format;
}

public void setFormat(char format) {
this.format = format;
}

public boolean isWidthStar() {
return widthStar;
}

public void setWidthStar(boolean widthStar) {
this.widthStar = widthStar;
}

public boolean isPrecisionStar() {
return precisionStar;
}

public void setPrecisionStar(boolean precisionStar) {
this.precisionStar = precisionStar;
}

public boolean hasPrecision() {
return precision != null || precisionStar || precisionVisited;
}

public boolean hasWidth() {
return width != null || widthStar;
}

public boolean isLiteral() {
return literal;
}

public void setLiteral(boolean literal) {
this.literal = literal;
}

public byte[] getLiteralBytes() {
return literalBytes;
}

public void setLiteralBytes(byte[] literalBytes) {
this.literalBytes = literalBytes;
}

public Integer getAbsoluteArgumentIndex() {
return absoluteArgumentIndex;
}

public void setAbsoluteArgumentIndex(Integer absoluteArgumentIndex) {
this.absoluteArgumentIndex = absoluteArgumentIndex;
}

public boolean isArgWidth() {
return argWidth;
}

public void setArgWidth(boolean argWidth) {
this.argWidth = argWidth;
}


public boolean isPrecisionVisited() {
return precisionVisited;
}

public void setPrecisionVisited(boolean precisionVisited) {
this.precisionVisited = precisionVisited;
}

public byte[] getNamesBytes() {
return namesBytes;
}

public void setNamesBytes(byte[] namesBytes) {
this.namesBytes = namesBytes;
}

public boolean isPrecisionArg() {
return precisionArg;
}

public void setPrecisionArg(boolean precisionArg) {
this.precisionArg = precisionArg;
}

public boolean hasFlags() {
return literal || precision != null || precisionVisited || width != null || hasSpace || fsharp || plus || minus || zero || precisionStar || widthStar || formatType != null;
}
}

0 comments on commit 7bd4e8a

Please sign in to comment.