rust-diagnostics 0.1.13

A utility that embeds clippy diagnostics into Rust code.
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
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
% Using Base grammar for Rust
include "rust.grm" % Note: different from the innersource rust grammar

define func_return_entry
 [stringlit] '-> [id]
end define

define var_type_entry
  [id] '-> [id]
end define

% Main translation rule to match Rust programs
function main
    export FuncReturnMap [repeat func_return_entry]  
    % TODO: this can be extended with predefined funcs/user defined funcs
      "file_stem" -> 'Some
      "std :: str :: from_utf8" -> 'Ok
      ".parent" -> 'Some
      ".ok" -> 'Ok
      "fs :: read_to_string" -> 'Ok
      "read_to_string" -> 'Ok
      "spawn" -> 'Ok
      "wait_with_output" -> 'Ok
      "wait" -> 'Ok
      "parse_query" -> 'Ok
      "try_from" -> 'Ok
      "from_utf8"  -> 'Ok
      "take" -> 'Some
      ".get" -> 'Some
      "splitup" -> 'Ok
      "file_stem" -> 'Some      
      ".lock" -> 'Some
      ".last" -> 'Some
      ".next" -> 'Some
    export TempVarNo [number]
      0
    export VarTypeTable [repeat var_type_entry]
      _
    export ArithInconsistentVars [repeat id]
      _
    % export UseWrappingTag [id]
    %  'no
    replace [program] 
	    RustProgram [program]
    construct Message [id]
		  _ [message "Congratulations, matched it successfully!"]
    by
	    RustProgram 
          [fixUnwrapUsedOnLetStmt1] % TEST: let _foo = read_to_string("address.txt").unwrap();
          [fixUnwrapUsedOnLetStmt2] % TEST: let source = read_to_string(file).ok().unwrap();
          [fixUnwrapUsedOnLetStmt3] % unwrap is in between and belong to Infix_Postfix_Expressions*
          % [fixUnwrapUsedOnLetStmt3] 
          [fixUnwrapUsedOnExprStmt1]
          [fixUnwrapUsedOnExprStmt2]
          [fixUnwrapUsedOnExprStmt3]
          [fixUnwrapUsedOnTokenTree] % 处理unwrap在token tree中 let file_name = path
                                     % .join(format!("{}.rs.1",path.file_stem().unwrap().to_string_lossy()));
          % 需要统计unwrap used cases (i.e., stmt) in idiomatic projects, 
          % So that we mainly fix in this selected cases with most occurrences (since unwrap can occur everywhere)
          [fixExhaustiveStruct]
          [fixAsConversion]
          
          %[fixIntArithmetic]拆成下面三个
          [collectVarDefinedType]
          [collectTypeInconsistentArithmetic]
          [importWrapping] 
          [modifyVarDefInWrapping] % modify var type in Wrapping
end function

rule fixUnwrapUsedOnLetStmt1
  import FuncReturnMap [repeat func_return_entry]
  replace $ [repeat Statement]
    Stmt [Statement] Stmts [repeat Statement]
  deconstruct Stmt
    LetStmt [LetStatement]
  deconstruct not Stmt % ensure will only closes siblings
    _ [Expression] 
  deconstruct LetStmt
    OuterAttr [OuterAttribute*] 'let Pat [Pattern] ColonType [COLON_Type?] '= RightExpr [Expression] ';

  % whether unwrap is in the end
  deconstruct RightExpr
    PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] 
    InPoExprs [Infix_Postfix_Expressions*]
  construct InPoExprsLength [number]
    _ [length InPoExprs]
  construct LastFuncStartIndex [number]
    InPoExprsLength [- 1]
  construct LastFuncEndIndex [number]
    InPoExprsLength [- 1]

  construct LastFuncName [Infix_Postfix_Expressions*]
    InPoExprs [select LastFuncStartIndex LastFuncEndIndex]
  construct LastFuncStr [stringlit]
	  _ [quote LastFuncName]
  where
    LastFuncStr [= ".unwrap"] 
  where
    InPoExprsLength [= 3] % ("address.txt") .unwrap ()

  deconstruct RightExpr
    _ [Prefix_Expressions*] _ [ExpressionWithOrWithoutBlock]  % ExprWOWB is fs :: read_to_string
    '( OptionalParams [CallParams?] ') '.
    'unwrap() 
  construct CloselyPreFunc [stringlit]
	  _ [quote ExprWOWB]
  deconstruct * [func_return_entry] FuncReturnMap
    CloselyPreFunc -> EnclosePat [id]

  construct IfLetExprBlock [ExpressionStatement]
    'if 'let EnclosePat '( Pat ') '= PrefixExpr ExprWOWB '( OptionalParams ')
    '{
    Stmts
    '}
  by 
    IfLetExprBlock
end rule

rule fixUnwrapUsedOnLetStmt2
  import FuncReturnMap [repeat func_return_entry]
  replace $ [repeat Statement]
    Stmt [Statement] Stmts [repeat Statement]
  deconstruct Stmt
    LetStmt [LetStatement]
  deconstruct not Stmt % ensure will only closes siblings
    _ [Expression] 
  deconstruct LetStmt
    OuterAttr [OuterAttribute*] 'let Pat [Pattern] ColonType [COLON_Type?] '= RightExpr [Expression] ';
  
   % whether unwrap is in the end
  deconstruct RightExpr
    PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] 
    InPoExprs [Infix_Postfix_Expressions*]
  construct InPoExprsLength [number]
    _ [length InPoExprs]
  construct LastFuncStartIndex [number]
    InPoExprsLength [- 1]
  construct LastFuncEndIndex [number]
    InPoExprsLength [- 1]

  construct LastFuncName [Infix_Postfix_Expressions*]
    InPoExprs [select LastFuncStartIndex LastFuncEndIndex]
  construct LastFuncStr [stringlit]
	  _ [quote LastFuncName]
  where
    LastFuncStr [= ".unwrap"] 
  where not
    InPoExprsLength [= 3] % .ok() .unwrap ()

  construct PreFuncStartIndex [number]
    InPoExprsLength [- 3]
  construct PreFuncEndIndex [number]
    InPoExprsLength [- 3]

  construct CloseFuncName [Infix_Postfix_Expressions*]
    InPoExprs [select PreFuncStartIndex PreFuncEndIndex]

  construct CloselyPreFunc [stringlit]
	  _ [quote CloseFuncName]
  
  deconstruct * [func_return_entry] FuncReturnMap
    CloselyPreFunc -> EnclosePat [id]

  construct Until [number]
    InPoExprsLength [- 2] %.ok
  construct removelastPara [Infix_Postfix_Expressions*]
    InPoExprs [head Until]

  construct IfLetExprBlock [ExpressionStatement]
    'if 'let  EnclosePat '( Pat ') '= PrefixExpr ExprWOWB removelastPara
    '{
    Stmts
    '}
  by 
    IfLetExprBlock
end rule

