Source file clerk_scan.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
open Catala_utils
module L = Surface.Lexer_common
type item = {
file_name : File.t;
module_def : string Mark.pos option;
extrnal : bool;
used_modules : string Mark.pos list;
included_files : File.t Mark.pos list;
has_inline_tests : bool;
has_scope_tests : bool Lazy.t;
}
let catala_suffix_regex =
Re.(compile (seq [str ".catala_"; group (seq [alpha; alpha]); eos]))
let test_command_args =
let open Re in
let re =
compile
@@ seq
[
bos;
char '$';
rep space;
str "catala";
rep space;
group (rep1 notnl);
char '\n';
]
in
fun str ->
exec_opt re str |> Option.map (fun g -> String.trim (Re.Group.get g 1))
let get_lang file =
Option.bind (Re.exec_opt catala_suffix_regex file)
@@ fun g -> List.assoc_opt (Re.Group.get g 1) Catala_utils.Cli.languages
let rec find_test_scope ~lang file =
let lang = Option.value (get_lang file) ~default:lang in
let rec scan lines =
match Seq.uncons lines with
| Some ((_, L.LINE_TEST_ATTRIBUTE, _), _) -> true
| Some ((_, L.LINE_INCLUDE f, _), lines) ->
let f = if Filename.is_relative f then File.(file /../ f) else f in
scan lines || find_test_scope ~lang f
| Some (_, lines) -> scan lines
| None -> false
in
scan (Surface.Parser_driver.lines file lang)
let catala_file (file : File.t) (lang : Catala_utils.Global.backend_lang) : item
=
let rec parse
(lines :
(string * L.line_token * (Lexing.position * Lexing.position)) Seq.t)
n
acc =
match Seq.uncons lines with
| None -> acc
| Some ((_, line, lpos), lines) -> (
let pos = Pos.from_lpos lpos in
parse lines (n + 1)
@@
match line with
| L.LINE_INCLUDE f ->
let f = if Filename.is_relative f then File.(file /../ f) else f in
{ acc with included_files = Mark.add pos f :: acc.included_files }
| L.LINE_MODULE_DEF (m, extrnal) ->
{ acc with module_def = Some (Mark.add pos m); extrnal }
| L.LINE_MODULE_USE m ->
{ acc with used_modules = Mark.add pos m :: acc.used_modules }
| L.LINE_INLINE_TEST -> { acc with has_inline_tests = true }
| L.LINE_TEST_ATTRIBUTE -> { acc with has_scope_tests = lazy true }
| _ -> acc)
in
let item =
parse
(Surface.Parser_driver.lines file lang)
1
{
file_name = file;
module_def = None;
extrnal = false;
used_modules = [];
included_files = [];
has_inline_tests = false;
has_scope_tests = lazy false;
}
in
let has_scope_tests =
lazy
(
Lazy.force item.has_scope_tests
|| List.exists
(fun l -> find_test_scope ~lang (Mark.remove l))
item.included_files)
in
{ item with has_scope_tests }
let tree (dir : File.t) : (File.t * File.t list * item list) Seq.t =
File.scan_tree
(fun f ->
match get_lang f with
| None -> None
| Some lang -> Some (catala_file f lang))
dir
let target_file_name t =
let open File in
let dir =
if Filename.is_relative t.file_name then File.dirname t.file_name
else "libcatala"
in
match t.module_def with
| Some m -> dir / String.to_id (Mark.remove m)
| None -> dir / String.to_id (basename t.file_name -.- "")