Implemented TypeParamInfo to TypeInfo and JSTypeInfo, and resolved all type params of JS API types after all are loaded

This commit is contained in:
bigguy345 committed 2026-01-08 02:23:36 +02:00
1 parent 798e238804
commit 7725d16e82
5 files changed
+203 -42

No files matched your search

@@ -1,5 +1,7 @@
package noppes.npcs.client.gui.util.script.interpreter.js_parser;
import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo;
import java.util.*;
/**
@@ -8,34 +10,6 @@ import java.util.*;
*/
public class JSTypeInfo {
/**
* Represents a generic type parameter like "T extends Entity".
* Stores the parameter name, the bound type, and optionally the full Java class name.
*/
public static class TypeParamInfo {
private final String name; // e.g., "T"
private final String boundType; // e.g., "EntityPlayerMP"
private final String fullBoundType; // e.g., "net.minecraft.entity.player.EntityPlayerMP"
public TypeParamInfo(String name, String boundType, String fullBoundType) {
this.name = name;
this.boundType = boundType;
this.fullBoundType = fullBoundType;
}
public String getName() { return name; }
public String getBoundType() { return boundType; }
public String getFullBoundType() { return fullBoundType; }
@Override
public String toString() {
if (boundType != null) {
return name + " extends " + boundType + (fullBoundType != null ? " (" + fullBoundType + ")" : "");
}
return name;
}
}
private final String simpleName; // e.g., "InteractEvent"
private final String fullName; // e.g., "IPlayerEvent.InteractEvent"
private final String namespace; // e.g., "IPlayerEvent" (parent namespace, null for top-level)
@@ -102,11 +76,7 @@ public class JSTypeInfo {
public void setResolvedParent(JSTypeInfo parent) {
this.resolvedParent = parent;
}
public void addTypeParam(TypeParamInfo param) {
typeParams.add(param);
}
// Getters
public String getSimpleName() { return simpleName; }
public String getFullName() { return fullName; }
@@ -133,16 +103,43 @@ public class JSTypeInfo {
}
return null;
}
public void addTypeParam(TypeParamInfo param) {
typeParams.add(param);
}
/**
* Resolve all type parameters for this type.
* Called during Phase 2 after all types are loaded into the registry.
*/
public void resolveTypeParameters() {
for (TypeParamInfo param : typeParams) {
param.resolveBoundType();
}
}
/**
* Resolves a type parameter to its bound type.
* For example, if this type has "T extends EntityPlayerMP", resolveTypeParam("T") returns "EntityPlayerMP".
* If no type parameter is found with that name, returns the input.
* Resolves a type parameter to its bound TypeInfo.
* For example, if this type has "T extends EntityPlayerMP", resolveTypeParam("T") returns the TypeInfo for EntityPlayerMP.
* If no type parameter is found with that name, returns null.
*/
public TypeInfo resolveTypeParamToTypeInfo(String typeName) {
TypeParamInfo param = getTypeParam(typeName);
if (param != null) {
return param.getBoundTypeInfo();
}
return null;
}
/**
* Resolves a type parameter to its bound type name (for backward compatibility).
* @deprecated Use resolveTypeParamToTypeInfo instead
*/
@Deprecated
public String resolveTypeParam(String typeName) {
TypeParamInfo param = getTypeParam(typeName);
if (param != null && param.getBoundType() != null) {
return param.getBoundType();
if (param != null && param.getBoundTypeInfo() != null) {
return param.getBoundTypeInfo().getSimpleName();
}
return typeName;
}
@@ -83,6 +83,9 @@ public class JSTypeRegistry {
}
}
// Phase 2: Resolve all type parameters now that all types are loaded
resolveAllTypeParameters();
resolveInheritance();
registerEngineGlobalObjects();
@@ -223,6 +226,7 @@ public class JSTypeRegistry {
try {
TypeScriptDefinitionParser parser = new TypeScriptDefinitionParser(this);
parser.parseDirectory(directory);
resolveAllTypeParameters();
resolveInheritance();
initialized = true;
System.out.println("[JSTypeRegistry] Loaded " + types.size() + " types, " + hooks.size() + " hooks");
@@ -241,6 +245,7 @@ public class JSTypeRegistry {
try {
TypeScriptDefinitionParser parser = new TypeScriptDefinitionParser(this);
parser.parseVsixArchive(vsixFile);
resolveAllTypeParameters();
resolveInheritance();
initialized = true;
System.out.println("[JSTypeRegistry] Loaded " + types.size() + " types, " + hooks.size() + " hooks from VSIX");
@@ -360,6 +365,17 @@ public class JSTypeRegistry {
return null;
}
/**
* Resolve all type parameters for all types.
* Called after all .d.ts files are loaded (Phase 2).
* This ensures that type parameters can reference any type in the registry.
*/
public void resolveAllTypeParameters() {
for (JSTypeInfo type : types.values()) {
type.resolveTypeParameters();
}
}
/**
* Resolve inheritance relationships between types.
* For each type, walks up the parent chain and resolves all ancestors.
@@ -0,0 +1,68 @@
package noppes.npcs.client.gui.util.script.interpreter.js_parser;
import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo;
import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver;
/**
* Represents a generic type parameter like "T extends Entity".
* Stores the parameter name and both the string representation (for deferred resolution)
* and the resolved TypeInfo for the bound.
*/
public class TypeParamInfo {
private final String name; // e.g., "T"
private final String boundType; // Simple name like "EntityPlayerMP" (may be null)
private final String fullBoundType; // Full name like "net.minecraft.entity.player.EntityPlayerMP" (may be null)
private TypeInfo boundTypeInfo; // Resolved TypeInfo for the bound (resolved in Phase 2)
/**
* Constructor for parse-time (Phase 1) - stores string names only.
*/
public TypeParamInfo(String name, String boundType, String fullBoundType) {
this.name = name;
this.boundType = boundType;
this.fullBoundType = fullBoundType;
this.boundTypeInfo = null; // Will be resolved later
}
public String getName() { return name; }
public TypeInfo getBoundTypeInfo() {
return boundTypeInfo;
}
/**
* Resolve the bound type using TypeResolver.
* Called during Phase 2 after all types are loaded.
*/
public void resolveBoundType() {
if (boundTypeInfo != null)
return; // Already resolved
if (fullBoundType != null && !fullBoundType.isEmpty()) {
// Try to load the Java class using the full name
boundTypeInfo = TypeResolver.getInstance().resolveFullName(fullBoundType);
} else if (boundType != null && !boundType.isEmpty()) {
// Try to resolve using the simple name
boundTypeInfo = TypeResolver.getInstance().resolveJSType(boundType);
}
}
/**
* Get simple display name for the bound type.
*/
public String getBoundTypeName() {
if (boundTypeInfo == null)
return null;
return boundTypeInfo.getSimpleName();
}
@Override
public String toString() {
if (boundTypeInfo != null) {
return name + " extends " + boundTypeInfo.getSimpleName();
} else if (boundType != null || fullBoundType != null) {
return name + " extends " + (boundType != null ? boundType : fullBoundType);
}
return name;
}
}
@@ -311,6 +311,7 @@ public class TypeScriptDefinitionParser {
/**
* Parse type parameters from a string like "T extends EntityPlayerMP /* net.minecraft.entity.player.EntityPlayerMP *`/".
* Handles multiple parameters separated by commas.
* Stores strings only - resolution happens in Phase 2 after all types are loaded.
*/
private void parseTypeParameters(String typeParamsStr, JSTypeInfo typeInfo) {
// Split by comma, but be careful with nested generics (shouldn't happen at this level, but be safe)
@@ -322,10 +323,11 @@ public class TypeScriptDefinitionParser {
Matcher m = TYPE_PARAM_PATTERN.matcher(param);
if (m.find()) {
String name = m.group(1);
String boundType = m.group(2);
String fullBoundType = m.group(3);
String boundType = m.group(2); // Simple name like "EntityPlayerMP"
String fullBoundType = m.group(3); // Full name like "net.minecraft.entity.player.EntityPlayerMP"
typeInfo.addTypeParam(new JSTypeInfo.TypeParamInfo(name, boundType, fullBoundType));
// Store strings only - resolution happens in Phase 2
typeInfo.addTypeParam(new TypeParamInfo(name, boundType, fullBoundType));
}
}
}
@@ -5,6 +5,7 @@ import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo;
import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSFieldInfo;
import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSMethodInfo;
import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSTypeInfo;
import noppes.npcs.client.gui.util.script.interpreter.js_parser.TypeParamInfo;
import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo;
import noppes.npcs.client.gui.util.script.interpreter.token.TokenType;
@@ -60,6 +61,9 @@ public class TypeInfo {
// JavaScript/TypeScript type info (for types from .d.ts files)
private final JSTypeInfo jsTypeInfo; // The JS type info (null if Java type)
// Type parameters (generics)
private final List<TypeParamInfo> typeParams = new ArrayList<>();
private TypeInfo(String simpleName, String fullName, String packageName,
Kind kind, Class<?> javaClass, boolean resolved, TypeInfo enclosingType) {
@@ -477,7 +481,8 @@ public class TypeInfo {
// Check JS type first
if (jsTypeInfo != null) {
for (JSMethodInfo jsMethod : jsTypeInfo.getMethodOverloads(methodName)) {
overloads.add(MethodInfo.fromJSMethod(jsMethod, this));
// Pass jsTypeInfo as context for type parameter resolution
overloads.add(MethodInfo.fromJSMethod(jsMethod, this, jsTypeInfo));
}
return overloads;
}
@@ -679,6 +684,79 @@ public class TypeInfo {
public void validate() {
// Default: no validation for Java types
}
// ==================== Type Parameter Methods ====================
/**
* Add a type parameter to this type.
* Used during parsing/construction of types with generics.
*/
public void addTypeParam(TypeParamInfo param) {
// If this is a JS type, delegate to JSTypeInfo
if (jsTypeInfo != null) {
jsTypeInfo.addTypeParam(param);
} else {
typeParams.add(param);
}
}
/**
* Get all type parameters for this type.
* @return List of type parameters (empty if none)
*/
public List<TypeParamInfo> getTypeParams() {
// If this is a JS type, delegate to JSTypeInfo
if (jsTypeInfo != null) {
return jsTypeInfo.getTypeParams();
}
return typeParams;
}
/**
* Resolve all type parameters for this type.
* Called during Phase 2 after all types are loaded into the registry.
*/
public void resolveTypeParameters() {
// If this is a JS type, delegate to JSTypeInfo
if (jsTypeInfo != null) {
jsTypeInfo.resolveTypeParameters();
} else {
for (TypeParamInfo param : typeParams) {
param.resolveBoundType();
}
}
}
/**
* Get the type parameter info for a given parameter name (e.g., "T").
* @return TypeParamInfo or null if not found
*/
public TypeParamInfo getTypeParam(String name) {
// If this is a JS type, delegate to JSTypeInfo
if (jsTypeInfo != null) {
return jsTypeInfo.getTypeParam(name);
}
for (TypeParamInfo param : typeParams) {
if (param.getName().equals(name)) {
return param;
}
}
return null;
}
/**
* Resolves a type parameter to its bound TypeInfo.
* For example, if this type has "T extends EntityPlayerMP", resolveTypeParamToTypeInfo("T") returns the TypeInfo for EntityPlayerMP.
* If no type parameter is found with that name, returns null.
*/
public TypeInfo resolveTypeParamToTypeInfo(String typeName) {
TypeParamInfo param = getTypeParam(typeName);
if (param != null) {
return param.getBoundTypeInfo();
}
return null;
}
@Override
public String toString() {