@@ -3,6 +3,7 @@ import { FuncFile } from "./FuncFile";
33import { Func } from "@server/languages/func/psi/Decls" ;
44import { Expression } from "./FuncNode" ;
55import { closestNamedSibling } from "@server/psi/utils" ;
6+ import { FUNC_PARSED_FILES_CACHE } from "@server/files" ;
67
78type 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