qsp_parser.ml 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. open StdLabels
  2. module Report = Qsp_syntax.Report
  3. type result = Report.t list [@@deriving show]
  4. (** Filter the results given by the analysis *)
  5. let filter_report : Args.filters -> Report.t list -> Report.t -> Report.t list =
  6. fun filters reports r ->
  7. let is_ok =
  8. match filters.level with
  9. | None -> true
  10. | Some level -> Report.level_to_enum level >= Report.level_to_enum r.level
  11. in
  12. match is_ok with true -> r :: reports | _ -> reports
  13. type ctx = { error_nb : int; warn_nb : int; debug_nb : int }
  14. (*
  15. List all the controls to apply
  16. *)
  17. let _, _, _, e1 = Qsp_syntax.Check.build (module Qsp_syntax.Type_of)
  18. let _, _, _, e2 = Qsp_syntax.Check.build (module Qsp_syntax.Dead_end)
  19. module Check = Qsp_syntax.Check.Make (struct
  20. let t = [| e1; e2 |]
  21. end)
  22. (** Read the source file until getting a report (the whole location has been
  23. read properly), or until the first syntax error.
  24. *)
  25. let parse_location : ctx:ctx -> Qparser.Lexbuf.t -> Args.filters -> ctx =
  26. fun ~ctx lexbuf filters ->
  27. let result =
  28. Qparser.Analyzer.parse (module Check) lexbuf
  29. |> Result.map (fun (_, f) ->
  30. List.fold_left f ~init:[] ~f:(filter_report filters))
  31. in
  32. match result with
  33. | Ok report -> (
  34. (* Display the result *)
  35. match report with
  36. | [] -> ctx
  37. | _ ->
  38. let start_position, _ = Qparser.Lexbuf.positions lexbuf in
  39. Format.fprintf Format.std_formatter "Location@ %s@;@[%a@]@."
  40. start_position.Lexing.pos_fname pp_result report;
  41. List.fold_left report ~init:ctx ~f:(fun ctx report ->
  42. match report.Report.level with
  43. | Error -> { ctx with error_nb = ctx.error_nb + 1 }
  44. | Warn -> { ctx with warn_nb = ctx.warn_nb + 1 }
  45. | Debug -> { ctx with debug_nb = ctx.debug_nb + 1 }))
  46. | Error e ->
  47. let start_position, _ = Qparser.Lexbuf.positions lexbuf in
  48. Format.fprintf Format.std_formatter "Location@ %s@;@[%a]@."
  49. start_position.Lexing.pos_fname Report.pp e;
  50. { ctx with error_nb = ctx.error_nb + 1 }
  51. let default_ctx = { error_nb = 0; warn_nb = 0; debug_nb = 0 }
  52. let () =
  53. let file_names, parameters = Args.parse () in
  54. let file_name = List.hd file_names in
  55. let ic = Stdlib.open_in_bin file_name in
  56. (*let lexer = Lexing.from_channel ~with_positions:true ic in*)
  57. let lexer, parameters =
  58. match Filename.extension file_name with
  59. | ".qsrc" ->
  60. (* The source file are in UTF-8, and we can use the file line number as
  61. we have only a single location. *)
  62. (Sedlexing.Utf8.from_channel ic, { parameters with reset_line = false })
  63. | ".txt" ->
  64. (Sedlexing.Utf16.from_channel ic (Some Little_endian), parameters)
  65. | _ -> raise (Failure "unknown extension")
  66. in
  67. let lexer =
  68. Qparser.Lexbuf.from_lexbuf ~reset_line:parameters.reset_line lexer
  69. in
  70. let ctx = ref default_ctx in
  71. let () =
  72. try
  73. while true do
  74. ctx := parse_location ~ctx:!ctx lexer parameters.filters
  75. done
  76. with Qparser.Lexer.EOF -> ()
  77. in
  78. let () =
  79. match (!ctx.error_nb, !ctx.warn_nb) with
  80. | 0, 0 -> print_endline "No errors found"
  81. | _ ->
  82. Printf.printf "Found %d error(s), %d warning(s)\n" !ctx.error_nb
  83. !ctx.warn_nb
  84. in
  85. let () =
  86. match parameters.interractive with
  87. | true ->
  88. print_endline "Press <Enter> to terminate";
  89. ignore @@ read_line ()
  90. | _ -> ()
  91. in
  92. ()