rule fixUnwrapUsedOnLetStmt3
  import FuncReturnMap [repeat func_return_entry]
  replace $ [repeat Statement]
    Stmt [Statement] Stmts [repeat Statement]
  deconstruct Stmt
    LetStmt [LetStatement]
  deconstruct not Stmt % ensure will only closes siblings
    _ [Expression] 
  deconstruct LetStmt
    OuterAttr [OuterAttribute*] 'let Pat [Pattern] ColonType [COLON_Type?] '= RightExpr [Expression] ';

  % whether contains unwrap
  deconstruct * [PathExprSegment] RightExpr
    'unwrap Colon [COLON_COLON_GenericArgs?]
  
  % unwrap is not in the end
  deconstruct RightExpr
    PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] 
    InPoExprs [Infix_Postfix_Expressions*]
  construct InPoExprsLength [number]
    _ [length InPoExprs]
  construct LastFuncStartIndex [number]
    InPoExprsLength [- 1]
  construct LastFuncEndIndex [number]
    InPoExprsLength [- 1]

  construct LastFuncName [Infix_Postfix_Expressions*]
    InPoExprs [select LastFuncStartIndex LastFuncEndIndex]
  construct LastFuncStr [stringlit]
	  _ [quote LastFuncName]
  where not
    LastFuncStr [= ".unwrap"] 

  export IncreIndex [number]
    0

  construct UnwrapIndexes [repeat number]
	  _ [checkUnwrapIndex1 each InPoExprs]  % TODO: 这里是unwrap 在第三个repeat里

  %construct Message [id]
  %  _ [message UnwrapIndexes]

  deconstruct UnwrapIndexes
    II [number] III [number*]
  construct preII [number]
    II [- 1]
  construct postII [number]
    II [+ 2]
  construct LeftSlices [Infix_Postfix_Expressions*]
    InPoExprs [head preII]
  
  construct rightSlices [Infix_Postfix_Expressions*]
    InPoExprs [tail postII]
  
  export IncreIndex 
    0
  
  construct TempStr [id]
	  _ [quote 't_] [quote Pat]

  construct IPreFuncIndex [number]
    II [- 2]
  construct IPreFunc [Infix_Postfix_Expressions*]
    InPoExprs [select IPreFuncIndex IPreFuncIndex]
  deconstruct IPreFunc
    CloselyPreFuncName [Infix_Postfix_Expressions] _ [Infix_Postfix_Expressions*]

  %construct Message1 [id]
  % _ [message CloselyPreFuncName]

  construct CloselyPreFunc [stringlit]
	  _ [quote CloselyPreFuncName]
  deconstruct * [func_return_entry] FuncReturnMap
    CloselyPreFunc -> EnclosePat [id]
  
  by  
    'if 'let EnclosePat '( TempStr ') = PrefixExpr ExprWOWB LeftSlices
    '{
      'let Pat '= TempStr rightSlices ';
      %'let nihao '= '2 ';
    Stmts
    '}
end rule

function checkUnwrapIndex1 InPoExpr [Infix_Postfix_Expressions]
  import IncreIndex [number]
  export IncreIndex
    IncreIndex [+ 1]
  deconstruct InPoExpr
    '.unwrap
  replace [repeat number]
    Indexes [repeat number]
  by
    Indexes [. IncreIndex]
end function

function checkUnwrapIndex2 TokenTree [TokenTree]
  import IncreIndex [number]
  export IncreIndex
    IncreIndex [+ 1]
  deconstruct TokenTree
    'unwrap
  replace [repeat number]
    Indexes [repeat number]
  by
    Indexes [. IncreIndex]
end function

