check.ml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. (** This module provide a way to create new Id dynamically in the runtime,
  2. and some fonctions for comparing them. *)
  3. module Id : sig
  4. type 'a typeid
  5. (** The type created on-the-fly. *)
  6. val newtype : unit -> 'a typeid
  7. (** Create a new instance of a dynamic type *)
  8. type ('a, 'b) eq = Eq : ('a, 'a) eq
  9. val try_cast : 'a typeid -> 'b typeid -> ('a, 'b) eq option
  10. (** Compare two types using the Eq pattern *)
  11. end = struct
  12. type 'a witness = ..
  13. module type Witness = sig
  14. type t
  15. type _ witness += Id : t witness
  16. end
  17. type 'a typeid = (module Witness with type t = 'a)
  18. type ('a, 'b) eq = Eq : ('a, 'a) eq
  19. let try_cast : type a b. a typeid -> b typeid -> (a, b) eq option =
  20. fun x y ->
  21. let module X : Witness with type t = a = (val x) in
  22. let module Y : Witness with type t = b = (val y) in
  23. match X.Id with Y.Id -> Some Eq | _ -> None
  24. let newtype (type u) () =
  25. (* The extensible type need to be extended in a module, it is not possible
  26. to declare a type in a function. That’s why we need to pack a module
  27. here *)
  28. let module Witness = struct
  29. type t = u
  30. type _ witness += Id : t witness
  31. end in
  32. (module Witness : Witness with type t = u)
  33. end
  34. (** The the Id module, wrap a value in an existencial type with a witness
  35. associate with. *)
  36. type result = R : { value : 'a; witness : 'a Id.typeid } -> result
  37. let get : type a. a Id.typeid -> result -> a option =
  38. fun typeid (R { value; witness }) ->
  39. match Id.try_cast typeid witness with Some Eq -> Some value | None -> None
  40. type t =
  41. | E : {
  42. module_ :
  43. (module S.Analyzer
  44. with type Expression.t = 'a
  45. and type Expression.t' = 'b
  46. and type Instruction.t = 'c
  47. and type Instruction.t' = 'd
  48. and type Location.t = 'e);
  49. expr_witness : 'a Id.typeid;
  50. expr' : 'b Id.typeid;
  51. instr_witness : 'c Id.typeid;
  52. instr' : 'd Id.typeid;
  53. location_witness : 'e Id.typeid;
  54. }
  55. -> t
  56. let build :
  57. (module S.Analyzer
  58. with type Expression.t = _
  59. and type Expression.t' = _
  60. and type Instruction.t = _
  61. and type Instruction.t' = _
  62. and type Location.t = 'a) ->
  63. 'a Id.typeid * t =
  64. fun module_ ->
  65. let expr_witness = Id.newtype ()
  66. and expr' = Id.newtype ()
  67. and instr_witness = Id.newtype ()
  68. and instr' = Id.newtype ()
  69. and location_witness = Id.newtype () in
  70. let t =
  71. E { module_; expr_witness; expr'; instr_witness; instr'; location_witness }
  72. in
  73. (location_witness, t)
  74. let get_module : t -> (module S.Analyzer) =
  75. fun (E { module_; _ }) -> (module_ :> (module S.Analyzer))
  76. module type App = sig
  77. val t : t array
  78. end
  79. open StdLabels
  80. module Helper = struct
  81. type 'a expr_list = { witness : 'a Id.typeid; values : 'a list }
  82. let expr_i : result array list -> 'a Id.typeid -> int -> 'a expr_list =
  83. fun args witness i ->
  84. let result =
  85. List.fold_left args ~init:{ values = []; witness }
  86. ~f:(fun (type a) ({ values; witness } : a expr_list) t : a expr_list ->
  87. match get witness (Array.get t i) with
  88. | None -> failwith "Does not match"
  89. | Some value_1 -> { values = value_1 :: values; witness })
  90. in
  91. { result with values = result.values }
  92. end
  93. module Make (A : App) = struct
  94. let identifier = "main_checker"
  95. let description = "Internal module"
  96. let active = ref false
  97. (* Global variable for the whole module *)
  98. let len = Array.length A.t
  99. module Expression : S.Expression with type t' = result array = struct
  100. type t = result array
  101. type t' = result array
  102. let literal : S.pos -> t T.literal list -> t =
  103. fun pos values ->
  104. Array.mapi A.t ~f:(fun i (E { module_ = (module S); expr_witness; _ }) ->
  105. (* Map every values to the Checker *)
  106. let values' =
  107. List.map values
  108. ~f:
  109. (T.map_litteral ~f:(fun expr ->
  110. match get expr_witness (Array.get expr i) with
  111. | None -> failwith "Does not match"
  112. | Some value -> value))
  113. in
  114. let value = S.Expression.literal pos values' in
  115. R { value; witness = expr_witness })
  116. let integer : S.pos -> string -> t =
  117. fun pos value ->
  118. Array.map A.t ~f:(fun (E { module_ = (module S); expr_witness; _ }) ->
  119. let value = S.Expression.integer pos value in
  120. R { value; witness = expr_witness })
  121. (** Unary operator like [-123] or [+'Text']*)
  122. let uoperator : S.pos -> T.uoperator -> t -> t =
  123. fun pos op values ->
  124. (* Evaluate the nested expression *)
  125. let results = values in
  126. (* Now evaluate the remaining expression.
  127. Traverse both the module the apply, and the matching expression already
  128. evaluated.
  129. It’s easer to use [map] and declare [report] as reference instead of
  130. [fold_left2] and accumulate the report inside the closure, because I
  131. don’t manage the order of the results.
  132. *)
  133. let results =
  134. Array.map2 A.t results
  135. ~f:(fun (E { module_ = (module S); expr_witness; _ }) value ->
  136. match get expr_witness value with
  137. | None -> failwith "Does not match"
  138. | Some value ->
  139. (* Evaluate the single expression *)
  140. let value = S.Expression.uoperator pos op value in
  141. R { witness = expr_witness; value })
  142. in
  143. results
  144. (** Basically the same as uoperator, but operate over two operands instead
  145. of a single one. *)
  146. let boperator : S.pos -> T.boperator -> t -> t -> t =
  147. fun pos op expr1 expr2 ->
  148. Array.init len ~f:(fun i ->
  149. let (E { module_ = (module S); expr_witness; _ }) = Array.get A.t i in
  150. match
  151. ( get expr_witness (Array.get expr1 i),
  152. get expr_witness (Array.get expr2 i) )
  153. with
  154. | Some value_1, Some value_2 ->
  155. let value = S.Expression.boperator pos op value_1 value_2 in
  156. R { witness = expr_witness; value }
  157. | _ -> failwith "Does not match")
  158. (** Call a function. The functions list is hardcoded in lib/lexer.mll *)
  159. let function_ : S.pos -> T.function_ -> t list -> t =
  160. fun pos func args ->
  161. Array.init len ~f:(fun i ->
  162. let (E { module_ = (module S); expr_witness; _ }) = Array.get A.t i in
  163. (* Extract the arguments for each module *)
  164. let args_i = List.rev (Helper.expr_i args expr_witness i).values in
  165. let value = S.Expression.function_ pos func args_i in
  166. R { witness = expr_witness; value })
  167. let ident : (S.pos, t) S.variable -> t =
  168. fun { pos : S.pos; name : string; index : t option } ->
  169. Array.init len ~f:(fun i ->
  170. let (E { module_ = (module S); expr_witness; _ }) = Array.get A.t i in
  171. match index with
  172. | None ->
  173. (* Easest case, just return the plain ident *)
  174. let value = S.Expression.ident { pos; name; index = None } in
  175. R { witness = expr_witness; value }
  176. | Some t -> (
  177. match get expr_witness (Array.get t i) with
  178. | None -> failwith "Does not match"
  179. | Some value_1 ->
  180. let value =
  181. S.Expression.ident { pos; name; index = Some value_1 }
  182. in
  183. R { witness = expr_witness; value }))
  184. (** Convert each internal represention for the expression into its external
  185. representation *)
  186. let v : t -> t' =
  187. fun t ->
  188. let result =
  189. Array.map2 A.t t
  190. ~f:(fun (E { module_ = (module S); expr_witness; expr'; _ }) result ->
  191. match get expr_witness result with
  192. | None -> failwith "Does not match"
  193. | Some value ->
  194. let value = S.Expression.v value in
  195. R { witness = expr'; value })
  196. in
  197. result
  198. end
  199. module Instruction :
  200. S.Instruction
  201. with type expression = Expression.t'
  202. and type t' = result array = struct
  203. type expression = Expression.t'
  204. type t = result array
  205. type t' = result array
  206. let location : S.pos -> string -> t =
  207. fun pos label ->
  208. Array.map A.t ~f:(fun (E { module_ = (module S); instr_witness; _ }) ->
  209. let value = S.Instruction.location pos label in
  210. R { value; witness = instr_witness })
  211. let comment : S.pos -> t =
  212. fun pos ->
  213. Array.map A.t ~f:(fun (E { module_ = (module S); instr_witness; _ }) ->
  214. let value = S.Instruction.comment pos in
  215. R { value; witness = instr_witness })
  216. let expression : expression -> t =
  217. fun expr ->
  218. Array.map2 A.t expr
  219. ~f:(fun (E { module_ = (module S); instr_witness; expr'; _ }) result ->
  220. match get expr' result with
  221. | None -> failwith "Does not match"
  222. | Some value ->
  223. (* The evaluate the instruction *)
  224. let value = S.Instruction.expression value in
  225. R { value; witness = instr_witness })
  226. let call : S.pos -> T.keywords -> expression list -> t =
  227. fun pos keyword args ->
  228. (* The arguments are given like an array of array. Each expression is
  229. actually the list of each expression in the differents modules. *)
  230. Array.init len ~f:(fun i ->
  231. let (E { module_ = (module S); expr'; instr_witness; _ }) =
  232. Array.get A.t i
  233. in
  234. let values = List.rev (Helper.expr_i args expr' i).values in
  235. let value = S.Instruction.call pos keyword values in
  236. R { witness = instr_witness; value })
  237. let act : S.pos -> label:expression -> t list -> t =
  238. fun pos ~label instructions ->
  239. Array.init len ~f:(fun i ->
  240. let (E { module_ = (module S); instr_witness; expr'; _ }) =
  241. Array.get A.t i
  242. in
  243. let values =
  244. List.rev (Helper.expr_i instructions instr_witness i).values
  245. in
  246. match get expr' (Array.get label i) with
  247. | None -> failwith "Does not match"
  248. | Some label_i ->
  249. let value = S.Instruction.act pos ~label:label_i values in
  250. R { witness = instr_witness; value })
  251. (* I think it’s one of the longest module I’ve ever written in OCaml… *)
  252. let assign :
  253. S.pos ->
  254. (S.pos, expression) S.variable ->
  255. T.assignation_operator ->
  256. expression ->
  257. t =
  258. fun pos { pos = var_pos; name; index } op expression ->
  259. Array.init len ~f:(fun i ->
  260. let (E { module_ = (module A); instr_witness; expr'; _ }) =
  261. Array.get A.t i
  262. in
  263. let index_i =
  264. Option.map
  265. (fun expression ->
  266. match get expr' (Array.get expression i) with
  267. | None -> failwith "Does not match"
  268. | Some value -> value)
  269. index
  270. in
  271. let variable = S.{ pos = var_pos; name; index = index_i } in
  272. match get expr' (Array.get expression i) with
  273. | None -> failwith "Does not match"
  274. | Some value ->
  275. let value = A.Instruction.assign pos variable op value in
  276. R { value; witness = instr_witness })
  277. let rebuild_clause :
  278. type a b.
  279. int ->
  280. a Id.typeid ->
  281. b Id.typeid ->
  282. S.pos * result array * result array list ->
  283. (b, a) S.clause =
  284. fun i instr_witness expr' clause ->
  285. let pos_clause, expr_clause, ts = clause in
  286. match get expr' (Array.get expr_clause i) with
  287. | None -> failwith "Does not match"
  288. | Some value ->
  289. let ts = Helper.expr_i ts instr_witness i in
  290. let ts = List.rev ts.values in
  291. let clause = (pos_clause, value, ts) in
  292. clause
  293. let if_ :
  294. S.pos ->
  295. (expression, t) S.clause ->
  296. elifs:(expression, t) S.clause list ->
  297. else_:(S.pos * t list) option ->
  298. t =
  299. fun pos clause ~elifs ~else_ ->
  300. (* First, apply the report for all the instructions *)
  301. let else_ =
  302. match else_ with
  303. | None -> None
  304. | Some (pos, instructions) -> Some (pos, instructions)
  305. in
  306. Array.init len ~f:(fun i ->
  307. let (E { module_ = (module A); instr_witness; expr'; _ }) =
  308. Array.get A.t i
  309. in
  310. let clause = rebuild_clause i instr_witness expr' clause
  311. and elifs = List.map elifs ~f:(rebuild_clause i instr_witness expr')
  312. and else_ =
  313. match else_ with
  314. | None -> None
  315. | Some (pos, instructions) ->
  316. let elses = Helper.expr_i instructions instr_witness i in
  317. Some (pos, List.rev elses.values)
  318. in
  319. let value = A.Instruction.if_ pos clause ~elifs ~else_ in
  320. R { value; witness = instr_witness })
  321. (** This code is almost a copy/paste from Expression.v but I did not found
  322. a way to factorize it. *)
  323. let v : t -> t' =
  324. fun t ->
  325. let result =
  326. Array.map2 A.t t
  327. ~f:(fun
  328. (E { module_ = (module S); instr_witness; instr'; _ }) result ->
  329. match get instr_witness result with
  330. | None -> failwith "Does not match"
  331. | Some value ->
  332. let value = S.Instruction.v value in
  333. R { witness = instr'; value })
  334. in
  335. result
  336. end
  337. module Location :
  338. S.Location with type t = result array and type instruction = Instruction.t' =
  339. struct
  340. type instruction = Instruction.t'
  341. type t = result array
  342. let location : S.pos -> instruction list -> t =
  343. fun pos args ->
  344. ignore pos;
  345. let result =
  346. Array.init len ~f:(fun i ->
  347. let (E { module_ = (module A); instr'; location_witness; _ }) =
  348. Array.get A.t i
  349. in
  350. let instructions = List.rev (Helper.expr_i args instr' i).values in
  351. let value = A.Location.location pos instructions in
  352. R { value; witness = location_witness })
  353. in
  354. result
  355. let v : t -> Report.t list =
  356. fun args ->
  357. let report = ref [] in
  358. let () =
  359. Array.iteri args ~f:(fun i result ->
  360. let (E { module_ = (module A); location_witness; _ }) =
  361. Array.get A.t i
  362. in
  363. match get location_witness result with
  364. | None -> failwith "Does not match"
  365. | Some value ->
  366. let re = A.Location.v value in
  367. report := List.rev_append re !report)
  368. in
  369. !report
  370. end
  371. end