-
-
Notifications
You must be signed in to change notification settings - Fork 925
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3551 from jruby/truffle-antlr-printf
[Truffle] Antlr printf
- 9.4.12.0
- 9.4.11.0
- 9.4.10.0
- 9.4.9.0
- 9.4.8.0
- 9.4.7.0
- 9.4.6.0
- 9.4.5.0
- 9.4.4.0
- 9.4.3.0
- 9.4.2.0
- 9.4.1.0
- 9.4.0.0
- 9.3.15.0
- 9.3.14.0
- 9.3.13.0
- 9.3.12.0
- 9.3.11.0
- 9.3.10.0
- 9.3.9.0
- 9.3.8.0
- 9.3.7.0
- 9.3.6.0
- 9.3.5.0
- 9.3.4.0
- 9.3.3.0
- 9.3.2.0
- 9.3.1.0
- 9.3.0.0
- 9.2.21.0
- 9.2.20.1
- 9.2.20.0
- 9.2.19.0
- 9.2.18.0
- 9.2.17.0
- 9.2.16.0
- 9.2.15.0
- 9.2.14.0
- 9.2.13.0
- 9.2.12.0
- 9.2.11.1
- 9.2.11.0
- 9.2.10.0
- 9.2.9.0
- 9.2.8.0
- 9.2.7.0
- 9.2.6.0
- 9.2.5.0
- 9.2.4.1
- 9.2.4.0
- 9.2.3.0
- 9.2.2.0
- 9.2.1.0
- 9.2.0.0
- 9.1.17.0
- 9.1.16.0
- 9.1.15.0
- 9.1.14.0
- 9.1.13.0
- 9.1.12.0
- 9.1.11.0
- 9.1.10.0
- 9.1.9.0
- 9.1.8.0
- 9.1.7.0
- 9.1.6.0
- 9.1.5.0
- 9.1.4.0
- 9.1.3.0
- 9.1.2.0
- 9.1.1.0
- 9.1.0.0
- 9.0.5.0
Showing
13 changed files
with
406 additions
and
434 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
*.versionsBackup | ||
*.zip | ||
*~ | ||
*.tokens | ||
|
||
.DS_Store | ||
.debug.properties | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
truffle/src/main/antlr4/org/jruby/truffle/format/parser/PrintfLexer.g4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* 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 | ||
*/ | ||
lexer grammar PrintfLexer; | ||
|
||
FORMAT : '%' -> mode(FORMAT_MODE); | ||
LITERAL : (~'%')* ; | ||
|
||
mode FORMAT_MODE; | ||
|
||
ANGLE_KEY : '<' .*? '>' ; | ||
ZERO : '0' ; | ||
NUMBER : [1-9] [0-9]* ; | ||
SPACE : ' ' ; | ||
PLUS : '+' ; | ||
MINUS : '-' ; | ||
STAR : '*' ; | ||
DOLLAR : '$' ; | ||
DOT : '.' ; | ||
CURLY_KEY : '{' .*? '}' -> mode(DEFAULT_MODE) ; | ||
TYPE : [bBdiouxXeEfgGaAcps] -> mode(DEFAULT_MODE) ; | ||
ESCAPED : '%' -> mode(DEFAULT_MODE) ; |
31 changes: 31 additions & 0 deletions
31
truffle/src/main/antlr4/org/jruby/truffle/format/parser/PrintfParser.g4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* 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 | ||
*/ | ||
parser grammar PrintfParser; | ||
|
||
options { tokenVocab=PrintfLexer; } | ||
|
||
sequence : (FORMAT directive | literal)* ; | ||
|
||
directive : CURLY_KEY # string | ||
| ESCAPED # escaped | ||
| ANGLE_KEY? | ||
flag* | ||
width=NUMBER? | ||
(DOT precision=NUMBER)? | ||
TYPE # format ; | ||
|
||
flag : SPACE | ||
| ZERO | ||
| PLUS | ||
| MINUS | ||
| STAR | ||
| NUMBER DOLLAR ; | ||
|
||
literal : LITERAL ; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 0 additions & 61 deletions
61
truffle/src/main/java/org/jruby/truffle/format/parser/FormatDirective.java
This file was deleted.
Oops, something went wrong.
197 changes: 0 additions & 197 deletions
197
truffle/src/main/java/org/jruby/truffle/format/parser/FormatParser.java
This file was deleted.
Oops, something went wrong.
161 changes: 0 additions & 161 deletions
161
truffle/src/main/java/org/jruby/truffle/format/parser/FormatTokenizer.java
This file was deleted.
Oops, something went wrong.
70 changes: 70 additions & 0 deletions
70
truffle/src/main/java/org/jruby/truffle/format/parser/PrintfCompiler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* 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.parser; | ||
|
||
import com.oracle.truffle.api.CallTarget; | ||
import com.oracle.truffle.api.Truffle; | ||
import org.antlr.v4.runtime.ANTLRInputStream; | ||
import org.antlr.v4.runtime.CommonTokenStream; | ||
import org.jruby.truffle.format.nodes.PackRootNode; | ||
import org.jruby.truffle.format.runtime.PackEncoding; | ||
import org.jruby.truffle.nodes.RubyNode; | ||
import org.jruby.truffle.runtime.RubyContext; | ||
|
||
import org.jruby.truffle.format.parser.PrintfLexer; | ||
import org.jruby.truffle.format.parser.PrintfParser; | ||
import org.jruby.util.ByteList; | ||
|
||
public class PrintfCompiler { | ||
|
||
private final RubyContext context; | ||
private final RubyNode currentNode; | ||
|
||
public PrintfCompiler(RubyContext context, RubyNode currentNode) { | ||
this.context = context; | ||
this.currentNode = currentNode; | ||
} | ||
|
||
public CallTarget compile(ByteList format) { | ||
final PackErrorListener errorListener = new PackErrorListener(context, currentNode); | ||
|
||
final ANTLRInputStream input = new ANTLRInputStream(bytesToChars(format.bytes()), format.realSize()); | ||
|
||
final PrintfLexer lexer = new PrintfLexer(input); | ||
lexer.removeErrorListeners(); | ||
lexer.addErrorListener(errorListener); | ||
|
||
final CommonTokenStream tokens = new CommonTokenStream(lexer); | ||
|
||
final PrintfParser parser = new PrintfParser(tokens); | ||
|
||
final PrintfTreeBuilder builder = new PrintfTreeBuilder(context, format); | ||
parser.addParseListener(builder); | ||
|
||
parser.removeErrorListeners(); | ||
parser.addErrorListener(errorListener); | ||
|
||
parser.sequence(); | ||
|
||
return Truffle.getRuntime().createCallTarget( | ||
new PackRootNode(PackCompiler.describe(format.toString()), PackEncoding.DEFAULT, builder.getNode())); | ||
} | ||
|
||
public static char[] bytesToChars(byte[] bytes) { | ||
final char[] chars = new char[bytes.length]; | ||
|
||
for (int n = 0; n < bytes.length; n++) { | ||
chars[n] = (char) bytes[n]; | ||
} | ||
|
||
return chars; | ||
} | ||
|
||
} |
252 changes: 252 additions & 0 deletions
252
truffle/src/main/java/org/jruby/truffle/format/parser/PrintfTreeBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
/* | ||
* 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.parser; | ||
|
||
import com.oracle.truffle.api.object.DynamicObject; | ||
import org.antlr.v4.runtime.Token; | ||
import org.antlr.v4.runtime.misc.Interval; | ||
import org.jruby.truffle.format.nodes.PackNode; | ||
import org.jruby.truffle.format.nodes.SourceNode; | ||
import org.jruby.truffle.format.nodes.control.SequenceNode; | ||
import org.jruby.truffle.format.nodes.format.FormatFloatNodeGen; | ||
import org.jruby.truffle.format.nodes.format.FormatIntegerNodeGen; | ||
import org.jruby.truffle.format.nodes.read.*; | ||
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; | ||
import org.jruby.truffle.runtime.RubyContext; | ||
import org.jruby.truffle.runtime.layouts.Layouts; | ||
import org.jruby.util.ByteList; | ||
import org.jruby.util.StringSupport; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class PrintfTreeBuilder extends org.jruby.truffle.format.parser.PrintfParserBaseListener { | ||
|
||
public static final int PADDING_FROM_ARGUMENT = -2; | ||
|
||
public static final int DEFAULT = -1; | ||
|
||
private final RubyContext context; | ||
private final ByteList source; | ||
|
||
private final List<PackNode> sequence = new ArrayList<>(); | ||
|
||
public PrintfTreeBuilder(RubyContext context, ByteList source) { | ||
this.context = context; | ||
this.source = source; | ||
} | ||
|
||
@Override | ||
public void exitEscaped(org.jruby.truffle.format.parser.PrintfParser.EscapedContext ctx) { | ||
sequence.add(new WriteByteNode(context, (byte) '%')); | ||
} | ||
|
||
@Override | ||
public void exitString(org.jruby.truffle.format.parser.PrintfParser.StringContext ctx) { | ||
final ByteList keyBytes = tokenAsBytes(ctx.CURLY_KEY().getSymbol(), 1); | ||
final DynamicObject key = context.getSymbol(keyBytes); | ||
|
||
sequence.add( | ||
WriteBytesNodeGen.create(context, | ||
ToStringNodeGen.create(context, true, "to_s", false, new ByteList(), | ||
ReadHashValueNodeGen.create(context, key, new SourceNode())))); | ||
} | ||
|
||
@Override | ||
public void exitFormat(org.jruby.truffle.format.parser.PrintfParser.FormatContext ctx) { | ||
final int width; | ||
|
||
if (ctx.width != null) { | ||
width = Integer.parseInt(ctx.width.getText()); | ||
} else { | ||
width = DEFAULT; | ||
} | ||
|
||
boolean leftJustified = false; | ||
int spacePadding = DEFAULT; | ||
int zeroPadding = DEFAULT; | ||
|
||
|
||
for (int n = 0; n < ctx.flag().size(); n++) { | ||
final org.jruby.truffle.format.parser.PrintfParser.FlagContext flag = ctx.flag(n); | ||
|
||
if (flag.MINUS() != null) { | ||
leftJustified = true; | ||
} else if (flag.SPACE() != null) { | ||
if (n + 1 < ctx.flag().size() && ctx.flag(n + 1).STAR() != null) { | ||
spacePadding = PADDING_FROM_ARGUMENT; | ||
} else { | ||
spacePadding = width; | ||
} | ||
} else if (flag.ZERO() != null) { | ||
if (n + 1 < ctx.flag().size() && ctx.flag(n + 1).STAR() != null) { | ||
zeroPadding = PADDING_FROM_ARGUMENT; | ||
} else { | ||
zeroPadding = width; | ||
} | ||
} else if (flag.STAR() != null) { | ||
// Handled in space and zero, above | ||
} else { | ||
throw new UnsupportedOperationException(); | ||
} | ||
} | ||
|
||
if (spacePadding == DEFAULT && zeroPadding == DEFAULT) { | ||
spacePadding = width; | ||
} | ||
|
||
final char type = ctx.TYPE().getSymbol().getText().charAt(0); | ||
|
||
final PackNode valueNode; | ||
|
||
if (ctx.ANGLE_KEY() == null) { | ||
valueNode = ReadValueNodeGen.create(context, new SourceNode()); | ||
} else { | ||
final ByteList keyBytes = tokenAsBytes(ctx.ANGLE_KEY().getSymbol(), 1); | ||
final DynamicObject key = context.getSymbol(keyBytes); | ||
valueNode = ReadHashValueNodeGen.create(context, key, new SourceNode()); | ||
} | ||
|
||
final int precision; | ||
|
||
if (ctx.precision != null) { | ||
precision = Integer.parseInt(ctx.precision.getText()); | ||
} else { | ||
precision = DEFAULT; | ||
} | ||
|
||
final PackNode node; | ||
|
||
switch (type) { | ||
case 's': | ||
if (ctx.ANGLE_KEY() == null) { | ||
if (spacePadding == DEFAULT) { | ||
node = WriteBytesNodeGen.create(context, ReadStringNodeGen.create( | ||
context, true, "to_s", false, new ByteList(), new SourceNode())); | ||
} else { | ||
node = WritePaddedBytesNodeGen.create(context, spacePadding, leftJustified, | ||
ReadStringNodeGen.create(context, true, "to_s", false, new ByteList(), new SourceNode())); | ||
} | ||
} else { | ||
if (spacePadding == DEFAULT) { | ||
node = WriteBytesNodeGen.create(context, ToStringNodeGen.create( | ||
context, true, "to_s", false, new ByteList(), valueNode)); | ||
} else { | ||
node = WritePaddedBytesNodeGen.create(context, spacePadding, leftJustified, | ||
ToStringNodeGen.create(context, true, "to_s", false, new ByteList(), valueNode)); | ||
} | ||
} | ||
break; | ||
case 'd': | ||
case 'i': | ||
case 'o': | ||
case 'u': | ||
case 'x': | ||
case 'X': | ||
final PackNode spacePaddingNode; | ||
if (spacePadding == PADDING_FROM_ARGUMENT) { | ||
spacePaddingNode = ReadIntegerNodeGen.create(context, new SourceNode()); | ||
} else { | ||
spacePaddingNode = new LiteralIntegerNode(context, spacePadding); | ||
} | ||
|
||
final PackNode zeroPaddingNode; | ||
|
||
/* | ||
* Precision and zero padding both set zero padding - | ||
* but precision has priority and explicit zero padding | ||
* is actually ignored if it's set. | ||
*/ | ||
|
||
if (zeroPadding == PADDING_FROM_ARGUMENT) { | ||
zeroPaddingNode = ReadIntegerNodeGen.create(context, new SourceNode()); | ||
} else if (ctx.precision != null) { | ||
zeroPaddingNode = new LiteralIntegerNode(context, Integer.parseInt(ctx.precision.getText())); | ||
} else { | ||
zeroPaddingNode = new LiteralIntegerNode(context, zeroPadding); | ||
} | ||
|
||
final char format; | ||
|
||
switch (type) { | ||
case 'd': | ||
case 'i': | ||
case 'u': | ||
format = 'd'; | ||
break; | ||
case 'o': | ||
format = 'o'; | ||
break; | ||
case 'x': | ||
case 'X': | ||
format = type; | ||
break; | ||
default: | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
node = WriteBytesNodeGen.create(context, | ||
FormatIntegerNodeGen.create(context, format, | ||
spacePaddingNode, | ||
zeroPaddingNode, | ||
ToIntegerNodeGen.create(context, valueNode))); | ||
break; | ||
case 'f': | ||
case 'g': | ||
case 'G': | ||
case 'e': | ||
case 'E': | ||
node = WriteBytesNodeGen.create(context, | ||
FormatFloatNodeGen.create(context, spacePadding, | ||
zeroPadding, precision, | ||
type, | ||
ToDoubleWithCoercionNodeGen.create(context, | ||
valueNode))); | ||
break; | ||
default: | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
sequence.add(node); | ||
} | ||
|
||
@Override | ||
public void exitLiteral(org.jruby.truffle.format.parser.PrintfParser.LiteralContext ctx) { | ||
final ByteList text = tokenAsBytes(ctx.LITERAL().getSymbol()); | ||
|
||
final PackNode node; | ||
|
||
if (text.length() == 1) { | ||
node = new WriteByteNode(context, (byte) text.get(0)); | ||
} else { | ||
node = WriteBytesNodeGen.create(context, new LiteralBytesNode(context, text)); | ||
} | ||
|
||
sequence.add(node); | ||
} | ||
|
||
public PackNode getNode() { | ||
return new SequenceNode(context, sequence.toArray(new PackNode[sequence.size()])); | ||
} | ||
|
||
private ByteList tokenAsBytes(Token token) { | ||
return tokenAsBytes(token, 0); | ||
} | ||
|
||
private ByteList tokenAsBytes(Token token, int trim) { | ||
return new ByteList(source, token.getStartIndex() + trim, token.getStopIndex() - token.getStartIndex() + 1 - 2 * trim); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters