summary refs log tree commit diff stats
path: root/compiler/suggest.nim
Commit message (Collapse)AuthorAgeFilesLines
* fixes #19278; make `privateAccess` work with generic ref object (#20640)ringabout2022-10-241-2/+2
| | | | | * fixes #19278; make `privateAccess` work with generic ref object * fixes
* fixes #20572 (#20585)Andreas Rumpf2022-10-171-1/+1
| | | | | * fixes #20572 * added a test case
* Fix/improve handling of forward declarations in nimsuggest (#20493)Ivan Yonchovski2022-10-061-1/+1
| | | | | | | | | | | | | | | | | * Fix/improve handling of forward declarations in nimsuggest - ideUse now works fine when invoked on the implementation - implemented ideDeclaration to make cover lsp feature textDocument/declaration - fixed performance issue related to deduplicating symbols. Now the deduplication happens after the symbols are filtered. As a alternative we might change the way cached symbols are stored(e. g. use set). - I also fixed the way globalSymbols work. Now it will sort the responses based on the match location to make sure that the results are sorted in user friendly way. * Update nimsuggest/nimsuggest.nim Co-authored-by: Andreas Rumpf <rumpf_a@web.de> Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
* store full definition AST for consts, fix noRewrite (#20115)metagn2022-09-281-10/+0
| | | | | | | | | | | | | | | | | | | | | | | * continue #9582 for consts, close #9331, fix #20114 also move extractPragma to ast to pave the way for things like {.strdefine: "abc".} etc * changelog correctly * fix jsgen * update tgetimpl * fix sighashes * fix #19766, add comment about postfix * fix noRewrite LOL refs #16620 * fix changelog * fix destructors
* [nimsuggest] fix def call on identifier 2 times on the line (#20228)Ivan Yonchovski2022-08-301-1/+14
| | | | | | | - apparently TLineInfo's implementation of `==` ignores the column. After I fixed the code to use exact TLineInfo comparison I fixed several other issues hidden by that issue. - Replaced `tuple[sym, info]` with `SymInfoPair`
* Use module actual file instead of PSym.info (#19956)Ivan Yonchovski2022-07-151-12/+18
| | | After this you can do goto module from module import
* Change `styleCheck` to ignore foreign packages (#19822)quantimnot2022-07-141-2/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Change `styleCheck` to ignore foreign packages * Symbols from foreign packages are now ignored. * Fixed `styleCheck` violations in `compiler` package. * Added symbol ownership to custom annotation pragmas. * Minor refactors to cleanup style check callsites. * Minor internal documentation of reasons why a symbol isn't checked. Style violations were fixed in the compiler after thet were exposed by the changes. The compiler wouldn't compile otherwise. Symbol ownership for custom pragma annotations is needed for checking the annotation's style. A NPE was raised otherwise. Fixes #10201 See also nim-lang/RFCs#456 * Fix a misunderstanding about excluding field style checks I had refactored the callsites of `styleCheckUse` to apply the DRY principle, but I misunderstood the field access handling in a template as a general case. This corrects it. * Fix some `styleCheck` violations in `compiler/evalffi` The violations were exposed in CI when the compiler was built with libffi. * Removed some uneeded transitionary code * Add changelog entry Co-authored-by: quantimnot <quantimnot@users.noreply.github.com>
* Initial implementation of nimsuggest v3 (#19826)Ivan Yonchovski2022-06-131-5/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Initial implementation of nimsuggest v3 Rework `nimsuggest` to use caching to make usage of ide commands more efficient. Previously, all commands no matter what the state of the process is were causing clean build. In the context of Language Server Protocol(LSP) and lsp clients this was causing perf issues and overall instability. Overall, the goal of v3 is to fit to LSP Server needs - added two new commands: - `recompile` to do clean compilation - `changed` which can be used by the IDEs to notify that a particular file has been changed. The later can be utilized when using LSP file watches. - `globalSymbols` - searching global references - added `segfaults` dependency to allow fallback to clean build when incremental fails. I wish the error to be propagated to the client so we can work on fixing the incremental build failures (typically hitting pointer) - more efficient rebuild flow. ATM incremental rebuild is triggered when the command needs that(i. e. it is global) while the commands that work on the current source rebuild only it Things missing in this PR: - Documentation - Extensive unit testing. Although functional I still see this more as a POC that this approach can work. Next steps: - Implement `sug` request. - Rework/extend the protocol to allow better client/server communication. Ideally we will need push events, diagnostics should be restructored to allow per file notifications, etc. - implement v3 test suite. - better logging * Add tests for v3 and implement ideSug * Remove typeInstCache/procInstCache cleanup * Add ideChkFile command * Avoid contains call when adding symbol info * Remove log * Remove segfaults
* get rid of the warnings during bootstrapping (#18741)Miran2021-08-241-1/+1
| | | | | * fix bootstrapping hints and warnings * revert removals in ccgtypes
* followup #18362: make `UnusedImport` work robustly (#18366)Timothee Cour2021-06-271-2/+3
| | | | * warnDuplicateModuleImport => hintDuplicateModuleImport * improve DuplicateModuleImport msg, add test
* fix https://github.com/nim-lang/RFCs/issues/311 remove unary slice (#16714)Timothee Cour2021-04-191-1/+1
|
* privateAccess now works with ref | ptr (#17760)Timothee Cour2021-04-191-1/+3
|
* `import foo {.all.}` reboot (#17706)Timothee Cour2021-04-161-4/+9
|
* nimsuggest prioritize non-deprecated suggestions (#16816)Saem Ghani2021-01-291-15/+27
| | | | | | | | | | | * penalizes the quality score of deprecated symbols * uses quality more pervasively in order to reflect deprecation impact * impacts both sug and con additional notes: * linux i386 CI was failing * this is because the suggested results differ slightly in their sort * 64 bit tables.getOrDefault:441 was returned, while 32 bit returned 422 * for now simply removing the last line is good enough
* fixed nim-lang/nimsuggest#48 type aware sug (#16814)Saem Ghani2021-01-251-2/+7
| | | | * suggesting identifiers accounts context over scope (distance) * key takeaway: context fit is prioritized over a heuristics like scope
* fixes nim-lang/nimsuggest#103 con dot exprs (#16657)Saem Ghani2021-01-121-0/+1
| | | | - con calls for dot exprs now returns results - discovered an issue with dot expr results -- documented
* fixed nim-lang/nimsuggest#82 pure enum field sug (#16676)Saem Ghani2021-01-111-10/+11
| | | | - previous code wasn't account for tyEnum being wrapped in tyTypeDesc - now pure enum fields are suggested
* IC: next steps (#16550)Andreas Rumpf2021-01-071-38/+39
| | | | | | | | | | | | | | | | | | * cleanups * ast.nim: cleanups * IC: no more sym.tab field, stored externally in the module graph * nimble compiles again * rodfiles: store bitwidth of integers and the endianness in the cookie because we serialize 'int' directly * rodfiles: added compilerproc and export sections * rodfiles: added all the missing sections * rodfiles: track the missing information * IC: architecture for lazy loading of proc bodies * make tests green again * completed the lazy loading of proc bodies * symbol lookup integration, part 1 * symbol lookup integration, part 2 * symbol lookup integration, part 3 * make tcompilerapi work again * rodfiles: fixed config change handling
* fixes nim-lang/nimsuggest#119 outline includes (#16608)Saem Ghani2021-01-061-3/+13
| | | | | | nimsuggest outline should account for includes, now it does: - the module prefix will be of the module doing the including - the filename will be of the module that was included - adds a test case for it
* refactorings to prepare the compiler for IC (#15935)Andreas Rumpf2020-12-171-33/+17
| | | | | | | | | | | | | | * added ic specific Nim code; WIP * make the symbol import mechanism lazy; WIP * ensure that modules can be imported multiple times * ambiguity checking * handle converters and TR macros properly * make 'enum' test category green again * special logic for semi-pure enums * makes nimsuggest tests green again * fixes nimdata * makes nimpy green again * makes more important packages work
* suggest: try to find the implementation of a symbol when def is used (#15555)alaviss2020-10-141-7/+15
| | | | | * suggest: try to find the implementation of a symbol when def is used * suggest: return all declarations of the symbol on `def`
* Big compiler Cleanup (#14777)Clyybber2020-08-281-1/+1
|
* compiler: minor code cleanupsAraq2020-07-271-1/+1
|
* fix #11009 (#14935)flywind2020-07-091-1/+6
|
* Clean out oldast (#14837)Juan Carlos2020-06-301-4/+1
| | | | * Clean out old Deprecated CLI switch * Update to remove --oldast CLI option
* compiler/suggest: highlight squashed operators (#11796)alaviss2020-04-201-3/+7
| | | | | | The operator fetching proc is greedy, so operators such as `%*` in expression `%*{}` can't be highlighted. This commit fixes that.
* make `usage of foo is a user-defined error` more informative (#13833)Timothee Cour2020-04-011-3/+5
|
* fix .deprecated. object typedef crash (#13643)Andy Davidoff2020-03-161-3/+5
| | | | | * fix .deprecated. object typedef crash * fixup a test that i don't understand * disable the test rather than debug ci
* Cosmetic compiler cleanup (#12718)Clyybber2019-11-281-30/+28
| | | | | | | | | | | | | | | | | | * Cleanup compiler code base * Unify add calls * Unify len invocations * Unify range operators * Fix oversight * Remove {.procvar.} pragma * initCandidate -> newCandidate where reasonable * Unify safeLen calls
* compiler/suggest: add variable support to `con` (#12569)alaviss2019-11-041-1/+9
| | | This allows for the type of a variable to be retrieved.
* Small ast.nim cleanup (#12156)Clyybber2019-09-091-5/+5
| | | | | * Remove sonsLen * Use Indexable
* fixes nimsuggest/#108: RangeError with d:releasenarimiran2019-09-041-1/+1
|
* new gensym handling (#11985)Andreas Rumpf2019-08-231-3/+3
| | | | | | | | | | | * new .gensym implementation * make astspec test green again * introduce a --useVersion switch to group compatibility switches * fixes #10180 * fixes #11494 * fixes #11483 * object constructor fields and named parameters are also not gensym'ed * disabled broken package
* fixes 'unused module' feature for 32 bit builds of Nim for good [nobackport]Araq2019-08-091-2/+2
|
* [refactoring] compiler: simplified markUsedAndreas Rumpf2019-08-081-2/+2
|
* fixes #11809Andreas Rumpf2019-08-081-1/+2
|
* Merge branch 'devel' into araq-detect-unused-importsAndreas Rumpf2019-07-181-2/+2
|\
| * [refactoring] remove unused imports in the compiler and in some stdlib modulesAraq2019-07-181-2/+2
| |
* | [feature] detect unused importsAraq2019-07-171-1/+16
|/
* minor style changesAraq2019-07-111-1/+1
|
* nim styleChecker: implemented all the missing features (bugfix)Araq2019-07-101-1/+3
|
* rename tyExpr/tyStmt to tyUntyped/tyTyped (#11227)Arne Döring2019-05-111-3/+3
|
* Replace countup(x, y-1) with x ..< yClyybber2019-05-071-3/+3
|
* Less warnings in macros (#10799)Arne Döring2019-03-111-4/+0
|
* make nimsuggest aware of tyOwnedAndreas Rumpf2019-02-251-1/+1
|
* 32 bit fixes (#10608)Arne Döring2019-02-131-1/+1
|
* compiler/[msgs, suggest]: improve highlighter accuracy (#10496)alaviss2019-02-071-2/+37
| | | | | | | | | | Previously the compiler would generate suggestions based on the symbol identifier length, but that might not reflect the actual representation of it within the actual source code. This commit implements a simple source scanner for the suggest module to address the problem outlined above. Fixes nim-lang/nimsuggest#24
* suggest: quote operators and keywords on suggestion (#10460)alaviss2019-01-281-2/+6
|
* {.deprecated: msg.} now works for vars and lets (#10234)Neelesh Chandola2019-01-081-2/+6
|
* Deprecate gc v2 (#10151)Neelesh Chandola2019-01-011-2/+2
| | | | | | * Deprecate gc v2 * warnDeprecated now has custom messages
0200 refs #11402; now koch ships a fixed version of Nimble so that the connection between Nim and Nimble version is obvious when you do 'git checkout v0.20' in Nim's repo' href='/ahoang/Nim/commit/koch.nim?h=devel&id=8ab94cdd45a9730ec4401feead74b2c86e10ce6b'>8ab94cdd4 ^
e7471ceba ^
5be5bf022 ^

9605a0f87 ^
5be5bf022 ^


d8430f5a7 ^
5be5bf022 ^

d862d2272 ^
5be5bf022 ^

2eb14bdd4 ^
5be5bf022 ^



5b5bd3811 ^
7d1a96151 ^
5be5bf022 ^

e6ff6dd9c ^
2e477979a ^
5be5bf022 ^


41f32f5fb ^

06b986dbd ^
8a5373291 ^
13b72ed0c ^
1fa23e347 ^
2990a5ea5 ^




1fa23e347 ^
2e477979a ^
1fa23e347 ^
41f32f5fb ^

ba2aa474a ^


13b72ed0c ^
41f32f5fb ^
dfc17e5f8 ^
765366c1f ^
5be5bf022 ^








41f32f5fb ^
2e477979a ^
5be5bf022 ^


5f8ab1653 ^
8ed3e295a ^
a4f8a89c8 ^
3b00d9cc7 ^
3905cfeac ^

13b72ed0c ^
813a4f1d8 ^
90119066a ^
6655537c6 ^
41f32f5fb ^

6655537c6 ^
08d82e4b1 ^



b1b58b88c ^




90119066a ^
b1b58b88c ^


3ee048eaa ^
b1b58b88c ^


76c3b314d ^
90119066a ^

3b00d9cc7 ^
90119066a ^
0f4567d59 ^

0f4567d59 ^






90119066a ^
2169fd63b ^
3b00d9cc7 ^
0f4567d59 ^
cd292568d ^

3b00d9cc7 ^
0f4567d59 ^


90119066a ^

3b00d9cc7 ^
0f4567d59 ^
3b00d9cc7 ^
90119066a ^
0f4567d59 ^

f3756d2cc ^
2039dad27 ^
721534119 ^
38bdf1cd7 ^
3b00d9cc7 ^
42bac5242 ^
42bac5242 ^

2039dad27 ^
5b789f2da ^
42bac5242 ^
1d6622290 ^
42bac5242 ^
1d6622290 ^
42bac5242 ^
6870345cd ^
e0afacb9f ^
42bac5242 ^





1d6622290 ^
3d88d06b3 ^



1d6622290 ^
3d88d06b3 ^


5b789f2da ^





142e849b9 ^
90119066a ^





76235348f ^
ae6dac6b6 ^
90119066a ^

0f4567d59 ^
90119066a ^

3b00d9cc7 ^
90119066a ^


d6074a7c7 ^
90119066a ^





3b00d9cc7 ^
90119066a ^

346443d1b ^
73c355176 ^
346443d1b ^
90119066a ^
3b00d9cc7 ^

90119066a ^


3b00d9cc7 ^
90119066a ^


6ff8752be ^
3b00d9cc7 ^
4d5c3ebd4 ^
9c3751a37 ^
6ff8752be ^
8b93e4132 ^

2d3385c22 ^




ecdc478da ^
5492190bc ^
2d3385c22 ^


ecdc478da ^
2d3385c22 ^



07553034d ^


e7471ceba ^
ecdc478da ^
2d3385c22 ^

a5b19ba86 ^


2d3385c22 ^

07553034d ^

2d3385c22 ^
07553034d ^

ecdc478da ^

2d3385c22 ^
07553034d ^

723d83855 ^
2d3385c22 ^
723d83855 ^
2d3385c22 ^
8b93e4132 ^
740527813 ^

d6074a7c7 ^
37229df7f ^
6ff8752be ^
ef44c12a3 ^
97738a4f2 ^
411e602d1 ^
411e602d1 ^

90119066a ^
b4e25a637 ^
885f250f1 ^













eb6225ad8 ^


511b6ae27 ^
7a39eb13a ^
6d125da93 ^


7a39eb13a ^
49c6dbf4a ^
6d125da93 ^
b4e25a637 ^
04a4ff567 ^
885f250f1 ^
b4e25a637 ^
82effc581 ^




c6471b8f7 ^
82effc581 ^




c60916a2a ^





54fecdb8d ^
adbabf145 ^
721534119 ^
d2b95cb47 ^

54fecdb8d ^
c60916a2a ^
c5dbb0379 ^
adbabf145 ^


dee9a9427 ^
091da5c97 ^
dee9a9427 ^
























c60916a2a ^
73b76b916 ^






















7ee6774fb ^

2e477979a ^
7ee6774fb ^

















e7471ceba ^
7ee6774fb ^
34f0b9110 ^
9f9867800 ^
7ee6774fb ^




15a8996d5 ^
7ba565258 ^

















15a8996d5 ^
7ba565258 ^
15a8996d5 ^
3b00d9cc7 ^

99b36cb71 ^
90119066a ^
a5b19ba86 ^

2e477979a ^






923086253 ^
2e477979a ^

















c60916a2a ^
2e477979a ^


5be5bf022 ^


d2b95cb47 ^
5be5bf022 ^
b2b9af6a5 ^
5be5bf022 ^

2e477979a ^

5be5bf022 ^
2e477979a ^


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636

 
                                     
                                         



                                                   

                                        
 
     
                                                                          
 




                                       
 
                                                          
                                              
                                                         
                                             
 
      

                                         

                       
                                         
 


                                                                   
                                                                   
                         
                                                                   



                                                                   
                                              

                                                    
                                                                            
                                                                               

                                                                     
                                                      
                                                   

                                                                   
                                                 

                                                                    
                                                                         
                                                  


                                                                           

                             
                                                                           
                                                           




                                                                 

                                                                         
                                                                   
                                                               


                                                                              
   
 
                                                                                                                                                               
                                                                    



                                     


                                                
                             
                           



                      
                      
 
                             

                          
                                 


                                 


                                               



                                          


                                    
                                                                    
 
     
                                          
 
                            


                                                                     
 
                                

                                                                      

                                                         
 
                                                  





                                                                        
                                           

                                                         
 
                                              

                                                                  
                                












                                                                                
                        
           
                         
                                                  

                                                                        
 


                                                                   
 

                                                                           
 

                                                                
 



                                                             
             
                                    

                                                                                          
 
                                      


                               

                                                                                                               
                                                                                                  
                                                      
 
                       




                                                                    
 
                                     
                  

                                                                                                               


                                                                                                 
                                        
                                        
                                                                          
 








                                                                
 
                                       


                               
                                                        
                                          
                                   
                            

                                                   
                                                                              
                                                                                  
 
                          

                                                                                                                  
 



                                   




                                                                                
 


                                                                                          
 


                                                                                      
 

                                                                               
                           
                                           

               






                                                                        
                      
                                  
                               
                                                        

                                   
                               


                                                                      

                 
                                
                                        
 
                         

                                     
                                   
                                                              
                                                                                                     
                                            
 
                               

                                                   
                                                                                       
                           
                        
                          
              
                     
                                                      
                                               
                                                                               





                                                          
 



                                                                             
                                                           


                                                             





                                            
                                                                             





                                                                               
                                                                           
                  

            
                                                                    

   
                            


                                 
                                          





                                             
                    

                                   
                                         
                          
                 
 

                                     


                        
                          


                             
                                                       
                     
                                 
                     
 

                                                                               




                                                 
                                 
                                                                         


            
                              



                                                                      


                                                                     
                                                    
                                                        

                                                                            


                                                                       

                     

                                  
                                            

                                                              

                                                                     
            

                                
                            
                       
                            
                       
 

                                                                               
                                                      
 
                          
                                           
                                                                   
                                                   

                                     
 
                         













                                                                


                                            
                                                                          
                                               


                                     
                                   
                         
                                                                                                                   
                            
                        
                                                             
 




                                                              
            




                                                                





                                                                            
                                
                                                              
                                                                   

                                                                        
                                        
 
             


                                                                                      
                                                    
                                                                                              
























                                                                                                              
 






















                                                                             

                                           
                        

















                                                                      
                                   
                             
                                                  
                                                                                 




                                   
                            

















                                                                        
                                                    
                                                  
 

                                                                     
                                                          
 

                          






                                     
                                 

















                                                       
                                       


                                               


                                                       
                         
                                  
                 

                                           

                                                      
                                             


                      
#
#
#         Maintenance program for Nim
#        (c) Copyright 2017 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#
#    See doc/koch.txt for documentation.
#

const
  NimbleStableCommit = "da82e3111e662fc1b12f96b3cddd66c749c0f686" # master

when defined(gcc) and defined(windows):
  when defined(x86):
    {.link: "icons/koch.res".}
  else:
    {.link: "icons/koch_icon.o".}

when defined(amd64) and defined(windows) and defined(vcc):
  {.link: "icons/koch-amd64-windows-vcc.res".}
when defined(i386) and defined(windows) and defined(vcc):
  {.link: "icons/koch-i386-windows-vcc.res".}

import
  os, strutils, parseopt, osproc, streams

import tools / kochdocs

const VersionAsString = system.NimVersion

const
  HelpText = """
+-----------------------------------------------------------------+
|         Maintenance program for Nim                             |
|             Version $1|
|             (c) 2017 Andreas Rumpf                              |
+-----------------------------------------------------------------+
Build time: $2, $3

Usage:
  koch [options] command [options for command]
Options:
  --help, -h               shows this help and quits
  --latest                 bundle the installers with a bleeding edge Nimble
  --stable                 bundle the installers with a stable Nimble (default)
Possible Commands:
  boot [options]           bootstraps with given command line options
  distrohelper [bindir]    helper for distro packagers
  tools                    builds Nim related tools
  toolsNoNimble            builds Nim related tools (except nimble)
                           doesn't require network connectivity
  nimble                   builds the Nimble tool
Boot options:
  -d:release               produce a release version of the compiler
  -d:useLinenoise          use the linenoise library for interactive mode
                           (not needed on Windows)
  -d:leanCompiler          produce a compiler without JS codegen or
                           documentation generator in order to use less RAM
                           for bootstrapping

Commands for core developers:
  runCI                    runs continuous integration (CI), eg from travis
  docs [options]           generates the full documentation
  csource -d:release       builds the C sources for installation
  pdf                      builds the PDF documentation
  zip                      builds the installation zip package
  xz                       builds the installation tar.xz package
  testinstall              test tar.xz package; Unix only!
  tests [options]          run the testsuite (run a subset of tests by
                           specifying a category, e.g. `tests cat async`)
  temp options             creates a temporary compiler for testing
  pushcsource              push generated C sources to its repo
Web options:
  --googleAnalytics:UA-... add the given google analytics code to the docs. To
                           build the official docs, use UA-48159761-1
"""

let kochExe* = when isMainModule: os.getAppFilename() # always correct when koch is main program, even if `koch` exe renamed eg: `nim c -o:koch_debug koch.nim`
               else: getAppDir() / "koch".exe # works for winrelease

proc kochExec*(cmd: string) =
  exec kochExe.quoteShell & " " & cmd

proc kochExecFold*(desc, cmd: string) =
  execFold(desc, kochExe.quoteShell & " " & cmd)

template withDir(dir, body) =
  let old = getCurrentDir()
  try:
    setCurrentDir(dir)
    body
  finally:
    setCurrentDir(old)

let origDir = getCurrentDir()
setCurrentDir(getAppDir())

proc tryExec(cmd: string): bool =
  echo(cmd)
  result = execShellCmd(cmd) == 0

proc safeRemove(filename: string) =
  if existsFile(filename): removeFile(filename)

proc overwriteFile(source, dest: string) =
  safeRemove(dest)
  moveFile(source, dest)

proc copyExe(source, dest: string) =
  safeRemove(dest)
  copyFile(dest=dest, source=source)
  inclFilePermissions(dest, {fpUserExec, fpGroupExec, fpOthersExec})

const
  compileNimInst = "tools/niminst/niminst"

proc csource(args: string) =
  nimexec(("cc $1 -r $3 --var:version=$2 --var:mingw=none csource " &
           "--main:compiler/nim.nim compiler/installer.ini $1") %
       [args, VersionAsString, compileNimInst])

proc bundleC2nim(args: string) =
  if not dirExists("dist/c2nim/.git"):
    exec("git clone https://github.com/nim-lang/c2nim.git dist/c2nim")
  nimCompile("dist/c2nim/c2nim",
             options = "--noNimblePath --path:. " & args)

proc bundleNimbleExe(latest: bool, args: string) =
  if not dirExists("dist/nimble/.git"):
    exec("git clone https://github.com/nim-lang/nimble.git dist/nimble")
  if not latest:
    withDir("dist/nimble"):
      exec("git fetch")
      exec("git checkout " & NimbleStableCommit)
  # installer.ini expects it under $nim/bin
  nimCompile("dist/nimble/src/nimble.nim",
             options = "-d:release --nilseqs:on " & args)

proc buildNimble(latest: bool, args: string) =
  # if koch is used for a tar.xz, build the dist/nimble we shipped
  # with the tarball:
  var installDir = "dist/nimble"
  if not latest and dirExists(installDir) and not dirExists("dist/nimble/.git"):
    discard "don't do the git dance"
  else:
    if not dirExists("dist/nimble/.git"):
      if dirExists(installDir):
        var id = 0
        while dirExists("dist/nimble" & $id):
          inc id
        installDir = "dist/nimble" & $id
      exec("git clone https://github.com/nim-lang/nimble.git " & installDir)
    withDir(installDir):
      if latest:
        exec("git checkout -f master")
        exec("git pull")
      else:
        exec("git fetch")
        exec("git checkout " & NimbleStableCommit)
  nimCompile(installDir / "src/nimble.nim",
             options = "--noNimblePath --nilseqs:on -d:release " & args)

proc bundleNimsuggest(args: string) =
  nimCompileFold("Compile nimsuggest", "nimsuggest/nimsuggest.nim",
                 options = "-d:release -d:danger " & args)

proc buildVccTool(args: string) =
  nimCompileFold("Compile Vcc", "tools/vccexe/vccexe.nim ", options = args)

proc bundleWinTools(args: string) =
  nimCompile("tools/finish.nim", outputDir = "", options = args)

  buildVccTool(args)
  nimCompile("tools/nimgrab.nim", options = "-d:ssl " & args)
  nimCompile("tools/nimgrep.nim", options = args)
  bundleC2nim(args)
  when false:
    # not yet a tool worth including
    nimCompile(r"tools\downloader.nim",
               options = r"--cc:vcc --app:gui -d:ssl --noNimblePath --path:..\ui " & args)

proc zip(latest: bool; args: string) =
  bundleNimbleExe(latest, args)
  bundleNimsuggest(args)
  bundleWinTools(args)
  nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
       [VersionAsString, compileNimInst])
  exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" %
       ["tools/niminst/niminst".exe, VersionAsString])

proc ensureCleanGit() =
  let (outp, status) = osproc.execCmdEx("git diff")
  if outp.len != 0:
    quit "Not a clean git repository; 'git diff' not empty!"
  if status != 0:
    quit "Not a clean git repository; 'git diff' returned non-zero!"

proc xz(latest: bool; args: string) =
  ensureCleanGit()
  nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
       [VersionAsString, compileNimInst])
  exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim xz compiler/installer.ini" %
       ["tools" / "niminst" / "niminst".exe, VersionAsString])

proc buildTool(toolname, args: string) =
  nimexec("cc $# $#" % [args, toolname])
  copyFile(dest="bin" / splitFile(toolname).name.exe, source=toolname.exe)

proc buildTools(args: string = "") =
  bundleNimsuggest(args)
  nimCompileFold("Compile nimgrep", "tools/nimgrep.nim",
                 options = "-d:release " & args)
  when defined(windows): buildVccTool(args)
  nimCompileFold("Compile nimpretty", "nimpretty/nimpretty.nim",
                 options = "-d:release " & args)
  nimCompileFold("Compile nimfind", "tools/nimfind.nim",
                 options = "-d:release " & args)

proc nsis(latest: bool; args: string) =
  bundleNimbleExe(latest, args)
  bundleNimsuggest(args)
  bundleWinTools(args)
  # make sure we have generated the niminst executables:
  buildTool("tools/niminst/niminst", args)
  #buildTool("tools/nimgrep", args)
  # produce 'nim_debug.exe':
  #exec "nim c compiler" / "nim.nim"
  #copyExe("compiler/nim".exe, "bin/nim_debug".exe)
  exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw$#" &
        " nsis compiler/installer.ini") % [VersionAsString, $(sizeof(pointer)*8)])

proc geninstall(args="") =
  nimexec("cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini $#" %
       [compileNimInst, VersionAsString, args])

proc install(args: string) =
  geninstall()
  exec("sh ./install.sh $#" % args)

when false:
  proc web(args: string) =
    nimexec("js tools/dochack/dochack.nim")
    nimexec("cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" %
        [args, VersionAsString])

  proc website(args: string) =
    nimexec("cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" %
        [args, VersionAsString])

  proc pdf(args="") =
    exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" %
        [findNim(), args, VersionAsString], additionalPATH=findNim().splitFile.dir)

# -------------- boot ---------------------------------------------------------

proc findStartNim: string =
  # we try several things before giving up:
  # * bin/nim
  # * $PATH/nim
  # If these fail, we try to build nim with the "build.(sh|bat)" script.
  var nim = "nim".exe
  result = "bin" / nim
  if existsFile(result): return
  for dir in split(getEnv("PATH"), PathSep):
    if existsFile(dir / nim): return dir / nim

  when defined(Posix):
    const buildScript = "build.sh"
    if existsFile(buildScript):
      if tryExec("./" & buildScript): return "bin" / nim
  else:
    const buildScript = "build.bat"
    if existsFile(buildScript):
      if tryExec(buildScript): return "bin" / nim

  echo("Found no nim compiler and every attempt to build one failed!")
  quit("FAILURE")

proc thVersion(i: int): string =
  result = ("compiler" / "nim" & $i).exe

proc boot(args: string) =
  var output = "compiler" / "nim".exe
  var finalDest = "bin" / "nim".exe
  # default to use the 'c' command:
  let useCpp = getEnv("NIM_COMPILE_TO_CPP", "false") == "true"
  let smartNimcache = (if "release" in args or "danger" in args: "nimcache/r_" else: "nimcache/d_") &
                      hostOS & "_" & hostCPU

  let nimStart = findStartNim()
  for i in 0..2:
    let defaultCommand = if useCpp: "cpp" else: "c"
    let bootOptions = if args.len == 0 or args.startsWith("-"): defaultCommand else: ""
    echo "iteration: ", i+1
    var extraOption = ""
    var nimi = i.thVersion
    if i == 0:
      nimi = nimStart
      extraOption.add " --skipUserCfg --skipParentCfg"
        # The configs are skipped for bootstrap
        # (1st iteration) to prevent newer flags from breaking bootstrap phase.
      let ret = execCmdEx(nimStart & " --version")
      doAssert ret.exitCode == 0
      let version = ret.output.splitLines[0]
      if version.startsWith "Nim Compiler Version 0.19.0":
        extraOption.add " -d:nimBoostrapCsources0_19_0"
        # remove this when csources get updated

    # in order to use less memory, we split the build into two steps:
    # --compileOnly produces a $project.json file and does not run GCC/Clang.
    # jsonbuild then uses the $project.json file to build the Nim binary.
    exec "$# $# $# $# --nimcache:$# --compileOnly compiler" / "nim.nim" %
      [nimi, bootOptions, extraOption, args, smartNimcache]
    exec "$# jsonscript --nimcache:$# compiler" / "nim.nim" %
      [nimi, smartNimcache]

    if sameFileContent(output, i.thVersion):
      copyExe(output, finalDest)
      echo "executables are equal: SUCCESS!"
      return
    copyExe(output, (i+1).thVersion)
  copyExe(output, finalDest)
  when not defined(windows): echo "[Warning] executables are still not equal"

# -------------- clean --------------------------------------------------------

const
  cleanExt = [
    ".ppu", ".o", ".obj", ".dcu", ".~pas", ".~inc", ".~dsk", ".~dpr",
    ".map", ".tds", ".err", ".bak", ".pyc", ".exe", ".rod", ".pdb", ".idb",
    ".idx", ".ilk"
  ]
  ignore = [
    ".bzrignore", "nim", "nim.exe", "koch", "koch.exe", ".gitignore"
  ]

proc cleanAux(dir: string) =
  for kind, path in walkDir(dir):
    case kind
    of pcFile:
      var (_, name, ext) = splitFile(path)
      if ext == "" or cleanExt.contains(ext):
        if not ignore.contains(name):
          echo "removing: ", path
          removeFile(path)
    of pcDir:
      case splitPath(path).tail
      of "nimcache":
        echo "removing dir: ", path
        removeDir(path)
      of "dist", ".git", "icons": discard
      else: cleanAux(path)
    else: discard

proc removePattern(pattern: string) =
  for f in walkFiles(pattern):
    echo "removing: ", f
    removeFile(f)

proc clean(args: string) =
  removePattern("web/*.html")
  removePattern("doc/*.html")
  cleanAux(getCurrentDir())
  for kind, path in walkDir(getCurrentDir() / "build"):
    if kind == pcDir:
      echo "removing dir: ", path
      removeDir(path)

# -------------- builds a release ---------------------------------------------

proc winReleaseArch(arch: string) =
  doAssert arch in ["32", "64"]
  let cpu = if arch == "32": "i386" else: "amd64"

  template withMingw(path, body) =
    let prevPath = getEnv("PATH")
    putEnv("PATH", (if path.len > 0: path & PathSep else: "") & prevPath)
    try:
      body
    finally:
      putEnv("PATH", prevPath)

  withMingw r"..\mingw" & arch & r"\bin":
    # Rebuilding koch is necessary because it uses its pointer size to
    # determine which mingw link to put in the NSIS installer.
    inFold "winrelease koch":
      nimexec "c --cpu:$# koch" % cpu
    kochExecFold("winrelease boot", "boot -d:release --cpu:$#" % cpu)
    kochExecFold("winrelease zip", "zip -d:release")
    overwriteFile r"build\nim-$#.zip" % VersionAsString,
             r"web\upload\download\nim-$#_x$#.zip" % [VersionAsString, arch]

proc winRelease*() =
  # Now used from "tools/winrelease" and not directly supported by koch
  # anymore!
  # Build -docs file:
  when true:
    inFold "winrelease buildDocs":
      buildDocs(gaCode)
    withDir "web/upload/" & VersionAsString:
      inFold "winrelease zipdocs":
        exec "7z a -tzip docs-$#.zip *.html" % VersionAsString
    overwriteFile "web/upload/$1/docs-$1.zip" % VersionAsString,
                  "web/upload/download/docs-$1.zip" % VersionAsString
  when true:
    inFold "winrelease csource":
      csource("-d:release")
  when sizeof(pointer) == 4:
    winReleaseArch "32"
  when sizeof(pointer) == 8:
    winReleaseArch "64"

# -------------- tests --------------------------------------------------------

template `|`(a, b): string = (if a.len > 0: a else: b)

proc tests(args: string) =
  nimexec "cc --opt:speed testament/tester"
  let tester = quoteShell(getCurrentDir() / "testament/tester".exe)
  let success = tryExec tester & " " & (args|"all")
  if not success:
    quit("tests failed", QuitFailure)

proc temp(args: string) =
  proc splitArgs(a: string): (string, string) =
    # every --options before the command (indicated by starting
    # with not a dash) is part of the bootArgs, the rest is part
    # of the programArgs:
    let args = os.parseCmdLine a
    result = ("", "")
    var i = 0
    while i < args.len and args[i][0] == '-':
      result[0].add " " & quoteShell(args[i])
      inc i
    while i < args.len:
      result[1].add " " & quoteShell(args[i])
      inc i

  let d = getAppDir()
  var output = d / "compiler" / "nim".exe
  var finalDest = d / "bin" / "nim_temp".exe
  # 125 is the magic number to tell git bisect to skip the current commit.
  var (bootArgs, programArgs) = splitArgs(args)
  if "doc" notin programArgs and
      "threads" notin programArgs and
      "js" notin programArgs:
    bootArgs.add " -d:leanCompiler"
  let nimexec = findNim()
  exec(nimexec & " c -d:debug --debugger:native -d:nimBetterRun " & bootArgs & " " & (d / "compiler" / "nim"), 125)
  copyExe(output, finalDest)
  setCurrentDir(origDir)
  if programArgs.len > 0: exec(finalDest & " " & programArgs)

proc xtemp(cmd: string) =
  let d = getAppDir()
  copyExe(d / "bin" / "nim".exe, d / "bin" / "nim_backup".exe)
  try:
    withDir(d):
      temp""
    copyExe(d / "bin" / "nim_temp".exe, d / "bin" / "nim".exe)
    exec(cmd)
  finally:
    copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe)

proc runCI(cmd: string) =
  doAssert cmd.len == 0, cmd # avoid silently ignoring
  echo "runCI:", cmd
  # note(@araq): Do not replace these commands with direct calls (eg boot())
  # as that would weaken our testing efforts.
  when defined(posix): # appveyor (on windows) didn't run this
    kochExecFold("Boot", "boot")
  # boot without -d:nimHasLibFFI to make sure this still works
  kochExecFold("Boot in release mode", "boot -d:release -d:danger")

  ## build nimble early on to enable remainder to depend on it if needed
  kochExecFold("Build Nimble", "nimble")

  when false:
    execFold("nimble install -y libffi", "nimble install -y libffi")
    kochExecFold("boot -d:release -d:nimHasLibFFI", "boot -d:release -d:nimHasLibFFI")

  if getEnv("NIM_TEST_PACKAGES", "false") == "true":
    execFold("Test selected Nimble packages", "nim c -r testament/tester cat nimble-packages")
  else:
    buildTools() # altenatively, kochExec "tools --toolsNoNimble"

    ## run tests
    execFold("Test nimscript", "nim e tests/test_nimscript.nims")
    when defined(windows):
      # note: will be over-written below
      execFold("Compile tester", "nim c -d:nimCoroutines --os:genode -d:posix --compileOnly testament/tester")

    # main bottleneck here
    execFold("Run tester", "nim c -r -d:nimCoroutines testament/tester --pedantic all -d:nimCoroutines")

    execFold("Run nimdoc tests", "nim c -r nimdoc/tester")
    execFold("Run nimpretty tests", "nim c -r nimpretty/tester.nim")
    when defined(posix):
      execFold("Run nimsuggest tests", "nim c -r nimsuggest/tester")

    ## remaining actions
    when defined(posix):
      kochExecFold("Docs", "docs --git.commit:devel")
      kochExecFold("C sources", "csource")
    elif defined(windows):
      when false:
        kochExec "csource"
        kochExec "zip"

proc pushCsources() =
  if not dirExists("../csources/.git"):
    quit "[Error] no csources git repository found"
  csource("-d:release")
  let cwd = getCurrentDir()
  try:
    copyDir("build/c_code", "../csources/c_code")
    copyFile("build/build.sh", "../csources/build.sh")
    copyFile("build/build.bat", "../csources/build.bat")
    copyFile("build/build64.bat", "../csources/build64.bat")
    copyFile("build/makefile", "../csources/makefile")

    setCurrentDir("../csources")
    for kind, path in walkDir("c_code"):
      if kind == pcDir:
        exec("git add " & path / "*.c")
    exec("git commit -am \"updated csources to version " & NimVersion & "\"")
    exec("git push origin master")
    exec("git tag -am \"Version $1\" v$1" % NimVersion)
    exec("git push origin v$1" % NimVersion)
  finally:
    setCurrentDir(cwd)

proc testUnixInstall(cmdLineRest: string) =
  csource("-d:release " & cmdLineRest)
  xz(false, cmdLineRest)
  let oldCurrentDir = getCurrentDir()
  try:
    let destDir = getTempDir()
    copyFile("build/nim-$1.tar.xz" % VersionAsString,
             destDir / "nim-$1.tar.xz" % VersionAsString)
    setCurrentDir(destDir)
    execCleanPath("tar -xJf nim-$1.tar.xz" % VersionAsString)
    setCurrentDir("nim-$1" % VersionAsString)
    execCleanPath("sh build.sh")
    # first test: try if './bin/nim --version' outputs something sane:
    let output = execProcess("./bin/nim --version").splitLines
    if output.len > 0 and output[0].contains(VersionAsString):
      echo "Version check: success"
      execCleanPath("./bin/nim c koch.nim")
      execCleanPath("./koch boot -d:release", destDir / "bin")
      # check the docs build:
      execCleanPath("./koch docs", destDir / "bin")
      # check nimble builds:
      execCleanPath("./koch tools")
      # check the tests work:
      putEnv("NIM_EXE_NOT_IN_PATH", "NOT_IN_PATH")
      execCleanPath("./koch tests --nim:./bin/nim cat megatest", destDir / "bin")
    else:
      echo "Version check: failure"
  finally:
    setCurrentDir oldCurrentDir

proc valgrind(cmd: string) =
  # somewhat hacky: '=' sign means "pass to valgrind" else "pass to Nim"
  let args = parseCmdLine(cmd)
  var nimcmd = ""
  var valcmd = ""
  for i, a in args:
    if i == args.len-1:
      # last element is the filename:
      valcmd.add ' '
      valcmd.add changeFileExt(a, ExeExt)
      nimcmd.add ' '
      nimcmd.add a
    elif '=' in a:
      valcmd.add ' '
      valcmd.add a
    else:
      nimcmd.add ' '
      nimcmd.add a
  exec("nim c" & nimcmd)
  let supp = getAppDir() / "tools" / "nimgrind.supp"
  exec("valgrind --suppressions=" & supp & valcmd)

proc showHelp() =
  quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
                   CompileDate, CompileTime], QuitSuccess)

when isMainModule:
  var op = initOptParser()
  var latest = false
  while true:
    op.next()
    case op.kind
    of cmdLongOption, cmdShortOption:
      case normalize(op.key)
      of "latest": latest = true
      of "stable": latest = false
      else: showHelp()
    of cmdArgument:
      case normalize(op.key)
      of "boot": boot(op.cmdLineRest)
      of "clean": clean(op.cmdLineRest)
      of "doc", "docs": buildDocs(op.cmdLineRest)
      of "doc0", "docs0":
        # undocumented command for Araq-the-merciful:
        buildDocs(op.cmdLineRest & gaCode)
      of "pdf": buildPdfDoc(op.cmdLineRest, "doc/pdf")
      of "csource", "csources": csource(op.cmdLineRest)
      of "zip": zip(latest, op.cmdLineRest)
      of "xz": xz(latest, op.cmdLineRest)
      of "nsis": nsis(latest, op.cmdLineRest)
      of "geninstall": geninstall(op.cmdLineRest)
      of "distrohelper": geninstall()
      of "install": install(op.cmdLineRest)
      of "testinstall": testUnixInstall(op.cmdLineRest)
      of "runci": runCI(op.cmdLineRest)
      of "test", "tests": tests(op.cmdLineRest)
      of "temp": temp(op.cmdLineRest)
      of "xtemp": xtemp(op.cmdLineRest)
      of "wintools": bundleWinTools(op.cmdLineRest)
      of "nimble": buildNimble(latest, op.cmdLineRest)
      of "nimsuggest": bundleNimsuggest(op.cmdLineRest)
      of "toolsnonimble":
        buildTools(op.cmdLineRest)
      of "tools":
        buildTools(op.cmdLineRest)
        buildNimble(latest, op.cmdLineRest)
      of "pushcsource", "pushcsources": pushCsources()
      of "valgrind": valgrind(op.cmdLineRest)
      of "c2nim": bundleC2nim(op.cmdLineRest)
      else: showHelp()
      break
    of cmdEnd: break