Skip to content

Commit b45bd4e

Browse files
committed
fix pack() WIP
1 parent 77595da commit b45bd4e

File tree

2 files changed

+120
-9
lines changed

2 files changed

+120
-9
lines changed

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

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ public static RuntimeScalar pack(RuntimeList args) {
5757
// Track if 'U' was used in normal mode (not byte mode)
5858
boolean hasUnicodeInNormalMode = false;
5959

60+
// Stack to track byte order for nested groups
61+
java.util.Stack<Character> groupEndianStack = new java.util.Stack<>();
62+
groupEndianStack.push(' '); // Default: no specific endianness
63+
6064
for (int i = 0; i < template.length(); i++) {
6165
char format = template.charAt(i);
6266

@@ -74,15 +78,37 @@ public static RuntimeScalar pack(RuntimeList args) {
7478
continue;
7579
}
7680

77-
// Skip spaces
78-
if (Character.isWhitespace(format)) {
79-
continue;
80-
}
81+
// Handle parentheses for grouping
82+
if (format == '(') {
83+
// Find matching closing parenthesis
84+
int closePos = findMatchingParen(template, i);
85+
if (closePos == -1) {
86+
throw new PerlCompilerException("pack: unmatched parenthesis in template");
87+
}
8188

82-
// Skip comments
83-
if (format == '#') {
84-
// Skip to end of line or end of template
85-
while (i + 1 < template.length() && template.charAt(i + 1) != '\n') {
89+
// Check for endianness modifier after the group
90+
char groupEndian = ' '; // default: inherit from parent
91+
if (closePos + 1 < template.length()) {
92+
char nextChar = template.charAt(closePos + 1);
93+
if (nextChar == '<' || nextChar == '>') {
94+
groupEndian = nextChar;
95+
}
96+
}
97+
98+
// Extract group content
99+
String groupContent = template.substring(i + 1, closePos);
100+
101+
// Check for conflicting endianness within the group
102+
if (groupEndian != ' ' && hasConflictingEndianness(groupContent, groupEndian)) {
103+
throw new PerlCompilerException("Can't use both '<' and '>' in a group with different byte-order in pack");
104+
}
105+
106+
// Process group (recursive pack)
107+
// For now, let's skip the actual processing and focus on the error detection
108+
109+
// Move past the group and any endianness modifier
110+
i = closePos;
111+
if (closePos + 1 < template.length() && (template.charAt(closePos + 1) == '<' || template.charAt(closePos + 1) == '>')) {
86112
i++;
87113
}
88114
continue;
@@ -563,4 +589,45 @@ private static boolean isNumericFormat(char format) {
563589
return false;
564590
}
565591
}
592+
593+
private static int findMatchingParen(String template, int openPos) {
594+
int depth = 1;
595+
for (int i = openPos + 1; i < template.length(); i++) {
596+
if (template.charAt(i) == '(') depth++;
597+
else if (template.charAt(i) == ')') {
598+
depth--;
599+
if (depth == 0) return i;
600+
}
601+
}
602+
return -1;
603+
}
604+
605+
private static boolean hasConflictingEndianness(String groupContent, char groupEndian) {
606+
// Check if the group content has endianness modifiers that conflict with the group's endianness
607+
for (int i = 0; i < groupContent.length(); i++) {
608+
char c = groupContent.charAt(i);
609+
if ((c == '<' && groupEndian == '>') || (c == '>' && groupEndian == '<')) {
610+
// Check if this is actually a modifier (follows a format that supports it)
611+
if (i > 0) {
612+
char prevChar = groupContent.charAt(i - 1);
613+
if ("sSiIlLqQjJfFdDpP".indexOf(prevChar) >= 0) {
614+
return true;
615+
}
616+
}
617+
}
618+
// Also check for nested groups with conflicting endianness
619+
if (c == '(') {
620+
int closePos = findMatchingParen(groupContent, i);
621+
if (closePos != -1 && closePos + 1 < groupContent.length()) {
622+
char nestedEndian = groupContent.charAt(closePos + 1);
623+
if ((nestedEndian == '<' && groupEndian == '>') ||
624+
(nestedEndian == '>' && groupEndian == '<')) {
625+
return true;
626+
}
627+
}
628+
i = closePos; // Skip the nested group
629+
}
630+
}
631+
return false;
632+
}
566633
}

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,27 @@ public static RuntimeList unpack(int ctx, RuntimeBase... args) {
118118
throw new PerlCompilerException("unpack: unmatched parenthesis in template");
119119
}
120120

121+
// Check for endianness modifier after the group
122+
char groupEndian = ' '; // default: no specific endianness
123+
int nextPos = closePos + 1;
124+
if (nextPos < template.length()) {
125+
char nextChar = template.charAt(nextPos);
126+
if (nextChar == '<' || nextChar == '>') {
127+
groupEndian = nextChar;
128+
nextPos++;
129+
}
130+
}
131+
121132
// Extract group content
122133
String groupContent = template.substring(i + 1, closePos);
123134

135+
// Check for conflicting endianness within the group
136+
if (groupEndian != ' ' && hasConflictingEndianness(groupContent, groupEndian)) {
137+
throw new PerlCompilerException("Can't use both '<' and '>' in a group with different byte-order in unpack");
138+
}
139+
124140
// Check for repeat count after closing paren
125141
int groupRepeatCount = 1;
126-
int nextPos = closePos + 1;
127142

128143
if (nextPos < template.length()) {
129144
char nextChar = template.charAt(nextPos);
@@ -384,6 +399,35 @@ else if (template.charAt(i) == ')') {
384399
return -1;
385400
}
386401

402+
private static boolean hasConflictingEndianness(String groupContent, char groupEndian) {
403+
// Check if the group content has endianness modifiers that conflict with the group's endianness
404+
for (int i = 0; i < groupContent.length(); i++) {
405+
char c = groupContent.charAt(i);
406+
if ((c == '<' && groupEndian == '>') || (c == '>' && groupEndian == '<')) {
407+
// Check if this is actually a modifier (follows a format that supports it)
408+
if (i > 0) {
409+
char prevChar = groupContent.charAt(i - 1);
410+
if ("sSiIlLqQjJfFdDpP".indexOf(prevChar) >= 0) {
411+
return true;
412+
}
413+
}
414+
}
415+
// Also check for nested groups with conflicting endianness
416+
if (c == '(') {
417+
int closePos = findMatchingParen(groupContent, i);
418+
if (closePos != -1 && closePos + 1 < groupContent.length()) {
419+
char nestedEndian = groupContent.charAt(closePos + 1);
420+
if ((nestedEndian == '<' && groupEndian == '>') ||
421+
(nestedEndian == '>' && groupEndian == '<')) {
422+
return true;
423+
}
424+
}
425+
i = closePos; // Skip the nested group
426+
}
427+
}
428+
return false;
429+
}
430+
387431
private static void processGroup(String groupTemplate, UnpackState state, List<RuntimeBase> values,
388432
int repeatCount, boolean startsWithU, Stack<Boolean> modeStack) {
389433
// Save current mode

0 commit comments

Comments
 (0)