-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathMicro_Rust_Shallow_Embedding.thy
More file actions
1599 lines (1453 loc) · 84 KB
/
Copy pathMicro_Rust_Shallow_Embedding.thy
File metadata and controls
1599 lines (1453 loc) · 84 KB
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
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT *)
(*<*)
theory Micro_Rust_Shallow_Embedding
imports
Micro_Rust_Parsing_Frontend.Micro_Rust_Syntax
Core_Syntax
Micro_Rust_Notations
Prompts_And_Responses
"HOL-Library.Datatype_Records"
Autogen.Autogen
Lenses_And_Other_Optics.Lenses_And_Other_Optics
Tuple
keywords
"micro_rust_record" :: thy_decl
begin
(*>*)
section\<open>The shallow embedding of uRust into HOL\<close>
text\<open>In this section we define the shallow embedding of uRust into HOL as
a syntax transformations \<^text>\<open>urust \<Rightarrow> logic\<close> from the syntactic category of Micro Rust programs
to the category of HOL terms.\<close>
subsection\<open>Custom identifiers and identifier remapping\<close>
text\<open>The in-built syntax category \<^verbatim>\<open>id\<close> of HOL identifiers does not encompass qualified
Rust names such as \<^verbatim>\<open>Foo::Bar\<close>. The path-flattening AST translation in
\<^file>\<open>../Micro_Rust_Parsing_Frontend/Micro_Rust_Syntax.thy\<close> turns such paths into
\<^verbatim>\<open>_urust_identifier_id\<close> nodes whose payload is a plain \<^verbatim>\<open>Ast.Variable\<close> carrying
the joined name (e.g. \<^verbatim>\<open>"Foo::Bar"\<close>); downstream consumers therefore see no
structural difference between path and plain identifiers --- only the name
string contains \<^verbatim>\<open>::\<close>.
For general \<^verbatim>\<open>id\<close>s, we introduce an intermediate \<^verbatim>\<open>_urust_identifier_id_const\<close>. This allows us
to register Micro-Rust-to-HOL name changes for those identifiers which \<^emph>\<open>do\<close> fall
under the \<^verbatim>\<open>id\<close> syntax category.\<close>
syntax
"_urust_identifier_id_const" :: \<open>id \<Rightarrow> logic\<close> ("URUST'_CONST _")
parse_ast_translation\<open>
let
fun urust_const_ast_tr _ [Ast.Variable c] = Ast.Appl [Ast.Constant "_urust_identifier_id", Ast.Constant c]
| urust_const_ast_tr _ asts = raise Ast.AST ("urust_const_ast_tr", asts)
in
[(\<^syntax_const>\<open>_urust_identifier_id_const\<close>, urust_const_ast_tr)]
end
\<close>
\<comment>\<open>Path-style uRust names (\<^verbatim>\<open>Foo::Bar\<close>) and plain identifiers both reach
\<open>lookup_id_tr\<close> (the \<open>parse_translation\<close> on \<open>_shallow_identifier_as_*\<close>)
as the same \<^verbatim>\<open>Free name\<close> shape; resolution proceeds via the
\<^ML_structure>\<open>Micro_Rust_Names\<close> table, populated by the
\<^theory_text>\<open>micro_rust_notation\<close> command in
\<^theory>\<open>Shallow_Micro_Rust.Micro_Rust_Notations\<close>.\<close>
named_theorems micro_rust_record_simps
named_theorems micro_rust_record_intros
ML\<open>
fun number_of_type_arguments ctxt (tyname : string) =
tyname
|> Proof_Context.read_type_name {proper = true, strict = false} ctxt
|> Term.dest_Type
|> snd
|> List.length
fun repeat (_ : 'a) 0 : 'a list = []
| repeat (x : 'a) n : 'a list = x :: repeat x (n-1)
fun generic_type_arguments ctxt tyname =
tyname
|> number_of_type_arguments ctxt
|> repeat "type"
(* Mimicking "instance {rec_name} :: (type, type, ...) localizable .." *)
fun instantiate_localizable_class rec_name (ctxt : Proof.context) =
let val typeargs = generic_type_arguments ctxt rec_name
val full_tyname = Proof_Context.read_type_name {proper = true, strict = false} ctxt rec_name
|> Term.dest_Type |> fst
in
((Class.instance_arity_cmd ([full_tyname], typeargs, @{class localizable})
#> Proof.global_default_proof
#> Proof_Context.theory_of)
|> Local_Theory.background_theory) ctxt
end
\<close>
ML\<open>
\<comment>\<open>Register an auto-generated field lens as \<^verbatim>\<open>micro_rust_notation (field)\<close>
under its uRust name, via the command's \<open>do_register\<close>. By default the
uRust name is the bare (record-prefixed) HOL field name; the optional
\<^verbatim>\<open>(hol_field = "urust_name", \<dots>)\<close> mapping passed to \<^verbatim>\<open>micro_rust_record\<close>
overrides this per field — useful because HOL field names are usually
disambiguated with a record-name prefix that one does not want to repeat
at every uRust use site. The uRust name is a plain identifier
(grammatical, so no bespoke grammar production is emitted) and the lens
has type \<open>_ lens\<close> (so the forced \<open>field\<close> kind validates against the
term's type).\<close>
fun register_lens_with_micro_rust rec_name overrides field lthy =
let val name = lens_name rec_name field
val full_name = Local_Theory.full_name lthy (Binding.name name)
val (rust_name, rust_pos) =
case AList.lookup (op =) overrides field of
SOME name_and_pos => name_and_pos
| NONE => (field, Position.thread_data ())
in
Micro_Rust_Notation_Cmd.do_register (SOME Micro_Rust_Names.NField)
(full_name, (rust_name, rust_pos)) lthy
end
\<comment>\<open>Reject a uRust-name mapping whose left-hand sides are not all fields of
the record: an unmatched entry is silently dropped otherwise, masking a
typo in the field name.\<close>
fun check_override_fields rec_name fields overrides =
let val unknown = filter_out (member (op =) fields) (map fst overrides) in
if null unknown then ()
else error ("micro_rust_record: unknown field(s) in uRust-name mapping: "
^ commas_quote unknown ^ "\nRecord " ^ quote rec_name
^ " has fields: " ^ commas_quote fields)
end
fun register_lenses_with_micro_rust rec_name overrides thy =
let val fields = get_fields rec_name thy in
fold (register_lens_with_micro_rust rec_name overrides) fields thy
end
\<comment>\<open>Pretty-print, as a bullet list, the definitions and theorems
\<^verbatim>\<open>micro_rust_record\<close> emits for a record (one bullet per artifact), so the
(otherwise opaque) autogen output is replaced by the concrete names a user
can reference. The trailing bullets record the uRust field-access names
(\<open>urust_name \<mapsto> hol_field\<close>, collapsing to the bare field where no override
applies) and the localizable class instance.\<close>
fun summarise_micro_rust_record rec_name fields overrides with_fields =
let fun urust_of f =
case AList.lookup (op =) overrides f of
SOME (rust_name, _) => rust_name
| NONE => f
fun field_facts f =
let val base = rec_name ^ "_" ^ f in
[base ^ "_lens", base ^ "_lens_view_update_modify", base ^ "_lens_valid",
base ^ "_focus", base ^ "_focus_view_update_modify", base ^ "_focus_code",
base ^ "_update_explicit", base ^ "_update_localI"]
end
fun render_field_map f =
let val rust_name = urust_of f in
if rust_name = f then f else rust_name ^ " \<mapsto> " ^ f
end
val urust_facts =
if with_fields then map (fn f => "uRust field access: " ^ render_field_map f) fields
else []
val bullets =
maps field_facts fields @ urust_facts @ [rec_name ^ " :: localizable"]
in
Pretty.writeln (Pretty.chunks (map (fn s => Pretty.str ("• " ^ s)) bullets))
end
fun make_lenses ((with_fields, rec_name), overrides) _ lthy =
let val _ =
if with_fields orelse null overrides then ()
else error "micro_rust_record: a uRust-name mapping cannot be combined \
\with [no_fields], which suppresses field registration"
val fields = get_fields rec_name lthy
val _ = check_override_fields rec_name fields overrides
val _ = summarise_micro_rust_record rec_name fields overrides with_fields
in
lthy
|> lens_autogen_defs rec_name
|> lens_autogen_defining_equations @{attributes [micro_rust_record_simps, focus_simps]} rec_name
|> lens_autogen_prove_lens_validity @{attributes [micro_rust_record_intros, focus_intros,
micro_rust_record_simps, focus_simps]} rec_name
|> lens_autogen_prove_update_equations @{attributes [micro_rust_record_simps, focus_simps]}
@{attributes [micro_rust_record_intros, focus_intros]} rec_name
|> focus_autogen_make_field_foci @{attributes [focus_components]} rec_name
|> (if with_fields then
register_lenses_with_micro_rust rec_name overrides
else
I)
|> instantiate_localizable_class rec_name
end
\<comment>\<open>Parse an optional \<^verbatim>\<open>(hol_field = "urust_name", \<dots>)\<close> mapping after the
record name. Each \<^verbatim>\<open>"urust_name"\<close> is position-tracked so its use-site
markup points back at the literal in the command.\<close>
val parse_field_overrides =
Scan.optional
(Parse.$$$ "(" |--
Parse.enum1 "," (Parse.short_ident -- (Parse.$$$ "=" |-- Parse.position Parse.string))
--| Parse.$$$ ")")
[]
val _ =
Outer_Syntax.local_theory' \<^command_keyword>\<open>micro_rust_record\<close> "make lenses for datatype record"
((((Scan.optional ((Args.bracks (Args.$$$ "no_fields")) >> K false) true) -- Parse.short_ident)
-- parse_field_overrides) >> make_lenses)
\<close>
subsection\<open>The embedding\<close>
syntax
\<comment>\<open>The shallow embedding of uRust into HOL\<close>
"_shallow" :: \<open>urust \<Rightarrow> logic\<close> ("\<lbrakk>_\<rbrakk>"[0]1000)
\<comment> \<open>Intermediate helper for applying parameters\<close>
"_shallow_apply_params" :: \<open>logic \<Rightarrow> urust_params \<Rightarrow> logic\<close>
\<comment> \<open>Intermediate helper for building closures\<close>
"_shallow_abstract_args" :: \<open>urust_formal_args \<Rightarrow> urust \<Rightarrow> logic\<close>
\<comment> \<open>Intermediate helper for lowering identifiers to HOL\<close>
"_shallow_identifier_as_literal" :: \<open>urust_identifier \<Rightarrow> logic\<close>
"_shallow_identifier_as_function" :: \<open>urust_identifier \<Rightarrow> logic\<close>
"_shallow_identifier_as_field" :: \<open>urust_identifier \<Rightarrow> logic\<close>
\<comment> \<open>Lower a uRust identifier in BINDER-INTRODUCTION position (let-pattern
leaf, for-loop binder, etc.) to a plain \<^verbatim>\<open>Free\<close> suitable as the binder
slot of \<open>_abs\<close>. Distinct from \<open>_shallow_identifier_as_literal\<close>: pure
binders never consult the dispatch table --- their identifier IS the
binder, and any registered uRust notation of the same name is shadowed
by the let.\<close>
"_shallow_pattern_id" :: \<open>urust_identifier \<Rightarrow> logic\<close>
"_shallow_match_branches" :: \<open>urust_match_branches \<Rightarrow> urust_shallow_match_branches\<close>
"_shallow_match_branch" :: \<open>urust_match_branch \<Rightarrow> urust_shallow_match_branch \<close>
"_shallow_match_pattern" :: \<open>urust_pattern \<Rightarrow> urust_shallow_match_pattern\<close>
"_shallow_match_args" :: \<open>urust_pattern_args \<Rightarrow> urust_shallow_match_pattern_args \<close>
"_shallow_match_arg" :: \<open>urust_pattern \<Rightarrow> urust_shallow_match_pattern_arg\<close>
"_shallow_let_pattern" :: \<open>urust_pattern \<Rightarrow> pttrns\<close>
"_shallow_let_pattern_args" :: \<open>urust_let_pattern_args \<Rightarrow> pttrns\<close>
"_urust_struct_expr_to_args" :: \<open>urust_struct_expr_fields \<Rightarrow> urust_args\<close>
"_urust_array_expr_to_shallow" :: \<open>urust_args \<Rightarrow> logic\<close>
"_string_token_to_hol" :: \<open>string_token \<Rightarrow> logic\<close>
text\<open>We define the shallow embedding of uRust into HOL via a series of transformations
at the syntax level.\<close>
context
notes [[syntax_ast_trace]]
begin
term\<open>let (x, _ :: int) = (5,6) in x+12\<close>
end
\<comment>\<open>Path-style names like \<^verbatim>\<open>Foo::Bar\<close> are resolved by the
\<^verbatim>\<open>parse_translation\<close> for \<^verbatim>\<open>_shallow_identifier_as_*\<close> (see
\<open>lookup_id_tr\<close> below): it looks the name up in the
\<^ML_structure>\<open>Micro_Rust_Names\<close> table and falls back to the bare
identifier on miss, so paths participate in the same multi-backend,
type-driven dispatch as plain identifiers.\<close>
translations
\<comment>\<open>The shallow embedding of a HOL term is the corresponding literal\<close>
"_shallow(_urust_literal f)"
\<rightharpoonup> "CONST literal f"
"_shallow(_urust_fun_literal1 f)"
\<rightharpoonup> "CONST lift_fun1 f"
"_shallow(_urust_fun_literal2 f)"
\<rightharpoonup> "CONST lift_fun2 f"
"_shallow(_urust_fun_literal3 f)"
\<rightharpoonup> "CONST lift_fun3 f"
"_shallow(_urust_fun_literal4 f)"
\<rightharpoonup> "CONST lift_fun4 f"
"_shallow(_urust_fun_literal5 f)"
\<rightharpoonup> "CONST lift_fun5 f"
"_shallow(_urust_fun_literal6 f)"
\<rightharpoonup> "CONST lift_fun6 f"
"_shallow(_urust_fun_literal7 f)"
\<rightharpoonup> "CONST lift_fun7 f"
"_shallow(_urust_fun_literal8 f)"
\<rightharpoonup> "CONST lift_fun8 f"
"_shallow(_urust_fun_literal9 f)"
\<rightharpoonup> "CONST lift_fun9 f"
"_shallow(_urust_fun_literal10 f)"
\<rightharpoonup> "CONST lift_fun10 f"
"_shallow(_urust_fun_literal11 f)"
\<rightharpoonup> "CONST lift_fun11 f"
"_shallow(_urust_fun_literal12 f)"
\<rightharpoonup> "CONST lift_fun12 f"
"_shallow(_urust_fun_literal13 f)"
\<rightharpoonup> "CONST lift_fun13 f"
"_shallow(_urust_fun_literal14 f)"
\<rightharpoonup> "CONST lift_fun14 f"
"_shallow(_urust_numeral num)"
\<rightharpoonup> "CONST literal (_Numeral num)" \<comment>\<open>TODO: What type should we cast numerals to by default?\<close>
"_shallow(_urust_numeral_0)"
\<rightharpoonup> "CONST literal 0"
"_shallow(_urust_numeral_1)"
\<rightharpoonup> "CONST literal 1"
"_shallow(_urust_string_token str)"
\<rightharpoonup> "CONST literal (_string_token_to_hol str)"
\<comment> \<open>The shallow embedding of a shallow Micro Rust \<^typ>\<open>('s, 'v, 'r, 'abort, 'i, 'o) expression\<close> is the expression itself\<close>
"_shallow(_urust_antiquotation exp)"
\<rightharpoonup> "exp"
"_shallow(_urust_unit)"
\<rightharpoonup> "CONST literal ()"
"_shallow(_urust_pause)"
\<rightharpoonup> "CONST pause"
"_shallow(_urust_log priority logval)"
\<rightharpoonup> "CONST log priority logval"
"_shallow(_urust_parens exp)"
\<rightharpoonup> "_shallow exp"
\<comment>\<open>Primitive casts\<close>
"_shallow(_urust_primitive_integral_cast_u8 e)"
\<rightharpoonup> "CONST ucastu8 (_shallow e)"
"_shallow(_urust_primitive_integral_cast_u16 e)"
\<rightharpoonup> "CONST ucastu16 (_shallow e)"
"_shallow(_urust_primitive_integral_cast_u32 e)"
\<rightharpoonup> "CONST ucastu32 (_shallow e)"
"_shallow(_urust_primitive_integral_cast_u64 e)"
\<rightharpoonup> "CONST ucastu64 (_shallow e)"
"_shallow(_urust_primitive_integral_cast_i32 e)"
\<rightharpoonup> "CONST ucasti32 (_shallow e)"
"_shallow(_urust_primitive_integral_cast_i64 e)"
\<rightharpoonup> "CONST ucasti64 (_shallow e)"
"_shallow(_urust_primitive_integral_cast_usize e)"
\<rightharpoonup> "CONST ucastu64 (_shallow e)"
\<comment>\<open>Raw pointer casts\<close>
"_shallow(_urust_ptr_const_cast_u8 e)"
\<rightharpoonup> "CONST raw_ptr_cast_u8 (_shallow e)"
"_shallow(_urust_ptr_const_cast_u16 e)"
\<rightharpoonup> "CONST raw_ptr_cast_u16 (_shallow e)"
"_shallow(_urust_ptr_const_cast_u32 e)"
\<rightharpoonup> "CONST raw_ptr_cast_u32 (_shallow e)"
"_shallow(_urust_ptr_const_cast_u64 e)"
\<rightharpoonup> "CONST raw_ptr_cast_u64 (_shallow e)"
"_shallow(_urust_ptr_const_cast_usize e)"
\<rightharpoonup> "CONST raw_ptr_cast_u64 (_shallow e)"
"_shallow(_urust_numeral_ascription_0_u8)"
\<rightharpoonup> "CONST ascribeu8 0"
"_shallow(_urust_numeral_ascription_1_u8)"
\<rightharpoonup> "CONST ascribeu8 1"
"_shallow(_urust_numeral_ascription_u8 e)"
\<rightharpoonup> "CONST ascribeu8 (_Numeral e)"
"_shallow(_urust_numeral_ascription_0_u16)"
\<rightharpoonup> "CONST ascribeu16 0"
"_shallow(_urust_numeral_ascription_1_u16)"
\<rightharpoonup> "CONST ascribeu16 1"
"_shallow(_urust_numeral_ascription_u16 e)"
\<rightharpoonup> "CONST ascribeu16 (_Numeral e)"
"_shallow(_urust_numeral_ascription_0_u32)"
\<rightharpoonup> "CONST ascribeu32 0"
"_shallow(_urust_numeral_ascription_1_u32)"
\<rightharpoonup> "CONST ascribeu32 1"
"_shallow(_urust_numeral_ascription_u32 e)"
\<rightharpoonup> "CONST ascribeu32 (_Numeral e)"
"_shallow(_urust_numeral_ascription_0_u64)"
\<rightharpoonup> "CONST ascribeu64 0"
"_shallow(_urust_numeral_ascription_1_u64)"
\<rightharpoonup> "CONST ascribeu64 1"
"_shallow(_urust_numeral_ascription_u64 e)"
\<rightharpoonup> "CONST ascribeu64 (_Numeral e)"
"_shallow(_urust_numeral_ascription_0_usize)"
\<rightharpoonup> "CONST ascribeu64 0"
"_shallow(_urust_numeral_ascription_1_usize)"
\<rightharpoonup> "CONST ascribeu64 1"
"_shallow(_urust_numeral_ascription_usize e)"
\<rightharpoonup> "CONST ascribeu64 (_Numeral e)"
\<comment>\<open>Explicit scopes are relevant for initial parsing and can be removed when operating on ASTs\<close>
"_shallow(_urust_scoping f)"
\<rightharpoonup> "(_shallow f)"
\<comment>\<open>The shallow embedding of standard if-then-else conditional\<close>
"_shallow (_urust_if_then_else c t e)"
\<rightharpoonup> "if (_shallow c) \<lbrace> (_shallow t) \<rbrace> else \<lbrace> (_shallow e) \<rbrace>"
"_shallow (_urust_if_then c t)"
\<rightharpoonup> "if (_shallow c) \<lbrace> (_shallow t) \<rbrace> else \<lbrace> (CONST skip) \<rbrace>"
\<comment>\<open>Unsafe blocks are semantically meaningless and merely included to make \<^verbatim>\<open>\<mu>Rust\<close> look closer to
upstream Rust code.\<close>
"_shallow (_urust_unsafe_block t)"
\<rightharpoonup> "_shallow t"
\<comment> \<open>TODO: Can we not have one case that handles all this? See also \<^url>\<open>https://github.com/awslabs/AutoCorrode/issues/29\<close>\<close>
"_shallow (_urust_funcall_with_args (_urust_callable_id id) args)"
\<rightharpoonup> "_urust_shallow_fun_with_args (_shallow_identifier_as_function id) (_shallow args)"
"_shallow (_urust_funcall_with_args (_urust_antiquotation emb) args)"
\<rightharpoonup> "_urust_shallow_fun_with_args emb (_shallow args)"
"_shallow (_urust_funcall_with_args (_urust_callable_fun_literal f) args)"
\<rightharpoonup> "_urust_shallow_fun_with_args (_shallow f) (_shallow args)"
"_shallow (_urust_funcall_with_args (_urust_callable_struct f id) args)"
\<rightharpoonup> "_urust_shallow_fun_with_args (_shallow_identifier_as_function id) (_shallow (_urust_args_app f args))"
\<comment>\<open>Turbofish with args\<close>
"_shallow (_urust_funcall_with_args (_urust_callable_with_params (_urust_callable_id id) params) args)"
\<rightharpoonup> "_urust_shallow_fun_with_args (_shallow_apply_params (_shallow_identifier_as_function id) params) (_shallow args)"
"_shallow (_urust_funcall_with_args (_urust_callable_with_params (_urust_callable_fun_literal f) params) args)"
\<rightharpoonup> "_urust_shallow_fun_with_args (_shallow_apply_params (_shallow f) params) (_shallow args)"
"_shallow (_urust_funcall_with_args (_urust_callable_with_params (_urust_callable_struct f id) params) args)"
\<rightharpoonup> "_urust_shallow_fun_with_args (_shallow_apply_params (_shallow_identifier_as_function id) params) (_shallow (_urust_args_app f args))"
"_urust_struct_expr_to_args (_urust_struct_expr_fields_single (_urust_struct_expr_field fld e))"
\<rightharpoonup> "_urust_args_single e"
"_urust_struct_expr_to_args (_urust_struct_expr_fields_app (_urust_struct_expr_field fld e) rest)"
\<rightharpoonup> "_urust_args_app e (_urust_struct_expr_to_args rest)"
"_shallow (_urust_struct_expr id fields)"
\<rightharpoonup> "_shallow (_urust_funcall_with_args (_urust_callable_id id) (_urust_struct_expr_to_args fields))"
"_shallow (_urust_array_expr_empty)"
\<rightharpoonup> "CONST literal ([])"
"_shallow (_urust_array_expr args)"
\<rightharpoonup> "_urust_array_expr_to_shallow args"
"_urust_array_expr_to_shallow (_urust_args_single a)"
\<rightharpoonup> "CONST bindlift2 (CONST List.list.Cons) (_shallow a) (CONST literal ([]))"
"_urust_array_expr_to_shallow (_urust_args_app a rest)"
\<rightharpoonup> "CONST bindlift2 (CONST List.list.Cons) (_shallow a) (_urust_array_expr_to_shallow rest)"
"_shallow (_urust_args_app a bs)"
\<rightharpoonup> "_urust_shallow_args_app (_shallow a) (_shallow bs)"
"_shallow (_urust_args_single a)"
\<rightharpoonup> "_urust_shallow_args_single (_shallow a)"
"_shallow (_urust_funcall_no_args (_urust_callable_id id))"
\<rightharpoonup> "_urust_shallow_fun_no_args (_shallow_identifier_as_function id)"
"_shallow (_urust_funcall_no_args (_urust_callable_antiquotation emb))"
\<rightharpoonup> "_urust_shallow_fun_no_args emb"
"_shallow (_urust_funcall_no_args (_urust_callable_fun_literal f))"
\<rightharpoonup> "_urust_shallow_fun_no_args (_shallow f)"
"_shallow (_urust_funcall_no_args (_urust_callable_struct f id))"
\<rightharpoonup> "_shallow (_urust_funcall_with_args (_urust_callable_id id) (_urust_args_single f))"
\<comment>\<open>Turbofish no args\<close>
"_shallow (_urust_funcall_no_args (_urust_callable_with_params (_urust_callable_id id) params))"
\<rightharpoonup> "_urust_shallow_fun_no_args (_shallow_apply_params (_shallow_identifier_as_function id) params)"
"_shallow (_urust_funcall_no_args (_urust_callable_with_params (_urust_callable_fun_literal f) params))"
\<rightharpoonup> "_urust_shallow_fun_no_args (_shallow_apply_params (_shallow f) params)"
"_shallow (_urust_funcall_no_args (_urust_callable_with_params (_urust_callable_struct f id) params))"
\<rightharpoonup> "_urust_shallow_fun_with_args (_shallow_apply_params (_shallow_identifier_as_function id) params) (_shallow (_urust_args_single f))"
"_shallow (_urust_return_unit)"
\<rightharpoonup> "_urust_shallow_return (CONST literal ())"
"_shallow (_urust_return exp)"
\<rightharpoonup> "_urust_shallow_return (_shallow exp)"
"_shallow (_urust_bind_immutable pattern exp cont)"
\<rightharpoonup> "CONST Core_Expression.bind (_shallow exp) (_abs (_shallow_let_pattern pattern) (_shallow cont))"
"_shallow (_urust_bind_immutable' pattern exp cont)"
\<rightharpoonup> "CONST Core_Expression.bind (_shallow exp) (_abs (_shallow_let_pattern pattern) (_shallow cont))"
\<comment>\<open>Let-pattern leaves use the binder-position resolver --- their
identifier IS the binder, so we must not emit a \<^verbatim>\<open>urust_dispatch\<close>
marker here (it would crash \<^ML>\<open>Syntax_Trans.abs_tr\<close>).\<close>
"_shallow_let_pattern (_urust_match_pattern_constr_no_args id)"
\<rightharpoonup> "_shallow_pattern_id id"
"_shallow_let_pattern _urust_match_pattern_other"
\<rightharpoonup> "_idtdummy"
"_shallow_let_pattern (_urust_match_pattern_grouped pat)"
\<rightharpoonup> "_shallow_let_pattern pat"
\<comment>\<open>Tuples\<close>
"_shallow (_urust_tuple_args_double a b)"
\<rightleftharpoons> "CONST tuple_base_pair (_shallow a) (_shallow b)"
"_shallow (_urust_tuple_args_app a bs)"
\<rightleftharpoons> "CONST tuple_cons (_shallow a) (_shallow bs)"
"_shallow (_urust_tuple_constr args)"
\<rightleftharpoons> "_shallow args"
"_shallow (_urust_tuple_index_0 arg)"
\<rightleftharpoons> "CONST tuple_index_0 (_shallow arg)"
"_shallow (_urust_tuple_index_1 arg)"
\<rightleftharpoons> "CONST tuple_index_1 (_shallow arg)"
"_shallow (_urust_tuple_index_2 arg)"
\<rightleftharpoons> "CONST tuple_index_2 (_shallow arg)"
"_shallow (_urust_tuple_index_3 arg)"
\<rightleftharpoons> "CONST tuple_index_3 (_shallow arg)"
"_shallow (_urust_tuple_index_4 arg)"
\<rightleftharpoons> "CONST tuple_index_4 (_shallow arg)"
"_shallow (_urust_tuple_index_5 arg)"
\<rightleftharpoons> "CONST tuple_index_5 (_shallow arg)"
"_shallow (_urust_tuple_index_6 arg)"
\<rightleftharpoons> "CONST tuple_index_6 (_shallow arg)"
"_shallow (_urust_tuple_index_7 arg)"
\<rightleftharpoons> "CONST tuple_index_7 (_shallow arg)"
"_shallow (_urust_tuple_index_8 arg)"
\<rightleftharpoons> "CONST tuple_index_8 (_shallow arg)"
"_shallow (_urust_tuple_index_9 arg)"
\<rightleftharpoons> "CONST tuple_index_9 (_shallow arg)"
"_shallow (_urust_tuple_index_10 arg)"
\<rightleftharpoons> "CONST tuple_index_10 (_shallow arg)"
"_shallow (_urust_tuple_index_11 arg)"
\<rightleftharpoons> "CONST tuple_index_11 (_shallow arg)"
"_shallow (_urust_tuple_index_12 arg)"
\<rightleftharpoons> "CONST tuple_index_12 (_shallow arg)"
"_shallow (_urust_tuple_index_13 arg)"
\<rightleftharpoons> "CONST tuple_index_13 (_shallow arg)"
"_shallow (_urust_tuple_index_14 arg)"
\<rightleftharpoons> "CONST tuple_index_14 (_shallow arg)"
"_shallow (_urust_tuple_index_15 arg)"
\<rightleftharpoons> "CONST tuple_index_15 (_shallow arg)"
"_shallow_let_pattern (_urust_let_pattern_tuple args)"
\<rightleftharpoons> "_shallow_let_pattern_args args"
"_shallow_let_pattern_args (_urust_let_pattern_tuple_base_pair fst_pat snd_pat)"
\<rightleftharpoons> "_pattern (_shallow_let_pattern fst_pat) (_pattern (_shallow_let_pattern snd_pat) (_idtdummy :: Tuple.tnil))"
"_shallow_let_pattern_args (_urust_let_pattern_tuple_app fst_pat snd_pat)"
\<rightleftharpoons> "_pattern (_shallow_let_pattern fst_pat) (_shallow_let_pattern_args snd_pat)"
"_shallow (_urust_bind_mutable (_urust_identifier_hol_id var) exp cont)"
\<rightharpoonup> "CONST bind (Ref::new \<langle>(_shallow exp)\<rangle>) (\<lambda>var. (_shallow cont))"
\<comment>\<open>Mutable binding with tuple pattern: \<^verbatim>\<open>let mut (x, y) = expr\<close>. The \<^verbatim>\<open>mut\<close> annotation is
dropped since Rust's local-variable mutability is not modelled in the shallow embedding.\<close>
"_shallow (_urust_bind_mutable_pattern args exp cont)"
\<rightharpoonup> "CONST Core_Expression.bind (_shallow exp) (_abs (_shallow_let_pattern_args args) (_shallow cont))"
"_shallow (_urust_sequence seqA seqB)"
\<rightharpoonup> "CONST sequence (_shallow seqA) (_shallow seqB)"
"_shallow (_urust_sequence_mono seqA)"
\<rightharpoonup> "CONST sequence (_shallow seqA) (CONST skip)"
"_shallow (_urust_identifier ident)"
\<rightharpoonup> "CONST literal (_shallow_identifier_as_literal ident)"
"_shallow (_urust_true)"
\<rightharpoonup> "_urust_shallow_bool_true"
"_shallow (_urust_false)"
\<rightharpoonup> "_urust_shallow_bool_false"
"_shallow (_urust_field_access exp fld)"
\<rightharpoonup> "_urust_shallow_field_access (_shallow exp) (_shallow_identifier_as_field fld)"
"_shallow (_urust_propagate exp)"
\<rightharpoonup> "_urust_shallow_propagate (_shallow exp)"
"_shallow (_urust_borrow (_urust_array_expr_empty))"
\<rightharpoonup> "_shallow (_urust_array_expr_empty)"
"_shallow (_urust_borrow (_urust_array_expr args))"
\<rightharpoonup> "_shallow (_urust_array_expr args)"
"_shallow (_urust_borrow_mut (_urust_array_expr_empty))"
\<rightharpoonup> "_shallow (_urust_array_expr_empty)"
"_shallow (_urust_borrow_mut (_urust_array_expr args))"
\<rightharpoonup> "_shallow (_urust_array_expr args)"
"_shallow (_urust_borrow exp)"
\<rightharpoonup> "CONST bindlift1 (CONST ro_ref_from_ref) (_shallow exp)"
"_shallow (_urust_borrow_mut exp)"
\<rightharpoonup> "CONST bindlift1 (CONST mut_ref_from_ref) (_shallow exp)"
"_shallow (_urust_deref exp)"
\<rightharpoonup> "_urust_shallow_store_dereference (_shallow exp)"
"_shallow (_urust_assign lhs exp)"
\<rightharpoonup> "_urust_shallow_store_update (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_word_assign_or lhs exp)"
\<rightharpoonup> "_urust_shallow_word_assign_or (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_word_assign_xor lhs exp)"
\<rightharpoonup> "_urust_shallow_word_assign_xor (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_word_assign_and lhs exp)"
\<rightharpoonup> "_urust_shallow_word_assign_and (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_assign_add lhs exp)"
\<rightharpoonup> "_urust_shallow_assign_add (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_assign_minus lhs exp)"
\<rightharpoonup> "_urust_shallow_assign_minus (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_assign_mul lhs exp)"
\<rightharpoonup> "_urust_shallow_assign_mul (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_assign_mod lhs exp)"
\<rightharpoonup> "_urust_shallow_assign_mod (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_word_assign_shift_left lhs exp)"
\<rightharpoonup> "_urust_shallow_word_assign_shift_left (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_word_assign_shift_right lhs exp)"
\<rightharpoonup> "_urust_shallow_word_assign_shift_right (_shallow (_urust_lhs_as_urust lhs)) (_shallow exp)"
"_shallow (_urust_closure_no_args exp)"
\<rightharpoonup> "CONST literal (CONST FunctionBody (_shallow exp))"
"_shallow (_urust_closure_with_args args exp)"
\<rightharpoonup> "CONST literal (_shallow_abstract_args args exp)"
\<comment>\<open>Closure-formal lowering routes the binder through \<^verbatim>\<open>_abs\<close> (and
hence \<^ML>\<open>Syntax_Trans.abs_tr\<close>) so the source position carried by
the formal's \<open>id_position\<close> survives into a \<open>_constrainAbs\<close>
wrapper. The decoder then emits \<open>Markup.bound\<close> at the binder's
source range, paired with each in-scope use site --- which is what
makes ctrl-click on a closure-body identifier jump back to the
\<^verbatim>\<open>|x|\<close> binder.
The previous form \<open>\<lambda>arg. _\<close> using a translations meta-variable
discarded the \<open>_constrain\<close> wrapper at substitution time and so
produced binder-markup-less closures.\<close>
"_shallow_abstract_args (_urust_formal_single id) exp"
\<rightharpoonup> "_abs id (CONST FunctionBody (_shallow exp))"
"_shallow_abstract_args (_urust_formal_app id args) exp"
\<rightharpoonup> "_abs id (_shallow_abstract_args args exp)"
"_shallow_apply_params f (_urust_param_app p params)"
\<rightharpoonup> "_shallow_apply_params (f p) params"
"_shallow_apply_params f (_urust_param_single p)"
\<rightharpoonup> "f p"
(* Explicit translations for specific macro forms. *)
"_shallow (_urust_macro_no_args (URUST_CONST panic))"
\<rightharpoonup> "CONST panic (CONST String.implode [])"
"_shallow (_urust_macro_no_args (URUST_CONST unimplemented))"
\<rightharpoonup> "CONST unimplemented (CONST String.implode [])"
"_shallow (_urust_macro_no_args (URUST_CONST todo))"
\<rightharpoonup> "CONST unimplemented (CONST String.implode [])"
"_shallow (_urust_macro_no_args (URUST_CONST fatal))"
\<rightharpoonup> "CONST fatal (CONST String.implode [])"
"_shallow (_urust_macro_with_args
(URUST_CONST assert) (_urust_args_single exp))"
\<rightharpoonup> "CONST assert (_shallow exp)"
"_shallow (_urust_macro_with_args
(URUST_CONST assert) (_urust_args_app exp rest))"
\<rightharpoonup> "CONST assert (_shallow exp)"
"_shallow (_urust_macro_with_args
(URUST_CONST debug_assert) (_urust_args_single exp))"
\<rightharpoonup> "CONST assert (_shallow exp)"
"_shallow (_urust_macro_with_args
(URUST_CONST debug_assert) (_urust_args_app exp rest))"
\<rightharpoonup> "CONST assert (_shallow exp)"
"_shallow (_urust_macro_with_args
(URUST_CONST assert_ne) (_urust_args_app expA (_urust_args_single expB)))"
\<rightharpoonup> "CONST assert_ne (_shallow expA) (_shallow expB)"
"_shallow (_urust_macro_with_args
(URUST_CONST assert_ne) (_urust_args_app expA (_urust_args_app expB rest)))"
\<rightharpoonup> "CONST assert_ne (_shallow expA) (_shallow expB)"
"_shallow (_urust_macro_with_args
(URUST_CONST assert_eq) (_urust_args_app expA (_urust_args_single expB)))"
\<rightharpoonup> "CONST assert_eq (_shallow expA) (_shallow expB)"
"_shallow (_urust_macro_with_args
(URUST_CONST assert_eq) (_urust_args_app expA (_urust_args_app expB rest)))"
\<rightharpoonup> "CONST assert_eq (_shallow expA) (_shallow expB)"
"_shallow (_urust_macro_with_args
(URUST_CONST debug_assert_ne) (_urust_args_app expA (_urust_args_single expB)))"
\<rightharpoonup> "CONST assert_ne (_shallow expA) (_shallow expB)"
"_shallow (_urust_macro_with_args
(URUST_CONST debug_assert_ne) (_urust_args_app expA (_urust_args_app expB rest)))"
\<rightharpoonup> "CONST assert_ne (_shallow expA) (_shallow expB)"
"_shallow (_urust_macro_with_args
(URUST_CONST debug_assert_eq) (_urust_args_app expA (_urust_args_single expB)))"
\<rightharpoonup> "CONST assert_eq (_shallow expA) (_shallow expB)"
"_shallow (_urust_macro_with_args
(URUST_CONST debug_assert_eq) (_urust_args_app expA (_urust_args_app expB rest)))"
\<rightharpoonup> "CONST assert_eq (_shallow expA) (_shallow expB)"
"_shallow (_urust_macro_with_args
(URUST_CONST panic) (_urust_args_app first rest))"
\<rightharpoonup> "_shallow (_urust_macro_with_args
(URUST_CONST panic) (_urust_args_single first))"
"_shallow (_urust_macro_with_args
(URUST_CONST panic) (_urust_args_single (_urust_identifier a)))"
\<rightharpoonup> "CONST panic (_shallow_identifier_as_literal a)"
"_shallow (_urust_macro_with_args
(URUST_CONST panic) (_urust_args_single (_urust_literal x)))"
\<rightharpoonup> "CONST panic (CONST String.implode x)"
"_shallow (_urust_macro_with_args
(URUST_CONST panic) (_urust_args_single (_urust_string_token str)))"
\<rightharpoonup> "CONST panic (_string_token_to_hol str)"
"_shallow (_urust_macro_with_args
(URUST_CONST unimplemented) (_urust_args_app first rest))"
\<rightharpoonup> "_shallow (_urust_macro_with_args
(URUST_CONST unimplemented) (_urust_args_single first))"
"_shallow (_urust_macro_with_args
(URUST_CONST unimplemented) (_urust_args_single (_urust_identifier a)))"
\<rightharpoonup> "CONST unimplemented (_shallow_identifier_as_literal a)"
"_shallow (_urust_macro_with_args
(URUST_CONST unimplemented) (_urust_args_single (_urust_literal x)))"
\<rightharpoonup> "CONST unimplemented (CONST String.implode x)"
"_shallow (_urust_macro_with_args
(URUST_CONST unimplemented) (_urust_args_single (_urust_string_token str)))"
\<rightharpoonup> "CONST unimplemented (_string_token_to_hol str)"
"_shallow (_urust_macro_with_args
(URUST_CONST todo) (_urust_args_app first rest))"
\<rightharpoonup> "_shallow (_urust_macro_with_args
(URUST_CONST todo) (_urust_args_single first))"
"_shallow (_urust_macro_with_args
(URUST_CONST todo) (_urust_args_single (_urust_identifier a)))"
\<rightharpoonup> "CONST unimplemented (_shallow_identifier_as_literal a)"
"_shallow (_urust_macro_with_args
(URUST_CONST todo) (_urust_args_single (_urust_literal x)))"
\<rightharpoonup> "CONST unimplemented (CONST String.implode x)"
"_shallow (_urust_macro_with_args
(URUST_CONST todo) (_urust_args_single (_urust_string_token str)))"
\<rightharpoonup> "CONST unimplemented (_string_token_to_hol str)"
"_shallow (_urust_macro_with_args
(URUST_CONST fatal) (_urust_args_app first rest))"
\<rightharpoonup> "_shallow (_urust_macro_with_args
(URUST_CONST fatal) (_urust_args_single first))"
"_shallow (_urust_macro_with_args
(URUST_CONST fatal) (_urust_args_single (_urust_identifier a)))"
\<rightharpoonup> "CONST fatal (_shallow_identifier_as_literal a)"
"_shallow (_urust_macro_with_args
(URUST_CONST fatal) (_urust_args_single (_urust_literal x)))"
\<rightharpoonup> "CONST fatal (CONST String.implode x)"
"_shallow (_urust_macro_with_args
(URUST_CONST fatal) (_urust_args_single (_urust_string_token str)))"
\<rightharpoonup> "CONST fatal (_string_token_to_hol str)"
"_shallow (_urust_macro_no_args (URUST_CONST unreachable))"
\<rightharpoonup> "CONST panic (CONST String.implode [])"
"_shallow (_urust_macro_with_args
(URUST_CONST unreachable) (_urust_args_app first rest))"
\<rightharpoonup> "_shallow (_urust_macro_with_args
(URUST_CONST unreachable) (_urust_args_single first))"
"_shallow (_urust_macro_with_args
(URUST_CONST unreachable) (_urust_args_single (_urust_identifier a)))"
\<rightharpoonup> "CONST panic (_shallow_identifier_as_literal a)"
"_shallow (_urust_macro_with_args
(URUST_CONST unreachable) (_urust_args_single (_urust_literal x)))"
\<rightharpoonup> "CONST panic (CONST String.implode x)"
"_shallow (_urust_macro_with_args
(URUST_CONST unreachable) (_urust_args_single (_urust_string_token str)))"
\<rightharpoonup> "CONST panic (_string_token_to_hol str)"
"_shallow (_urust_macro_with_args (URUST_CONST vec) args)"
\<rightharpoonup> "_shallow (_urust_array_expr args)"
"_shallow (_urust_macro_no_args (URUST_CONST vec))"
\<rightharpoonup> "_shallow (_urust_array_expr_empty)"
"_shallow (_urust_macro_with_args (URUST_CONST addr_of) (_urust_args_single exp))"
\<rightharpoonup> "CONST bindlift1 (CONST ref_address) (_shallow exp)"
"_shallow (_urust_macro_with_args (URUST_CONST addr_of_mut) (_urust_args_single exp))"
\<rightharpoonup> "CONST bindlift1 (CONST ref_address) (_shallow exp)"
"_shallow (_urust_matches_macro expr pat)"
\<rightharpoonup> "_urust_shallow_match (_shallow expr)
(_urust_shallow_match2
(_urust_shallow_match1 (_shallow_match_pattern pat) (CONST literal (CONST True)))
(_urust_shallow_match1 _urust_shallow_match_pattern_other (CONST literal (CONST False))))"
"_shallow (_urust_index exp idx)"
\<rightharpoonup> "_urust_shallow_index (_shallow exp) (_shallow idx)"
"_shallow (_urust_add x y)"
\<rightharpoonup> "_urust_shallow_add (_shallow x) (_shallow y)"
"_shallow (_urust_minus x y)"
\<rightharpoonup> "_urust_shallow_minus (_shallow x) (_shallow y)"
"_shallow (_urust_mul x y)"
\<rightharpoonup> "_urust_shallow_mul (_shallow x) (_shallow y)"
"_shallow (_urust_div x y)"
\<rightharpoonup> "_urust_shallow_div (_shallow x) (_shallow y)"
"_shallow (_urust_mod x y)"
\<rightharpoonup> "_urust_shallow_mod (_shallow x) (_shallow y)"
"_shallow (_urust_equality x y)"
\<rightharpoonup> "_urust_shallow_equality (_shallow x) (_shallow y)"
"_shallow (_urust_nonequality x y)"
\<rightharpoonup> "_urust_shallow_nonequality (_shallow x) (_shallow y)"
"_shallow (_urust_greater_equal x y)"
\<rightharpoonup> "_urust_shallow_bool_ge (_shallow x) (_shallow y)"
"_shallow (_urust_greater x y)"
\<rightharpoonup> "_urust_shallow_bool_gt (_shallow x) (_shallow y)"
"_shallow (_urust_less_equal x y)"
\<rightharpoonup> "_urust_shallow_bool_le (_shallow x) (_shallow y)"
"_shallow (_urust_less x y)"
\<rightharpoonup> "_urust_shallow_bool_lt (_shallow x) (_shallow y)"
"_shallow (_urust_bitwise_or x y)"
\<rightharpoonup> "_urust_shallow_word_bitwise_or (_shallow x) (_shallow y)"
"_shallow (_urust_bitwise_and x y)"
\<rightharpoonup> "_urust_shallow_word_bitwise_and (_shallow x) (_shallow y)"
"_shallow (_urust_bitwise_xor x y)"
\<rightharpoonup> "_urust_shallow_word_bitwise_xor (_shallow x) (_shallow y)"
"_shallow (_urust_shift_left x y)"
\<rightharpoonup> "_urust_shallow_word_shift_left (_shallow x) (_shallow y)"
"_shallow (_urust_shift_right x y)"
\<rightharpoonup> "_urust_shallow_word_shift_right (_shallow x) (_shallow y)"
"_shallow (_urust_negation exp)"
\<rightharpoonup> "_urust_shallow_negation (_shallow exp)"
"_shallow (_urust_bool_conjunction x y)"
\<rightharpoonup> "_urust_shallow_bool_conjunction (_shallow x) (_shallow y)"
"_shallow (_urust_bool_disjunction x y)"
\<rightharpoonup> "_urust_shallow_bool_disjunction (_shallow x) (_shallow y)"
"_shallow( _urust_range x y)"
\<rightharpoonup> "_urust_shallow_range (_shallow x) (_shallow y)"
"_shallow( _urust_range_eq x y)"
\<rightharpoonup> "_urust_shallow_range_eq (_shallow x) (_shallow y)"
"_shallow (_urust_let_else (_urust_let_pattern_tuple args) exp el tail)"
\<rightharpoonup> "CONST Core_Expression.bind (_shallow exp)
(_abs (_shallow_let_pattern (_urust_let_pattern_tuple args)) (_shallow tail))"
"_shallow (_urust_if_let (_urust_let_pattern_tuple args) exp this)"
\<rightharpoonup> "CONST Core_Expression.bind (_shallow exp)
(_abs (_shallow_let_pattern (_urust_let_pattern_tuple args)) (_shallow this))"
"_shallow (_urust_if_let_else (_urust_let_pattern_tuple args) exp this that )"
\<rightharpoonup> "CONST Core_Expression.bind (_shallow exp)
(_abs (_shallow_let_pattern (_urust_let_pattern_tuple args)) (_shallow this))"
"_shallow (_urust_let_else ptrn exp el tail)"
\<rightharpoonup> "_urust_shallow_let_else (_shallow_match_pattern ptrn) (_shallow exp) (_shallow el) (_shallow tail)"
"_shallow (_urust_if_let ptrn exp this)"
\<rightharpoonup> "_urust_shallow_if_let (_shallow_match_pattern ptrn) (_shallow exp) (_shallow this)"
"_shallow (_urust_if_let_else ptrn exp this that )"
\<rightharpoonup> "_urust_shallow_if_let_else (_shallow_match_pattern ptrn) (_shallow exp) (_shallow this) (_shallow that)"
"_shallow (_urust_match_case exp branches)"
\<rightharpoonup> "_urust_shallow_match (_shallow exp) (_shallow_match_branches branches)"
"_shallow_match_branches (_urust_match1 pattern exp)"
\<rightharpoonup> "_urust_shallow_match1 (_shallow_match_pattern pattern) (_shallow exp)"
"_shallow_match_branches (_urust_match1_guard pattern guard exp)"
\<rightharpoonup> "_urust_shallow_match1_guard (_shallow_match_pattern pattern) (_shallow guard) (_shallow exp)"
"_shallow_match_branches (_urust_match2 b0 b1)"
\<rightharpoonup> "_urust_shallow_match2 (_shallow_match_branches b0) (_shallow_match_branches b1)"
"_shallow_match_pattern _urust_match_pattern_other"
\<rightharpoonup> "_urust_shallow_match_pattern_other"
"_shallow_match_pattern (_urust_match_pattern_num_const num)"
\<rightharpoonup> "_urust_shallow_match_pattern_num_const num"
"_shallow_match_pattern (_urust_match_pattern_zero)"
\<rightharpoonup> "_urust_shallow_match_pattern_zero"
"_shallow_match_pattern (_urust_match_pattern_one)"
\<rightharpoonup> "_urust_shallow_match_pattern_one"
\<comment>\<open>Match-arm constructor heads continue to route through the
value-position \<^verbatim>\<open>_shallow_identifier_as_literal\<close>: \<open>case_tr\<close>
downstream tolerates a \<^verbatim>\<open>urust_dispatch\<close> marker as the head and
the term_check phase resolves it after type inference (which is
necessary for value-position match arms like \<open>match x { number::three => \<dots> }\<close>
where the registration target is a non-constructor constant).\<close>
"_shallow_match_pattern (_urust_match_pattern_constr_no_args id)"
\<rightharpoonup> "_urust_shallow_match_pattern_constr_no_args (_shallow_identifier_as_literal id)"
"_shallow_match_pattern (_urust_match_pattern_constr_with_args id args)"
\<rightharpoonup> "_urust_shallow_match_pattern_constr_with_args (_shallow_identifier_as_literal id) (_shallow_match_args args)"
"_shallow_match_pattern (_urust_match_pattern_disjunction p1 p2)"
\<rightharpoonup> "_urust_shallow_match_pattern_disjunction (_shallow_match_pattern p1) (_shallow_match_pattern p2)"
"_shallow_match_pattern (_urust_match_pattern_grouped pat)"
\<rightharpoonup> "_shallow_match_pattern pat"
"_shallow_match_pattern (_urust_let_pattern_tuple (_urust_let_pattern_tuple_base_pair a b))"
\<rightharpoonup> "_urust_shallow_match_pattern_constr_with_args (CONST Pair)
(_urust_shallow_match_pattern_args_app (_shallow_match_arg a)
(_urust_shallow_match_pattern_args_single
(_urust_shallow_match_pattern_arg_pattern
(_urust_shallow_match_pattern_constr_with_args (CONST Pair)
(_urust_shallow_match_pattern_args_app (_shallow_match_arg b)
(_urust_shallow_match_pattern_args_single
(_urust_shallow_match_pattern_arg_pattern
(_urust_shallow_match_pattern_constr_no_args (CONST TNil)))))))))"
"_shallow_match_args (_urust_match_pattern_args_single arg)"
\<rightharpoonup> "_urust_shallow_match_pattern_args_single (_shallow_match_arg arg)"
"_shallow_match_args (_urust_match_pattern_args_app a bs)"
\<rightharpoonup> "_urust_shallow_match_pattern_args_app (_shallow_match_arg a) (_shallow_match_args bs)"
"_shallow (_urust_match_switch exp branches)"
\<rightharpoonup> "_urust_shallow_switch (_shallow exp) (_shallow_match_branches branches)"
"_shallow (_urust_for_loop x iter body)"
\<rightharpoonup> "_urust_shallow_for_loop (_shallow_let_pattern x) (_shallow iter) (_shallow body)"
"_shallow (_urust_while_loop (_urust_antiquotation fuel) cond body)"
\<rightharpoonup> "_urust_shallow_while_loop fuel (_shallow cond) (_shallow body)"
"_shallow (_urust_loop (_urust_antiquotation fuel) body)"
\<rightharpoonup> "_urust_shallow_loop fuel (_shallow body)"
\<comment>\<open>While let — tuple pattern special case (irrefutable)\<close>
"_shallow (_urust_while_let (_urust_antiquotation fuel) (_urust_let_pattern_tuple args) expr body)"
\<rightharpoonup> "CONST bounded_while fuel
(CONST Core_Expression.bind (_shallow expr)
(_abs (_shallow_let_pattern (_urust_let_pattern_tuple args))
(CONST Core_Expression.sequence (_shallow body) (CONST Core_Expression.literal (CONST HOL.True)))))
(CONST skip)"
\<comment>\<open>While let — general pattern case\<close>
"_shallow (_urust_while_let (_urust_antiquotation fuel) ptrn expr body)"
\<rightharpoonup> "_urust_shallow_while_let fuel (_shallow_match_pattern ptrn) (_shallow expr) (_shallow body)"
micro_rust_notation \<open>lift_fun1 Some\<close> ("Some")
micro_rust_notation \<open>lift_fun1 Ok\<close> ("Ok")
micro_rust_notation \<open>lift_fun1 Err\<close> ("Err")
text\<open>By default, we map all identifiers to HOL through the identity function on their names.
We register this as a parse translation rather than a rule so that names registered via
\<^theory_text>\<open>micro_rust_notation\<close> (which the translation looks up in
\<^ML_structure>\<open>Micro_Rust_Names\<close>) take precedence.\<close>
\<comment>\<open>NB: We could save some manual invocations of \<^theory_text>\<open>micro_rust_notation\<close> if we changed the
default renaming convention here, and e.g. prepend all field names with \<^verbatim>\<open>field_lens_\<close>,
for example.\<close>
parse_translation\<open>
let
\<comment>\<open>Lower a uRust identifier in \<open>kind\<close>-position to HOL: if \<open>name\<close> has any
backends registered in \<^ML_structure>\<open>Micro_Rust_Names\<close>, emit a typed
\<^const>\<open>urust_dispatch\<close> marker that the term_check phase resolves
against the occurrence's inferred type. Otherwise fall back to the
bare identifier (the historical \<open>K hd\<close> behaviour: a fresh free
variable named \<open>name\<close> --- which is what unregistered uRust
identifiers should still produce).
The arg arrives as a position-tagged identifier
\<open>_constrain $ Free name $ Free <pos>\<close> after the \<open>id_position\<close>
grammar; strip positions only for the lookup, not for the fallback
return value (so unregistered names retain their source markup).\<close>
\<comment>\<open>Extract the source position(s) of a position-tagged identifier
\<open>_constrain $ Free name $ Free <encoded-pos>\<close>. Returns \<open>[]\<close> for
untagged identifiers; the use-site markup is then emitted at
\<open>Position.none\<close> and silently dropped.\<close>
fun source_positions_of (Const (\<^syntax_const>\<open>_constrain\<close>, _) $ _ $ enc) =
(case Term_Position.decode_position1 enc of
SOME {pos, ...} => [pos]
| NONE => [])
| source_positions_of _ = [];
\<comment>\<open>Pick the leftmost decoded source position (if any) to fold into
the marker; \<open>Position.none\<close> when nothing is attached.\<close>
fun pick_pos source_positions =
(case source_positions of p :: _ => p | [] => Position.none);
\<comment>\<open>Lower a uRust identifier in \<open>kind\<close>-position to HOL. After AST
flattening of paths into \<^verbatim>\<open>_urust_identifier_id\<close>, plain identifiers
and path identifiers (\<open>foo::bar\<close>) arrive uniformly as
\<^verbatim>\<open>Free name\<close> (possibly \<open>_constrain\<close>-wrapped with a source position).
For paths the name simply contains \<open>::\<close> separators; downstream
consumers only look at the name string, so no shape match is needed.
We ALWAYS emit a \<^verbatim>\<open>urust_dispatch\<close> marker carrying the original
\<open>arg\<close> as a witness. HOL elaboration resolves the witness through
normal binding, and the term_check phase uses witness precedence:
a \<^verbatim>\<open>Bound\<close> witness (a \<lambda>-binder of the same name) wins over any
table registration; a \<^verbatim>\<open>Free\<close> or \<^verbatim>\<open>Const\<close> witness defers to the
table, falling back to itself on miss. This is what stops a
registered \<open>("mask")\<close> from hijacking a \<open>\<lambda>mask. \<dots> mask \<dots>\<close> use site.
Path identifiers (\<open>Foo::Bar\<close>) cannot be HOL binders, so the witness
elaborates to a \<^verbatim>\<open>Free\<close> with a \<open>::\<close>-containing name; the table
lookup proceeds exactly as for plain ids.\<close>
fun lookup_id_tr kind ctxt [arg] =
(case Term_Position.strip_positions arg of
Free (name, _) =>
\<comment>\<open>Only emit a marker when the table actually has a registration
for this \<open>(kind, name)\<close>. If there is none, return the bare
\<open>arg\<close> --- otherwise we'd disrupt downstream constructions
like \<open>_abs\<close> binders that expect the binder slot to be a
recognisable \<open>Free\<close>/\<open>_constrain\<close>-wrapped shape, not a
\<open>urust_dispatch\<close> application.\<close>
(case Micro_Rust_Names.lookups ctxt kind name of
[] => arg
| _ =>
\<comment>\<open>Markup emission is deferred to \<open>Micro_Rust_Dispatch.resolve\<close>:
we emit the use-site markup ONLY when a marker is
actually replaced by a registered backend, never
when the witness ends up winning (\<lambda>-binder shadow).\<close>
Micro_Rust_Dispatch.mk_marker kind name
(pick_pos (source_positions_of arg)) arg)
| _ => arg)
| lookup_id_tr _ _ ts = hd ts;
in
[(\<^syntax_const>\<open>_urust_identifier_id\<close>, K hd),
(\<^syntax_const>\<open>_shallow_identifier_as_literal\<close>,
lookup_id_tr Micro_Rust_Names.NLiteral),
(\<^syntax_const>\<open>_shallow_identifier_as_function\<close>,
lookup_id_tr Micro_Rust_Names.NFunction),
(\<^syntax_const>\<open>_shallow_identifier_as_field\<close>,
lookup_id_tr Micro_Rust_Names.NField)]
end
\<close>
\<comment>\<open>Binder-introduction resolver: a let-pattern leaf or other binder slot.
Pure identity --- the identifier IS the binder, so the dispatch table
is never consulted. A registered uRust notation of the same name is
silently shadowed by the let, mirroring Rust's lexical scoping. Runs
at parse-translation time so \<^ML>\<open>Syntax_Trans.abs_tr\<close> sees the bare
\<^verbatim>\<open>Free\<close>/\<open>_constrain\<close> shape it expects.
Match-arm constructor heads do NOT use this resolver --- they keep
routing through the value-position \<open>_shallow_identifier_as_literal\<close>
so the term_check phase can resolve registered names AFTER type
inference (necessary for value-position match arms like
\<open>match x { number::three => \<dots> }\<close> where the registration target is a
non-constructor constant).\<close>
parse_translation\<open>
[(\<^syntax_const>\<open>_shallow_pattern_id\<close>, fn _ => hd)]
\<close>
ML\<open>
fun known_constructor_name ctxt name =
let
val full = Proof_Context.intern_const ctxt name
val thy = Proof_Context.theory_of ctxt
in
if can (Sign.the_const_type thy) full andalso Code.is_constr thy full
then SOME full
else NONE
end;
\<comment>\<open>Resolve a constructor identifier \<open>id\<close> to its fully-qualified
\<^verbatim>\<open>Const\<close>. We must preserve the original \<^verbatim>\<open>_constrain $ _ $ <pos\<close>
wrapper so the decoder's namespace markup ends up at the user's
source token --- otherwise pattern heads like \<open>Some\<close> in
\<open>match x { Some(y) => \<dots> }\<close> or \<open>if let Some(y) = \<dots>\<close> have no
clickable entity ref attached.\<close>
fun preserve_position id new_inner =
(case id of
Const (\<^syntax_const>\<open>_constrain\<close>, T) $ _ $ pos_enc =>
Const (\<^syntax_const>\<open>_constrain\<close>, T) $ new_inner $ pos_enc
| _ => new_inner);
fun resolve_constructor_id ctxt id =
(case Term_Position.strip_positions id of
t as Const _ => SOME (preserve_position id t)
| Free (name, _) =>
Option.map (fn n => preserve_position id (Syntax.const n))
(known_constructor_name ctxt name)
| _ => NONE);
fun dest_ident_name ctxt t =
(case Term_Position.strip_positions t of
Free (name, _) => name
| Const (name, _) => name
| _ => error ("invalid identifier term: " ^ Syntax.string_of_term ctxt t));
fun canonical_name s = Long_Name.base_name s;
fun name_matches a b = a = b orelse canonical_name a = canonical_name b;
fun term_name_of (Const (name, _)) = SOME name