Got classes defined in script fully functional

This commit is contained in:
bigguy345 committed 2025-12-28 00:19:00 +02:00
1 parent 992aea663b
commit dfc0232e99
3 files changed
+100 -21

No files matched your search

@@ -336,9 +336,11 @@ public class ScriptDocument {
* Creates ScriptTypeInfo instances and stores them for later resolution.
*/
private void parseScriptTypes() {
// Pattern: (class|interface|enum) ClassName { ... }
// Pattern: [modifiers] (class|interface|enum) ClassName [optional ()] { ... }
// Matches optional modifiers (public, private, static, final, abstract) before class/interface/enum
// Also allows optional () after the class name (common mistake)
Pattern typeDecl = Pattern.compile(
"\\b(class|interface|enum)\\s+([A-Za-z_][a-zA-Z0-9_]*)\\s*(?:extends\\s+[A-Za-z_][a-zA-Z0-9_.]*)?\\s*(?:implements\\s+[A-Za-z_][a-zA-Z0-9_.,\\s]*)?\\s*\\{");
"(?:(?:public|private|protected|static|final|abstract)\\s+)*(class|interface|enum)\\s+([A-Za-z_][a-zA-Z0-9_]*)\\s*(?:\\(\\))?\\s*(?:extends\\s+[A-Za-z_][a-zA-Z0-9_.]*)?\\s*(?:implements\\s+[A-Za-z_][a-zA-Z0-9_.,\\s]*)?\\s*\\{");
Matcher m = typeDecl.matcher(text);
while (m.find()) {
@@ -361,8 +363,12 @@ public class ScriptDocument {
default: kind = TypeInfo.Kind.CLASS; break;
}
// Extract modifiers from the matched text
String fullMatch = text.substring(m.start(), m.end());
int modifiers = parseModifiers(fullMatch);
ScriptTypeInfo scriptType = ScriptTypeInfo.create(
typeName, kind, m.start(), bodyStart, bodyEnd);
typeName, kind, m.start(), bodyStart, bodyEnd, modifiers);
// Parse fields and methods inside this type
parseScriptTypeMembers(scriptType);
@@ -1697,22 +1703,30 @@ public class ScriptDocument {
} else {
if (isScriptMethod(methodName)) {
resolvedMethod = getScriptMethodInfo(methodName);
MethodCallInfo callInfo = new MethodCallInfo(
methodName, nameStart, nameEnd, openParen, closeParen,
arguments, null, resolvedMethod
);
// Only set expected type if this is the final expression (not followed by .field or .method)
if (!isFollowedByDot(closeParen)) {
TypeInfo expectedType = findExpectedTypeAtPosition(nameStart);
if (expectedType != null) {
callInfo.setExpectedType(expectedType);
// Check if this is a method from a script type
// Instance methods from script types cannot be called without a receiver
if (resolvedMethod != null && isMethodFromScriptType(resolvedMethod) && !resolvedMethod.isStatic()) {
// Instance method called without receiver - mark as undefined
marks.add(new ScriptLine.Mark(nameStart, nameEnd, TokenType.UNDEFINED_VAR));
} else {
MethodCallInfo callInfo = new MethodCallInfo(
methodName, nameStart, nameEnd, openParen, closeParen,
arguments, null, resolvedMethod
);
// Only set expected type if this is the final expression (not followed by .field or .method)
if (!isFollowedByDot(closeParen)) {
TypeInfo expectedType = findExpectedTypeAtPosition(nameStart);
if (expectedType != null) {
callInfo.setExpectedType(expectedType);
}
}
callInfo.validate();
methodCalls.add(callInfo);
marks.add(new ScriptLine.Mark(nameStart, nameEnd, TokenType.METHOD_CALL, callInfo));
}
callInfo.validate();
methodCalls.add(callInfo);
marks.add(new ScriptLine.Mark(nameStart, nameEnd, TokenType.METHOD_CALL, callInfo));
} else {
marks.add(new ScriptLine.Mark(nameStart, nameEnd, TokenType.UNDEFINED_VAR));
}
@@ -2476,6 +2490,30 @@ public class ScriptDocument {
}
return null;
}
/**
* Check if a method belongs to a script-defined type (class/interface/enum).
* Returns true if the method is defined inside a script type.
*/
private boolean isMethodFromScriptType(MethodInfo method) {
if (method == null || !method.isDeclaration()) {
return false;
}
int declPos = method.getDeclarationOffset();
if (declPos < 0) {
return false;
}
// Check if the method's declaration position is inside any script type's body
for (ScriptTypeInfo scriptType : scriptTypes.values()) {
if (scriptType.containsPosition(declPos)) {
return true;
}
}
return false;
}
private void markVariables(List<ScriptLine.Mark> marks) {
Set<String> knownKeywords = new HashSet<>(Arrays.asList(
@@ -18,6 +18,7 @@ public class ScriptTypeInfo extends TypeInfo {
private final int declarationOffset;
private final int bodyStart;
private final int bodyEnd;
private final int modifiers; // Java reflection modifiers (public, static, final, etc.)
// Script-defined members
private final Map<String, FieldInfo> fields = new HashMap<>();
@@ -28,24 +29,25 @@ public class ScriptTypeInfo extends TypeInfo {
private ScriptTypeInfo outerClass;
private ScriptTypeInfo(String simpleName, String fullName, Kind kind,
int declarationOffset, int bodyStart, int bodyEnd) {
int declarationOffset, int bodyStart, int bodyEnd, int modifiers) {
super(simpleName, fullName, "", kind, null, true, null, true);
this.scriptClassName = simpleName;
this.declarationOffset = declarationOffset;
this.bodyStart = bodyStart;
this.bodyEnd = bodyEnd;
this.modifiers = modifiers;
}
// Factory method
public static ScriptTypeInfo create(String simpleName, Kind kind,
int declarationOffset, int bodyStart, int bodyEnd) {
return new ScriptTypeInfo(simpleName, simpleName, kind, declarationOffset, bodyStart, bodyEnd);
int declarationOffset, int bodyStart, int bodyEnd, int modifiers) {
return new ScriptTypeInfo(simpleName, simpleName, kind, declarationOffset, bodyStart, bodyEnd, modifiers);
}
public static ScriptTypeInfo createInner(String simpleName, Kind kind, ScriptTypeInfo outer,
int declarationOffset, int bodyStart, int bodyEnd) {
int declarationOffset, int bodyStart, int bodyEnd, int modifiers) {
String fullName = outer.getFullName() + "$" + simpleName;
ScriptTypeInfo inner = new ScriptTypeInfo(simpleName, fullName, kind, declarationOffset, bodyStart, bodyEnd);
ScriptTypeInfo inner = new ScriptTypeInfo(simpleName, fullName, kind, declarationOffset, bodyStart, bodyEnd, modifiers);
inner.outerClass = outer;
outer.innerClasses.add(inner);
return inner;
@@ -56,6 +58,7 @@ public class ScriptTypeInfo extends TypeInfo {
public int getDeclarationOffset() { return declarationOffset; }
public int getBodyStart() { return bodyStart; }
public int getBodyEnd() { return bodyEnd; }
public int getModifiers() { return modifiers; }
public ScriptTypeInfo getOuterClass() { return outerClass; }
public List<ScriptTypeInfo> getInnerClasses() { return innerClasses; }
@@ -351,6 +351,44 @@ public class TokenHoverInfo {
addSegment(", ...", TokenType.DEFAULT.getHexColor());
}
}
} else if (typeInfo instanceof ScriptTypeInfo) {
// Script-defined type
ScriptTypeInfo scriptType = (ScriptTypeInfo) typeInfo;
// Icon
if (scriptType.getKind() == TypeInfo.Kind.INTERFACE) {
iconIndicator = "I";
} else if (scriptType.getKind() == TypeInfo.Kind.ENUM) {
iconIndicator = "E";
} else {
iconIndicator = "C";
}
// Build declaration with modifiers
int mods = scriptType.getModifiers();
// Modifiers
if (Modifier.isPublic(mods)) addSegment("public ", TokenType.MODIFIER.getHexColor());
if (Modifier.isAbstract(mods) && scriptType.getKind() != TypeInfo.Kind.INTERFACE)
addSegment("abstract ", TokenType.MODIFIER.getHexColor());
if (Modifier.isFinal(mods)) addSegment("final ", TokenType.MODIFIER.getHexColor());
if (Modifier.isStatic(mods)) addSegment("static ", TokenType.MODIFIER.getHexColor());
// Class type keyword
if (scriptType.getKind() == TypeInfo.Kind.INTERFACE) {
addSegment("interface ", TokenType.MODIFIER.getHexColor());
} else if (scriptType.getKind() == TypeInfo.Kind.ENUM) {
addSegment("enum ", TokenType.MODIFIER.getHexColor());
} else {
addSegment("class ", TokenType.MODIFIER.getHexColor());
}
// Class name
int classColor = scriptType.getKind() == TypeInfo.Kind.INTERFACE ? TokenType.INTERFACE_DECL.getHexColor()
: scriptType.getKind() == TypeInfo.Kind.ENUM ? TokenType.ENUM_DECL.getHexColor()
: TokenType.IMPORTED_CLASS.getHexColor();
addSegment(typeInfo.getSimpleName(), classColor);
} else {
// Unresolved type
iconIndicator = "?";