Skip to content

Commit 4dac75a

Browse files
committed
Fix parsing of gstring expressions
Signed-off-by: Ben Sherman <bentshermann@gmail.com>
1 parent 1d7896f commit 4dac75a

File tree

3 files changed

+85
-38
lines changed

3 files changed

+85
-38
lines changed

modules/compiler/src/main/java/config/parser/ConfigAstBuilder.java

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -891,36 +891,63 @@ private Expression gstring(GstringContext ctx) {
891891
var text = ctx.getText();
892892
var beginQuotation = beginQuotation(text);
893893
var verbatimText = stringLiteral(text);
894-
var strings = new ArrayList<ConstantExpression>();
895-
var values = new ArrayList<Expression>();
894+
var builder = new GStringBuilder();
896895

897896
for( var part : ctx.gstringDqPart() ) {
898897
if( part instanceof GstringDqTextAltContext tac )
899-
strings.add(ast( gstringText(tac, beginQuotation), tac ));
898+
builder.appendString(ast( gstringText(tac, beginQuotation), tac ));
900899

901900
if( part instanceof GstringDqPathAltContext pac )
902-
values.add(ast( gstringPath(pac), pac ));
901+
builder.appendValue(ast( gstringPath(pac), pac ));
903902

904903
if( part instanceof GstringDqExprAltContext eac )
905-
values.add(expression(eac.expression()));
904+
builder.appendValue(expression(eac.expression()));
906905
}
907906

908907
for( var part : ctx.gstringTdqPart() ) {
909908
if( part instanceof GstringTdqTextAltContext tac )
910-
strings.add(ast( gstringText(tac, beginQuotation), tac ));
909+
builder.appendString(ast( gstringText(tac, beginQuotation), tac ));
911910

912911
if( part instanceof GstringTdqPathAltContext pac )
913-
values.add(ast( gstringPath(pac), pac ));
912+
builder.appendValue(ast( gstringPath(pac), pac ));
914913

915914
if( part instanceof GstringTdqExprAltContext eac )
916-
values.add(expression(eac.expression()));
915+
builder.appendValue(expression(eac.expression()));
917916
}
918917

919-
var result = new GStringExpression(verbatimText, strings, values);
918+
var result = builder.build(verbatimText);
920919
result.putNodeMetaData(QUOTE_CHAR, beginQuotation);
921920
return result;
922921
}
923922

