Skip to content

Commit d94a657

Browse files
author
Trinketer22
committed
Basic bind resolution
1 parent 213432f commit d94a657

File tree

1 file changed

+208
-0
lines changed

1 file changed

+208
-0
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import type { Node as SyntaxNode } from "web-tree-sitter";
2+
import { FuncFile } from "./FuncFile";
3+
import { Func } from "@server/languages/func/psi/Decls";
4+
5+
type Binding = {
6+
identifier: SyntaxNode,
7+
producer_exp: SyntaxNode[]
8+
}
9+
10+
type BindingResult = {
11+
lhs: SyntaxNode[],
12+
rhs: SyntaxNode[],
13+
bindings: Map<string, Binding>
14+
}
15+
16+
export class FunCBindingResolver {
17+
18+
19+
protected funcMap: Map<string, Func>;
20+
protected bindings: Map<string, Binding>;
21+
constructor(file: FuncFile) {
22+
this.bindings = new Map();
23+
this.funcMap = new Map();
24+
25+
file.getFunctions().forEach((f => {
26+
this.funcMap.set(f.name(), f);
27+
}))
28+
}
29+
30+
resolve(expression: SyntaxNode): BindingResult {
31+
32+
let lhs: SyntaxNode[] = [];
33+
let rhs: SyntaxNode[] = [];
34+
let equalsFound = false;
35+
36+
for (let curChild of expression.children) {
37+
if (!curChild) {
38+
continue;
39+
}
40+
41+
if (curChild.text == '=') {
42+
equalsFound = true;
43+
if (lhs.length == 0) {
44+
throw RangeError("Equals encountered before first lhs identifier");
45+
}
46+
}
47+
if (curChild.isNamed) {
48+
if (equalsFound) {
49+
rhs.push(curChild);
50+
} else {
51+
lhs.push(curChild);
52+
}
53+
}
54+
}
55+
56+
let bindRes: BindingResult = {
57+
lhs,
58+
rhs,
59+
bindings: new Map()
60+
}
61+
if (!equalsFound || lhs[0].type == "underscore") {
62+
return bindRes;
63+
}
64+
if (lhs.length > 1) {
65+
// Do we even need dat?
66+
throw new RangeError("TODO multi lhs bindings");
67+
}
68+
69+
const pattern = lhs[0]
70+
this.walkPattern(pattern, rhs[0]);
71+
72+
// Copy the map for the output
73+
for (let [k, v] of this.bindings.entries()) {
74+
bindRes.bindings.set(k, v);
75+
}
76+
// Free up the map
77+
this.bindings.clear();
78+
return bindRes;
79+
}
80+
81+
private walkPattern(pattern: SyntaxNode, value: SyntaxNode) {
82+
if (!pattern || pattern.type == "underscore") {
83+
return
84+
}
85+
86+
switch (pattern.type) {
87+
case "identifier":
88+
this.bindIdentifier(pattern, value);
89+
break;
90+
case "local_vars_declaration":
91+
const curLhs = pattern.childForFieldName("lhs");
92+
if (!curLhs) {
93+
throw new Error("No lhs in var declaration")
94+
}
95+
this.walkPattern(curLhs, value);
96+
break;
97+
case "var_declaration":
98+
this.bindIdentifier(pattern.childForFieldName("name")!, value);
99+
break;
100+
case "tensor_vars_declaration":
101+
case "tensor_expression":
102+
this.bindTensor(pattern, value);
103+
break;
104+
}
105+
}
106+
107+
private bindIdentifier(target: SyntaxNode, value: SyntaxNode) {
108+
this.bindings.set(target.text, {
109+
identifier: target,
110+
producer_exp: [value]
111+
});
112+
}
113+
114+
private bindTensor(target: SyntaxNode, value: SyntaxNode) {
115+
const curValueType = value.type;
116+
if (curValueType == "function_application") {
117+
this.bindToFunctionCall(target, value);
118+
} else if (curValueType == "tensor_expression") {
119+
120+
for (let i = 0; i < target.namedChildCount; i++) {
121+
const nextTarget = target.namedChildren[i];
122+
if (!nextTarget) {
123+
continue;
124+
}
125+
const nextValue = value.namedChildren[i];
126+
if (!nextValue) {
127+
throw new Error("Undefined value");
128+
}
129+
this.walkPattern(nextTarget, nextValue);
130+
}
131+
} else {
132+
throw new TypeError(`Type ${curValueType} is not yet supported!`);
133+
}
134+
/*
135+
switch (value.type) {
136+
case "function_application":
137+
break;
138+
case "tensor_expression":
139+
this.walkPattern(target, value);
140+
break;
141+
default:
142+
throw new Error(`Failed to bind tensor to ${value.type} ${target} ${value}`)
143+
}
144+
*/
145+
}
146+
147+
private bindToFunctionCall(target: SyntaxNode, value: SyntaxNode) {
148+
const funcIdentifier = value.childForFieldName("callee");
149+
if (!funcIdentifier) {
150+
throw new Error(`Calle not found: ${value}`)
151+
}
152+
const funcName = funcIdentifier.text;
153+
const funcDecl = this.funcMap.get(funcName);
154+
if (!funcDecl) {
155+
throw new Error(`Failed to find function declaration ${funcName}`)
156+
}
157+
const retType = funcDecl.returnType();
158+
if (!retType) {
159+
throw new Error(`Function ${funcName} without return type. Grammar failure?`)
160+
}
161+
this.bindToReturnType(target, value, retType.node);
162+
163+
}
164+
private bindToReturnType(target: SyntaxNode, callNode: SyntaxNode, retType: SyntaxNode) {
165+
const targetFiltered = target.type == "tensor_vars_declaration" ? target.childrenForFieldName("vars").filter(v => v?.isNamed) : target.namedChildren;
166+
167+
if (targetFiltered.length != retType.namedChildCount) {
168+
throw new Error(`Return type arity error ${target} ${retType}`);
169+
}
170+
171+
for (let i = 0; i < targetFiltered.length; i++) {
172+
const pattern = targetFiltered[i];
173+
const bindRhs = retType.namedChildren[i];
174+
175+
if (pattern == null || pattern.type == "underscore") {
176+
continue;
177+
}
178+
if (!bindRhs) {
179+
throw new Error(`Type node can't be null`)
180+
}
181+
182+
const bindType = bindRhs.type;
183+
const patternType = pattern.type;
184+
185+
switch (patternType) {
186+
case "tuple_expression":
187+
if (bindType != "tuple_type_expression") {
188+
throw new Error(`Can't map ${patternType} to ${bindType}`)
189+
}
190+
this.bindToReturnType(pattern, callNode, bindRhs);
191+
break;
192+
case "tensor_var_declaration":
193+
case "tensor_expression":
194+
if (bindType !== "tensor_type") {
195+
throw new Error(`Cant map ${patternType} to ${bindType}`)
196+
}
197+
this.bindToReturnType(pattern, callNode, bindRhs);
198+
break;
199+
case "var_declaration":
200+
this.bindIdentifier(pattern.childForFieldName("name")!, callNode);
201+
break;
202+
case "identifier":
203+
this.bindIdentifier(pattern, callNode);
204+
break;
205+
}
206+
}
207+
}
208+
}

0 commit comments

Comments
 (0)