From dc3e25bcba971daa9844478be061d9e7074d5738 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Mon, 9 Mar 2026 00:35:05 +0200 Subject: [PATCH] Added JS [] array resolution i.e. var list = ["hi", player] + added missing Array.d.ts overloads --- dts-patches/ecmascript/Array.d.ts | 4 +++ .../interpreter/ObjectLiteralParser.java | 4 --- .../script/interpreter/ScriptDocument.java | 35 +++++++++++++++++++ .../script/interpreter/type/TypeChecker.java | 8 +++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/dts-patches/ecmascript/Array.d.ts b/dts-patches/ecmascript/Array.d.ts index 45c6e345f..6ffd25a8c 100644 --- a/dts-patches/ecmascript/Array.d.ts +++ b/dts-patches/ecmascript/Array.d.ts @@ -73,12 +73,14 @@ export interface Array { forEach(callback: Java.java.util.function.Consumer): void; /** Returns the first index at which an element is found, or -1 if not present */ + indexOf(searchElement: T): number; indexOf(searchElement: T, fromIndex: number): number; /** Joins all elements of an array into a string separated by the given separator */ join(separator: string): string; /** Returns the last index at which an element is found, or -1 if not present */ + lastIndexOf(searchElement: T): number; lastIndexOf(searchElement: T, fromIndex: number): number; /** Creates a new array with the results of calling a function on every element */ @@ -91,9 +93,11 @@ export interface Array { push(...items: T[]): number; /** Applies a function against an accumulator and each element to reduce the array to a single value */ + reduce(callback: Java.java.util.function.BiFunction): any; reduce(callback: Java.java.util.function.BiFunction, initialValue: any): any; /** Same as reduce() but processes the array from right to left */ + reduceRight(callback: Java.java.util.function.BiFunction): any; reduceRight(callback: Java.java.util.function.BiFunction, initialValue: any): any; /** Reverses an array in place. The first element becomes the last, and vice versa */ diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ObjectLiteralParser.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ObjectLiteralParser.java index 1ca72ec9a..9ddec2a92 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ObjectLiteralParser.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ObjectLiteralParser.java @@ -1114,10 +1114,6 @@ public final class ObjectLiteralParser { return TypeInfo.ANY; } - if (first == '[') { - return TypeInfo.ANY; - } - TypeInfo inferred = typeResolver.resolve(valueExpr, valueStartAbs); return (inferred != null) ? inferred : TypeInfo.ANY; } 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 f26c3cd9d..cc54eb690 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 @@ -5347,6 +5347,12 @@ public class ScriptDocument { return resolveExpressionWithParserAPI(expr, position); } + // JS array literals: [], [a, b], ["hi", "bye"] + if (isJavaScript() && expr.startsWith("[") && expr.endsWith("]")) { + String inner = expr.substring(1, expr.length() - 1).trim(); + return TypeInfo.arrayOf(unifyJsArrayElementType(inner, position + 1)); + } + // Invalid expressions starting with brackets if (expr.startsWith("[") || expr.startsWith("]")) { return null; // Invalid syntax @@ -5430,6 +5436,13 @@ public class ScriptDocument { if (varInfo != null && varInfo.getTypeInfo() instanceof ClassTypeInfo) { return ((ClassTypeInfo) varInfo.getTypeInfo()).getInstanceType(); } + if (isJavaScript() && typeName.equals("Array")) { + String rest = expr.substring(newMatcher.end()).trim(); + String argsText = (rest.startsWith("(") && rest.endsWith(")")) + ? rest.substring(1, rest.length() - 1).trim() + : ""; + return TypeInfo.arrayOf(unifyJsArrayElementType(argsText, position)); + } TypeInfo baseType = resolveType(typeName); if (baseType == null) return null; String rest = expr.substring(newMatcher.end()); @@ -5753,6 +5766,28 @@ public class ScriptDocument { return argTypes; } + /** + * For JavaScript array literals, unify the element types to determine the array's element type. + */ + private TypeInfo unifyJsArrayElementType(String argsText, int position) { + if (argsText.isEmpty()) return TypeInfo.ANY; + TypeInfo[] elementTypes = parseArgumentTypes(argsText, position); + if (elementTypes.length == 1 && TypeInfo.NUMBER.equals(elementTypes[0])) return TypeInfo.ANY; + TypeInfo common = null; + boolean allSame = true; + for (TypeInfo t : elementTypes) { + boolean isUnresolvable = t == null || TypeInfo.NULL.equals(t); + if (isUnresolvable) continue; + if (common == null) { + common = t; + } else if (!common.equals(t)) { + allSame = false; + break; + } + } + return allSame && common != null ? common : TypeInfo.ANY; + } + /** * Helper class for chain segments (can be field access or method call). */ diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeChecker.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeChecker.java index d98ba7460..a9516f3e5 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeChecker.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/type/TypeChecker.java @@ -33,6 +33,14 @@ public final class TypeChecker { if (expected == null) return true; // void can accept anything (shouldn't happen) if (actual == null) return true; // Can't verify, assume compatible + // Handle array types: compatible if element types are compatible + if (expected.isArray() && actual.isArray()) { + TypeInfo expectedElement = expected.getElementType(); + TypeInfo actualElement = actual.getElementType(); + if (expectedElement != null && actualElement != null) + return isTypeCompatible(expectedElement, actualElement); + } + // Script method reference placeholder: only compatible with functional interface params. // Used to help overload selection choose SAM overloads in JavaScript. if ("__script_method_ref__".equals(actual.getFullName())) {