rule fixUnwrapUsedOnExprStmt1
  import FuncReturnMap [repeat func_return_entry]
  import TempVarNo [number]
  export TempVarNo
    TempVarNo [+ 1]
  replace $ [repeat Statement]
    Stmt [Statement] Stmts [repeat Statement]
  deconstruct Stmt
    ExprStmt [ExpressionStatement]
  
  deconstruct not Stmt % ensure will only closes siblings
    _ [Expression] 
  
  %Find smallest expr containing unwrap and unwrap is in the end
  deconstruct * [Expression] ExprStmt
    PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] 
    InPoExpr1 [Infix_Postfix_Expressions] '.unwrap  _ [Infix_Postfix_Expressions]
    %InPoExprs [Infix_Postfix_Expressions*]
  
  %(construct InPoExprsStr [stringlit]
    _ [quote InPoExprs]
  construct InPoExprsStrLength [number]
    _ [# InPoExprsStr]
  construct InPoExprsStrLastStartIndex [number]
    InPoExprsStrLength [- 10]
  construct InPoExprsLastStr [stringlit]
    InPoExprsStr [: InPoExprsStrLastStartIndex InPoExprsStrLength]
  where 
    InPoExprsStr [= ".unwrap ()"])%
  
  %check tail is .unwrap

  construct UnwrapBigPartStr [stringlit]
    _ [unparse ExprWOWB] [+ " "] [unparse InPoExpr1] [+ ".unwrap ()"]

  %find unwrap occurs
  construct ExprStmtStr [stringlit]
    _ [unparse ExprStmt]

  construct UnwrapBigPartIndex [number] 
    _ [index ExprStmtStr UnwrapBigPartStr]

  %construct Message [id]
  %  _ [message UnwrapBigPartIndex]
  deconstruct not UnwrapBigPartIndex
    0
  construct LeftEndIndex [number]
    UnwrapBigPartIndex [- 1]
  construct leftPart [stringlit]
    ExprStmtStr [: 1 LeftEndIndex]
  
  construct ExprStmtStrLength [number]
    _ [# ExprStmtStr] 

  construct IfLetPosStr [stringlit]
    _ [unparse ExprWOWB] [+ " "] [unparse InPoExpr1]
  construct IfLetPos [id]
    _ [+ IfLetPosStr]

  construct UnwrapBigPartStrLength [number]
    _ [# UnwrapBigPartStr]

  construct RightStartIndex [number]
    UnwrapBigPartIndex [+ UnwrapBigPartStrLength] 
  construct rightPart [stringlit]
    ExprStmtStr [: RightStartIndex ExprStmtStrLength]
  
  construct TempVarStr [id]
	  _ [quote 't_] [quote TempVarNo]

  construct NewExprStmt [stringlit]
    _ [+ leftPart] [quote 't_] [quote TempVarNo] [+ rightPart]

  construct NewExpr [id]
    _ [+ NewExprStmt]
  
  construct CloselyPreFunc [stringlit]
	  _ [quote ExprWOWB]
  deconstruct * [func_return_entry] FuncReturnMap
    CloselyPreFunc -> EnclosePat [id]
  export TempVarNo
    TempVarNo [+ 1]
  by
    'if 'let EnclosePat '( TempVarStr ') '= IfLetPos
    '{
      NewExpr
      Stmts
    '}
end rule
%unwrap occurs in which part

rule fixUnwrapUsedOnExprStmt2
  import FuncReturnMap [repeat func_return_entry]
  import TempVarNo [number]
  export TempVarNo
    TempVarNo [+ 1]
  replace $ [repeat Statement]
    Stmt [Statement] Stmts [repeat Statement]
  deconstruct Stmt
    ExprStmt [ExpressionStatement]
  deconstruct not Stmt % ensure will only closes siblings
    _ [Expression] 
  
  %Find smallest expr containing unwrap and unwrap is in the end
  deconstruct * [Expression] ExprStmt
    PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] 
    InPoExprs1 [Infix_Postfix_Expressions] InPoExprs2 [Infix_Postfix_Expressions] '.unwrap  _ [Infix_Postfix_Expressions]

  construct UnwrapBigPartStr [stringlit]
    _ [unparse PrefixExpr] [+ " "] [unparse ExprWOWB] [unparse InPoExprs1] [+ " "] [unparse InPoExprs2] [+ ".unwrap ()"]

  %find unwrap occurs
  construct ExprStmtStr [stringlit]
    _ [unparse ExprStmt]

  construct UnwrapBigPartIndex [number] 
    _ [index ExprStmtStr UnwrapBigPartStr]

  %construct Message [id]
  %  _ [message UnwrapBigPartIndex]

  deconstruct not UnwrapBigPartIndex
    0
  construct LeftEndIndex [number]
    UnwrapBigPartIndex [- 1]
  construct leftPart [stringlit]
    ExprStmtStr [: 1 LeftEndIndex]
  
  construct ExprStmtStrLength [number]
    _ [# ExprStmtStr] 

  construct IfLetPosStr [stringlit]
    _ [unparse PrefixExpr] [unparse ExprWOWB] [unparse InPoExprs1] [unparse InPoExprs2]
  construct IfLetPos [id]
    _ [+ IfLetPosStr]

  construct UnwrapBigPartStrLength [number]
    _ [# UnwrapBigPartStr]

  construct RightStartIndex [number]
    UnwrapBigPartIndex [+ UnwrapBigPartStrLength] 
  construct rightPart [stringlit]
    ExprStmtStr [: RightStartIndex ExprStmtStrLength]
  
  construct TempVarStr [id]
	  _ [quote 't_] [quote TempVarNo]

  construct NewExprStmt [stringlit]
    _ [+ leftPart] [quote 't_] [quote TempVarNo] [+ rightPart]

  construct NewExpr [id]
    _ [+ NewExprStmt]
  
  construct CloselyPreFunc [stringlit]
	  _ [quote InPoExprs1]
  deconstruct * [func_return_entry] FuncReturnMap
    CloselyPreFunc -> EnclosePat [id]
  export TempVarNo
    TempVarNo [+ 1]
  by
    'if 'let EnclosePat '( TempVarStr ') '= IfLetPos
    '{
      NewExpr
      Stmts
    '}
end rule

rule fixUnwrapUsedOnExprStmt3 % 当前先只处理ifExpression, 其他含{}的expression可修改此规则
  import FuncReturnMap [repeat func_return_entry]
  import TempVarNo [number]
  export TempVarNo
    TempVarNo [+ 1]
  replace $ [repeat Statement]
    IfExprStmt [IfExpression] Stmts [repeat Statement]
  deconstruct IfExprStmt
    'if ExcptExpr[ExpressionExceptStructExpression] BlockExpr [BlockExpression] ElseExpr [ElseExpression?]
  deconstruct ExcptExpr
    PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] 
    InPoExprs [Infix_Postfix_Expressions*]

  export IncreIndex [number]
    0
  
  construct UnwrapIndexes [repeat number]
	  _ [checkUnwrapIndex1 each InPoExprs]

  deconstruct UnwrapIndexes
    II [number] III [number*]
  construct preII [number]
    II [- 1]
  construct postII [number]
    II [+ 2]
  construct LeftSlices [Infix_Postfix_Expressions*]
    InPoExprs [head preII]
  
  construct rightSlices [Infix_Postfix_Expressions*]
    InPoExprs [tail postII]

  export IncreIndex 
    0
  construct IPreFuncIndex [number]
    II [- 2]
  construct IPreFunc [Infix_Postfix_Expressions*]
    InPoExprs [select IPreFuncIndex IPreFuncIndex]
  deconstruct IPreFunc
    CloselyPreFuncName [Infix_Postfix_Expressions] _ [Infix_Postfix_Expressions*]

  %construct Message1 [id]
  % _ [message CloselyPreFuncName]

  construct CloselyPreFunc [stringlit]
	  _ [quote CloselyPreFuncName]
  deconstruct * [func_return_entry] FuncReturnMap
    CloselyPreFunc -> EnclosePat [id]

  construct TempVarStr [id]
	  _ [quote 't_] [quote TempVarNo]

  export TempVarNo
    TempVarNo [+ 1]

  by  
    'if 'let EnclosePat '( TempVarStr ') = PrefixExpr ExprWOWB LeftSlices
    '{
      'if TempVarStr rightSlices BlockExpr ElseExpr
      Stmts
    '}

end rule

rule fixUnwrapUsedOnTokenTree %find the most closed pre comma
  % check in let expression
  import FuncReturnMap [repeat func_return_entry]
  import TempVarNo [number]
  export TempVarNo
    TempVarNo [+ 1]
  replace $ [repeat Statement]
    Stmt [Statement] Stmts [repeat Statement]
  deconstruct Stmt
    LetStmt [LetStatement]
  deconstruct not Stmt % ensure will only closes siblings
    _ [Expression] 
  deconstruct LetStmt
    OuterAttr [OuterAttribute*] 'let Pat [Pattern] ColonType [COLON_Type?] '= RightExpr [Expression] ';

   % whether contains unwrap
  deconstruct * [token_or_key] RightExpr
    'unwrap

  construct RightExprStr [stringlit]
    _ [unparse RightExpr]
  construct UnwrapStartIndex [number] 
    _ [index RightExprStr ".unwrap ()"]
  deconstruct not UnwrapStartIndex
    0
  construct UnwrapRightStartIndex [number] 
    UnwrapStartIndex [+ 10]
  construct CommaStartIndex [number] 
    _ [index RightExprStr ","]  % string between comma and unwrap will be put in if let expr
  deconstruct not CommaStartIndex
    0

  deconstruct * [TokenTree*] RightExpr
    TTs [TokenTree*]

  export IncreIndex [number]
    0
  construct UnwrapIndexes [repeat number]
	  _ [checkUnwrapIndex2 each TTs] 

  deconstruct UnwrapIndexes
    II [number] III [number*]

  export IncreIndex 
    0

  construct IPreFuncIndex [number]
    II [- 3]
  construct IPreFunc [TokenTree*]
    TTs [select IPreFuncIndex IPreFuncIndex]
  deconstruct IPreFunc
    CloselyPreFuncName [TokenTree] _ [TokenTree*]
  
  construct CloselyPreFunc [stringlit]
	  _ [quote CloselyPreFuncName]
  deconstruct * [func_return_entry] FuncReturnMap
    CloselyPreFunc -> EnclosePat [id]

  construct TempVarStr [stringlit]
	  _ [quote 't_] [quote TempVarNo]
  construct TempVarId [id]
	  _ [+ TempVarStr]

  construct leftSlices [stringlit]
    RightExprStr [: 1 CommaStartIndex]
  construct RightExprLength [number]
    _ [# RightExprStr]
  construct rightSlices [stringlit]
    RightExprStr [: UnwrapRightStartIndex RightExprLength]

  construct auxiliaryNum1 [number]
    CommaStartIndex [+ 2]
  construct auxiliaryNum2 [number]
    UnwrapRightStartIndex [- 11]
  construct RightExprStrInIfLet [stringlit]
    RightExprStr [: auxiliaryNum1 auxiliaryNum2]
  construct RightExprInIfLet [id]
    _ [+ RightExprStrInIfLet]

  construct NewRightStr [stringlit]
    leftSlices [+ TempVarStr] [+ rightSlices]
  construct NewRight [id]
    _ [+ NewRightStr]
  export TempVarNo
    TempVarNo [+ 1]
  by
    'if 'let EnclosePat '( TempVarId ') = RightExprInIfLet
    '{
      'let Pat = NewRight ;
      Stmts
    '}
end rule

rule fixExhaustiveStruct
  replace $ [Item]
    OuterAttr [OuterAttribute*] VisOrMacroItem [VisItem_or_MacroItem]
  deconstruct VisOrMacroItem
    'pub _ [Struct]
  deconstruct not OuterAttr
    '# '[ 'non_exhaustive ']
  construct NewOuterAttr [OuterAttribute]
    '# '[ 'non_exhaustive ']
  by
    NewOuterAttr
    OuterAttr
    VisOrMacroItem 
end rule

rule fixAsConversion
  import TempVarNo [number]
  export TempVarNo
    TempVarNo [+ 1]
  replace $ [repeat Statement]
    Stmt [Statement] Stmts [repeat Statement]
  deconstruct not Stmt % ensure will only closes siblings
    _ [Expression]
  
  construct AllExprs [repeat Expression]
    _ [^ Stmt]  % 最后一个Expression must be the closest and innermost one
  construct NumberOfExprs [number]
    _ [length AllExprs]
  construct LastExprRepeat [repeat Expression]
    AllExprs [tail NumberOfExprs] 
  deconstruct LastExprRepeat
    LastExpr [Expression] _ [repeat Expression]
  
  %find substring containing as
  construct LastExprStr [stringlit]
     _ [quote LastExpr]
  construct AsStartIndex [number] 
    _ [index LastExprStr "as"]  % string between comma and unwrap will be put in if let expr
  deconstruct not AsStartIndex
    0  % We find this as expression

  construct AsSubLeftStrEndIndex [number]
    AsStartIndex [- 2]
  construct AsSubLeftstr [stringlit]
    LastExprStr [: 1 AsSubLeftStrEndIndex]
  construct AsSubLeftId [id]
	  _ [+ AsSubLeftstr]
  construct AsSubRightStrStartIndex [number]
    AsStartIndex [+ 3]
   construct LastExprStrLength [number]
    _ [# LastExprStr]
  construct AsSubRightstr [stringlit]
    LastExprStr [: AsSubRightStrStartIndex LastExprStrLength]
  construct AsSubRightId [id]
	  _ [+ AsSubRightstr]

  construct StmtStr [stringlit]
    _ [quote Stmt]
  construct AsExprStartIndex [number]
    _ [index StmtStr LastExprStr]
  deconstruct not AsExprStartIndex
    0

  construct AsExprLeftStrIndex [number]
    AsExprStartIndex [- 1]
  construct AsExprLeftStr [stringlit]
    StmtStr [: 1 AsExprLeftStrIndex] 
  
  construct AsRightExprStrStartIndex [number]
    AsExprStartIndex [+ LastExprStrLength]
  construct StmtStrLength [number]
    _ [# StmtStr]
  construct AsExprRightstr [stringlit]
    StmtStr [: AsRightExprStrStartIndex StmtStrLength]

  construct TempVarStr [stringlit]
	  _ [quote 't_] [quote TempVarNo]
  construct TempVarId [id]
	  _ [+ TempVarStr]

  construct NewStmtStr [stringlit]
    _ [+ AsExprLeftStr] [+ TempVarStr] [+ AsExprRightstr]

  construct NewStmtId [id]
    _ [+ NewStmtStr]
  
  export TempVarNo
    TempVarNo [+ 1]

  by
    'if 'let 'Ok '( TempVarId ') = AsSubRightId ':: 'try_from '( AsSubLeftId ') 
    '{
      NewStmtId
      Stmts
    '}
end rule

rule collectVarDefinedType
  import VarTypeTable [repeat var_type_entry]
  replace $ [LetStatement]
    LetStmt [LetStatement]
  deconstruct LetStmt
    _ [OuterAttribute*] 'let Pat [id] ColonType [COLON_Type?] '= RightExpr [Expression] ';
  deconstruct ColonType
    ': TypeId [id] 
  construct VarTypeEntry [var_type_entry]
    Pat -> TypeId
  export VarTypeTable
    VarTypeTable [. VarTypeEntry]
  %construct Message [id]
  %  _ [message VarTypeTable]
  by
    LetStmt
end rule

rule collectTypeInconsistentArithmetic %dispose a+b, don't touch a+b+b
  import VarTypeTable [repeat var_type_entry]
  replace $ [Expression]
    PreExpr [Prefix_Expressions*] LeftVar [id] ArithExpr [Infix_ArithmeticOrLogicalExpression]
  where
     ArithExpr [_isAddOp] [_isMinusOp] [_isMultiplyOp] [isDivideOp] [isModOp]
  import RightVar [id]
  
  deconstruct * [var_type_entry] VarTypeTable
     LeftVar -> LeftVarType [id]
  deconstruct * [var_type_entry] VarTypeTable
     RightVar -> RightVarType [id]
  %construct Message [id]
  %  _ [message LeftVarType]
  where LeftVarType [~= RightVarType]

  import ArithInconsistentVars [repeat id]
  export ArithInconsistentVars
    ArithInconsistentVars [. LeftVar] [. RightVar]
  %construct Message [id]
  %  _ [message ArithInconsistentVars]
  by 
    PreExpr LeftVar ArithExpr
end rule 

rule importWrapping
  import ArithInconsistentVars [repeat id]
  replace $ [Crate]
    Items [Item*]
  construct Length [number]
    _ [length ArithInconsistentVars]
  where 
    Length [> 0]
  by 
    'use  'std::num::Wrapping;
    Items
end rule

rule modifyVarDefInWrapping
  import ArithInconsistentVars [repeat id]
  replace $ [LetStatement]
    LetStmt [LetStatement]
  deconstruct LetStmt
    OuterAttrs [OuterAttribute*] 'let Pat [id] ColonType [COLON_Type?] '= RightExpr [Expression] ';

  %check pat is in ArithInconsistentVars
  deconstruct * [id] ArithInconsistentVars
    Pat
    
  by
    OuterAttrs 'let Pat '= 'Wrapping '( RightExpr  ') ';
end rule

function _isAddOp
    match [Infix_ArithmeticOrLogicalExpression]
      '+  RightVar [id]
    export RightVar
end function

function _isMinusOp
    match [Infix_ArithmeticOrLogicalExpression]
      '-  RightVar [id]
    export RightVar
end function

function _isMultiplyOp
    match [Infix_ArithmeticOrLogicalExpression]
      '*  RightVar [id]
    export RightVar
end function

function isDivideOp
    match [Infix_ArithmeticOrLogicalExpression]
      '/  RightVar [id]
    export RightVar
end function

function isModOp
    match [Infix_ArithmeticOrLogicalExpression]
      '%  RightVar [id]
    export RightVar
end function




% 可用as conversion's idea rewrite the transformations for unwraps

% rule 会在每次子树替换后自动搜索整个新树