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 d2e6d51d1..0023724bd 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 @@ -448,7 +448,9 @@ public class ScriptDocument { // 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 + scriptType, + // Return type is the type itself + scriptType, params, fullDeclOffset, typeOffset, @@ -456,8 +458,7 @@ public class ScriptDocument { constructorBodyStart, constructorBodyEnd, modifiers, - documentation - ); + documentation); scriptType.addConstructor(constructorInfo); } } @@ -504,10 +505,10 @@ public class ScriptDocument { String methodName = m.group(2); String paramList = m.group(3); String delimiter = m.group(4); - boolean bodyless = delimiter.equals(";"); + boolean hasBody = delimiter.equals("{"); - int bodyStart = bodyless ? m.end() : text.indexOf('{', m.end() - 1); - int bodyEnd = bodyless ? m.end() : findMatchingBrace(bodyStart); + int bodyStart = !hasBody ? m.end() : text.indexOf('{', m.end() - 1); + int bodyEnd = !hasBody ? m.end() : findMatchingBrace(bodyStart); if (bodyEnd < 0) bodyEnd = text.length(); @@ -523,11 +524,19 @@ public class ScriptDocument { int nameOffset = m.start(2); // Start of method name int fullDeclOffset = findFullDeclarationStart(m.start(1), text); // Start including modifiers + ScriptTypeInfo scriptType = null; + for (ScriptTypeInfo type : scriptTypes.values()) + if (type.containsPosition(bodyStart)) { + scriptType = type; + break; + } + // Parse parameters with their actual positions List params = parseParametersWithPositions(paramList, m.start(3)); MethodInfo methodInfo = MethodInfo.declaration( methodName, + scriptType, resolveType(returnType), params, fullDeclOffset, @@ -539,25 +548,15 @@ public class ScriptDocument { documentation ); - ScriptTypeInfo scriptType = null; - for (ScriptTypeInfo type : scriptTypes.values()) - if (type.containsPosition(bodyStart)) { - scriptType = type; - break; - } - - - // 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)); if (scriptType != null) { - if (scriptType.getKind() == TypeInfo.Kind.INTERFACE) - methodInfo.setBodyless(bodyless); - scriptType.addMethod(methodInfo); } else methods.add(methodInfo); + + // Validate the method (return statements, parameters) with type resolution + String methodBodyText = bodyEnd > bodyStart + 1 ? text.substring(bodyStart + 1, bodyEnd) : ""; + methodInfo.validate(methodBodyText, hasBody, (expr, pos) -> resolveExpressionType(expr, pos)); } // Check for duplicate method declarations diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java index 1d4092d7b..5b64373bf 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/method/MethodInfo.java @@ -33,7 +33,8 @@ public final class MethodInfo { */ public enum ErrorType { NONE, - MISSING_RETURN, // Non-void method missing return statement + MISSING_RETURN, // Non-void method missing return statement, + INTERFACE_METHOD_BODY, // Interface method has a body MISSING_BODY, // Non-void method missing return statement RETURN_TYPE_MISMATCH, // Return statement type doesn't match method return type VOID_METHOD_RETURNS_VALUE, // Void method returns a value @@ -57,7 +58,6 @@ public final class MethodInfo { private final String documentation; // Javadoc/comment documentation for this method private final java.lang.reflect.Method javaMethod; // The Java reflection Method, if this was created from reflection - private boolean bodyless; // Error tracking for method declarations private ErrorType errorType = ErrorType.NONE; private String errorMessage; @@ -84,31 +84,10 @@ public final class MethodInfo { this.javaMethod = javaMethod; } - // Factory methods - public static MethodInfo declaration(String name, TypeInfo returnType, List params, - 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, null); - } - - public static MethodInfo declaration(String name, TypeInfo returnType, List params, - 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, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, null, null); - } - - public static MethodInfo declaration(String name, TypeInfo returnType, List params, - 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, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, documentation, null); - } - - public static MethodInfo declaration(String name, TypeInfo returnType, List params, + public static MethodInfo declaration(String name, TypeInfo containingType, TypeInfo returnType, List params, 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, null); + return new MethodInfo(name, returnType, containingType, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, documentation, null); } public static MethodInfo call(String name, TypeInfo containingType, int paramCount) { @@ -195,8 +174,6 @@ public final class MethodInfo { public boolean isPrivate() { return Modifier.isPrivate(modifiers); } public boolean isProtected() { return Modifier.isProtected(modifiers); } public String getDocumentation() { return documentation; } - public boolean isBodyless() { return bodyless; } - public void setBodyless(boolean bodyless) { this.bodyless = bodyless; } /** * Check if a position is inside this method's body. @@ -407,16 +384,7 @@ public final class MethodInfo { public interface TypeResolver { TypeInfo resolveExpression(String expression, int position); } - - /** - * Validate this method declaration. - * Checks for parameter errors and missing return statements. - * - * @param methodBodyText The text content of the method body (between { and }) - */ - public void validate(String methodBodyText) { - validate(methodBodyText, null); - } + /** * Validate this method declaration with type resolution for return statements. @@ -425,16 +393,22 @@ public final class MethodInfo { * @param methodBodyText The text content of the method body (between { and }) * @param typeResolver Optional callback to resolve expression types (for return type checking) */ - public void validate(String methodBodyText, TypeResolver typeResolver) { + public void validate(String methodBodyText, boolean hasBody, TypeResolver typeResolver) { if (!isDeclaration) return; // Validate parameters validateParameters(); - + boolean interfaceMember = containingType != null && containingType.isInterface(); + if (hasBody && (interfaceMember || isAbstract() || isNative())) { + setError(MethodInfo.ErrorType.INTERFACE_METHOD_BODY, "Interface or abstract methods cannot have a body"); + return; + } + //No need to check for return types/statements - if(bodyless) + if(interfaceMember) return; + //If no body and not interface or abstract/native if (bodyStart == bodyEnd && !isAbstract() && !isNative()) { setError(ErrorType.MISSING_BODY, "Method must have a body or be declared abstract/native."); return; diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java index 9fdf8dac4..7e2b512c2 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeInfo.java @@ -130,7 +130,9 @@ public class TypeInfo { public boolean isResolved() { return resolved; } public TypeInfo getEnclosingType() { return enclosingType; } public boolean isInnerClass() { return enclosingType != null; } - + public boolean isInterface() {return kind == Kind.INTERFACE;} + public boolean isEnum() {return kind == Kind.ENUM;} + /** * Get the appropriate TokenType for highlighting this type. */