@@ -15,6 +15,9 @@ import (
15
15
"unicode/utf8"
16
16
)
17
17
18
+ // requireToken is the token used for require statements.
19
+ const requireToken = "require"
20
+
18
21
// A Position describes an arbitrary source position in a file, including the
19
22
// file, line, column, and byte offset.
20
23
type Position struct {
@@ -187,6 +190,108 @@ func (x *FileSyntax) addLine(hint Expr, tokens ...string) *Line {
187
190
return new
188
191
}
189
192
193
+ // requireHint returns a hint for adding a new require line.
194
+ // It tries to maintain the standard order of require blocks, with
195
+ // the first block being the direct requires and the second block
196
+ // being the indirect requires.
197
+ func (x * FileSyntax ) requireHint (indirect bool ) Expr {
198
+ if indirect {
199
+ // Indirect block requested return the first require
200
+ // block with indirect dependencies.
201
+ for _ , stmt := range x .Stmt {
202
+ switch stmt := stmt .(type ) {
203
+ case * Line :
204
+ if stmt .Token != nil && stmt .Token [0 ] == requireToken && isIndirect (stmt ) {
205
+ return stmt
206
+ }
207
+ case * LineBlock :
208
+ if stmt .Token [0 ] == requireToken {
209
+ for _ , line := range stmt .Line {
210
+ if isIndirect (line ) {
211
+ return line
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+
218
+ // No indirect require found, append a new block and return
219
+ // is as the hint. This prevents adding the indirect to an
220
+ // existing direct block.
221
+ block := & LineBlock {
222
+ Token : []string {requireToken },
223
+ }
224
+ x .Stmt = append (x .Stmt , block )
225
+
226
+ return block
227
+ }
228
+
229
+ // Direct block requested.
230
+ var last Expr
231
+ for _ , stmt := range x .Stmt {
232
+ switch stmt := stmt .(type ) {
233
+ case * Line :
234
+ if stmt .Token != nil && stmt .Token [0 ] == requireToken {
235
+ if ! isIndirect (stmt ) {
236
+ // Direct require line found, return it as hint to
237
+ // combine with it.
238
+ return stmt
239
+ }
240
+
241
+ // Indirect line first, which is unexpected. We return
242
+ // the last stmt as hint to create a new require block
243
+ // before it, to try to maintain the standard order.
244
+ if last != nil {
245
+ return last
246
+ }
247
+
248
+ // Indirect line at the beginning of the file, prepend
249
+ // a new require block and return it as hint, to try to
250
+ // maintain the standard order.
251
+ block := & LineBlock {
252
+ Token : []string {requireToken },
253
+ }
254
+ x .Stmt = append ([]Expr {block }, x .Stmt ... )
255
+
256
+ return block
257
+ }
258
+ case * LineBlock :
259
+ if stmt .Token [0 ] == requireToken {
260
+ for _ , line := range stmt .Line {
261
+ if ! isIndirect (line ) {
262
+ // Direct require block found, return it as hint to
263
+ // combine with it.
264
+ return line
265
+ }
266
+ }
267
+
268
+ // Indirect block before first, which is unexpected.
269
+ // Return the last stmt as hint to create a new require
270
+ // block before it to try to maintain the standard order.
271
+ if last != nil {
272
+ return last
273
+ }
274
+
275
+ // Indirect block at the beginning of the file, which is
276
+ // unexpected. Prepend a new require block and return it
277
+ // as hint to try to maintain the standard order.
278
+ block := & LineBlock {
279
+ Token : []string {requireToken },
280
+ }
281
+ x .Stmt = append ([]Expr {block }, x .Stmt ... )
282
+
283
+ return block
284
+ }
285
+ }
286
+
287
+ last = stmt
288
+ continue
289
+ }
290
+
291
+ // No requires found, addLine will create one.
292
+ return nil
293
+ }
294
+
190
295
func (x * FileSyntax ) updateLine (line * Line , tokens ... string ) {
191
296
if line .InBlock {
192
297
tokens = tokens [1 :]
0 commit comments