Source file gen_ocaml_server.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
let lower_module_filename name = String.lowercase_ascii name
let handler_lines types_module command =
match command.Manifest.event with
| None ->
[ Printf.sprintf " val %s :" command.name
; Printf.sprintf " %s.%s ->" types_module command.request
; Printf.sprintf " (%s.%s, Transom_runtime.Error.t) result" types_module command.response
]
| Some event ->
[ Printf.sprintf " val %s :" command.name
; Printf.sprintf " %s.%s ->" types_module command.request
; Printf.sprintf " emit:(%s.%s -> unit) ->" types_module event
; Printf.sprintf " (%s.%s, Transom_runtime.Error.t) result" types_module command.response
]
let handlers_module_type manifest =
[ "module type HANDLERS = sig" ]
@ List.concat_map (handler_lines manifest.Manifest.types_module) manifest.commands
@ [ "end" ]
let dispatch_signature =
[ " val dispatch :"
; " method_:string ->"
; " params:Yojson.Safe.t ->"
; " emit:(Yojson.Safe.t -> unit) ->"
; " (Yojson.Safe.t, Transom_runtime.Error.t) result"
; ""
; " val run_stdio : unit -> unit"
]
let interface manifest =
String.concat
"\n"
(handlers_module_type manifest
@ [ ""
; "module Make (_ : HANDLERS) : sig"
]
@ dispatch_signature
@ [ "end"; "" ])
let response_encode json_module command =
Printf.sprintf
"Yojson.Safe.from_string (%s.string_of_%s res)"
json_module
command.Manifest.response
let request_decode json_module command =
Printf.sprintf
"%s.%s_of_string (Yojson.Safe.to_string params)"
json_module
command.Manifest.request
let event_emit json_module event =
Printf.sprintf
"emit (Yojson.Safe.from_string (%s.string_of_%s ev))"
json_module
event
let branch manifest command =
let json_module = manifest.Manifest.json_module in
let decode = request_decode json_module command in
let encode = response_encode json_module command in
let handler_lines =
match command.Manifest.event with
| None -> [ Printf.sprintf " match H.%s req with" command.name ]
| Some event ->
[ Printf.sprintf " let emit_event ev = %s in" (event_emit json_module event)
; Printf.sprintf " match H.%s req ~emit:emit_event with" command.name
]
in
[ Printf.sprintf " | %S ->" command.name
; " (match"
; " (try Ok"
; Printf.sprintf " (%s)" decode
; " with exn -> Error (bad_request method_ exn))"
; " with"
; " | Error err -> Error err"
; " | Ok req ->"
]
@ handler_lines
@
[ Printf.sprintf " | Ok res -> Ok (%s)" encode
; " | Error err -> Error err)"
]
let implementation manifest =
let branches = List.concat_map (branch manifest) manifest.Manifest.commands in
String.concat
"\n"
(handlers_module_type manifest
@ [ ""
; "module Make (H : HANDLERS) = struct"
; " let bad_request method_ exn ="
; " Transom_runtime.Error.bad_request"
; " (\"Invalid params for \" ^ method_ ^ \": \" ^ Printexc.to_string exn)"
; ""
; " let dispatch ~method_ ~params ~emit ="
; " match method_ with"
]
@ branches
@ [ " | _ -> Error (Transom_runtime.Error.unknown_method method_)"
; ""
; " let run_stdio () = Transom_runtime.run ~dispatch"
; "end"
; ""
])