-
Notifications
You must be signed in to change notification settings - Fork 8
/
mcp.ml
139 lines (118 loc) · 5.04 KB
/
mcp.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
open Util
open Core
open Parser
open Syntax
open Value
open Norm
open Asai.Range
let () = Arity.install ()
(* The current context of assumptions, including names. *)
type ctx = Ctx : ('n, 'b) Ctx.t * (string option, 'n) Bwv.t -> ctx
let ectx = Ctx (Ctx.empty, Emp)
let context = ref ectx
(* Functions to synth and check terms *)
let parse_term : type n. (string option, n) Bwv.t -> string -> n Raw.check located =
fun names tm ->
let p = Parse.Term.parse (`String { content = tm; title = Some "user-supplied term" }) in
let (Term tm) = Parse.Term.final p in
Postprocess.process names tm
module Terminal = Asai.Tty.Make (Core.Reporter.Code)
let synth (tm : string) : kinetic value * kinetic value =
let (Ctx (ctx, names)) = !context in
Reporter.run ~emit:Terminal.display ~fatal:(fun d ->
Terminal.display d;
raise (Failure "Failed to synthesize"))
@@ fun () ->
match parse_term names tm with
| { value = Synth raw; loc } ->
let syn, ty = Check.synth (Kinetic `Nolet) ctx { value = raw; loc } in
let esyn = eval_term (Ctx.env ctx) syn in
(esyn, ty)
| _ -> Reporter.fatal (Nonsynthesizing "toplevel synth")
let check (tm : string) (ty : kinetic value) : kinetic value =
let (Ctx (ctx, names)) = !context in
Reporter.run ~emit:Terminal.display ~fatal:(fun d ->
Terminal.display d;
raise (Failure "Failed to check"))
@@ fun () -> eval_term (Ctx.env ctx) (Check.check (Kinetic `Nolet) ctx (parse_term names tm) ty)
(* Assert that a term *doesn't* synthesize or check, and possibly ensure it gives a specific error code. *)
let unsynth : ?print:unit -> ?code:Reporter.Code.t -> ?short:string -> string -> unit =
fun ?print ?code ?short tm ->
let (Ctx (ctx, names)) = !context in
Reporter.try_with ~fatal:(fun d ->
match code with
| None -> (
match short with
| None -> if Option.is_some print then Terminal.display d
| Some str ->
if Reporter.Code.short_code d.message = str then (
if Option.is_some print then Terminal.display d)
else (
Terminal.display d;
raise (Failure "Unexpected error code")))
| Some c ->
if d.message = c then (if Option.is_some print then Terminal.display d)
else (
Terminal.display d;
raise (Failure "Unexpected error code")))
@@ fun () ->
match parse_term names tm with
| { value = Synth raw; loc } ->
let _ = Check.synth (Kinetic `Nolet) ctx { value = raw; loc } in
raise (Failure "Synthesis success")
| _ -> Reporter.fatal (Nonsynthesizing "top-level unsynth")
let uncheck :
?print:unit -> ?code:Reporter.Code.t -> ?short:string -> string -> kinetic value -> unit =
fun ?print ?code ?short tm ty ->
let (Ctx (ctx, names)) = !context in
Reporter.try_with ~fatal:(fun d ->
match code with
| None -> (
match short with
| None -> if Option.is_some print then Terminal.display d
| Some str ->
if Reporter.Code.short_code d.message = str then (
if Option.is_some print then Terminal.display d)
else (
Terminal.display d;
raise (Failure "Unexpected error code")))
| Some c ->
if d.message = c then (if Option.is_some print then Terminal.display d)
else (
Terminal.display d;
raise (Failure "Unexpected error code")))
@@ fun () ->
let _ = Check.check (Kinetic `Nolet) ctx (parse_term names tm) ty in
raise (Failure "Checking success")
(* Assert that a term doesn't parse *)
let unparse : ?print:unit -> string -> unit =
fun ?print tm ->
let (Ctx (_, names)) = !context in
Reporter.try_with
~fatal:(fun d -> if Option.is_some print then Terminal.display d)
(fun () ->
let _ = parse_term names tm in
raise (Failure "Unexpected parse success"))
(* Add to the context of assumptions *)
let assume (x : string) (ty : kinetic value) : kinetic value =
let (Ctx (ctx, names)) = !context in
context := Ctx (Ctx.ext ctx (Some x) ty, Bwv.snoc names (Some x));
fst (synth x)
(* Check that two terms are, or aren't, equal, at a type or synthesizing *)
let equal_at (tm1 : kinetic value) (tm2 : kinetic value) (ty : kinetic value) : unit =
let (Ctx (ctx, _)) = !context in
if Option.is_some (Equal.equal_at (Ctx.length ctx) tm1 tm2 ty) then ()
else raise (Failure "Unequal terms")
let unequal_at (tm1 : kinetic value) (tm2 : kinetic value) (ty : kinetic value) : unit =
let (Ctx (ctx, _)) = !context in
if Option.is_none (Equal.equal_at (Ctx.length ctx) tm1 tm2 ty) then ()
else raise (Failure "Equal terms")
let equal (tm1 : kinetic value) (tm2 : kinetic value) : unit =
let (Ctx (ctx, _)) = !context in
if Option.is_some (Equal.equal_val (Ctx.length ctx) tm1 tm2) then ()
else raise (Failure "Unequal terms")
let unequal (tm1 : kinetic value) (tm2 : kinetic value) : unit =
let (Ctx (ctx, _)) = !context in
if Option.is_none (Equal.equal_val (Ctx.length ctx) tm1 tm2) then ()
else raise (Failure "Equal terms")
let run f = Repl.run f