Skip to content

Commit cacc818

Browse files
author
Trinketer22
committed
LHS only bindings for modifying methods
1 parent ec909b5 commit cacc818

File tree

1 file changed

+72
-34
lines changed

1 file changed

+72
-34
lines changed

server/src/languages/func/psi/BindingResolver.ts

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FuncFile } from "./FuncFile";
33
import { Func } from "@server/languages/func/psi/Decls";
44
import { Expression } from "./FuncNode";
55
import { closestNamedSibling } from "@server/psi/utils";
6+
import { FUNC_PARSED_FILES_CACHE } from "@server/files";
67

78
type Binding = {
89
identifier: SyntaxNode,
@@ -21,14 +22,37 @@ export class FunCBindingResolver {
2122

2223
protected funcMap: Map<string, Func>;
2324
protected bindings: Map<string, Binding>;
25+
protected assignmentOps: Set<string>;
2426

2527
constructor(readonly file: FuncFile) {
2628
this.bindings = new Map();
2729
this.funcMap = new Map();
30+
this.assignmentOps = new Set([
31+
"=",
32+
"+=",
33+
"-=",
34+
"*=",
35+
"/=",
36+
"~/=",
37+
"^/=",
38+
"%=",
39+
"~%=",
40+
"^%=",
41+
"<<=",
42+
">>=",
43+
"~>>=",
44+
"^>>=",
45+
"&=",
46+
"|=",
47+
"^=",
48+
]);
2849

29-
file.getFunctions().forEach((f => {
30-
this.funcMap.set(f.name(), f);
31-
}))
50+
51+
FUNC_PARSED_FILES_CACHE.forEach(parsedFile => {
52+
parsedFile.getFunctions().forEach(f => {
53+
this.funcMap.set(f.name(), f);
54+
})
55+
});
3256
}
3357

3458
resolve(expression: SyntaxNode): BindingResult {
@@ -42,23 +66,13 @@ export class FunCBindingResolver {
4266
continue;
4367
}
4468

45-
if (curChild.text == '=') {
69+
if (this.assignmentOps.has(curChild.text)) {
4670
equalsFound = true;
4771
if (lhs.length == 0) {
4872
throw RangeError("Equals encountered before first lhs identifier");
4973
}
5074
}
5175
if (curChild.isNamed) {
52-
// If modirying method call
53-
/*
54-
if (curChild.type == "method_call" && curChild.children[0]?.text == "~") {
55-
const firstArg = closestNamedSibling(curChild, 'prev', (sibling => sibling.type == "identifier"))
56-
if (firstArg) {
57-
// Not really lhs, but semantically it is
58-
lhs.push(firstArg)
59-
}
60-
}
61-
*/
6276
if (equalsFound) {
6377
rhs.push(curChild);
6478
} else {
@@ -73,16 +87,22 @@ export class FunCBindingResolver {
7387
rhs,
7488
bindings: new Map()
7589
}
76-
if (!equalsFound || lhs[0].type == "underscore") {
90+
if (lhs[0].type == "underscore") {
7791
return bindRes;
7892
}
79-
if (lhs.length > 1) {
93+
if (lhs.length > 1 && rhs.length > 0) {
8094
// Do we even need dat?
8195
throw new RangeError("TODO multi lhs bindings");
8296
}
8397

8498
const pattern = lhs[0]
85-
this.walkPattern(pattern, rhs);
99+
if (rhs.length > 0) {
100+
this.walkPattern(pattern, rhs);
101+
} else {
102+
// Without rhs there still may be method calls on left.
103+
// ds~skip_bits(32); ;; Stuff like that
104+
this.bindModifyingCalls(lhs);
105+
}
86106

87107
// Copy the map for the output
88108
for (let [k, v] of this.bindings.entries()) {
@@ -93,7 +113,7 @@ export class FunCBindingResolver {
93113
return bindRes;
94114
}
95115

96-
private walkPattern(pattern: SyntaxNode, value: SyntaxNode[]) {
116+
protected walkPattern(pattern: SyntaxNode, value: SyntaxNode[]) {
97117
if (!pattern || pattern.type == "underscore") {
98118
return
99119
}
@@ -127,20 +147,32 @@ export class FunCBindingResolver {
127147
}
128148
}
129149

130-
private bindIdentifier(target: SyntaxNode, value: SyntaxNode[], checkMethodRhs: boolean = true) {
131-
if (checkMethodRhs) {
132-
value.forEach(curNode => {
133-
if (curNode.type == "method_call") {
134-
this.bindToMethodCall(target, curNode);
135-
} else {
136-
// In case calls are in tensor expressions
137-
curNode.descendantsOfType("method_call").forEach(methodCall => {
138-
if (methodCall) {
139-
this.bindToMethodCall(target, methodCall);
140-
}
141-
})
150+
protected bindModifyingCalls(value: SyntaxNode[]) {
151+
value.forEach(curNode => {
152+
if (curNode.type == "method_call") {
153+
// Only modifying calls
154+
if (curNode.children[0]?.text == "~") {
155+
const identifier = curNode.previousNamedSibling;
156+
if (identifier && identifier.type == "identifier") {
157+
this.bindToMethodCall(identifier, curNode);
158+
}
142159
}
143-
})
160+
} else {
161+
// In case calls are in tensor expressions
162+
curNode.descendantsOfType("method_call").forEach(methodCall => {
163+
if (methodCall && methodCall.children[0]?.text == "~") {
164+
const identifier = curNode.previousNamedSibling;
165+
if (identifier && identifier.type == "identifier") {
166+
this.bindToMethodCall(identifier, curNode);
167+
}
168+
}
169+
})
170+
}
171+
})
172+
}
173+
protected bindIdentifier(target: SyntaxNode, value: SyntaxNode[], checkMethodRhs: boolean = true) {
174+
if (checkMethodRhs) {
175+
this.bindModifyingCalls(value);
144176
}
145177
this.bindings.set(target.text, {
146178
identifier: target,
@@ -197,19 +229,25 @@ export class FunCBindingResolver {
197229
if (!retType) {
198230
throw new Error(`Method ${methodName} has no return type`)
199231
}
200-
if (retType.node.type !== "tensor_type") {
201-
throw new TypeError(`Expected tensor_type for modifying method return type got ${retType.node.type}`)
202-
}
203232

204233
// For non-modofiying method bind as normal function call;
205234
let bindScope = retType.node;
206235

207236
if (isModifying) {
237+
if (retType.node.type !== "tensor_type") {
238+
throw new TypeError(`Expected tensor_type for modifying method return type got ${retType.node.type}`)
239+
}
240+
208241
const firstArg = closestNamedSibling(value, 'prev', (sybl => sybl.type == "identifier"));
209242
if (!firstArg) {
210243
throw new Error(`First arg not found for modifying method call ${value}`)
211244
}
212245
this.bindIdentifier(firstArg, [value], false);
246+
// If firstArg is same as target, we're done here.
247+
if (firstArg.id == target.id) {
248+
return;
249+
}
250+
213251
// Next tensor type
214252
let retTensor: SyntaxNode | undefined;
215253
const childrenCount = bindScope.namedChildCount;

0 commit comments

Comments
 (0)