Skip to content

Commit 24b4ae3

Browse files
author
Raphaël Monat
authored
Merge pull request MLanguage#147 from MLanguage/custom-chains
Support for custom M chains
2 parents 32fee5d + d4e1931 commit 24b4ae3

File tree

8 files changed

+136
-12
lines changed

8 files changed

+136
-12
lines changed

mpp_specs/dgfip_base.mpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ sauve_base_HR():
108108

109109
ENCH_TL():
110110
X = X
111-
# outputs <- call_m(ENCH_TL)
111+
outputs <- call_m(ENCH_TL)
112112

113113
verif_calcul_primitive_isf():
114114
call_m_verif(isf,calculee)

src/mlang/m_frontend/format_mast.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ let format_chaining fmt (c : chaining) = Format.fprintf fmt "%s" c
4242
let format_chain_tag fmt (t : chain_tag) =
4343
Format.pp_print_string fmt
4444
(match t with
45+
| Custom name -> "\"" ^ name ^ "\""
46+
| PrimCorr -> ""
4547
| Primitif -> "primitif"
4648
| Corrective -> "corrective"
4749
| Isf -> "isf"

src/mlang/m_frontend/mast.ml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ type chaining = string
3535
(** "enchaineur" in the M source code, utility unknown *)
3636

3737
type chain_tag =
38+
| Custom of string (* Custom chain, not an actual rule tag *)
39+
| PrimCorr (* empty tag *)
3840
| Primitif
3941
| Corrective
4042
| Isf
@@ -147,7 +149,7 @@ let chain_tag_of_string : string -> chain_tag = function
147149
| "base_stratemajo" -> Base_stratemajo
148150
| "non_auto_cc" -> Non_auto_cc
149151
| "horizontale" -> Horizontale
150-
| _ -> raise Not_found
152+
| s -> Custom s
151153

152154
let number_and_tags_of_name (name : string Pos.marked list) :
153155
int Pos.marked * chain_tag Pos.marked list =
@@ -174,8 +176,10 @@ let number_and_tags_of_name (name : string Pos.marked list) :
174176
in
175177
let number, tags = aux [] name in
176178
if List.length tags = 0 then
177-
(number, [ (Primitif, Pos.no_pos); (Corrective, Pos.no_pos) ])
178-
(* No tags means both in primitive and corrective *)
179+
( number,
180+
[
181+
(PrimCorr, Pos.no_pos); (Primitif, Pos.no_pos); (Corrective, Pos.no_pos);
182+
] ) (* No tags means both in primitive and corrective *)
179183
else (number, tags)
180184

181185
type variable_name = string

src/mlang/m_frontend/mast_to_mir.ml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,12 @@ let get_rules_and_var_data (idmap : Mir.idmap)
12861286
data_to_add)
12871287
([], var_data, 0) r.Mast.rule_formulaes
12881288
in
1289-
let rule = (List.rev rule_vars, r.rule_number, r.rule_tags) in
1289+
let rule_tags =
1290+
match r.rule_chaining with
1291+
| None -> r.rule_tags
1292+
| Some (chain, pos) -> (Mast.Custom chain, pos) :: r.rule_tags
1293+
in
1294+
let rule = (List.rev rule_vars, r.rule_number, rule_tags) in
12901295
( Mir.RuleMap.add (Pos.unmark r.rule_number) rule rule_data,
12911296
var_data )
12921297
| Mast.VariableDecl (Mast.ConstVar _) ->
@@ -1464,6 +1469,10 @@ let get_conds (error_decls : Mir.Error.t list)
14641469
(Mast.Primitif, Pos.no_pos);
14651470
(Mast.Corrective, Pos.no_pos);
14661471
]
1472+
| [ (Mast.Custom _, _) ] as l ->
1473+
(Mast.Primitif, Pos.no_pos)
1474+
:: (Mast.Corrective, Pos.no_pos)
1475+
:: l
14671476
| l -> l);
14681477
}
14691478
conds)

src/mlang/m_ir/mir.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,10 @@ end)
406406
module TagMap = Map.Make (struct
407407
type t = Mast.chain_tag
408408

409-
let compare = compare
409+
let compare t1 t2 =
410+
match (t1, t2) with
411+
| Mast.Custom s1, Mast.Custom s2 -> String.compare s1 s2
412+
| _ -> Stdlib.compare t1 t2
410413
end)
411414

412415
(**{1 Verification conditions}*)

src/mlang/m_ir/mir_dependency_graph.ml

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,46 @@ let check_for_cycle (g : RG.t) (p : Mir.program) (print_debug : bool) : bool =
184184
end
185185
else false
186186

187-
module RuleExecutionOrder = Graph.Topological.Make (RG)
188-
189187
type rule_execution_order = Mir.rule_id list
190188

