Skip to content

Commit 78a6a29

Browse files
committed
Validated right hand expression type is the expected type at variable declaration, and underlined the mismatched type's token if not.
1 parent b38f193 commit 78a6a29

File tree

5 files changed

+486
-8
lines changed

5 files changed

+486
-8
lines changed

src/main/java/noppes/npcs/client/gui/util/GuiScriptTextArea.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ public void drawTextBox(int xMouse, int yMouse) {
839839

840840
// data.drawString(x + LINE_NUMBER_GUTTER_WIDTH + 1, yPos, 0xFFe0e0e0);
841841
scriptLine.drawString(x+LINE_NUMBER_GUTTER_WIDTH + 1, yPos, 0xFFe0e0e0);
842+
// scriptLine.drawStringHex(x+LINE_NUMBER_GUTTER_WIDTH + 1, yPos, ScriptLine.createDefaultHexRenderer());
842843

843844
// Draw cursor: pause blinking while user is active recently
844845
boolean recentInput = selection.hadRecentInput();
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package noppes.npcs.client.gui.util.script.interpreter;
2+
3+
/**
4+
* Metadata for field access validation.
5+
* Parallel to MethodCallInfo but for field accesses like `obj.field` or `Class.staticField`.
6+
*/
7+
public class FieldAccessInfo {
8+
9+
/**
10+
* Validation error type for field accesses.
11+
*/
12+
public enum ErrorType {
13+
NONE,
14+
TYPE_MISMATCH, // Field type doesn't match expected type (e.g., assignment LHS)
15+
UNRESOLVED_FIELD, // Field doesn't exist on the receiver type
16+
STATIC_ACCESS_ERROR // Trying to access instance field statically or vice versa
17+
}
18+
19+
private final String fieldName;
20+
private final int fieldNameStart;
21+
private final int fieldNameEnd;
22+
private final TypeInfo receiverType; // The type on which this field is accessed
23+
private final FieldInfo resolvedField; // The resolved field (null if unresolved)
24+
private final boolean isStaticAccess; // True if this is Class.field style access
25+
private TypeInfo expectedType; // Expected field type (from assignment LHS, etc.)
26+
27+
private ErrorType errorType = ErrorType.NONE;
28+
private String errorMessage;
29+
30+
public FieldAccessInfo(String fieldName, int fieldNameStart, int fieldNameEnd,
31+
TypeInfo receiverType, FieldInfo resolvedField, boolean isStaticAccess) {
32+
this.fieldName = fieldName;
33+
this.fieldNameStart = fieldNameStart;
34+
this.fieldNameEnd = fieldNameEnd;
35+
this.receiverType = receiverType;
36+
this.resolvedField = resolvedField;
37+
this.isStaticAccess = isStaticAccess;
38+
}
39+
40+
// Getters
41+
public String getFieldName() {
42+
return fieldName;
43+
}
44+
45+
public int getFieldNameStart() {
46+
return fieldNameStart;
47+
}
48+
49+
public int getFieldNameEnd() {
50+
return fieldNameEnd;
51+
}
52+
53+
public TypeInfo getReceiverType() {
54+
return receiverType;
55+
}
56+
57+
public FieldInfo getResolvedField() {
58+
return resolvedField;
59+
}
60+
61+
public boolean isStaticAccess() {
62+
return isStaticAccess;
63+
}
64+
65+
public TypeInfo getExpectedType() {
66+
return expectedType;
67+
}
68+
69+
public void setExpectedType(TypeInfo expectedType) {
70+
this.expectedType = expectedType;
71+
}
72+
73+
public ErrorType getErrorType() {
74+
return errorType;
75+
}
76+
77+
public String getErrorMessage() {
78+
return errorMessage;
79+
}
80+
81+
/**
82+
* Validate this field access.
83+
* Checks type compatibility with expected type.
84+
*/
85+
public void validate() {
86+
// Check if field was resolved
87+
if (resolvedField == null) {
88+
setError(ErrorType.UNRESOLVED_FIELD, "Cannot resolve field '" + fieldName + "'");
89+
return;
90+
}
91+
92+
// Check return type compatibility with expected type (e.g., assignment LHS)
93+
if (expectedType != null && resolvedField != null) {
94+
TypeInfo fieldType = resolvedField.getDeclaredType();
95+
if (fieldType != null && !isTypeCompatible(fieldType, expectedType)) {
96+
setError(ErrorType.TYPE_MISMATCH,
97+
"Required type: " + expectedType.getSimpleName() + ", Provided: " + fieldType.getSimpleName());
98+
}
99+
}
100+
}
101+
102+
/**
103+
* Check if sourceType can be assigned to targetType.
104+
*/
105+
private boolean isTypeCompatible(TypeInfo sourceType, TypeInfo targetType) {
106+
if (sourceType == null || targetType == null) {
107+
return true; // Can't validate, assume compatible
108+
}
109+
110+
// Same type
111+
if (sourceType.getFullName().equals(targetType.getFullName())) {
112+
return true;
113+
}
114+
115+
// Check if sourceType is a subtype of targetType
116+
if (sourceType.isResolved() && targetType.isResolved()) {
117+
Class<?> sourceClass = sourceType.getJavaClass();
118+
Class<?> targetClass = targetType.getJavaClass();
119+
120+
if (sourceClass != null && targetClass != null) {
121+
return targetClass.isAssignableFrom(sourceClass);
122+
}
123+
}
124+
125+
// Primitive widening/boxing conversions would go here
126+
// For now, just check direct equality
127+
return false;
128+
}
129+
130+
private void setError(ErrorType type, String message) {
131+
this.errorType = type;
132+
this.errorMessage = message;
133+
}
134+
135+
/**
136+
* Check if this field access has any validation error.
137+
*/
138+
public boolean hasError() {
139+
return errorType != ErrorType.NONE;
140+
}
141+
142+
/**
143+
* Check if this is a type mismatch error.
144+
*/
145+
public boolean hasTypeMismatch() {
146+
return errorType == ErrorType.TYPE_MISMATCH;
147+
}
148+
149+
/**
150+
* Check if this is an unresolved field error.
151+
*/
152+
public boolean hasUnresolvedField() {
153+
return errorType == ErrorType.UNRESOLVED_FIELD;
154+
}
155+
156+
/**
157+
* Check if this is a static access error.
158+
*/
159+
public boolean hasStaticAccessError() {
160+
return errorType == ErrorType.STATIC_ACCESS_ERROR;
161+
}
162+
163+
@Override
164+
public String toString() {
165+
return "FieldAccessInfo{" +
166+
"fieldName='" + fieldName + "', " +
167+
"receiverType=" + receiverType + ", " +
168+
"resolvedField=" + resolvedField + ", " +
169+
"errorType=" + errorType +
170+
'}';
171+
}
172+
}

src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodCallInfo.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public enum ErrorType {
7979
WRONG_ARG_COUNT, // Number of args doesn't match any overload
8080
WRONG_ARG_TYPE, // Specific argument has wrong type
8181
STATIC_ACCESS_ERROR, // Trying to call instance method statically or vice versa
82+
RETURN_TYPE_MISMATCH, // Return type doesn't match expected type (e.g., assignment LHS)
8283
UNRESOLVED_METHOD, // Method doesn't exist
8384
UNRESOLVED_RECEIVER // Can't resolve the receiver type
8485
}
@@ -92,6 +93,7 @@ public enum ErrorType {
9293
private final TypeInfo receiverType; // The type on which this method is called (null for standalone)
9394
private final MethodInfo resolvedMethod; // The resolved method (null if unresolved)
9495
private final boolean isStaticAccess; // True if this is Class.method() style access
96+
private TypeInfo expectedType; // Expected return type (from assignment LHS, etc.)
9597

9698
private ErrorType errorType = ErrorType.NONE;
9799
private String errorMessage;
@@ -162,6 +164,14 @@ public boolean isStaticAccess() {
162164
return isStaticAccess;
163165
}
164166

167+
public TypeInfo getExpectedType() {
168+
return expectedType;
169+
}
170+
171+
public void setExpectedType(TypeInfo expectedType) {
172+
this.expectedType = expectedType;
173+
}
174+
165175
public ErrorType getErrorType() {
166176
return errorType;
167177
}
@@ -211,6 +221,13 @@ public boolean hasStaticAccessError() {
211221
return errorType == ErrorType.STATIC_ACCESS_ERROR;
212222
}
213223

224+
/**
225+
* Check if this is a return type mismatch error.
226+
*/
227+
public boolean hasReturnTypeMismatch() {
228+
return errorType == ErrorType.RETURN_TYPE_MISMATCH;
229+
}
230+
214231
// Setters for validation results
215232
public void setError(ErrorType type, String message) {
216233
this.errorType = type;
@@ -296,6 +313,15 @@ public void validate() {
296313
setArgTypeError(i, "Cannot resolve type of argument '" + arg.getText() + "'");
297314
}
298315
}
316+
317+
// Check return type compatibility with expected type (e.g., assignment LHS)
318+
if (expectedType != null && resolvedMethod != null) {
319+
TypeInfo returnType = resolvedMethod.getReturnType();
320+
if (returnType != null && !isTypeCompatible(returnType, expectedType)) {
321+
setError(ErrorType.RETURN_TYPE_MISMATCH,
322+
"Required type: " + expectedType.getSimpleName() + ", Provided: " + returnType.getSimpleName());
323+
}
324+
}
299325
}
300326

301327
/**

0 commit comments

Comments
 (0)