Skip to content

Commit b3d8ee8

Browse files
committed
fix sprintf WIP
1 parent 9644c32 commit b3d8ee8

File tree

2 files changed

+64
-19
lines changed

2 files changed

+64
-19
lines changed

src/main/java/org/perlonjava/operators/SprintfFormatParser.java

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,30 @@ public static ParseResult parse(String format) {
1313
int start = parser.pos;
1414

1515
if (parser.current() == '%') {
16+
int savedPos = parser.pos; // Save position before parsing
1617
FormatSpecifier spec = parser.parseSpecifier();
1718
if (spec != null) {
1819
result.addSpecifier(spec);
20+
21+
// Special case: if the format ends with % as conversion char,
22+
// check if that % starts another invalid format (for warning only)
23+
if (spec.conversionChar == '%' && !spec.isValid && !parser.isAtEnd()) {
24+
// Temporarily parse from the second % to check for invalid format
25+
int currentPos = parser.pos;
26+
parser.pos = savedPos + spec.raw.length() - 1;
27+
28+
if (parser.current() == '%') {
29+
FormatSpecifier overlapSpec = parser.parseSpecifier();
30+
if (overlapSpec != null && !overlapSpec.isValid) {
31+
// Mark as overlapping - generate warning but not output
32+
overlapSpec.isOverlapping = true;
33+
result.addSpecifier(overlapSpec);
34+
}
35+
}
36+
37+
// Restore original position
38+
parser.pos = currentPos;
39+
}
1940
} else {
2041
// Failed to parse, add % as literal
2142
result.addLiteral("%");
@@ -70,6 +91,7 @@ public static class FormatSpecifier {
7091
public char conversionChar;
7192
public boolean isValid = true;
7293
public String errorMessage;
94+
public boolean isOverlapping = false; // Don't include in output, just warn
7395
}
7496

7597
private static class Parser {
@@ -277,11 +299,17 @@ FormatSpecifier parseSpecifier() {
277299
} else {
278300
spec.conversionChar = current();
279301
advance();
302+
System.err.println("DEBUG: Parsed conversion char '" + spec.conversionChar + "'");
280303
}
281304

282305
spec.endPos = pos;
283306
spec.raw = input.substring(spec.startPos, spec.endPos);
284307

308+
// ADD DEBUG HERE:
309+
System.err.println("DEBUG parseSpecifier: raw='" + spec.raw +
310+
"', vectorFlag=" + spec.vectorFlag +
311+
", conversionChar='" + spec.conversionChar + "'");
312+
285313
// Add debug here to check the state before returning
286314
// System.err.println("DEBUG: Before return - isValid=" + spec.isValid +
287315
// ", errorMessage='" + spec.errorMessage + "'");
@@ -331,19 +359,19 @@ void validateSpecifier(FormatSpecifier spec) {
331359
return;
332360
}
333361

334-
// Check for vector formats FIRST (before %n check)
335-
if (spec.vectorFlag) {
336-
// Vector flag is only valid with certain conversions
337-
String validVectorConversions = "diouxXbB"; // Remove 's'
338-
// System.err.println("DEBUG: Checking vector conversion '" + spec.conversionChar +
339-
// "' in '" + validVectorConversions + "'");
340-
if (validVectorConversions.indexOf(spec.conversionChar) < 0) {
341-
// System.err.println("DEBUG: Setting invalid for vector format");
342-
spec.isValid = false;
343-
spec.errorMessage = "INVALID";
344-
return;
345-
}
346-
}
362+
// Check for vector formats FIRST (before %n check)
363+
if (spec.vectorFlag) {
364+
// Vector flag is only valid with certain conversions
365+
String validVectorConversions = "diouxXbB";
366+
System.err.println("DEBUG: Checking vector conversion '" + spec.conversionChar +
367+
"' in '" + validVectorConversions + "'");
368+
if (validVectorConversions.indexOf(spec.conversionChar) < 0) {
369+
System.err.println("DEBUG: Setting invalid for vector format");
370+
spec.isValid = false;
371+
spec.errorMessage = "INVALID";
372+
return;
373+
}
374+
}
347375

348376
if ("V".equals(spec.lengthModifier)) {
349377
// V is silently ignored in Perl

src/main/java/org/perlonjava/operators/SprintfOperator.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ public static RuntimeScalar sprintf(RuntimeScalar runtimeScalar, RuntimeList lis
5050
result.append(literal);
5151
charsWritten += literal.length();
5252
} else if (element instanceof SprintfFormatParser.FormatSpecifier spec) {
53+
// Check if this is an overlapping specifier (warning only, no output)
54+
if (spec.isOverlapping) {
55+
// Only generate warning, don't add to output
56+
if (!spec.isValid) {
57+
// Just generate the warning, don't add to result
58+
handleInvalidSpecifier(spec);
59+
}
60+
continue; // Skip adding to result and updating argIndex
61+
}
62+
5363
// Check if spec is invalid FIRST
5464
if (!spec.isValid) {
5565
String formatted = processFormatSpecifier(spec, list, argIndex, formatter);
@@ -77,7 +87,6 @@ public static RuntimeScalar sprintf(RuntimeScalar runtimeScalar, RuntimeList lis
7787
charsWritten += formatted.length();
7888

7989
// Update argument index if not using positional parameters
80-
// BUT don't update if the specifier was invalid
8190
if (spec.parameterIndex == null && spec.conversionChar != '%') {
8291
argIndex = updateArgIndex(spec, argIndex);
8392
}
@@ -113,6 +122,14 @@ private static String processFormatSpecifier(
113122
int argIndex,
114123
SprintfValueFormatter formatter) {
115124

125+
System.err.println("DEBUG processFormatSpecifier: raw='" + spec.raw +
126+
"', isValid=" + spec.isValid + ", errorMessage=" + spec.errorMessage);
127+
128+
// Handle invalid specifiers FIRST (before %% check)
129+
if (!spec.isValid) {
130+
return handleInvalidSpecifier(spec);
131+
}
132+
116133
// Handle %% - literal percent sign
117134
if (spec.conversionChar == '%') {
118135
if (spec.widthFromArg) {
@@ -127,11 +144,6 @@ private static String processFormatSpecifier(
127144
return handleInvalidSpecifier(spec);
128145
}
129146

130-
// Handle invalid specifiers
131-
if (!spec.isValid) {
132-
return handleInvalidSpecifier(spec);
133-
}
134-
135147
// Process width, precision, and value arguments
136148
FormatArguments args = extractFormatArguments(spec, list, argIndex);
137149

@@ -324,6 +336,9 @@ private static int updateArgIndex(SprintfFormatParser.FormatSpecifier spec,
324336
* Handle invalid format specifiers.
325337
*/
326338
private static String handleInvalidSpecifier(SprintfFormatParser.FormatSpecifier spec) {
339+
System.err.println("DEBUG handleInvalidSpecifier: raw='" + spec.raw +
340+
"', errorMessage='" + spec.errorMessage + "'");
341+
327342
String formatOnly = spec.raw;
328343
String trailing = "";
329344

@@ -351,10 +366,12 @@ private static String handleInvalidSpecifier(SprintfFormatParser.FormatSpecifier
351366
}
352367

353368
String warningMessage = "Invalid conversion in sprintf: \"" + formatForWarning + "\"";
369+
System.err.println("DEBUG: About to warn: " + warningMessage);
354370
WarnDie.warn(new RuntimeScalar(warningMessage), new RuntimeScalar(""));
355371
}
356372

357373
// Don't consume any arguments for invalid specifiers
374+
System.err.println("DEBUG: Returning from handleInvalidSpecifier: '" + formatOnly + trailing + "'");
358375
return formatOnly + trailing;
359376
}
360377

0 commit comments

Comments
 (0)