@@ -2,12 +2,46 @@ import * as debug from 'debug'
2
2
3
3
import { ISimpleToken , IRangeToken } from './IToken' ;
4
4
import { IModule , IModuleEnums } from './module'
5
- import { IMatcher , IMatcherState } from './matchers'
5
+ import { IMatcher , IMatcherState , createClassMatcher } from './matchers'
6
6
import { ITokenEmitter } from './tokenProducers'
7
7
import { isComment , isContinue , binarySearch , last } from './helpers'
8
+ import { ws } from './classes'
9
+ import { createTokenEmitter , rangeProducer } from './tokenProducers'
8
10
9
11
const printer = debug ( 'IChannel' )
10
12
13
+ export interface linePos {
14
+ ln : number ;
15
+ col : number ;
16
+ }
17
+ export interface Snippet {
18
+ line : string ;
19
+ f : number ;
20
+ t : number ;
21
+ }
22
+
23
+ export interface Processed {
24
+ snippets : Snippet [ ] ;
25
+ tokens : IRangeToken [ ] ;
26
+ }
27
+
28
+ function compare ( a : any , b : any ) : 0 | - 1 | 1 {
29
+ const df = a . f - b . f
30
+ if ( df > 0 ) return 1
31
+ if ( df < 0 ) return - 1
32
+ if ( a . t !== undefined && b . t !== undefined ) {
33
+ const dt = a . t - b . t
34
+ if ( dt > 0 ) return 1
35
+ if ( dt < 0 ) return - 1
36
+ }
37
+ return 0
38
+ }
39
+
40
+ const search = binarySearch ( compare )
41
+ const wsMatcher = createClassMatcher ( ws , '>1' )
42
+ const wsEmitter = createTokenEmitter ( rangeProducer , wsMatcher )
43
+
44
+
11
45
export interface IChannel < T extends ISimpleToken > {
12
46
mod : IModule ;
13
47
name : string ;
@@ -57,106 +91,185 @@ export function createLogicalEOLChannel<T extends ISimpleToken>(ch: IChannel<T>)
57
91
if ( ch !== ch . mod . channels . get ( 'lf' ) ) {
58
92
throw new TypeError ( `source "lf" channel is not registered with a module` )
59
93
}
94
+ let tokens : T [ ] = [ ]
60
95
const vCh : IChannel < T > = {
61
96
mod : ch . mod ,
62
- tokens : [ ] , //vtokens
97
+ tokens,
63
98
name : 'vlf' ,
64
99
process ( ) {
65
- const tokens = this . tokens = [ ]
100
+ tokens = [ ]
101
+ const lftok = ch . tokens . slice ( 0 )
102
+ const raw = ch . mod . raw
66
103
let prev = 0
67
- for ( let i = 0 ; i < ch . tokens . length ; i ++ ) {
104
+ for ( let i = 0 ; i < lftok . length ; i ++ ) {
68
105
const pos = ch . tokens [ i ] . f
69
- const line = ch . mod . raw . slice ( prev , pos )
106
+ const line = raw . slice ( prev , pos )
70
107
prev = pos + 1
71
108
if ( isContinue ( line ) ) {
72
- if ( tokens . length === 0 ) {
109
+ if ( i === 0 ) {
73
110
const err = `first line cannot be continuation: [${ line } ]`
74
111
printer ( err )
75
112
throw new Error ( err )
76
113
}
77
- tokens [ tokens . length - 1 ] = ch . tokens [ i ]
114
+ // update in place
115
+ tokens [ tokens . length - 1 ] = lftok [ i ]
78
116
continue
79
117
}
80
- tokens . push ( ch . tokens [ i ] )
118
+ tokens . push ( lftok [ i ] )
81
119
}
82
120
}
83
121
}
84
122
ch . mod . channels . set ( vCh . name , vCh )
85
123
return vCh
86
124
}
87
125
88
- export function createCommentsChannel < T extends ISimpleToken > ( ch : IChannel < T > ) : IChannel < T > {
126
+ export function createCommentsChannel ( ch : IChannel < ISimpleToken > ) : IChannel < IRangeToken > {
89
127
90
128
const vlf = ch . mod . channels . get ( 'vlf' )
91
129
const lf = ch . mod . channels . get ( 'lf' )
92
-
130
+
93
131
if ( ch !== vlf && ch !== lf ) {
94
132
throw new TypeError ( `source "lf/vlf" channel is not registered with a module` )
95
133
}
96
-
97
- const comm : IChannel < T > = {
134
+ const _lf = vlf || lf
135
+ const tokens : IRangeToken [ ] = [ ]
136
+ const raw = _lf . mod . raw
137
+ const comm : IChannel < IRangeToken > = {
98
138
mod : ch . mod ,
99
- tokens : [ ] , //vtokens
139
+ tokens,
100
140
name : 'comments' ,
101
141
process ( ) {
102
- const tokens = this . tokens = [ ]
103
- const lftok = ch . tokens . slice ( 0 ) //copy
104
-
142
+ tokens . splice ( 0 )
143
+ const lftok = _lf . tokens . slice ( 0 ) //copy
105
144
let prev = 0
106
- const raw = ch . mod . raw
107
145
for ( let i = 0 ; i < lftok . length ; i ++ ) {
108
146
const pos = lftok [ i ] . f
109
147
const line = raw . slice ( prev , pos )
110
-
111
148
if ( isComment ( line ) ) {
112
- tokens . push ( { f : prev , t : pos } )
113
-
149
+ tokens . push ( { f : prev , t : pos - 1 } )
114
150
}
115
151
prev = pos + 1
116
152
}
117
153
const lastf = last ( lftok ) . f
118
- if ( lastf < raw . length - 1 ) {
119
- const line = raw . slice ( lastf )
120
- if ( isComment ( line ) ) {
121
- tokens . push ( { f : lastf + 1 , t : raw . length - 1 } )
122
- }
154
+ if ( lastf < raw . length - 1 ) {
155
+ const line = raw . slice ( lastf + 1 )
156
+ if ( isComment ( line ) ) {
157
+ tokens . push ( { f : lastf + 1 , t : raw . length - 1 } )
158
+ }
123
159
}
124
160
}
125
161
}
126
162
ch . mod . channels . set ( comm . name , comm )
127
163
return comm
128
164
}
129
165
130
- export function createSourceChannel < T extends ISimpleToken > ( ch : IChannel < T > ) : IChannel < T > {
166
+ export function createSourceChannel ( ch : IChannel < ISimpleToken > ) : IChannel < IRangeToken > {
131
167
132
168
const vlf = ch . mod . channels . get ( 'vlf' )
133
- const comms = ch . mod . channels . get ( 'comments' )
134
- if ( vlf !== ch ) {
169
+ const comms = ch . mod . channels . get ( 'comments' ) as IChannel < IRangeToken >
170
+ if ( vlf !== ch ) {
135
171
throw new TypeError ( `source "vlf" channel is not registered with a module` )
136
172
}
137
- if ( comms === undefined ) {
173
+ if ( comms === undefined ) {
138
174
throw new TypeError ( `source "comments" channel is not registered with a module` )
139
175
}
140
- const source : IChannel < T > = {
176
+ const tokens : IRangeToken [ ] = [ ]
177
+
178
+ const source : IChannel < IRangeToken > = {
141
179
mod : ch . mod ,
142
- tokens : [ ] , //vtokens
180
+ tokens, //vtokens
143
181
name : 'source' ,
144
182
process ( ) {
145
- const tokens = this . tokens = [ ]
183
+ tokens . splice ( 0 ) // delete in palce
184
+ const lftok = vlf . tokens . slice ( 0 ) //copy
185
+ const raw = vlf . mod . raw
146
186
let prev = 0
147
- for ( let i = 0 ; i < ch . tokens . length ; i ++ ) {
148
- const pos = ch . tokens [ i ] . f
149
- const line = ch . mod . raw . slice ( prev , pos )
150
-
151
- if ( isComment ( line ) ) {
152
- tokens . push ( { f : prev , t : pos } )
153
-
187
+ const lastf = last ( lftok ) . f
188
+ for ( let i = 0 ; i < lftok . length ; i ++ ) {
189
+ const pos = lftok [ i ] . f
190
+ const line = raw . slice ( prev , pos )
191
+ if ( ! isComment ( line ) ) {
192
+ tokens . push ( { f : prev , t : pos - 1 } )
154
193
}
155
194
prev = pos + 1
195
+ }
196
+ if ( lastf < raw . length - 1 ) {
197
+ const line = raw . slice ( lastf + 1 )
198
+ if ( ! isComment ( line ) ) {
199
+ tokens . push ( { f : lastf + 1 , t : raw . length - 1 } )
200
+ }
201
+ }
202
+ }
203
+ }
204
+ ch . mod . channels . set ( source . name , source )
205
+ return source
206
+ }
156
207
208
+ export function createWSChannel ( ch : IChannel < IRangeToken > ) : IChannel < IRangeToken > {
209
+
210
+ const vlf = ch . mod . channels . get ( 'vlf' ) as IChannel < ISimpleToken >
211
+ const source = ch . mod . channels . get ( 'source' ) as IChannel < IRangeToken >
212
+ if ( vlf !== ch ) {
213
+ throw new TypeError ( `source "vlf" channel is not registered with a module` )
214
+ }
215
+ if ( source === undefined ) {
216
+ throw new TypeError ( `source "comments" channel is not registered with a module` )
217
+ }
218
+ const raw = vlf . mod . raw
219
+ const tokens : IRangeToken [ ] = [ ]
220
+ const nonWSSource : Snippet [ ] = [ ]
221
+ const ws : IChannel < IRangeToken > = {
222
+ mod : ch . mod ,
223
+ tokens : [ ] , //vtokens
224
+ name : 'ws' ,
225
+ process ( ) {
226
+ tokens . splice ( 0 )
227
+ nonWSSource . splice ( 0 )
228
+ const srctok = source . tokens . slice ( 0 ) //copy
229
+ for ( let i = 0 ; i < srctok . length ; i ++ ) {
230
+ const { f, t } = srctok [ i ]
231
+ let snip = { line : raw . slice ( f , t + 1 ) , f, t }
232
+ // split out continueation lines
233
+ const { snippets, tokens : _tokens } = processLineContinuation ( snip )
234
+ tokens . splice ( 0 , 0 , ..._tokens )
235
+ snippets . map ( processWS ) . forEach ( ( { snippets : snips , tokens : toks } ) => {
236
+ tokens . splice ( 0 , 0 , ...toks )
237
+ nonWSSource . splice ( 0 , 0 , ...snips )
238
+ } )
239
+ // here the ws token need to be extracted from line
157
240
}
241
+ //sort ws tokens because there will be continue line stuff here!!
158
242
}
159
243
}
160
244
ch . mod . channels . set ( source . name , source )
161
245
return source
162
- }
246
+ }
247
+
248
+ export function createProcessor ( regex : RegExp ) {
249
+
250
+ return function process ( s : Snippet ) : Processed {
251
+ const { line, f, t } = s
252
+ const found = line . match ( regex ) ;
253
+ const rc = {
254
+ snippets : [ s ] ,
255
+ tokens : [ ]
256
+ }
257
+
258
+ if ( found ) {
259
+ const first = line . slice ( 0 , found . index )
260
+ const second = line . slice ( found . index + found [ 0 ] . length )
261
+ rc . snippets [ 0 ] = { line : first , f, t : f + first . length - 1 }
262
+ rc . tokens [ 0 ] = { f : f + found . index , t : f + found . index + found [ 0 ] . length - 1 }
263
+ if ( second ) {
264
+ const rv = process ( { line : second , f : f + found . index + found [ 0 ] . length , t } )
265
+ rc . tokens . splice ( 0 , 0 , ...rv . tokens )
266
+ rc . snippets . splice ( 0 , 0 , ...rv . snippets )
267
+ }
268
+ }
269
+ return rc
270
+ }
271
+ }
272
+
273
+ export const processLineContinuation = createProcessor ( / \n \s { 5 } [ ^ \s ] / )
274
+ export const processWS = createProcessor ( / [ \s \t ] + / )
275
+
0 commit comments