diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index 4318facae..8a9a6c44d 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -4616,6 +4616,17 @@ public class ScriptDocument { return significantDigits > maxDigits; } + private TypeInfo narrowIntLiteral(String literalText) { + TypeInfo expectedType = ExpressionTypeResolver.CURRENT_EXPECTED_TYPE; + if (expectedType != null) { + TypeInfo narrowed = TypeChecker.narrowLiteralToExpectedType(literalText, expectedType); + if (narrowed != null) { + return narrowed; + } + } + return TypeInfo.fromPrimitive("int"); + } + /** * Comprehensive expression type resolver that handles: * - Literals (strings, numbers, booleans, null) @@ -4692,9 +4703,17 @@ public class ScriptDocument { if (expr.matches("-?\\d+[lL]")) { return TypeInfo.fromPrimitive("long"); } + // Hex integer literals: 0x7F, -0x80, 0X1A + if (expr.matches("[-+]?0[xX][0-9a-fA-F][0-9a-fA-F_]*")) { + return narrowIntLiteral(expr); + } + // Binary integer literals: 0b1010, -0b1100, 0B1111 + if (expr.matches("[-+]?0[bB][01][01_]*")) { + return narrowIntLiteral(expr); + } // Int: plain integers without suffix - if (expr.matches("-?\\d+")) { - return TypeInfo.fromPrimitive("int"); + if (expr.matches("[-+]?\\d[\\d_]*")) { + return narrowIntLiteral(expr); } // "this" keyword @@ -5459,8 +5478,16 @@ public class ScriptDocument { if (expr.matches("-?\\d+[lL]")) { return TypeInfo.fromPrimitive("long"); } - if (expr.matches("-?\\d+")) { - return TypeInfo.fromPrimitive("int"); + // Hex integer literals: 0x7F, -0x80, 0X1A + if (expr.matches("[-+]?0[xX][0-9a-fA-F][0-9a-fA-F_]*")) { + return narrowIntLiteral(expr); + } + // Binary integer literals: 0b1010, -0b1100, 0B1111 + if (expr.matches("[-+]?0[bB][01][01_]*")) { + return narrowIntLiteral(expr); + } + if (expr.matches("[-+]?\\d[\\d_]*")) { + return narrowIntLiteral(expr); } // "this" keyword diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/expression/ExpressionTypeResolver.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/expression/ExpressionTypeResolver.java index 17557668b..eee81cd2c 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/expression/ExpressionTypeResolver.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/expression/ExpressionTypeResolver.java @@ -75,7 +75,14 @@ public class ExpressionTypeResolver { private TypeInfo resolveNodeType(ExpressionNode node) { if (node == null) return null; - if (node instanceof ExpressionNode.IntLiteralNode) return TypeInfo.fromPrimitive("int"); + if (node instanceof ExpressionNode.IntLiteralNode) { + if (CURRENT_EXPECTED_TYPE != null) { + TypeInfo narrowed = TypeChecker.narrowLiteralToExpectedType( + ((ExpressionNode.IntLiteralNode) node).getValue(), CURRENT_EXPECTED_TYPE); + if (narrowed != null) return narrowed; + } + return TypeInfo.fromPrimitive("int"); + } if (node instanceof ExpressionNode.LongLiteralNode) return TypeInfo.fromPrimitive("long"); if (node instanceof ExpressionNode.FloatLiteralNode) return TypeInfo.fromPrimitive("float"); if (node instanceof ExpressionNode.DoubleLiteralNode) return TypeInfo.fromPrimitive("double"); @@ -132,6 +139,14 @@ public class ExpressionTypeResolver { if (node instanceof ExpressionNode.UnaryOpNode) { ExpressionNode.UnaryOpNode un = (ExpressionNode.UnaryOpNode) node; + // Special case: negation of an IntLiteralNode can narrow to byte/short + if (un.getOperator() == OperatorType.UNARY_MINUS + && un.getOperand() instanceof ExpressionNode.IntLiteralNode + && CURRENT_EXPECTED_TYPE != null) { + String negatedText = "-" + ((ExpressionNode.IntLiteralNode) un.getOperand()).getValue(); + TypeInfo narrowed = TypeChecker.narrowLiteralToExpectedType(negatedText, CURRENT_EXPECTED_TYPE); + if (narrowed != null) return narrowed; + } TypeInfo operandType = resolveNodeType(un.getOperand()); return TypeRules.resolveUnaryOperatorType(un.getOperator(), operandType); } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeChecker.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeChecker.java index c92f384a3..cd4a63261 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeChecker.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeChecker.java @@ -332,6 +332,136 @@ public final class TypeChecker { return null; } + /** + * Attempt to narrow an integer literal to byte, short, or char when the + * expected type requires it. The expression resolver normally infers integer + * literals as {@code int}; this helper allows callers to re-type a literal + * when {@code ExpressionTypeResolver.CURRENT_EXPECTED_TYPE} is set (e.g. + * method-argument second pass or assignment RHS). + * + *
Supported literal formats:
+ *Range checks:
+ *