Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static RuntimeScalar ensureMutableScalar(RuntimeBase val) {
copy.type = ro.type;
copy.value = ro.value;
copy.numericLiteralText = ro.numericLiteralText;
copy.numericContextSeen = ro.numericContextSeen;
return copy;
}
if (val instanceof ScalarSpecialVariable sv) {
Expand All @@ -39,6 +40,7 @@ static RuntimeScalar ensureMutableScalar(RuntimeBase val) {
copy.type = src.type;
copy.value = src.value;
copy.numericLiteralText = src.numericLiteralText;
copy.numericContextSeen = src.numericContextSeen;
return copy;
}
return (RuntimeScalar) val;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ static RuntimeScalar ensureMutableScalar(RuntimeBase val) {
copy.type = ro.type;
copy.value = ro.value;
copy.numericLiteralText = ro.numericLiteralText;
copy.numericContextSeen = ro.numericContextSeen;
return copy;
}
if (val instanceof ScalarSpecialVariable sv) {
Expand All @@ -47,6 +48,7 @@ static RuntimeScalar ensureMutableScalar(RuntimeBase val) {
copy.type = src.type;
copy.value = src.value;
copy.numericLiteralText = src.numericLiteralText;
copy.numericContextSeen = src.numericContextSeen;
return copy;
}
return (RuntimeScalar) val;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.perlonjava.runtime.runtimetypes.RuntimeArray;
import org.perlonjava.runtime.runtimetypes.RuntimeCode;
import org.perlonjava.runtime.runtimetypes.RuntimeList;
import org.perlonjava.runtime.runtimetypes.RuntimeScalar;

public class DataDumper extends PerlModuleBase {

Expand All @@ -22,6 +23,7 @@ public static void initialize() {
DataDumper dataDumper = new DataDumper();
try {
dataDumper.registerMethod("Dumpxs", null);
dataDumper.registerMethod("_perlonjava_numified_safe_decimal", "$");
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing Data::Dumper method: " + e.getMessage());
}
Expand All @@ -40,4 +42,11 @@ public static RuntimeList Dumpxs(RuntimeArray args, int ctx) {
return RuntimeCode.apply(
GlobalVariable.getGlobalCodeRef("Data::Dumper::Dumpperl"), args, ctx);
}

public static RuntimeList _perlonjava_numified_safe_decimal(RuntimeArray args, int ctx) {
if (args.size() != 1) {
throw new IllegalStateException("Bad number of arguments for _perlonjava_numified_safe_decimal() method");
}
return new RuntimeScalar(args.get(0).isDataDumperNumifiedSafeDecimal()).getList();
}
}
16 changes: 11 additions & 5 deletions src/main/java/org/perlonjava/runtime/perlmodule/DataUUID.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,19 +211,19 @@ public static RuntimeList compare(RuntimeArray args, int ctx) {
// --- Exported NameSpace constants ---------------------------------------

public static RuntimeList NameSpace_DNS(RuntimeArray args, int ctx) {
return new RuntimeScalar(NS_DNS).getList();
return byteStringScalar(NS_DNS).getList();
}

public static RuntimeList NameSpace_URL(RuntimeArray args, int ctx) {
return new RuntimeScalar(NS_URL).getList();
return byteStringScalar(NS_URL).getList();
}

public static RuntimeList NameSpace_OID(RuntimeArray args, int ctx) {
return new RuntimeScalar(NS_OID).getList();
return byteStringScalar(NS_OID).getList();
}

public static RuntimeList NameSpace_X500(RuntimeArray args, int ctx) {
return new RuntimeScalar(NS_X500).getList();
return byteStringScalar(NS_X500).getList();
}

// --- Internal helpers ---------------------------------------------------
Expand Down Expand Up @@ -296,7 +296,7 @@ private static byte[] createFromNameBytes(RuntimeArray args) {
private static RuntimeList makeRet(byte[] u, int type) {
switch (type) {
case F_BIN:
return new RuntimeScalar(bytesToLatin1(u)).getList();
return byteStringScalar(bytesToLatin1(u)).getList();
case F_STR: {
String hex = bytesToUpperHex(u);
StringBuilder sb = new StringBuilder(36);
Expand Down Expand Up @@ -382,6 +382,12 @@ private static String bytesToLatin1(byte[] bytes) {
return new String(bytes, StandardCharsets.ISO_8859_1);
}

private static RuntimeScalar byteStringScalar(String value) {
RuntimeScalar scalar = new RuntimeScalar(value);
scalar.type = RuntimeScalarType.BYTE_STRING;
return scalar;
}

private static String bytesToUpperHex(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
Expand Down
51 changes: 43 additions & 8 deletions src/main/java/org/perlonjava/runtime/regex/RuntimeRegex.java
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,8 @@ public static RuntimeScalar getQuotedRegex(RuntimeScalar patternString, RuntimeS
*/
public static RuntimeScalar getReplacementRegex(RuntimeScalar patternString, RuntimeScalar replacement, RuntimeScalar modifiers) {
// Use resolveRegex to properly handle qr objects and qr overloading
RuntimeRegex resolvedRegex = resolveRegex(patternString);
ResolvedRegex resolved = resolveRegexWithOrigin(patternString);
RuntimeRegex resolvedRegex = resolved.regex();
String modifierStr = modifiers.toString();

// Create a new regex instance with the replacement
Expand All @@ -995,7 +996,9 @@ public static RuntimeScalar getReplacementRegex(RuntimeScalar patternString, Run

// Only recompile if we have new modifiers that actually change the flags
if (!modifierStr.isEmpty()) {
RegexFlags newFlags = mergeRegexFlags(resolvedRegex.regexFlags, modifierStr, resolvedRegex.patternString);
RegexFlags newFlags = resolved.fromCompiledRegex()
? mergeOperationFlags(resolvedRegex.regexFlags, modifierStr, resolvedRegex.patternString)
: mergeRegexFlags(resolvedRegex.regexFlags, modifierStr, resolvedRegex.patternString);

// Check if the merged flags are actually different
boolean flagsChanged = false;
Expand All @@ -1006,7 +1009,7 @@ public static RuntimeScalar getReplacementRegex(RuntimeScalar patternString, Run
}

// Only recompile if flags actually changed (this is needed for /x preprocessing)
if (flagsChanged) {
if (flagsChanged && !resolved.fromCompiledRegex()) {
RuntimeRegex recompiledRegex = compile(resolvedRegex.patternString, newFlags.toFlagString());
regex.pattern = recompiledRegex.pattern;
regex.patternUnicode = recompiledRegex.patternUnicode;
Expand All @@ -1022,7 +1025,9 @@ public static RuntimeScalar getReplacementRegex(RuntimeScalar patternString, Run
regex.hasCodeBlockCaptures = recompiledRegex.hasCodeBlockCaptures;
regex.warningsOnUse = new ArrayList<>(recompiledRegex.warningsOnUse);
} else {
// Just update the flags without recompiling
// Just update the flags without recompiling. A compiled qr// used
// as the whole substitution pattern keeps its own pattern flags;
// outer s/// flags like /x or /i must not reinterpret its source.
regex.regexFlags = newFlags;
regex.hasPreservesMatch = regex.hasPreservesMatch || newFlags.preservesMatch();
regex.useGAssertion = newFlags.useGAssertion();
Expand Down Expand Up @@ -2441,6 +2446,32 @@ private static boolean hasInlineAsciiModifier(String pattern) {
return false;
}

private record ResolvedRegex(RuntimeRegex regex, boolean fromCompiledRegex) {}

private static RegexFlags mergeOperationFlags(RegexFlags baseFlags, String modifiers, String patternString) {
RegexFlags base = baseFlags != null ? baseFlags : fromModifiers("", patternString);
RegexFlags operation = fromModifiers(modifiers == null ? "" : modifiers, patternString);

return new RegexFlags(
base.isGlobalMatch() || operation.isGlobalMatch(),
base.keepCurrentPosition() || operation.keepCurrentPosition(),
base.isNonDestructive() || operation.isNonDestructive(),
base.isMatchExactlyOnce(),
base.useGAssertion(),
base.isExtendedWhitespace(),
base.isNonCapturing(),
base.isOptimized() || operation.isOptimized(),
base.isCaseInsensitive(),
base.isMultiLine(),
base.isDotAll(),
base.isExtended(),
base.preservesMatch() || operation.preservesMatch(),
base.isUnicode(),
base.isAscii(),
base.allowEvalGroup() || operation.allowEvalGroup()
);
}

/**
* Resolves a scalar to a RuntimeRegex, handling qr overloading if necessary.
*
Expand All @@ -2449,11 +2480,15 @@ private static boolean hasInlineAsciiModifier(String pattern) {
* @throws PerlCompilerException if qr overload doesn't return proper regex
*/
private static RuntimeRegex resolveRegex(RuntimeScalar quotedRegex) {
return resolveRegexWithOrigin(quotedRegex).regex();
}

private static ResolvedRegex resolveRegexWithOrigin(RuntimeScalar quotedRegex) {
// Unwrap readonly scalar
if (quotedRegex.type == RuntimeScalarType.READONLY_SCALAR) quotedRegex = (RuntimeScalar) quotedRegex.value;

if (quotedRegex.type == RuntimeScalarType.REGEX) {
return (RuntimeRegex) quotedRegex.value;
return new ResolvedRegex((RuntimeRegex) quotedRegex.value, true);
}

// Check if the object has qr overloading
Expand All @@ -2466,21 +2501,21 @@ private static RuntimeRegex resolveRegex(RuntimeScalar quotedRegex) {
if (overloadedResult != null) {
// The result must be a compiled regex
if (overloadedResult.type == RuntimeScalarType.REGEX) {
return (RuntimeRegex) overloadedResult.value;
return new ResolvedRegex((RuntimeRegex) overloadedResult.value, true);
}
throw new PerlCompilerException("Overloaded qr did not return a REGEXP");
}

// Try fallback to string conversion
RuntimeScalar fallbackResult = overloadCtx.tryOverloadFallback(quotedRegex, "(\"\"");
if (fallbackResult != null) {
return compile(fallbackResult.toString(), "");
return new ResolvedRegex(compile(fallbackResult.toString(), ""), false);
}
}
}

// Default: compile as string
return compile(quotedRegex.toString(), "");
return new ResolvedRegex(compile(quotedRegex.toString(), ""), false);
}

@Override
Expand Down
Loading
Loading