From c0d5bf3acc83ed653de3ffbe07987185902ae46c Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Sun, 8 Mar 2026 16:17:21 +0200 Subject: [PATCH] Expanded scope of "this." resolution to account for JS script types and inner scopes too. (compat for new ObjectLiterals & not implemented yet but soonTM JS prototypes) --- .../script/interpreter/FieldChainMarker.java | 16 ++++++---- .../interpreter/InnerCallableScope.java | 3 ++ .../script/interpreter/ScriptDocument.java | 29 ++++++++++++++----- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldChainMarker.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldChainMarker.java index a94d81bc8..0dbae818e 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldChainMarker.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldChainMarker.java @@ -188,7 +188,10 @@ public class FieldChainMarker { if (ctx.firstIsThis) { // 'this' - resolve to enclosing class/global fields - ctx.currentType = ctx.enclosingType; + ctx.currentType = document.resolveThisType(chainStart); + if (ctx.currentType == null) { + ctx.currentType = ctx.enclosingType; + } } else if (ctx.firstIsSuper) { // 'super' - resolve to parent class if (ctx.enclosingType != null && ctx.enclosingType.hasSuperClass()) { @@ -228,7 +231,7 @@ public class FieldChainMarker { // Case 2: this.field if (index == 1 && ctx.firstIsThis) { - return resolveThisFieldMark(ctx); + return resolveThisFieldMark(ctx); } // Case 3: super.field @@ -286,17 +289,18 @@ public class FieldChainMarker { boolean found = false; FieldInfo fieldInfo = null; - // First check enclosing script type fields - if (ctx.enclosingType != null && ctx.enclosingType.hasField(segment)) { + TypeInfo thisType = ctx.currentType != null ? ctx.currentType : ctx.enclosingType; + + if (thisType != null && thisType.hasField(segment)) { found = true; - fieldInfo = ctx.enclosingType.getFieldInfo(segment); + fieldInfo = thisType.getFieldInfo(segment); } else if (document.getGlobalFields().containsKey(segment)) { found = true; fieldInfo = document.getGlobalFields().get(segment); } if (found) { - FieldAccessInfo accessInfo = document.createFieldAccessInfo(segment, pos[0], pos[1], ctx.enclosingType, + FieldAccessInfo accessInfo = document.createFieldAccessInfo(segment, pos[0], pos[1], thisType, fieldInfo, isLast, false); return new MarkResult(new ScriptLine.Mark(pos[0], pos[1], getFieldTokenType(fieldInfo), accessInfo), diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/InnerCallableScope.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/InnerCallableScope.java index 20d273c21..e0fed4951 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/InnerCallableScope.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/InnerCallableScope.java @@ -29,6 +29,7 @@ public class InnerCallableScope { private final Map locals = new HashMap<>(); private InnerCallableScope parentScope; // Enclosing inner scope (for nested lambdas) private TypeInfo expectedType; // The expected functional interface type (set during resolution) + private TypeInfo containingObjectType; // For object-literal methods, the synthetic object-literal type public InnerCallableScope(Kind kind, int headerStart, int headerEnd, int bodyStart, int bodyEnd) { this.kind = kind; @@ -48,10 +49,12 @@ public class InnerCallableScope { public Map getLocals() { return locals; } public InnerCallableScope getParentScope() { return parentScope; } public TypeInfo getExpectedType() { return expectedType; } + public TypeInfo getContainingObjectType() { return containingObjectType; } // Setters public void setParentScope(InnerCallableScope parent) { this.parentScope = parent; } public void setExpectedType(TypeInfo type) { this.expectedType = type; } + public void setContainingObjectType(TypeInfo type) { this.containingObjectType = type; } public void addParameter(FieldInfo param) { parameters.add(param); 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 995a6641e..2a237f2af 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 @@ -5394,7 +5394,7 @@ public class ScriptDocument { // "this" keyword if (expr.equals("this")) { - return findEnclosingScriptType(position); + return resolveThisType(position); } if (expr.startsWith("new ")) { @@ -5430,7 +5430,7 @@ public class ScriptDocument { TypeInfo currentType = null; if (first.name.equals("this")) { - currentType = findEnclosingScriptType(position); + currentType = resolveThisType(position); // Handle this.field where we don't have a script type if (currentType == null && segments.size() > 1 && !segments.get(1).isMethodCall) { String fieldName = segments.get(1).name; @@ -5909,8 +5909,23 @@ public class ScriptDocument { } return null; } - + /** + * Resolve the type of "this" at a given position by finding the innermost scope and checking for containing object types. + * For both Java and JavaScript, this will correctly resolve to the appropriate type based on the current context (e.g., enclosing class, script type, or synthetic type). + * @param position + * @return + */ + TypeInfo resolveThisType(int position) { + Object innermostScope = findInnermostScopeAt(position); + if (innermostScope instanceof InnerCallableScope) { + TypeInfo objectType = ((InnerCallableScope) innermostScope).getContainingObjectType(); + if (objectType != null && objectType.isResolved()) { + return objectType; + } + } + return findEnclosingScriptType(position); + } // ==================== OPERATOR EXPRESSION RESOLUTION ==================== @@ -6099,7 +6114,7 @@ public class ScriptDocument { @Override public TypeInfo resolveIdentifier(String name) { if ("this".equals(name)) { - return findEnclosingScriptType(position); + return resolveThisType(position); } if ("super".equals(name)) { // Resolve super to parent class type @@ -6257,7 +6272,7 @@ public class ScriptDocument { // "this" keyword if (expr.equals("this")) { - return findEnclosingScriptType(position); + return resolveThisType(position); } // "new Type()" expressions @@ -6289,7 +6304,7 @@ public class ScriptDocument { TypeInfo currentType = null; if (first.name.equals("this")) { - currentType = findEnclosingScriptType(position); + currentType = resolveThisType(position); } else { // Check if first segment is a type name TypeInfo typeCheck = resolveType(first.name); @@ -8228,7 +8243,7 @@ public class ScriptDocument { // First check inner callable scopes (most specific) InnerCallableScope innermost = null; for (InnerCallableScope scope : innerScopes) { - if (scope.containsPosition(position)) { + if (scope.containsPosition(position) || scope.containsHeaderPosition(position)) { if (innermost == null || scope.getBodyStart() > innermost.getBodyStart()) { innermost = scope; }