-
Notifications
You must be signed in to change notification settings - Fork 0
/
client_proto_programs.ml
840 lines (806 loc) · 32.2 KB
/
client_proto_programs.ml
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
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2016. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
module Ed25519 = Environment.Ed25519
open Tezos_context
open Error_monad
(*
open Client_proto_args
*)
let report_parse_error _prefix exn _lexbuf =
prerr_endline "reporting parse error";
fail (Exn exn)
(*
let open Lexing in
let open Script_located_ir in
let print_loc ppf (s, e) =
if s.line = e.line then
if s.column = e.column then
Format.fprintf ppf
"at line %d character %d"
s.line s.column
else
Format.fprintf ppf
"at line %d characters %d to %d"
s.line s.column e.column
else
Format.fprintf ppf
"from line %d character %d to line %d character %d"
s.line s.column e.line e.column in
match exn with
| Missing_program_field n ->
failwith "missing script %s" n
| Illegal_character (loc, c) ->
failwith "%a, illegal character %C" print_loc loc c
| Illegal_escape (loc, c) ->
failwith "%a, illegal escape sequence %S" print_loc loc c
| Failure s ->
failwith "%s" s
| exn ->
failwith "%s" @@ Printexc.to_string exn
*)
let print_location_mark ppf = function
| None -> ()
| Some l -> Format.fprintf ppf " /* %d */" l
let no_locations _ = None
let rec print_expr_unwrapped locations ppf = function
| Script.Prim (loc, name, []) ->
begin match locations loc with
| None -> Format.fprintf ppf "%s" name
| Some _ as l -> Format.fprintf ppf "(%s%a)" name print_location_mark l
end
| Script.Prim (loc, name, args) ->
Format.fprintf ppf "@[<hov 2>%s%a@ %a@]"
name print_location_mark (locations loc)
(Format.pp_print_list
~pp_sep: Format.pp_print_space
(print_expr locations))
args
| Script.Seq (loc, []) ->
begin match locations loc with
| None -> Format.fprintf ppf "{}"
| Some _ as l -> Format.fprintf ppf "{%a }" print_location_mark l
end
| Script.Seq (loc, exprs) ->
begin match locations loc with
| None -> Format.fprintf ppf "@[<hv 2>{ "
| Some _ as l -> Format.fprintf ppf "@[<hv 2>{%a@ " print_location_mark l
end ;
Format.fprintf ppf "%a@] }"
(Format.pp_print_list
~pp_sep: (fun ppf () -> Format.fprintf ppf " ;@ ")
(print_expr_unwrapped locations))
exprs
| Script.Int (loc, n) ->
Format.fprintf ppf "%s%a" n print_location_mark (locations loc)
| Script.String (loc, s) ->
Format.fprintf ppf "%S%a" s print_location_mark (locations loc)
and print_expr locations ppf = function
| Script.Prim (_, _, _ :: _) as expr ->
Format.fprintf ppf "(%a)" (print_expr_unwrapped locations) expr
| expr -> print_expr_unwrapped locations ppf expr
let print_storage ppf ({ storage } : Script.storage) =
print_expr no_locations ppf storage
let print_stack ppf = function
| [] -> Format.fprintf ppf "[]"
| more ->
Format.fprintf ppf "@[<hov 2>[ %a ]@]"
(Format.pp_print_list
~pp_sep: (fun ppf () -> Format.fprintf ppf " :@ ")
(print_expr_unwrapped no_locations))
more
let print_typed_code locations ppf (expr, type_map) =
let rec print_typed_code_unwrapped ppf expr =
match expr with
| Script.Prim (loc, name, []) ->
Format.fprintf ppf "%s%a"
name print_location_mark (locations loc)
| Script.Prim (loc, name, args) ->
Format.fprintf ppf "@[<hov 2>%s%a@ %a@]"
name print_location_mark (locations loc)
(Format.pp_print_list
~pp_sep: Format.pp_print_space
print_typed_code)
args
| Script.Seq (loc, []) ->
begin match List.assoc loc type_map with
| exception Not_found -> Format.fprintf ppf "{}"
| (first, _) ->
match locations loc with
| None ->
Format.fprintf ppf "{} /* %a */"
print_stack first
| Some _ as l ->
Format.fprintf ppf "{%a %a }"
print_location_mark l print_stack first
end
| Script.Seq (loc, exprs) ->
begin match locations loc with
| None ->
Format.fprintf ppf "@[<v 2>{ "
| Some _ as l ->
Format.fprintf ppf "@[<v 2>{%a@,"
print_location_mark l
end ;
let rec loop = function
| [] -> assert false
| [ Script.Int (loc, _) | String (loc, _) | Prim (loc, _, _) as expr ] ->
begin match List.assoc loc type_map with
| exception Not_found ->
Format.fprintf ppf "%a }@]"
print_typed_code_unwrapped expr
| (before, after) ->
Format.fprintf ppf "/* %a */@,%a@,/* %a */ }@]"
print_stack before
print_typed_code_unwrapped expr
print_stack after
end ;
| Script.Int (loc, _) | String (loc, _) | Prim (loc, _, _) as expr :: rest ->
begin match List.assoc loc type_map with
| exception Not_found ->
Format.fprintf ppf "%a ;@,"
print_typed_code_unwrapped expr ;
loop rest
| (before, _) ->
Format.fprintf ppf "/* %a */@,%a ;@,"
print_stack before
print_typed_code_unwrapped expr ;
loop rest
end ;
| [ Seq (_, _) as expr ] ->
Format.fprintf ppf "%a }@]"
print_typed_code_unwrapped expr
| Seq (_, _) as expr :: rest ->
Format.fprintf ppf "%a@,"
print_typed_code_unwrapped expr ;
loop rest in
loop exprs ;
| Script.Int (loc, n) ->
Format.fprintf ppf "%s%a" n print_location_mark (locations loc)
| Script.String (loc, s) ->
Format.fprintf ppf "%S%a" s print_location_mark (locations loc)
and print_typed_code ppf = function
| Script.Prim (_, _, _ :: _) as expr ->
Format.fprintf ppf "(%a)" print_typed_code_unwrapped expr
| expr -> print_typed_code_unwrapped ppf expr in
print_typed_code_unwrapped ppf expr
let print_program locations ppf ((c : Script.code), type_map) =
Format.fprintf ppf
"@[<v 0>@[<hov 2>storage@ %a ;@]@,\
@[<hov 2>parameter@ %a ;@]@,\
@[<hov 2>return@ %a ;@]@,\
@[<hov 2>code@ %a@]@]"
(print_expr no_locations) c.storage_type
(print_expr no_locations) c.arg_type
(print_expr no_locations) c.ret_type
(print_typed_code locations) (c.code, type_map)
let collect_error_locations errs =
let open Script_typed_ir in
let open Script_ir_translator in
let open Script_interpreter in
let rec collect acc = function
| (Ill_typed_data (_, _, _)
| Ill_formed_type (_, _)
| Ill_typed_contract (_, _, _, _, _)) :: _
| [] -> acc
| (Invalid_arity (loc, _, _, _)
| Invalid_namespace (loc, _, _, _)
| Invalid_primitive (loc, _, _)
| Invalid_case (loc, _)
| Invalid_kind (loc, _, _)
| Fail_not_in_tail_position loc
| Undefined_binop (loc, _, _, _)
| Undefined_unop (loc, _, _)
| Bad_return (loc, _, _)
| Bad_stack (loc, _, _, _)
| Unmatched_branches (loc, _, _)
| Transfer_in_lambda loc
| Invalid_constant (loc, _, _)
| Invalid_contract (loc, _)
| Comparable_type_expected (loc, _)
| Overflow loc
| Reject loc) :: rest ->
collect (loc :: acc) rest
| _ :: rest -> collect acc rest in
collect [] errs
type ('a, 'b) lwt_format =
('a, Format.formatter, unit, 'b Lwt.t) format4
type context = {
error : 'a 'b. ('a, 'b) lwt_format -> 'a ;
warning : 'a. ('a, unit) lwt_format -> 'a ;
message : 'a. ('a, unit) lwt_format -> 'a ;
answer : 'a. ('a, unit) lwt_format -> 'a ;
log : 'a. string -> ('a, unit) lwt_format -> 'a ;
}
open Error_monad
let report_errors cctxt errs =
(* let open Client_commands in *)
let open Script_typed_ir in
let open Script_ir_translator in
let open Script_interpreter in
let rec print_ty (type t) ppf (ty : t ty) =
let expr = unparse_ty ty in
print_expr no_locations ppf expr in
let rec print_stack_ty (type t) ?(depth = max_int) ppf (s : t stack_ty) =
let rec loop
: type t. int -> Format.formatter -> t stack_ty -> unit
= fun depth ppf -> function
| Empty_t -> ()
| _ when depth <= 0 ->
Format.fprintf ppf "..."
| Item_t (last, Empty_t) ->
Format.fprintf ppf "%a"
print_ty last
| Item_t (last, rest) ->
Format.fprintf ppf "%a :@ %a"
print_ty last (loop (depth - 1)) rest in
match s with
| Empty_t ->
Format.fprintf ppf "[]"
| sty ->
Format.fprintf ppf "@[<hov 2>[ %a ]@]" (loop depth) sty in
let rec print_enumeration ppf = function
| [ single ] ->
Format.fprintf ppf "%a"
Format.pp_print_text single
| [ prev ; last ] ->
Format.fprintf ppf "%a@ or@ %a"
Format.pp_print_text prev Format.pp_print_text last
| first :: rest ->
Format.fprintf ppf "%a,@ %a"
Format.pp_print_text first print_enumeration rest
| [] -> assert false in
let print_error locations err =
let print_loc ppf loc =
match locations loc with
| None ->
Format.fprintf ppf "At (unmarked) location %d, " loc
| Some loc ->
Format.fprintf ppf "At mark /* %d */, " loc in
match err with
| Ill_typed_data (name, expr, ty) ->
cctxt.warning
"@[<hv 0>@[<hov 2>Ill typed %adata:@ %a@]@ \
@[<hov 2>is not an expression of type@ %a@]@]"
(fun ppf -> function
| None -> ()
| Some s -> Format.fprintf ppf "%s " s)
name
(print_expr locations) expr
print_ty ty
| Ill_formed_type (name, expr) ->
cctxt.warning
"@[<hov 2>Ill formed type %aexpression@ %a@]"
(fun ppf -> function
| None -> ()
| Some s -> Format.fprintf ppf "%s " s)
name
(print_expr locations) expr
(*
| Apply.Bad_contract_parameter (c, None, _) ->
cctxt.warning
"@[<v 0>Account %a is not a smart contract, it does not take arguments.@,\
The `-arg' flag cannot be used when transferring to an account.@]"
Contract.pp c
| Apply.Bad_contract_parameter (c, Some expected, None) ->
cctxt.warning
"@[<v 0>Contract %a expected an argument of type@, %a@,but no argument was provided.@,\
The `-arg' flag can be used when transferring to a smart contract.@]"
Contract.pp c
(print_expr_unwrapped no_locations) expected
| Apply.Bad_contract_parameter (c, Some expected, Some argument) ->
cctxt.warning
"@[<v 0>Contract %a expected an argument of type@, %a@but received@, %a@]"
Contract.pp c
(print_expr_unwrapped no_locations) expected
(print_expr_unwrapped no_locations) argument
*)
| Ill_typed_contract (expr, arg_ty, ret_ty, storage_ty, type_map) ->
cctxt.warning
"@[<v 2>Ill typed contract:@ %a@]"
(print_program locations)
({ Script.storage_type = unparse_ty storage_ty ;
arg_type = unparse_ty arg_ty ;
ret_type = unparse_ty ret_ty ;
code = expr }, type_map)
| Runtime_contract_error (contract, expr, arg_ty, ret_ty, storage_ty) ->
cctxt.warning
"@[<v 2>Runtime error in contract %a:@ %a@]"
Contract.pp contract
(print_program locations)
({ Script.storage_type = unparse_ty storage_ty ;
arg_type = unparse_ty arg_ty ;
ret_type = unparse_ty ret_ty ;
code = expr }, [])
| Invalid_arity (loc, name, exp, got) ->
cctxt.warning
"%aprimitive %s expects %d arguments but is given %d."
print_loc loc name exp got
| Invalid_namespace (loc, name, exp, got) ->
let human_namespace = function
| Instr_namespace -> ("an", "instruction")
| Type_namespace -> ("a", "type name")
| Constant_namespace -> ("a", "constant constructor") in
cctxt.warning
"@[%aunexpected %s %s, only@ %s@ %s@ can@ be@ used@ here."
print_loc loc
(snd (human_namespace got))
name
(fst (human_namespace exp)) (snd (human_namespace exp))
| Invalid_primitive (loc, exp, got) ->
cctxt.warning
"@[%ainvalid primitive %s, only@ %a@ can@ be@ used@ here."
print_loc loc
got
print_enumeration exp
| Invalid_case (loc, name) ->
cctxt.warning
"%a%s is not a valid primitive name."
print_loc loc
name
| Invalid_kind (loc, exp, got) ->
let human_kind = function
| Seq_kind -> ("a", "sequence")
| Prim_kind -> ("a", "primitive")
| Int_kind -> ("an", "int")
| String_kind -> ("a", "string") in
cctxt.warning
"@[%aunexpected %s, only@ %a@ can@ be@ used@ here."
print_loc loc
(snd (human_kind got))
print_enumeration
(List.map (fun k -> let (a, n) = human_kind k in a ^ " " ^ n) exp)
| Fail_not_in_tail_position loc ->
cctxt.warning
"%aThe FAIL instruction must appear in a tail position."
print_loc loc
| Undefined_binop (loc, name, tya, tyb) ->
cctxt.warning
"@[<hov 0>@[<hov 2>%aoperator %s is undefined between@ %a@]@ \
@[<hov 2>and@ %a.@]@]"
print_loc loc
name
print_ty tya
print_ty tyb
| Undefined_unop (loc, name, ty) ->
cctxt.warning
"@[<hov 0>@[<hov 2>%aoperator %s is undefined on@ %a@]@]"
print_loc loc
name
print_ty ty
| Bad_return (loc, got, exp) ->
cctxt.warning
"@[<v 2>%awrong stack type at end of body:@,\
- @[<hov>expected return stack type:@ %a,@]@,\
- @[<hov>actual stack type:@ %a.@]@]"
print_loc loc
(fun ppf -> print_stack_ty ppf) (Item_t (exp, Empty_t))
(fun ppf -> print_stack_ty ppf) got
| Bad_stack (loc, name, depth, sty) ->
cctxt.warning
"@[<hov 2>%awrong stack type for instruction %s:@ %a.@]"
print_loc loc name (print_stack_ty ~depth) sty
| Unmatched_branches (loc, sta, stb) ->
cctxt.warning
"@[<v 2>%atwo branches don't end with the same stack type:@,\
- @[<hov>first stack type:@ %a,@]@,\
- @[<hov>other stack type:@ %a.@]@]"
print_loc loc
(fun ppf -> print_stack_ty ppf) sta
(fun ppf -> print_stack_ty ppf) stb
| Transfer_in_lambda loc ->
cctxt.warning
"%aThe TRANSFER_TOKENS instruction cannot appear in a lambda."
print_loc loc
| Bad_stack_length ->
cctxt.warning
"Bad stack length."
| Bad_stack_item lvl ->
cctxt.warning
"Bad stack item %d ."
lvl
| Invalid_constant (loc, got, exp) ->
cctxt.warning
"@[<hov 0>@[<hov 2>%avalue@ %a@]@ \
@[<hov 2>is invalid for type@ %a.@]@]"
print_loc loc
(fun ppf -> print_expr no_locations ppf) got
print_ty exp
| Invalid_contract (loc, contract) ->
cctxt.warning
"%ainvalid contract %a."
print_loc loc Contract.pp contract
| Comparable_type_expected (loc, ty) ->
cctxt.warning "%acomparable type expected."
print_loc loc >>= fun () ->
cctxt.warning "@[<hov 0>@[<hov 2>Type@ %a@]@ is not comparable.@]"
print_ty ty
| Inconsistent_types (tya, tyb) ->
cctxt.warning
"@[<hov 0>@[<hov 2>Type@ %a@]@ \
@[<hov 2>is not compatible with type@ %a.@]@]"
print_ty tya print_ty tyb
| Reject _ -> cctxt.warning "Script reached FAIL instruction"
| Overflow _ -> cctxt.warning "Unexpected arithmetic overflow"
| err -> cctxt.warning "Unknown warning"
(* cctxt.warning "%a"
Local_environment.Environment.Error_monad.pp_print_error [ err ] *) in
let rec print_error_trace locations errs =
let locations = match errs with
| (Ill_typed_data (_, _, _)
| Ill_formed_type (_, _)
| Ill_typed_contract (_, _, _, _, _)
| Runtime_contract_error (_, _, _, _, _)) :: rest ->
let collected =
collect_error_locations rest in
let assoc, _ =
List.fold_left
(fun (acc, i) l ->
if List.mem_assoc l acc then
(acc, i)
else
((l, i) :: acc, i + 1))
([], 1) collected in
(fun l -> try Some (List.assoc l assoc) with Not_found -> None)
| _ -> locations in
match errs with
| [] -> Lwt.return ()
| err :: errs ->
print_error locations err >>= fun () ->
print_error_trace locations errs in
Lwt_list.iter_s
(function
(*
| Ecoproto_error errs ->
print_error_trace no_locations errs *)
| err -> cctxt.warning "%a" pp_print_error [ err ])
errs
type 'a parsed =
{ ast : 'a ;
source : string ;
loc_table : (string * (int * Script_located_ir.location) list) list }
let parse_program source =
let lexbuf = Lexing.from_string source in
try
return
(Concrete_parser.tree Concrete_lexer.(token (init_state ())) lexbuf |> fun fields ->
let rec get_field n = function
| Script_located_ir.Prim (_, pn, [ ctns ]) :: _ when n = pn -> ctns
| _ :: rest -> get_field n rest
| [] -> raise (Script_located_ir.Missing_program_field n) in
let code, code_loc_table =
Script_located_ir.strip_locations (get_field "code" fields) in
let arg_type, parameter_loc_table =
Script_located_ir.strip_locations (get_field "parameter" fields) in
let ret_type, return_loc_table =
Script_located_ir.strip_locations (get_field "return" fields) in
let storage_type, storage_loc_table =
Script_located_ir.strip_locations (get_field "storage" fields) in
let ast = Script.{ code ; arg_type ; ret_type ; storage_type } in
let loc_table =
[ "code", code_loc_table ;
"parameter", parameter_loc_table ;
"return", return_loc_table ;
"storage", storage_loc_table ] in
{ ast ; source ; loc_table })
with
| exn -> report_parse_error "program: " exn lexbuf
let parse_data source =
let lexbuf = Lexing.from_string source in
try
match Concrete_parser.tree Concrete_lexer.(token (init_state ())) lexbuf with
| [node] ->
let ast, loc_table = Script_located_ir.strip_locations node in
let loc_table = [ "data", loc_table ] in
return { ast ; source ; loc_table }
| _ -> failwith "single data expression expected"
with
| exn -> report_parse_error "data: " exn lexbuf
let parse_data_type source =
let lexbuf = Lexing.from_string source in
try
match Concrete_parser.tree Concrete_lexer.(token (init_state ())) lexbuf with
| [node] ->
let ast, loc_table = Script_located_ir.strip_locations node in
let loc_table = [ "data", loc_table ] in
return { ast ; source ; loc_table }
| _ -> failwith "single type expression expected"
with
| exn -> report_parse_error "data_type: " exn lexbuf
let unexpand_macros type_map (program : Script.code) =
let open Script in
let rec caddr type_map acc = function
| [] -> Some (List.rev acc)
| Prim (loc, "CAR" , []) :: rest when List.mem_assoc loc type_map ->
caddr type_map ((loc, "A") :: acc) rest
| Prim (loc, "CDR" , []) :: rest when List.mem_assoc loc type_map ->
caddr type_map ((loc, "D") :: acc) rest
| _ -> None in
let rec unexpand type_map node =
match node with
| Seq (loc, l) ->
begin match caddr type_map [] l with
| None | Some [] ->
let type_map, l =
List.fold_left
(fun (type_map, acc) e ->
let type_map, e = unexpand type_map e in
type_map, e :: acc)
(type_map, [])
l in
type_map, Seq (loc, List.rev l)
| Some l ->
let locs, steps = List.split l in
let name = "C" ^ String.concat "" steps ^ "R" in
let first, last = List.hd locs, List.hd (List.rev locs) in
let (before, _) = List.assoc first type_map in
let (_, after) = List.assoc last type_map in
let type_map =
List.filter
(fun (loc, _) -> not (List.mem loc locs))
type_map in
let type_map = (loc, (before, after)) :: type_map in
type_map, Prim (loc, name, [])
end
| oth -> type_map, oth in
let type_map, code = unexpand type_map program.code in
type_map, { program with code }
(*
module Program = Client_aliases.Alias (struct
type t = Script.code parsed
let encoding =
let open Data_encoding in
let loc_table_encoding =
assoc (list (tup2 uint16 Script_located_ir.location_encoding)) in
conv
(fun { ast ; source ; loc_table } -> (ast, source, loc_table))
(fun (ast, source, loc_table) -> { ast ; source ; loc_table })
(obj3
(req "ast" Script.code_encoding)
(req "source" string)
(req "loc_table" loc_table_encoding))
let of_source _cctxt s = parse_program s
let to_source _ { source } = return source
let name = "program"
end)
*)
(*
let group =
{ Cli_entries.name = "programs" ;
title = "Commands for managing the record of known programs" }
let commands () =
let open Cli_entries in
let show_types = ref false in
let show_types_arg =
"-details",
Arg.Set show_types,
"Show the types of each instruction" in
let emacs_mode = ref false in
let emacs_mode_arg =
"-emacs",
Arg.Set emacs_mode,
"Output in michelson-mode.el compatible format" in
let trace_stack = ref false in
let trace_stack_arg =
"-trace-stack",
Arg.Set trace_stack,
"Show the stack after each step" in
let amount, amount_arg =
Client_proto_args.tez_arg
~name:"-amount"
~desc:"The amount of the transfer in \xEA\x9C\xA9."
~default: "0.00" in
[
command ~group ~desc: "lists all known programs"
(fixed [ "list" ; "known" ; "programs" ])
(fun cctxt ->
Program.load cctxt >>=? fun list ->
Lwt_list.iter_s (fun (n, _) -> cctxt.message "%s" n) list >>= fun () ->
return ()) ;
command ~group ~desc: "remember a program under some name"
(prefixes [ "remember" ; "program" ]
@@ Program.fresh_alias_param
@@ Program.source_param
@@ stop)
(fun name hash cctxt -> Program.add cctxt name hash) ;
command ~group ~desc: "forget a remembered program"
(prefixes [ "forget" ; "program" ]
@@ Program.alias_param
@@ stop)
(fun (name, _) cctxt -> Program.del cctxt name) ;
command ~group ~desc: "display a program"
(prefixes [ "show" ; "known" ; "program" ]
@@ Program.alias_param
@@ stop)
(fun (_, program) cctxt ->
Program.to_source cctxt program >>=? fun source ->
cctxt.message "%s\n" source >>= fun () ->
return ()) ;
command ~group ~desc: "ask the node to run a program"
~args: [ trace_stack_arg ; amount_arg ]
(prefixes [ "run" ; "program" ]
@@ Program.source_param
@@ prefixes [ "on" ; "storage" ]
@@ Cli_entries.param ~name:"storage" ~desc:"the storage data"
(fun _cctxt data -> parse_data data)
@@ prefixes [ "and" ; "input" ]
@@ Cli_entries.param ~name:"storage" ~desc:"the input data"
(fun _cctxt data -> parse_data data)
@@ stop)
(fun program storage input cctxt ->
let open Data_encoding in
let print_errors errs =
report_errors cctxt errs >>= fun () ->
cctxt.error "error running program" >>= fun () ->
return () in
if !trace_stack then
Client_proto_rpcs.Helpers.trace_code cctxt.rpc_config
cctxt.config.block program.ast (storage.ast, input.ast, !amount) >>= function
| Ok (storage, output, trace) ->
cctxt.message
"@[<v 0>@[<v 2>storage@,%a@]@,\
@[<v 2>output@,%a@]@,@[<v 2>trace@,%a@]@]@."
(print_expr no_locations) storage
(print_expr no_locations) output
(Format.pp_print_list
(fun ppf (loc, gas, stack) ->
Format.fprintf ppf
"- @[<v 0>location: %d (remaining gas: %d)@,\
[ @[<v 0>%a ]@]@]"
loc gas
(Format.pp_print_list (print_expr no_locations))
stack))
trace >>= fun () ->
return ()
| Error errs -> print_errors errs
else
Client_proto_rpcs.Helpers.run_code cctxt.rpc_config
cctxt.config.block program.ast (storage.ast, input.ast, !amount) >>= function
| Ok (storage, output) ->
cctxt.message "@[<v 0>@[<v 2>storage@,%a@]@,@[<v 2>output@,%a@]@]@."
(print_expr no_locations) storage
(print_expr no_locations) output >>= fun () ->
return ()
| Error errs ->
print_errors errs);
command ~group ~desc: "ask the node to typecheck a program"
~args: [ show_types_arg ; emacs_mode_arg ]
(prefixes [ "typecheck" ; "program" ]
@@ Program.source_param
@@ stop)
(fun program cctxt ->
let open Data_encoding in
Client_proto_rpcs.Helpers.typecheck_code
cctxt.rpc_config cctxt.config.block program.ast >>= fun res ->
if !emacs_mode then
let emacs_type_map type_map =
(Utils.filter_map
(fun (n, loc) ->
try
let bef, aft = List.assoc n type_map in
Some (loc, bef, aft)
with
Not_found -> None)
(List.assoc "code" program.loc_table),
[]) in
begin match res with
| Ok type_map ->
Lwt.return (emacs_type_map type_map)
| Error errs ->
let msg = Buffer.create 5000 in
let cctxt = Client_commands.make_context
(fun _ t -> Buffer.add_string msg t ; Buffer.add_char msg '\n' ; Lwt.return ()) in
match errs with
| Ecoproto_error (Script_ir_translator.Ill_formed_type
(Some ("return" | "parameter" | "storage" as field), _) :: errs) :: _ ->
report_errors cctxt [ Ecoproto_error errs ] >>= fun () ->
Lwt.return ([], [ List.assoc 0 (List.assoc field program.loc_table), Buffer.contents msg ])
| Ecoproto_error (Script_ir_translator.Ill_typed_contract (_, _, _, _, type_map) :: errs) :: _ ->
(report_errors cctxt [ Ecoproto_error errs ] >>= fun () ->
let (types, _) = emacs_type_map type_map in
let loc = match collect_error_locations errs with
| hd :: _ -> hd
| [] -> 0 in
Lwt.return (types, [ List.assoc loc (List.assoc "code" program.loc_table), Buffer.contents msg ]))
| _ -> Lwt.return ([], [])
end >>= fun (types, errors) ->
cctxt.message
"(@[<v 0>(types . (@[<v 0>%a@]))@,\
(errors . (@[<v 0>%a@])))@]"
(Format.pp_print_list
(fun ppf (({ Script_located_ir.point = s },
{ Script_located_ir.point = e }),
bef, aft) ->
Format.fprintf ppf "(%d %d \"%s\")" (s + 1) (e + 1)
(String.concat "\\n"
(String.split_on_char '\n'
(Format.asprintf "@[<v 0>%a@, \\u2B87@,%a@]"
print_stack bef print_stack aft)))))
types
(Format.pp_print_list
(fun ppf (({ Script_located_ir.point = s },
{ Script_located_ir.point = e }),
err) ->
Format.fprintf ppf "(%d %d %S)" (s + 1) (e + 1) err))
errors >>= fun () ->
return ()
else
match res with
| Ok type_map ->
let type_map, program = unexpand_macros type_map program.ast in
cctxt.message "Well typed" >>= fun () ->
if !show_types then
cctxt.message "%a" (print_program no_locations) (program, type_map) >>= fun () ->
return ()
else return ()
| Error errs ->
report_errors cctxt errs >>= fun () ->
cctxt.error "ill-typed program") ;
command ~group ~desc: "ask the node to typecheck a data expression"
(prefixes [ "typecheck" ; "data" ]
@@ Cli_entries.param ~name:"data" ~desc:"the data to typecheck"
(fun _cctxt data -> parse_data data)
@@ prefixes [ "against" ; "type" ]
@@ Cli_entries.param ~name:"type" ~desc:"the expected type"
(fun _cctxt data -> parse_data data)
@@ stop)
(fun data exp_ty cctxt ->
let open Data_encoding in
Client_proto_rpcs.Helpers.typecheck_data cctxt.Client_commands.rpc_config
cctxt.config.block (data.ast, exp_ty.ast) >>= function
| Ok () ->
cctxt.message "Well typed" >>= fun () ->
return ()
| Error errs ->
report_errors cctxt errs >>= fun () ->
cctxt.error "ill-typed data") ;
command ~group
~desc: "ask the node to compute the hash of a data expression \
using the same algorithm as script instruction H"
(prefixes [ "hash" ; "data" ]
@@ Cli_entries.param ~name:"data" ~desc:"the data to hash"
(fun _cctxt data -> parse_data data)
@@ stop)
(fun data cctxt ->
let open Data_encoding in
Client_proto_rpcs.Helpers.hash_data cctxt.Client_commands.rpc_config
cctxt.config.block (data.ast) >>= function
| Ok hash ->
cctxt.message "%S" hash >>= fun () ->
return ()
| Error errs ->
cctxt.warning "%a" pp_print_error errs >>= fun () ->
cctxt.error "ill-formed data") ;
command ~group
~desc: "ask the node to compute the hash of a data expression \
using the same algorithm as script instruction H, sign it using \
a given secret key, and display it using the format expected by \
script instruction CHECK_SIGNATURE"
(prefixes [ "hash" ; "and" ; "sign" ; "data" ]
@@ Cli_entries.param ~name:"data" ~desc:"the data to hash"
(fun _cctxt data -> parse_data data)
@@ prefixes [ "for" ]
@@ Client_keys.Secret_key.alias_param
@@ stop)
(fun data (_, key) cctxt ->
let open Data_encoding in
Client_proto_rpcs.Helpers.hash_data cctxt.rpc_config
cctxt.config.block (data.ast) >>= function
| Ok hash ->
let signature = Ed25519.sign key (MBytes.of_string hash) in
cctxt.message "Hash: %S@.Signature: %S"
hash
(signature |>
Data_encoding.Binary.to_bytes Ed25519.Signature.encoding |>
Hex_encode.hex_of_bytes) >>= fun () ->
return ()
| Error errs ->
cctxt.warning "%a" pp_print_error errs >>= fun () ->
cctxt.error "ill-formed data") ;
]
*)