189+
module Traversal = Graph.Traverse.Dfs (RG)
190+
191+
let pull_rules_dependencies (g : RG.t) (rules : Mir.rule_id list) :
192+
RG.t * rule_execution_order =
193+
let order =
194+
List.fold_left
195+
(fun exec_order rule_id ->
196+
let new_deps =
197+
Traversal.fold_component
198+
(fun dep new_deps ->
199+
if List.mem dep exec_order then
200+
(* We already added this dependency from another rule, and thus
201+
all its own dependencies *)
202+
new_deps
203+
else dep :: new_deps)
204+
exec_order g rule_id
205+
in
206+
(* Here's a subtlety, we don't now in which order the rules given are,
207+
only that their should not be any cycles. So we can have three cases:
208+
The current rule we pull dependencies of is unrelated to previous
209+
ones, this is trivialy correct. Or, the current rule is already a
210+
dependency of previous ones, then nothing will be added, as seen
211+
above. Or finally, the current rule has dependencies in common with
212+
previous rules, in which case we know them to be already added, so to
213+
be topologically ordered we have to put the new dependencies at the
214+
end, it is safe since there is no cycles. *)
215+
exec_order @ new_deps)
216+
[] rules
217+
in
218+
let subgraph =
219+
RG.fold_vertex
220+
(fun rule_id subg ->
221+
if List.mem rule_id order then subg else RG.remove_vertex subg rule_id)
222+
g g
223+
in
224+
(subgraph, order)
225+
226+
module RuleExecutionOrder = Graph.Topological.Make (RG)
227+
191228
let get_rules_execution_order (dep_graph : RG.t) : rule_execution_order =
192229
RuleExecutionOrder.fold (fun var exec_order -> var :: exec_order) dep_graph []

src/mlang/m_ir/mir_dependency_graph.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,7 @@ val check_for_cycle : RG.t -> Mir.program -> bool -> bool
3636

3737
type rule_execution_order = Mir.rule_id list
3838

39+
val pull_rules_dependencies :
40+
RG.t -> Mir.rule_id list -> RG.t * rule_execution_order
41+
3942
val get_rules_execution_order : RG.t -> rule_execution_order

src/mlang/m_ir/mir_interface.ml

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ type full_program = {
6060

6161
let to_full_program (program : program) (chains : Mast.chain_tag list) :
6262
full_program =
63-
let chains_orders =
63+
let chains_orders, _ =
6464
List.fold_left
65-
(fun chains tag ->
65+
(fun (chains, seen_customs) tag ->
6666
let vars_to_rules, chain_rules =
6767
Mir.RuleMap.fold
6868
(fun rule_id rule (vars, rules) ->
@@ -84,7 +84,73 @@ let to_full_program (program : program) (chains : Mast.chain_tag list) :
8484
let execution_order =
8585
Mir_dependency_graph.get_rules_execution_order dep_graph
8686
in
87-
Mir.TagMap.add tag { dep_graph; execution_order } chains)
88-
Mir.TagMap.empty chains
87+
let customs, _ =
88+
RuleMap.fold
89+
(fun rule_id rule (customs, in_primcorr) ->
90+
List.fold_left
91+
(fun (customs, in_primcorr) tag ->
92+
match tag with
93+
| Mast.Custom _ -> (
94+
let ipc =
95+
Mast.are_tags_part_of_chain rule.rule_tags Mast.PrimCorr
96+
in
97+
if in_primcorr && not ipc then
98+
Errors.raise_error
99+
"Custom chain must be attributed to rules with all \
100+
the exact same tagging."
101+
else
102+
match TagMap.find_opt tag customs with
103+
| Some rs ->
104+
( TagMap.add tag (rule_id :: rs) customs,
105+
ipc || in_primcorr )
106+
| None ->
107+
( TagMap.add tag [ rule_id ] customs,
108+
ipc || in_primcorr ))
109+
| _ -> (customs, in_primcorr))
110+
(customs, in_primcorr) rule.rule_tags)
111+
chain_rules (TagMap.empty, false)
112+
in
113+
let customs =
114+
TagMap.map
115+
(fun rules ->
116+
Mir_dependency_graph.pull_rules_dependencies dep_graph rules)
117+
customs
118+
in
119+
let seen_customs =
120+
TagMap.merge
121+
(fun custom_tag seen curr ->
122+
match (seen, curr) with
123+
| None, None -> None
124+
| Some _, None -> seen
125+
| None, Some _ -> Some tag
126+
| Some s, Some _ -> (
127+
match (s, tag) with
128+
| Mast.Primitif, Mast.Corrective
129+
| Mast.Corrective, Mast.Primitif ->
130+
(* ignore this case *) seen
131+
| _ ->
132+
let custom_tag =
133+
match custom_tag with
134+
| Mast.Custom s -> s
135+
| _ -> assert false
136+
in
137+
Errors.raise_error
138+
(Format.asprintf
139+
"Rules with custom chain %s found with incompatible \
140+
tags %a and %a."
141+
custom_tag Format_mast.format_chain_tag s
142+
Format_mast.format_chain_tag tag)))
143+
seen_customs customs
144+
in
145+
let chains =
146+
TagMap.fold
147+
(fun tag (dep_graph, execution_order) chains ->
148+
TagMap.add tag { dep_graph; execution_order } chains)
149+
customs
150+
(Mir.TagMap.add tag { dep_graph; execution_order } chains)
151+
in
152+
(chains, seen_customs))
153+
(Mir.TagMap.empty, Mir.TagMap.empty)
154+
chains
89155
in
90156
{ program; chains_orders }

0 commit comments

Comments
 (0)