check.ml 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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. and type context = 'f);
  50. expr_witness : 'a Id.typeid;
  51. expr' : 'b Id.typeid;
  52. instr_witness : 'c Id.typeid;
  53. instr' : 'd Id.typeid;
  54. location_witness : 'e Id.typeid;
  55. context : 'f Id.typeid;
  56. }
  57. -> t
  58. let build :
  59. (module S.Analyzer
  60. with type Expression.t = _
  61. and type Expression.t' = _
  62. and type Instruction.t = _
  63. and type Instruction.t' = _
  64. and type Location.t = 'a
  65. and type context = _) ->
  66. 'a Id.typeid * t =
  67. fun module_ ->
  68. let expr_witness = Id.newtype ()
  69. and expr' = Id.newtype ()
  70. and instr_witness = Id.newtype ()
  71. and instr' = Id.newtype ()
  72. and location_witness = Id.newtype ()
  73. and context = Id.newtype () in
  74. let t =
  75. E
  76. {
  77. module_;
  78. expr_witness;
  79. expr';
  80. instr_witness;
  81. instr';
  82. location_witness;
  83. context;
  84. }
  85. in
  86. (location_witness, t)
  87. let get_module : t -> (module S.Analyzer) =
  88. fun (E { module_; _ }) -> (module_ :> (module S.Analyzer))
  89. module type App = sig
  90. val t : t array
  91. end
  92. open StdLabels
  93. module Helper = struct
  94. type 'a expr_list = { witness : 'a Id.typeid; values : 'a list }
  95. (** Extract a list of statements from the argements.
  96. The function return the list in reverse order.
  97. *)
  98. let expr_i : result array list -> 'a Id.typeid -> int -> 'a expr_list =
  99. fun args witness i ->
  100. let result =
  101. List.fold_left args ~init:{ values = []; witness }
  102. ~f:(fun (type a) ({ values; witness } : a expr_list) t : a expr_list ->
  103. match get witness (Array.get t i) with
  104. | None -> failwith "Does not match"
  105. | Some value_1 -> { values = value_1 :: values; witness })
  106. in
  107. { result with values = result.values }
  108. let variable :
  109. 'a Id.typeid ->
  110. int ->
  111. (S.pos, result array) S.variable ->
  112. (S.pos, 'a) S.variable =
  113. fun typeid i { pos = var_pos; name; index; local } ->
  114. let index_i =
  115. Option.map
  116. (fun expression -> Option.get (get typeid (Array.get expression i)))
  117. index
  118. in
  119. S.{ pos = var_pos; name; index = index_i; local }
  120. end
  121. module Make (A : App) = struct
  122. let identifier = "main_checker"
  123. let description = "Internal module"
  124. let is_global = false
  125. let active = ref false
  126. type context = result Array.t
  127. (** We associate each context from the differents test in an array. The
  128. context for this module is a sort of context of contexts *)
  129. (** Initialize each test, and keep the result in the context. *)
  130. let initialize : unit -> context =
  131. fun () ->
  132. Array.map A.t ~f:(fun (E { module_ = (module S); context; _ }) ->
  133. let value = S.initialize () in
  134. R { value; witness = context })
  135. let finalize : result Array.t -> (string * Report.t) list =
  136. fun context_array ->
  137. let _, report =
  138. Array.fold_left A.t ~init:(0, [])
  139. ~f:(fun (i, acc) (E { module_ = (module S); context; _ }) ->
  140. let result = Array.get context_array i in
  141. let local_context = Option.get (get context result) in
  142. let reports = S.finalize local_context in
  143. (i + 1, List.rev_append reports acc))
  144. in
  145. report
  146. (* Global variable for the whole module *)
  147. let len = Array.length A.t
  148. module Expression : S.Expression with type t' = result array = struct
  149. type t = result array
  150. type t' = result array
  151. let literal : S.pos -> t T.literal list -> t =
  152. fun pos values ->
  153. Array.mapi A.t ~f:(fun i (E { module_ = (module S); expr_witness; _ }) ->
  154. (* Map every values to the Checker *)
  155. let values' =
  156. List.map values
  157. ~f:
  158. (T.map_litteral ~f:(fun expr ->
  159. Option.get (get expr_witness (Array.get expr i))))
  160. in
  161. let value = S.Expression.literal pos values' in
  162. R { value; witness = expr_witness })
  163. let integer : S.pos -> string -> t =
  164. fun pos value ->
  165. Array.map A.t ~f:(fun (E { module_ = (module S); expr_witness; _ }) ->
  166. let value = S.Expression.integer pos value in
  167. R { value; witness = expr_witness })
  168. (** Unary operator like [-123] or [+'Text']*)
  169. let uoperator : S.pos -> T.uoperator -> t -> t =
  170. fun pos op values ->
  171. (* Evaluate the nested expression *)
  172. let results = values in
  173. (* Now evaluate the remaining expression.
  174. Traverse both the module the apply, and the matching expression already
  175. evaluated.
  176. It’s easer to use [map] and declare [report] as reference instead of
  177. [fold_left2] and accumulate the report inside the closure, because I
  178. don’t manage the order of the results.
  179. *)
  180. let results =
  181. Array.map2 A.t results
  182. ~f:(fun (E { module_ = (module S); expr_witness; _ }) value ->
  183. match get expr_witness value with
  184. | None -> failwith "Does not match"
  185. | Some value ->
  186. (* Evaluate the single expression *)
  187. let value = S.Expression.uoperator pos op value in
  188. R { witness = expr_witness; value })
  189. in
  190. results
  191. (** Basically the same as uoperator, but operate over two operands instead
  192. of a single one. *)
  193. let boperator : S.pos -> T.boperator -> t -> t -> t =
  194. fun pos op expr1 expr2 ->
  195. Array.init len ~f:(fun i ->
  196. let (E { module_ = (module S); expr_witness; _ }) = Array.get A.t i in
  197. match
  198. ( get expr_witness (Array.get expr1 i),
  199. get expr_witness (Array.get expr2 i) )
  200. with
  201. | Some value_1, Some value_2 ->
  202. let value = S.Expression.boperator pos op value_1 value_2 in
  203. R { witness = expr_witness; value }
  204. | _ -> failwith "Does not match")
  205. (** Call a function. The functions list is hardcoded in lib/lexer.mll *)
  206. let function_ : S.pos -> T.function_ -> t list -> t =
  207. fun pos func args ->
  208. Array.init len ~f:(fun i ->
  209. let (E { module_ = (module S); expr_witness; _ }) = Array.get A.t i in
  210. (* Extract the arguments for each module *)
  211. let args_i = List.rev (Helper.expr_i args expr_witness i).values in
  212. let value = S.Expression.function_ pos func args_i in
  213. R { witness = expr_witness; value })
  214. let ident : (S.pos, t) S.variable -> t =
  215. fun { pos : S.pos; name : string; index : t option; local } ->
  216. Array.init len ~f:(fun i ->
  217. let (E { module_ = (module S); expr_witness; _ }) = Array.get A.t i in
  218. match index with
  219. | None ->
  220. (* Easest case, just return the plain ident *)
  221. let value =
  222. S.Expression.ident { pos; name; index = None; local }
  223. in
  224. R { witness = expr_witness; value }
  225. | Some t -> (
  226. match get expr_witness (Array.get t i) with
  227. | None -> failwith "Does not match"
  228. | Some value_1 ->
  229. let value =
  230. S.Expression.ident
  231. { pos; name; index = Some value_1; local }
  232. in
  233. R { witness = expr_witness; value }))
  234. (** Convert each internal represention for the expression into its external
  235. representation *)
  236. let v : t -> t' =
  237. fun t ->
  238. let result =
  239. Array.map2 A.t t
  240. ~f:(fun (E { module_ = (module S); expr_witness; expr'; _ }) result ->
  241. match get expr_witness result with
  242. | None -> failwith "Does not match"
  243. | Some value ->
  244. let value = S.Expression.v value in
  245. R { witness = expr'; value })
  246. in
  247. result
  248. end
  249. module Instruction :
  250. S.Instruction
  251. with type expression = Expression.t'
  252. and type t' = result array = struct
  253. type expression = Expression.t'
  254. type t = result array
  255. type t' = result array
  256. let location : S.pos -> string -> t =
  257. fun pos label ->
  258. Array.map A.t ~f:(fun (E { module_ = (module S); instr_witness; _ }) ->
  259. let value = S.Instruction.location pos label in
  260. R { value; witness = instr_witness })
  261. let comment : S.pos -> t =
  262. fun pos ->
  263. Array.map A.t ~f:(fun (E { module_ = (module S); instr_witness; _ }) ->
  264. let value = S.Instruction.comment pos in
  265. R { value; witness = instr_witness })
  266. let expression : expression -> t =
  267. fun expr ->
  268. Array.map2 A.t expr
  269. ~f:(fun (E { module_ = (module S); instr_witness; expr'; _ }) result ->
  270. match get expr' result with
  271. | None -> failwith "Does not match"
  272. | Some value ->
  273. (* The evaluate the instruction *)
  274. let value = S.Instruction.expression value in
  275. R { value; witness = instr_witness })
  276. let call : S.pos -> T.keywords -> expression list -> t =
  277. fun pos keyword args ->
  278. (* The arguments are given like an array of array. Each expression is
  279. actually the list of each expression in the differents modules. *)
  280. Array.init len ~f:(fun i ->
  281. let (E { module_ = (module S); expr'; instr_witness; _ }) =
  282. Array.get A.t i
  283. in
  284. let values = List.rev (Helper.expr_i args expr' i).values in
  285. let value = S.Instruction.call pos keyword values in
  286. R { witness = instr_witness; value })
  287. let act : S.pos -> label:expression -> t list -> t =
  288. fun pos ~label instructions ->
  289. Array.init len ~f:(fun i ->
  290. let (E { module_ = (module S); instr_witness; expr'; _ }) =
  291. Array.get A.t i
  292. in
  293. let values =
  294. List.rev (Helper.expr_i instructions instr_witness i).values
  295. in
  296. match get expr' (Array.get label i) with
  297. | None -> failwith "Does not match"
  298. | Some label_i ->
  299. let value = S.Instruction.act pos ~label:label_i values in
  300. R { witness = instr_witness; value })
  301. (* I think it’s one of the longest module I’ve ever written in OCaml… *)
  302. let assign :
  303. S.pos ->
  304. (S.pos, expression) S.variable ->
  305. T.assignation_operator ->
  306. expression ->
  307. t =
  308. fun pos variable op expression ->
  309. Array.init len ~f:(fun i ->
  310. let (E { module_ = (module A); instr_witness; expr'; _ }) =
  311. Array.get A.t i
  312. in
  313. let variable = Helper.variable expr' i variable in
  314. match get expr' (Array.get expression i) with
  315. | None -> failwith "Does not match"
  316. | Some value ->
  317. let value = A.Instruction.assign pos variable op value in
  318. R { value; witness = instr_witness })
  319. let rebuild_clause :
  320. type a b.
  321. int ->
  322. a Id.typeid ->
  323. b Id.typeid ->
  324. S.pos * result array * result array list ->
  325. (b, a) S.clause =
  326. fun i instr_witness expr' clause ->
  327. let pos_clause, expr_clause, ts = clause in
  328. match get expr' (Array.get expr_clause i) with
  329. | None -> failwith "Does not match"
  330. | Some value ->
  331. let ts = Helper.expr_i ts instr_witness i in
  332. let ts = List.rev ts.values in
  333. let clause = (pos_clause, value, ts) in
  334. clause
  335. let if_ :
  336. S.pos ->
  337. (expression, t) S.clause ->
  338. elifs:(expression, t) S.clause list ->
  339. else_:(S.pos * t list) option ->
  340. t =
  341. fun pos clause ~elifs ~else_ ->
  342. (* First, apply the report for all the instructions *)
  343. let else_ =
  344. match else_ with
  345. | None -> None
  346. | Some (pos, instructions) -> Some (pos, instructions)
  347. in
  348. Array.init len ~f:(fun i ->
  349. let (E { module_ = (module A); instr_witness; expr'; _ }) =
  350. Array.get A.t i
  351. in
  352. let clause = rebuild_clause i instr_witness expr' clause
  353. and elifs = List.map elifs ~f:(rebuild_clause i instr_witness expr')
  354. and else_ =
  355. match else_ with
  356. | None -> None
  357. | Some (pos, instructions) ->
  358. let elses = Helper.expr_i instructions instr_witness i in
  359. Some (pos, List.rev elses.values)
  360. in
  361. let value = A.Instruction.if_ pos clause ~elifs ~else_ in
  362. R { value; witness = instr_witness })
  363. let for_ :
  364. S.pos ->
  365. (S.pos, expression) S.variable ->
  366. start:expression ->
  367. to_:expression ->
  368. step:expression option ->
  369. t list ->
  370. t =
  371. fun loc variable ~start ~to_ ~step statements ->
  372. Array.init len ~f:(fun i ->
  373. let (E { module_ = (module A); expr'; instr_witness; _ }) =
  374. Array.get A.t i
  375. in
  376. let start = Option.get @@ get expr' (Array.get start i)
  377. and to_ = Option.get @@ get expr' (Array.get to_ i)
  378. and step = Option.bind step (fun v -> get expr' (Array.get v i))
  379. and variable' = Helper.variable expr' i variable
  380. and statements' =
  381. List.rev (Helper.expr_i statements instr_witness i).values
  382. in
  383. let value =
  384. A.Instruction.for_ loc variable' ~start ~to_ ~step statements'
  385. in
  386. R { value; witness = instr_witness })
  387. (** This code is almost a copy/paste from Expression.v but I did not found
  388. a way to factorize it. *)
  389. let v : t -> t' =
  390. fun t ->
  391. let result =
  392. Array.map2 A.t t
  393. ~f:(fun
  394. (E { module_ = (module S); instr_witness; instr'; _ }) result ->
  395. match get instr_witness result with
  396. | None -> failwith "Does not match"
  397. | Some value ->
  398. let value = S.Instruction.v value in
  399. R { witness = instr'; value })
  400. in
  401. result
  402. end
  403. module Location :
  404. S.Location
  405. with type t = result array
  406. and type instruction = Instruction.t'
  407. and type context := context = struct
  408. type instruction = Instruction.t'
  409. type t = result array
  410. let location : context -> S.pos -> instruction list -> t =
  411. fun local_context pos args ->
  412. ignore pos;
  413. let result =
  414. Array.init len ~f:(fun i ->
  415. let (E
  416. { module_ = (module A); instr'; location_witness; context; _ })
  417. =
  418. Array.get A.t i
  419. in
  420. let local_context =
  421. Option.get (get context (Array.get local_context i))
  422. in
  423. let instructions = List.rev (Helper.expr_i args instr' i).values in
  424. let value = A.Location.location local_context pos instructions in
  425. R { value; witness = location_witness })
  426. in
  427. result
  428. let v : t -> Report.t list =
  429. fun args ->
  430. let report = ref [] in
  431. let () =
  432. Array.iteri args ~f:(fun i result ->
  433. let (E { module_ = (module A); location_witness; _ }) =
  434. Array.get A.t i
  435. in
  436. match get location_witness result with
  437. | None -> failwith "Does not match"
  438. | Some value ->
  439. let re = A.Location.v value in
  440. report := List.rev_append re !report)
  441. in
  442. !report
  443. end
  444. end