diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodInfo.java index c8bee1855..9e9ed9039 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodInfo.java @@ -5,11 +5,20 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * Metadata for a method declaration or method call. * Tracks method name, parameters, return type, and containing class. + * + *

This class delegates to helper classes for specific functionality:

+ * */ public final class MethodInfo { @@ -17,7 +26,9 @@ public final class MethodInfo { private final TypeInfo returnType; private final TypeInfo containingType; // The class/interface that owns this method private final List parameters; - private final int declarationOffset; // -1 for external methods (calls to library methods) + private final int fullDeclarationOffset; // Start of full declaration (including modifiers), -1 for external + private final int typeOffset; // Start of return type + private final int nameOffset; // Start of method name private final int bodyStart; // Start of method body (after {) private final int bodyEnd; // End of method body (before }) private final boolean resolved; @@ -26,14 +37,16 @@ public final class MethodInfo { private final String documentation; // Javadoc/comment documentation for this method private MethodInfo(String name, TypeInfo returnType, TypeInfo containingType, - List parameters, int declarationOffset, + List parameters, int fullDeclarationOffset, int typeOffset, int nameOffset, int bodyStart, int bodyEnd, boolean resolved, boolean isDeclaration, int modifiers, String documentation) { this.name = name; this.returnType = returnType; this.containingType = containingType; this.parameters = parameters != null ? new ArrayList<>(parameters) : new ArrayList<>(); - this.declarationOffset = declarationOffset; + this.fullDeclarationOffset = fullDeclarationOffset; + this.typeOffset = typeOffset; + this.nameOffset = nameOffset; this.bodyStart = bodyStart; this.bodyEnd = bodyEnd; this.resolved = resolved; @@ -44,25 +57,29 @@ public final class MethodInfo { // Factory methods public static MethodInfo declaration(String name, TypeInfo returnType, List params, - int declOffset, int bodyStart, int bodyEnd) { - return new MethodInfo(name, returnType, null, params, declOffset, bodyStart, bodyEnd, true, true, 0, null); + int fullDeclOffset, int typeOffset, int nameOffset, + int bodyStart, int bodyEnd) { + return new MethodInfo(name, returnType, null, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, 0, null); } public static MethodInfo declaration(String name, TypeInfo returnType, List params, - int declOffset, int bodyStart, int bodyEnd, boolean isStatic) { + int fullDeclOffset, int typeOffset, int nameOffset, + int bodyStart, int bodyEnd, boolean isStatic) { int modifiers = isStatic ? Modifier.STATIC : 0; - return new MethodInfo(name, returnType, null, params, declOffset, bodyStart, bodyEnd, true, true, modifiers, null); + return new MethodInfo(name, returnType, null, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, null); } public static MethodInfo declaration(String name, TypeInfo returnType, List params, - int declOffset, int bodyStart, int bodyEnd, boolean isStatic, String documentation) { + int fullDeclOffset, int typeOffset, int nameOffset, + int bodyStart, int bodyEnd, boolean isStatic, String documentation) { int modifiers = isStatic ? Modifier.STATIC : 0; - return new MethodInfo(name, returnType, null, params, declOffset, bodyStart, bodyEnd, true, true, modifiers, documentation); + return new MethodInfo(name, returnType, null, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, documentation); } public static MethodInfo declaration(String name, TypeInfo returnType, List params, - int declOffset, int bodyStart, int bodyEnd, int modifiers, String documentation) { - return new MethodInfo(name, returnType, null, params, declOffset, bodyStart, bodyEnd, true, true, modifiers, documentation); + int fullDeclOffset, int typeOffset, int nameOffset, + int bodyStart, int bodyEnd, int modifiers, String documentation) { + return new MethodInfo(name, returnType, null, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, documentation); } public static MethodInfo call(String name, TypeInfo containingType, int paramCount) { @@ -72,7 +89,7 @@ public final class MethodInfo { for (int i = 0; i < paramCount; i++) { params.add(FieldInfo.unresolved("arg" + i, FieldInfo.Scope.PARAMETER)); } - return new MethodInfo(name, null, containingType, params, -1, -1, -1, resolved, false, 0, null); + return new MethodInfo(name, null, containingType, params, -1, -1, -1, -1, -1, resolved, false, 0, null); } public static MethodInfo unresolvedCall(String name, int paramCount) { @@ -80,7 +97,7 @@ public final class MethodInfo { for (int i = 0; i < paramCount; i++) { params.add(FieldInfo.unresolved("arg" + i, FieldInfo.Scope.PARAMETER)); } - return new MethodInfo(name, null, null, params, -1, -1, -1, false, false, 0, null); + return new MethodInfo(name, null, null, params, -1, -1, -1, -1, -1, false, false, 0, null); } /** @@ -99,7 +116,7 @@ public final class MethodInfo { params.add(FieldInfo.reflectionParam("arg" + i, paramType)); } - return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, true, false, modifiers, null); + return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, -1, -1, true, false, modifiers, null); } /** @@ -118,7 +135,7 @@ public final class MethodInfo { params.add(FieldInfo.reflectionParam("arg" + i, paramType)); } - return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, true, true, modifiers, null); + return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, -1, -1, true, true, modifiers, null); } // Getters @@ -127,7 +144,12 @@ public final class MethodInfo { public TypeInfo getContainingType() { return containingType; } public List getParameters() { return Collections.unmodifiableList(parameters); } public int getParameterCount() { return parameters.size(); } - public int getDeclarationOffset() { return declarationOffset; } + /** @deprecated Use getTypeOffset() or getNameOffset() instead */ + @Deprecated + public int getDeclarationOffset() { return typeOffset; } + public int getFullDeclarationOffset() { return fullDeclarationOffset; } + public int getTypeOffset() { return typeOffset; } + public int getNameOffset() { return nameOffset; } public int getBodyStart() { return bodyStart; } public int getBodyEnd() { return bodyEnd; } public boolean isResolved() { return resolved; } 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 bd0458c13..73874410c 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 @@ -455,8 +455,23 @@ public class ScriptDocument { List params = parseParametersWithPositions(paramList, bodyStart + 1 + mm.start(3)); + // Calculate the three offsets + int typeOffset = bodyStart + 1 + mm.start(1); // Start of return type + int nameOffset = bodyStart + 1 + mm.start(2); // Start of method name + int fullDeclOffset = findFullDeclarationStart(mm.start(1), bodyText); + if (fullDeclOffset >= 0) { + fullDeclOffset += bodyStart + 1; + } else { + fullDeclOffset = typeOffset; + } + MethodInfo methodInfo = MethodInfo.declaration( - methodName, returnType, params, absPos, methodBodyStart, methodBodyEnd, modifiers, documentation); + methodName, returnType, params, fullDeclOffset, typeOffset, nameOffset, methodBodyStart, methodBodyEnd, modifiers, documentation); + + // Validate the method (including return type checking) + String methodBodyText = text.substring(methodBodyStart + 1, methodBodyEnd); + methodInfo.validate(methodBodyText, (expr, pos) -> resolveExpressionType(expr, pos)); + scriptType.addMethod(methodInfo); } @@ -485,12 +500,25 @@ public class ScriptDocument { // Parse parameters with their actual positions List params = parseParametersWithPositions(paramList, bodyStart + 1 + cm.start(1)); + // Calculate the three offsets for constructor + // For constructors, type offset and name offset are the same (start of constructor name) + int nameOffset = bodyStart + 1 + cm.start(); + int typeOffset = nameOffset; // No separate type for constructors + int fullDeclOffset = findFullDeclarationStart(cm.start(), bodyText); + if (fullDeclOffset >= 0) { + fullDeclOffset += bodyStart + 1; + } else { + fullDeclOffset = nameOffset; + } + // Constructors don't have a return type, but we'll use the containing type as a marker MethodInfo constructorInfo = MethodInfo.declaration( typeName, scriptType, // Return type is the type itself params, - absPos, + fullDeclOffset, + typeOffset, + nameOffset, constructorBodyStart, constructorBodyEnd, modifiers, @@ -547,6 +575,11 @@ public class ScriptDocument { // Extract modifiers by scanning backwards from match start int modifiers = extractModifiersBackwards(m.start() - 1, text); + + // Calculate offset positions + int typeOffset = m.start(1); // Start of return type + int nameOffset = m.start(2); // Start of method name + int fullDeclOffset = findFullDeclarationStart(m.start(1), text); // Start including modifiers // Parse parameters with their actual positions List params = parseParametersWithPositions(paramList, m.start(3)); @@ -555,12 +588,19 @@ public class ScriptDocument { methodName, resolveType(returnType), params, - m.start(), + fullDeclOffset, + typeOffset, + nameOffset, bodyStart, bodyEnd, modifiers, documentation ); + + // Validate the method (return statements, parameters) with type resolution + String methodBodyText = bodyEnd > bodyStart + 1 ? text.substring(bodyStart + 1, bodyEnd) : ""; + methodInfo.validate(methodBodyText, (expr, pos) -> resolveExpressionType(expr, pos)); + methods.add(methodInfo); } @@ -584,6 +624,48 @@ public class ScriptDocument { } } + /** + * Find the start of a full method declaration, including any modifiers before the type. + */ + private int findFullDeclarationStart(int typeStart, String sourceText) { + int pos = typeStart - 1; + + // Skip whitespace before type + while (pos >= 0 && Character.isWhitespace(sourceText.charAt(pos))) { + pos--; + } + + // Check for modifiers + int earliestPos = typeStart; + while (pos >= 0) { + // Skip whitespace + while (pos >= 0 && Character.isWhitespace(sourceText.charAt(pos))) { + pos--; + } + if (pos < 0) break; + + // Read word backwards + int wordEnd = pos + 1; + while (pos >= 0 && Character.isJavaIdentifierPart(sourceText.charAt(pos))) { + pos--; + } + int wordStart = pos + 1; + + if (wordStart < wordEnd) { + String word = sourceText.substring(wordStart, wordEnd); + if (TypeResolver.isModifier(word)) { + earliestPos = wordStart; + } else { + break; + } + } else { + break; + } + } + + return earliestPos; + } + private List parseParametersWithPositions(String paramList, int paramListStart) { List params = new ArrayList<>(); if (paramList == null || paramList.trim().isEmpty()) {