11import { ActionClass , ActionParameter , ActionMethod } from './action-elements' ;
22import { logIt , LogLevel , ActionConfig } from './config' ;
33import { ActionContext } from './action-context' ;
4+ import { Range } from 'vscode-languageserver' ;
45//import { loadWASM } from 'onigasm';
56
67enum ActionScope {
@@ -24,14 +25,14 @@ const stripComments = (str: string) => str.replace(commentMatcher, (match: strin
2425//TODO: use onigasm for regex instead
2526const Patterns = {
2627 IMPORT : / \b i m p o r t \s + ( [ \w $ \. \* ] + ) / ,
27- CLASS : / \b c l a s s \s + ( [ \w $ \. ] + ) / ,
28+ CLASS : / ( \b c l a s s \s + ) ( [ \w $ \. ] + ) / ,
2829 CLASS_EXTENDS : / \b e x t e n d s \s + ( [ \w $ \. ] + ) / ,
29- CLASS_VAR : / \b v a r \s + ( [ \w $ ] + ) (?: \s * : \s * ( [ \w $ \. ] + ) ) ? / , //Group 1 : var name; capture group 2 (optional): type
30+ CLASS_VAR : / ( \b v a r \s + ) ( [ \w $ ] + ) (?: \s * : \s * ( [ \w $ \. ] + ) ) ? / , //Group 2 : var name; group 3 (optional): type
3031 PRIVATE : / \b p r i v a t e \b / ,
3132 STATIC : / \b s t a t i c \b / ,
32- METHOD : / \b f u n c t i o n \s + ( [ \w $ ] + ) \s * \( ( .* ) \) (?: \s * : \s * ( [ \w $ \. ] + ) ) ? / , //Group 1 : method name; group 2 (optional): arg list; group 3 (optional): return type
33- IDENTIFIER_AND_TYPE : / \s * ( [ \w $ ] + ) (?: \s * : \ s* ( [ \w $ \. ] + ) ) ? / , //Group 1 : var/argument name; capture group 2 (optional): type
34- LOCAL_VARS : / \b v a r \b ( [ \s \w $ : , = . \[ \] ( ) - + * / ] + ) / ,
33+ METHOD : / ( \b f u n c t i o n \s + ) ( [ \w $ ] + ) ( \s * \( ) ( .* ) \) (?: \s * : \s * ( [ \w $ \. ] + ) ) ? / , //Group 2 : method name; group 4 (optional): arg list; group 5 (optional): return type
34+ IDENTIFIER_AND_TYPE : / ( \s * ) ( [ \w $ ] + ) ( \s * ) (?: \: \ s* ( [ \w $ \. ] + ) \s * ) ? / , //Group 2 : var/argument name; group 4 (optional): type
35+ LOCAL_VARS : / ( \b v a r \b ) ( [ \s \w $ : , = . \[ \] ( ) - + * / ] + ) / , //Group 2: content
3536 BRACES : / [ { } ] / g,
3637 MATCHED_BRACES : / { (?: (? ! { ) .) * ?} / g,
3738 MATCHED_BRACKETS : / \[ (?: (? ! \[ ) .) * ?\] / g,
@@ -56,6 +57,7 @@ export class ActionParser {
5657 this . wipClass . fileUri = fileUri ;
5758 this . wipClass . lines = fileContent . split ( / \r ? \n / ) ;
5859
60+ let includeLocations : boolean = ! ! fileUri ;
5961 let imports : string [ ] = [ ] ;
6062
6163 let scopeStack : ActionScope [ ] = [ ActionScope . BASE ] ;
@@ -76,7 +78,11 @@ export class ActionParser {
7678 Patterns . CLASS . lastIndex = 0 ;
7779 result = Patterns . CLASS . exec ( line ) ;
7880 if ( result ) {
79- fullType = result [ 1 ] ;
81+ fullType = result [ 2 ] ;
82+ if ( includeLocations ) {
83+ let charStart = result . index + result [ 1 ] . length ;
84+ this . wipClass . locationRange = { start : { line : i , character : charStart } , end : { line : i , character : charStart + result [ 2 ] . length } } ;
85+ }
8086 shortType = ActionContext . fullTypeToShortType ( fullType ) ;
8187 this . wipClass . fullType = fullType ;
8288 this . wipClass . shortType = shortType ;
@@ -102,12 +108,18 @@ export class ActionParser {
102108 Patterns . PRIVATE . lastIndex = Patterns . STATIC . lastIndex = 0 ;
103109 let privateRes = Patterns . PRIVATE . exec ( line ) ;
104110 let staticRes = Patterns . STATIC . exec ( line ) ;
105- this . wipClass . registerMember ( {
106- name : result [ 1 ] ,
107- returnType : result [ 2 ] || undefined ,
111+ let member : ActionParameter = {
112+ name : result [ 2 ] ,
113+ returnType : result [ 3 ] || undefined ,
108114 isPublic : ! ( privateRes && privateRes . index < result . index ) ,
109- isStatic : ! ! ( staticRes && staticRes . index < result . index )
110- } ) ;
115+ isStatic : ! ! ( staticRes && staticRes . index < result . index ) ,
116+ owningClass : this . wipClass
117+ } ;
118+ if ( includeLocations ) {
119+ let charStart = result . index + result [ 1 ] . length ;
120+ member . locationRange = { start : { line : i , character : charStart } , end : { line : i , character : charStart + result [ 2 ] . length } } ;
121+ }
122+ this . wipClass . registerMember ( member ) ;
111123 break ;
112124 }
113125
@@ -118,24 +130,35 @@ export class ActionParser {
118130 Patterns . PRIVATE . lastIndex = Patterns . STATIC . lastIndex = 0 ;
119131 let privateRes = Patterns . PRIVATE . exec ( line ) ;
120132 let staticRes = Patterns . STATIC . exec ( line ) ;
121- let isConstructor = result [ 1 ] && result [ 1 ] === this . wipClass . shortType ;
133+ let isConstructor = result [ 2 ] && result [ 2 ] === this . wipClass . shortType ;
134+
135+ let locationRange : Range , argsStart : number ;
136+ if ( includeLocations ) {
137+ let charStart = result . index + result [ 1 ] . length ;
138+ locationRange = { start : { line : i , character : charStart } , end : { line : i , character : charStart + result [ 2 ] . length } } ;
139+ argsStart = locationRange . end . character + result [ 3 ] . length ;
140+ }
122141
123142 let method : ActionMethod = {
124143 isMethod : true ,
125144 isConstructor : isConstructor ,
126- name : result [ 1 ] ,
127- parameters : this . getParameterArrayFromString ( result [ 2 ] , true ) ,
145+ name : result [ 2 ] ,
146+ parameters : this . getParameterArrayFromString ( result [ 4 ] , true , includeLocations , i , argsStart ) ,
147+ locationRange : locationRange ,
128148 locals : [ ] ,
129- returnType : result [ 3 ] || ( isConstructor ? result [ 1 ] : null ) ,
149+ returnType : result [ 5 ] || ( isConstructor ? result [ 2 ] : null ) ,
130150 isPublic : ! ( privateRes && privateRes . index < result . index ) ,
131151 isStatic : ! ! ( staticRes && staticRes . index < result . index ) ,
132- firstLineNumber : i + 1
152+ owningClass : this . wipClass
133153 } ;
134154
135155 let methodLines = this . wipClass . lines . slice ( i + 1 ) ;
136156 methodLines . unshift ( line . substr ( result . index + result [ 0 ] . length ) ) ;
137- let [ methodLength , locals ] = this . extractMethod ( methodLines , deep ) ;
138- method . lastLineNumber = method . firstLineNumber + methodLength - 1 ;
157+ let [ methodLength , locals ] = this . extractMethod ( methodLines , deep , includeLocations , i ) ;
158+ if ( includeLocations ) {
159+ method . firstLineNumber = i + 1 ;
160+ method . lastLineNumber = method . firstLineNumber + methodLength - 1 ;
161+ }
139162 method . locals = locals ;
140163 method . scopedMembers = method . parameters . concat ( method . locals ) ;
141164
@@ -167,17 +190,24 @@ export class ActionParser {
167190 return this . wipClass ;
168191 }
169192
170- private static getParameterArrayFromString ( paramString : string , isArgument = false ) : ActionParameter [ ] {
193+ private static getParameterArrayFromString ( paramString : string , isArgument = false , includeLocations = false , lineNumber ?: number , charIndex ?: number ) : ActionParameter [ ] {
171194 let parsedParams : ActionParameter [ ] = [ ] ;
172195 if ( ( ! paramString ) || paramString . trim ( ) === '' ) return parsedParams ;
173196
174- let rawParams = paramString . split ( ',' ) ;
197+ let rawParams = paramString . split ( ',' ) , charStart : number ;
175198 let result : RegExpExecArray ;
176199 for ( let i = 0 , l = rawParams . length ; i < l ; i ++ ) {
177- Patterns . IDENTIFIER_AND_TYPE . lastIndex = 0 ;
200+ Patterns . IDENTIFIER_AND_TYPE . lastIndex = 0 ;
178201 result = Patterns . IDENTIFIER_AND_TYPE . exec ( rawParams [ i ] ) ;
179- if ( result && result [ 1 ] ) {
180- parsedParams . push ( { name : result [ 1 ] , returnType : result [ 2 ] , isArgument : isArgument , isInline : ! isArgument } ) ;
202+ if ( result && result [ 2 ] ) {
203+ let param : ActionParameter = { name : result [ 2 ] , returnType : result [ 4 ] , isArgument : isArgument , isInline : ! isArgument } ;
204+ if ( includeLocations ) {
205+ charStart = charIndex + result . index + result [ 1 ] . length ;
206+ param . locationRange = { start : { line : lineNumber , character : charStart } , end : { line : lineNumber , character : charStart + result [ 2 ] . length } } ;
207+ param . owningClass = this . wipClass ;
208+ charIndex += rawParams [ i ] . length + 1 ;
209+ }
210+ parsedParams . push ( param ) ;
181211 }
182212 }
183213 return parsedParams ;
@@ -186,7 +216,7 @@ export class ActionParser {
186216 /**
187217 * Modifies the passed array to remove the method contents, returns an array with the local vars if desired; otherwise an empty array
188218 */
189- private static extractMethod ( lines : string [ ] , collectLocals = false ) : [ number , ActionParameter [ ] ] {
219+ private static extractMethod ( lines : string [ ] , collectLocals = false , includeLocations = false , lineNumber ?: number ) : [ number , ActionParameter [ ] ] {
190220 let locals : ActionParameter [ ] = [ ] ;
191221 let lineCount = - 1 ;
192222 let searchCount = - 1 ; //Denotes start not yet found
@@ -211,11 +241,11 @@ export class ActionParser {
211241 if ( collectLocals ) {
212242 Patterns . LOCAL_VARS . lastIndex = 0 ;
213243 result = Patterns . LOCAL_VARS . exec ( line ) ;
214- if ( result && result [ 1 ] ) {
215- let localString = recursiveReplace ( result [ 1 ] , Patterns . MATCHED_BRACES ) ;
216- localString = recursiveReplace ( localString , Patterns . MATCHED_BRACKETS ) ;
217- localString = recursiveReplace ( localString , Patterns . MATCHED_PARENS ) ;
218- locals = locals . concat ( this . getParameterArrayFromString ( localString , false ) ) ;
244+ if ( result && result [ 2 ] ) {
245+ let localString = recursiveReplaceAndPreserveLength ( result [ 2 ] , Patterns . MATCHED_BRACES ) ;
246+ localString = recursiveReplaceAndPreserveLength ( localString , Patterns . MATCHED_BRACKETS ) ;
247+ localString = recursiveReplaceAndPreserveLength ( localString , Patterns . MATCHED_PARENS ) ;
248+ locals = locals . concat ( this . getParameterArrayFromString ( localString , false , includeLocations , lineNumber + lineCount , result . index + result [ 1 ] . length ) ) ;
219249 }
220250 }
221251 //Find end / other opening braces
@@ -241,3 +271,16 @@ export function recursiveReplace(input: string, matcher: string | RegExp, replac
241271 } while ( output !== input ) ;
242272 return output ;
243273}
274+
275+ export function recursiveReplaceAndPreserveLength ( input : string , matcher : RegExp , replacement = ' ' ) : string {
276+ let output = input ;
277+ let result : RegExpExecArray ;
278+ do {
279+ input = output ;
280+ matcher . lastIndex = 0 ;
281+ result = matcher . exec ( input ) ;
282+ if ( ! result || ! result [ 0 ] ) break ;
283+ output = input . replace ( result [ 0 ] , replacement . repeat ( result [ 0 ] . length ) ) ;
284+ } while ( output !== input ) ;
285+ return output ;
286+ }
0 commit comments