923+
/**
924+
* Builder for GStringExpression that inserts empty strings
925+
* to ensure that there are n+1 strings for n values.
926+
*
927+
* @see org.codehaus.groovy.runtime.GStringUtil.writeToImpl()
928+
*/
929+
private static class GStringBuilder {
930+
private final List<ConstantExpression> strings = new ArrayList<>();
931+
private final List<Expression> values = new ArrayList<>();
932+
private boolean appendEmptyString = true;
933+
934+
public void appendString(ConstantExpression string) {
935+
strings.add(string);
936+
appendEmptyString = false;
937+
}
938+
939+
public void appendValue(Expression value) {
940+
if( appendEmptyString )
941+
appendString(constX(""));
942+
values.add(value);
943+
appendEmptyString = true;
944+
}
945+
946+
public GStringExpression build(String verbatimText) {
947+
return new GStringExpression(verbatimText, strings, values);
948+
}
949+
}
950+
924951
private String beginQuotation(String text) {
925952
if( text.startsWith(TDQ_STR) )
926953
return TDQ_STR;

modules/compiler/src/main/java/script/formatter/Formatter.java

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -685,28 +685,21 @@ else if( node.isSafe() )
685685

686686
@Override
687687
public void visitGStringExpression(GStringExpression node) {
688+
// see also: GStringUtil.writeToImpl()
688689
var quoteChar = (String) node.getNodeMetaData(QUOTE_CHAR, k -> DQ_STR);
689690
append(quoteChar);
690-
Stream
691-
.concat(
692-
node.getStrings().stream().map(v -> (Expression) v),
693-
node.getValues().stream()
694-
)
695-
.sorted((a, b) ->
696-
a.getLineNumber() != b.getLineNumber()
697-
? a.getLineNumber() - b.getLineNumber()
698-
: a.getColumnNumber() - b.getColumnNumber()
699-
)
700-
.forEach((part) -> {
701-
if( part.getNodeMetaData(VERBATIM_TEXT) != null ) {
702-
visit(part);
703-
}
704-
else {
705-
append("${");
706-
visit(part);
707-
append('}');
708-
}
709-
});
691+
var ss = node.getStrings();
692+
var vs = node.getValues();
693+
for( int i = 0; i < ss.size(); i++ ) {
694+
var string = ss.get(i);
695+
if( string.getNodeMetaData(VERBATIM_TEXT) != null )
696+
visit(string);
697+
if( i < vs.size() ) {
698+
append("${");
699+
visit(vs.get(i));
700+
append('}');
701+
}
702+
}
710703
append(quoteChar);
711704
}
712705

modules/compiler/src/main/java/script/parser/ScriptAstBuilder.java

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,36 +1230,63 @@ private Expression gstring(GstringContext ctx) {
12301230
var text = ctx.getText();
12311231
var beginQuotation = beginQuotation(text);
12321232
var verbatimText = stringLiteral(text);
1233-
var strings = new ArrayList<ConstantExpression>();
1234-
var values = new ArrayList<Expression>();
1233+
var builder = new GStringBuilder();
12351234

12361235
for( var part : ctx.gstringDqPart() ) {
12371236
if( part instanceof GstringDqTextAltContext tac )
1238-
strings.add(ast( gstringText(tac, beginQuotation), tac ));
1237+
builder.appendString(ast( gstringText(tac, beginQuotation), tac ));
12391238

12401239
if( part instanceof GstringDqPathAltContext pac )
1241-
values.add(ast( gstringPath(pac), pac ));
1240+
builder.appendValue(ast( gstringPath(pac), pac ));
12421241

12431242
if( part instanceof GstringDqExprAltContext eac )
1244-
values.add(expression(eac.expression()));
1243+
builder.appendValue(expression(eac.expression()));
12451244
}
12461245

12471246
for( var part : ctx.gstringTdqPart() ) {
12481247
if( part instanceof GstringTdqTextAltContext tac )
1249-
strings.add(ast( gstringText(tac, beginQuotation), tac ));
1248+
builder.appendString(ast( gstringText(tac, beginQuotation), tac ));
12501249

12511250
if( part instanceof GstringTdqPathAltContext pac )
1252-
values.add(ast( gstringPath(pac), pac ));
1251+
builder.appendValue(ast( gstringPath(pac), pac ));
12531252

12541253
if( part instanceof GstringTdqExprAltContext eac )
1255-
values.add(expression(eac.expression()));
1254+
builder.appendValue(expression(eac.expression()));
12561255
}
12571256

1258-
var result = new GStringExpression(verbatimText, strings, values);
1257+
var result = builder.build(verbatimText);
12591258
result.putNodeMetaData(QUOTE_CHAR, beginQuotation);
12601259
return result;
12611260
}
12621261

1262+
/**
1263+
* Builder for GStringExpression that inserts empty strings
1264+
* to ensure that there are n+1 strings for n values.
1265+
*
1266+
* @see org.codehaus.groovy.runtime.GStringUtil.writeToImpl()
1267+
*/
1268+
private static class GStringBuilder {
1269+
private final List<ConstantExpression> strings = new ArrayList<>();
1270+
private final List<Expression> values = new ArrayList<>();
1271+
private boolean appendEmptyString = true;
1272+
1273+
public void appendString(ConstantExpression string) {
1274+
strings.add(string);
1275+
appendEmptyString = false;
1276+
}
1277+
1278+
public void appendValue(Expression value) {
1279+
if( appendEmptyString )
1280+
appendString(constX(""));
1281+
values.add(value);
1282+
appendEmptyString = true;
1283+
}
1284+
1285+
public GStringExpression build(String verbatimText) {
1286+
return new GStringExpression(verbatimText, strings, values);
1287+
}
1288+
}
1289+
12631290
private String beginQuotation(String text) {
12641291
if( text.startsWith(TDQ_STR) )
12651292
return TDQ_STR;

0 commit comments

Comments
 (0)