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
20 changes: 17 additions & 3 deletions src/main/java/org/perlonjava/backend/jvm/EmitVariable.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.perlonjava.frontend.semantic.SymbolTable;
import org.perlonjava.runtime.perlmodule.Strict;
import org.perlonjava.runtime.perlmodule.Warnings;
import org.perlonjava.runtime.operators.WarnDie;
import org.perlonjava.runtime.runtimetypes.*;

import java.util.ArrayList;
Expand Down Expand Up @@ -767,6 +768,18 @@ static void handleAssignOperator(EmitterVisitor emitterVisitor, BinaryOperatorNo
if (!ctx.symbolTable.isFeatureCategoryEnabled("refaliasing")) {
throw new PerlCompilerException(node.tokenIndex, "Experimental aliasing via reference not enabled", ctx.errorUtil);
}
// Emit experimental warning if warnings are enabled
if (ctx.symbolTable.isWarningCategoryEnabled("experimental::refaliasing")) {
try {
WarnDie.warn(
new RuntimeScalar("Aliasing via reference is experimental"),
new RuntimeScalar(ctx.errorUtil.warningLocation(node.tokenIndex))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println("Aliasing via reference is experimental" + ctx.errorUtil.warningLocation(node.tokenIndex) + ".");
}
}
// TODO: Implement proper reference aliasing
// For now, we just assign the reference value without creating an alias
// This is not fully correct but allows tests to progress
Expand Down Expand Up @@ -1096,11 +1109,12 @@ static void handleMyOperator(EmitterVisitor emitterVisitor, OperatorNode node) {
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("MY " + operator + " " + sigil + name);
if (emitterVisitor.ctx.symbolTable.getVariableIndexInCurrentScope(var) != -1) {
if (Warnings.warningManager.isWarningEnabled("redefine")) {
String message = operator.equals("our")
? "\"" + operator + "\" variable " + var + " redeclared"
: "\"" + operator + "\" variable " + var + " masks earlier declaration in same scope";
System.err.println(
emitterVisitor.ctx.errorUtil.errorMessage(node.getIndex(),
"Warning: \"" + operator + "\" variable "
+ var
+ " masks earlier declaration in same ctx.symbolTable"));
message));
}
}
int varIndex = emitterVisitor.ctx.symbolTable.addVariable(var, operator, sigilNode);
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/perlonjava/frontend/parser/FieldParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import org.perlonjava.frontend.astnode.OperatorNode;
import org.perlonjava.frontend.lexer.LexerToken;
import org.perlonjava.frontend.lexer.LexerTokenType;
import org.perlonjava.runtime.operators.WarnDie;
import org.perlonjava.runtime.runtimetypes.PerlCompilerException;
import org.perlonjava.runtime.runtimetypes.RuntimeScalar;

/**
* FieldParser handles parsing of field declarations in Perl classes.
Expand All @@ -29,9 +31,23 @@ public class FieldParser {
* @return A comment node placeholder for the field
*/
public static Node parseFieldDeclaration(Parser parser) {
int index = parser.tokenIndex;
// Consume 'field' keyword
TokenUtils.consume(parser, LexerTokenType.IDENTIFIER, "field");

// Emit experimental warning for 'field' if warnings are enabled
if (parser.ctx.symbolTable.isWarningCategoryEnabled("experimental::class")) {
try {
WarnDie.warn(
new RuntimeScalar("field is experimental"),
new RuntimeScalar(parser.ctx.errorUtil.warningLocation(index))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println("field is experimental" + parser.ctx.errorUtil.warningLocation(index) + ".");
}
}

// Parse the field variable (sigil + name)
LexerToken token = TokenUtils.peek(parser);

Expand Down
24 changes: 12 additions & 12 deletions src/main/java/org/perlonjava/frontend/parser/OperatorParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,11 @@ private static void addVariableToScope(EmitterContext ctx, String operator, Oper
String name = ((IdentifierNode) identifierNode).name;
String var = sigil + name;
if (ctx.symbolTable.getVariableIndexInCurrentScope(var) != -1) {
String message = operator.equals("our")
? "\"" + operator + "\" variable " + var + " redeclared"
: "\"" + operator + "\" variable " + var + " masks earlier declaration in same scope";
System.err.println(
ctx.errorUtil.errorMessage(node.getIndex(),
"Warning: \"" + operator + "\" variable "
+ var
+ " masks earlier declaration in same ctx.symbolTable"));
ctx.errorUtil.errorMessage(node.getIndex(), message));
}
int varIndex = ctx.symbolTable.addVariable(var, operator, node);
// Note: the isDeclaredReference flag is stored in node.annotations
Expand Down Expand Up @@ -284,11 +284,11 @@ static OperatorNode parseVariableDeclaration(Parser parser, String operator, int
try {
WarnDie.warn(
new RuntimeScalar("Declaring references is experimental"),
new RuntimeScalar(parser.ctx.errorUtil.errorMessage(currentIndex, ""))
new RuntimeScalar(parser.ctx.errorUtil.warningLocation(currentIndex))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println(parser.ctx.errorUtil.errorMessage(currentIndex, "Declaring references is experimental"));
System.err.println("Declaring references is experimental" + parser.ctx.errorUtil.warningLocation(currentIndex) + ".");
}
}

Expand Down Expand Up @@ -328,11 +328,11 @@ static OperatorNode parseVariableDeclaration(Parser parser, String operator, int
try {
WarnDie.warn(
new RuntimeScalar("Declaring references is experimental"),
new RuntimeScalar(parser.ctx.errorUtil.errorMessage(operandNode.tokenIndex, ""))
new RuntimeScalar(parser.ctx.errorUtil.warningLocation(operandNode.tokenIndex))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println(parser.ctx.errorUtil.errorMessage(operandNode.tokenIndex, "Declaring references is experimental"));
System.err.println("Declaring references is experimental" + parser.ctx.errorUtil.warningLocation(operandNode.tokenIndex) + ".");
}
}

Expand Down Expand Up @@ -862,11 +862,11 @@ static OperatorNode parseLocal(Parser parser, LexerToken token, int currentIndex
try {
WarnDie.warn(
new RuntimeScalar("Declaring references is experimental"),
new RuntimeScalar(parser.ctx.errorUtil.errorMessage(currentIndex, ""))
new RuntimeScalar(parser.ctx.errorUtil.warningLocation(currentIndex))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println(parser.ctx.errorUtil.errorMessage(currentIndex, "Declaring references is experimental"));
System.err.println("Declaring references is experimental" + parser.ctx.errorUtil.warningLocation(currentIndex) + ".");
}
}

Expand Down Expand Up @@ -905,11 +905,11 @@ static OperatorNode parseLocal(Parser parser, LexerToken token, int currentIndex
try {
WarnDie.warn(
new RuntimeScalar("Declaring references is experimental"),
new RuntimeScalar(parser.ctx.errorUtil.errorMessage(operandNode.tokenIndex, ""))
new RuntimeScalar(parser.ctx.errorUtil.warningLocation(operandNode.tokenIndex))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println(parser.ctx.errorUtil.errorMessage(operandNode.tokenIndex, "Declaring references is experimental"));
System.err.println("Declaring references is experimental" + parser.ctx.errorUtil.warningLocation(operandNode.tokenIndex) + ".");
}
}

Expand Down
28 changes: 28 additions & 0 deletions src/main/java/org/perlonjava/frontend/parser/StatementParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.perlonjava.frontend.lexer.LexerTokenType;
import org.perlonjava.runtime.mro.InheritanceResolver;
import org.perlonjava.runtime.operators.ModuleOperators;
import org.perlonjava.runtime.operators.WarnDie;
import org.perlonjava.runtime.operators.VersionHelper;
import org.perlonjava.runtime.perlmodule.Universal;
import org.perlonjava.runtime.runtimetypes.*;
Expand Down Expand Up @@ -351,6 +352,19 @@ public static Node parseDeferStatement(Parser parser) {
int index = parser.tokenIndex;
TokenUtils.consume(parser, LexerTokenType.IDENTIFIER); // "defer"

// Emit experimental warning if warnings are enabled
if (parser.ctx.symbolTable.isWarningCategoryEnabled("experimental::defer")) {
try {
WarnDie.warn(
new RuntimeScalar("defer is experimental"),
new RuntimeScalar(parser.ctx.errorUtil.warningLocation(index))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println("defer is experimental" + parser.ctx.errorUtil.warningLocation(index) + ".");
}
}

// Parse the defer block
TokenUtils.consume(parser, LexerTokenType.OPERATOR, "{");
Node deferBlock = ParseBlock.parseBlock(parser);
Expand Down Expand Up @@ -679,6 +693,20 @@ public static Node parsePackageDeclaration(Parser parser, LexerToken token) {
packageExistsCache.put(packageName, true);

boolean isClass = token.text.equals("class");

// Emit experimental warning for 'class' if warnings are enabled
if (isClass && parser.ctx.symbolTable.isWarningCategoryEnabled("experimental::class")) {
try {
WarnDie.warn(
new RuntimeScalar("class is experimental"),
new RuntimeScalar(parser.ctx.errorUtil.warningLocation(parser.tokenIndex))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println("class is experimental" + parser.ctx.errorUtil.warningLocation(parser.tokenIndex) + ".");
}
}

IdentifierNode nameNode = new IdentifierNode(packageName, parser.tokenIndex);
OperatorNode packageNode = new OperatorNode(token.text, nameNode, parser.tokenIndex);
packageNode.setAnnotation("isClass", isClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import org.perlonjava.frontend.lexer.LexerToken;
import org.perlonjava.frontend.lexer.LexerTokenType;
import org.perlonjava.frontend.semantic.SymbolTable;
import org.perlonjava.runtime.operators.WarnDie;
import org.perlonjava.runtime.runtimetypes.NameNormalizer;
import org.perlonjava.runtime.runtimetypes.PerlCompilerException;
import org.perlonjava.runtime.runtimetypes.RuntimeScalar;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -121,6 +123,19 @@ public static Node parseStatement(Parser parser, String label) {

case "method" -> {
if (parser.ctx.symbolTable.isFeatureCategoryEnabled("class")) {
// Emit experimental warning for 'method' if warnings are enabled
if (parser.ctx.symbolTable.isWarningCategoryEnabled("experimental::class")) {
try {
WarnDie.warn(
new RuntimeScalar("method is experimental"),
new RuntimeScalar(parser.ctx.errorUtil.warningLocation(currentIndex))
);
} catch (Exception e) {
// If warning system isn't initialized yet, fall back to System.err
System.err.println("method is experimental" + parser.ctx.errorUtil.warningLocation(currentIndex) + ".");
}
}

// Parse method more directly
parser.tokenIndex++; // consume "method"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,18 @@ public String errorMessage(int index, String message) {
return message + " at " + loc.fileName() + " line " + loc.lineNumber() + ", near " + errorMessageQuote(nearString) + "\n";
}

/**
* Gets a simple warning location string in the format " at filename line N".
* This matches system Perl's warning format without the ", near" suffix.
*
* @param index the index of the token where the warning occurred
* @return the location string (e.g., " at script.pl line 42")
*/
public String warningLocation(int index) {
SourceLocation loc = getSourceLocationAccurate(index);
return " at " + loc.fileName() + " line " + loc.lineNumber();
}

private String buildNearString(int index) {
int end = Math.min(tokens.size() - 1, index + 5);
StringBuilder sb = new StringBuilder();
Expand Down
Loading