diff --git a/examples/dgfip_c/ml_primitif/ml_driver/m.ml b/examples/dgfip_c/ml_primitif/ml_driver/m.ml index 94a819db3..e15dee7d2 100644 --- a/examples/dgfip_c/ml_primitif/ml_driver/m.ml +++ b/examples/dgfip_c/ml_primitif/ml_driver/m.ml @@ -148,4 +148,5 @@ external get_err_list : TGV.t -> string list = "ml_get_err_list" external annee_calc : unit -> int = "ml_annee_calc" external export_errs : TGV.t -> unit = "ml_export_errs" external enchainement_primitif : TGV.t -> unit = "ml_enchainement_primitif" +external set_evt_list : TGV.t -> (float * float * string * float * float * float * float * float * float) list-> unit = "ml_set_evt_list" diff --git a/examples/dgfip_c/ml_primitif/ml_driver/main.ml b/examples/dgfip_c/ml_primitif/ml_driver/main.ml index 310d12d81..1f0bde022 100644 --- a/examples/dgfip_c/ml_primitif/ml_driver/main.ml +++ b/examples/dgfip_c/ml_primitif/ml_driver/main.ml @@ -3,29 +3,30 @@ open Common let read_test filename = let test = Read_test.read_test filename in let tgv = M.TGV.alloc_tgv () in - let res_prim, ctl_prim = - let fold_prim (res_prim, ctl_prim) s = + let evt_list, res_prim, ctl_prim = + let fold_prim (evt_list, res_prim, ctl_prim) s = match s with | `EntreesPrimitif pl -> List.iter (fun (code, montant) -> M.TGV.set tgv code montant) pl; - res_prim, ctl_prim + evt_list, res_prim, ctl_prim | `ResultatsPrimitif pl -> let res_prim = let fold res (code, montant) = StrMap.add code montant res in List.fold_left fold res_prim pl in - res_prim, ctl_prim + evt_list, res_prim, ctl_prim | `ControlesPrimitif el -> let ctl_prim = let fold err e = StrSet.add e err in List.fold_left fold ctl_prim el in - res_prim, ctl_prim - | _ -> res_prim, ctl_prim + evt_list, res_prim, ctl_prim + | `EntreesRappels evt_list -> evt_list, res_prim, ctl_prim + | _ -> evt_list, res_prim, ctl_prim in - List.fold_left fold_prim (StrMap.empty, StrSet.empty) test + List.fold_left fold_prim ([], StrMap.empty, StrSet.empty) test in - tgv, res_prim, ctl_prim + tgv, evt_list, res_prim, ctl_prim let check_result tgv err expected_tgv expected_err = let result = ref true in @@ -130,7 +131,8 @@ let compare_dump out outexp = let run_test test_file annee_exec = Printf.printf "Testing %s...\n%!" test_file; let annee_calc = M.annee_calc () in - let tgv, res_prim, ctl_prim = read_test test_file in + let tgv, evt_list, res_prim, ctl_prim = read_test test_file in + M.set_evt_list tgv evt_list; let annee_revenu = M.TGV.get_int_def tgv "ANREV" annee_calc in if annee_revenu <> annee_calc then ( Printf.eprintf diff --git a/examples/dgfip_c/ml_primitif/ml_driver/read_test.ml b/examples/dgfip_c/ml_primitif/ml_driver/read_test.ml index ce7967859..2384728f2 100644 --- a/examples/dgfip_c/ml_primitif/ml_driver/read_test.ml +++ b/examples/dgfip_c/ml_primitif/ml_driver/read_test.ml @@ -55,16 +55,25 @@ let parse_entree_corr s = | _ -> failwith (Printf.sprintf "Ligne entree correctif invalide: '%s'" s) let parse_entree_rap s = + let err () = failwith (Printf.sprintf "Ligne entree rappel invalide: '%s'" s) in let sl = String.split_on_char '/' s in match sl with | [ num_evt; num_rappel; code; montant; sens; penalite; base_tl; date_evt; ind20 ] -> - let date_evt = convert_int date_evt in - (convert_int num_evt, convert_int num_rappel, - code, convert_float montant, sens.[0], - convert_int penalite, convert_float base_tl, - (date_evt mod 10000, date_evt / 10000), String.equal ind20 "1") (* TODO: improve *) - | _ -> failwith (Printf.sprintf "Ligne entree rappel invalide: '%s'" s) + let sens_float = + if String.length sens = 0 then err (); + match sens.[0] with + | 'R' -> 0.0 + | 'C' -> 1.0 + | 'M' -> 2.0 + | 'P' -> 3.0 + | _ -> err () + in + (convert_float num_evt, convert_float num_rappel, + code, convert_float montant, sens_float, + convert_float penalite, convert_float base_tl, + convert_float date_evt, convert_float ind20) (* TODO: improve *) + | _ -> err () let read_section_contents f parsefun = let rec aux contents = diff --git a/examples/dgfip_c/ml_primitif/ml_driver/stubs.c b/examples/dgfip_c/ml_primitif/ml_driver/stubs.c index 741a412d4..fff6ca7eb 100644 --- a/examples/dgfip_c/ml_primitif/ml_driver/stubs.c +++ b/examples/dgfip_c/ml_primitif/ml_driver/stubs.c @@ -213,3 +213,49 @@ CAMLprim value ml_enchainement_primitif(value mlTgv) { CAMLreturn(mlErrListOut); } +CAMLprim value ml_set_evt_list(value mlTgv, value mlEvtList) { + CAMLparam2(mlTgv, mlEvtList); + CAMLlocal2(mlList, mlEvt); + + T_irdata *tgv = Tgv_val(mlTgv); + int len = 0; + mlList = mlEvtList; + while (mlList != Val_emptylist) { + len++; + mlList = Field(mlList, 1); + } + if (len > 0) { + tgv->events = (T_event *)malloc(len * sizeof (T_event)); + } else { + tgv->events = NULL; + } + tgv->nb_events = len; + + int i = 0; + mlList = mlEvtList; + while (mlList != Val_emptylist) { + mlEvt = Field(mlList, 0); + tgv->events[i].field_numero_def = 1; + tgv->events[i].field_numero_val = Double_val(Field(mlEvt, 0)); + tgv->events[i].field_rappel_def = 1; + tgv->events[i].field_rappel_val = Double_val(Field(mlEvt, 1)); + tgv->events[i].field_code_var = cherche_var(tgv, String_val(Field(mlEvt, 2))); + tgv->events[i].field_montant_def = 1; + tgv->events[i].field_montant_val = Double_val(Field(mlEvt, 3)); + tgv->events[i].field_sens_def = 1; + tgv->events[i].field_sens_val = Double_val(Field(mlEvt, 4)); + tgv->events[i].field_penalite_def = 1; + tgv->events[i].field_penalite_val = Double_val(Field(mlEvt, 5)); + tgv->events[i].field_base_tl_def = 1; + tgv->events[i].field_base_tl_val = Double_val(Field(mlEvt, 6)); + tgv->events[i].field_date_def = 1; + tgv->events[i].field_date_val = Double_val(Field(mlEvt, 7)); + tgv->events[i].field_2042_rect_def = 1; + tgv->events[i].field_2042_rect_val = Double_val(Field(mlEvt, 8)); + i++; + mlList = Field(mlList, 1); + } + CAMLreturn(Val_unit); +} + + diff --git a/m_ext/2023/cibles.m b/m_ext/2023/cibles.m index f6bcb2621..bc8c3a767 100644 --- a/m_ext/2023/cibles.m +++ b/m_ext/2023/cibles.m @@ -773,7 +773,6 @@ si nb_discordances() + nb_informatives() > 0 alors exporte_erreurs; finsi - fonction truc: application: iliad; argument: A0, A1; @@ -823,6 +822,38 @@ si nb_discordances() + nb_informatives() > 0 alors A1 = 3.6; calculer cible test_boucle : avec A0, A1; afficher_erreur "nb_evenements() = " (nb_evenements()) "\n"; +iterer +: variable I +: 0 .. (nb_evenements() - 1) increment 1 +: dans ( + afficher_erreur (I) ": "; + si (present(champ_evenement(I, numero))) alors afficher_erreur (champ_evenement(I, numero)); finsi + afficher_erreur "/"; + si (present(champ_evenement(I, rappel))) alors afficher_erreur (champ_evenement(I, rappel)); finsi + afficher_erreur "/" alias(I, code) "," nom(I, code) "/"; + si (present(champ_evenement(I, montant))) alors afficher_erreur (champ_evenement(I, montant)); finsi + afficher_erreur "/"; + si (present(champ_evenement(I, sens))) alors + si (champ_evenement(I, sens) = 0) alors + afficher_erreur "R"; + sinon_si (champ_evenement(I, sens) = 1) alors + afficher_erreur "C"; + sinon_si (champ_evenement(I, sens) = 2) alors + afficher_erreur "M"; + sinon_si (champ_evenement(I, sens) = 3) alors + afficher_erreur "P"; + finsi + finsi + afficher_erreur "/"; + si (present(champ_evenement(I, penalite))) alors afficher_erreur (champ_evenement(I, penalite)); finsi + afficher_erreur "/"; + si (present(champ_evenement(I, base_tl))) alors afficher_erreur (champ_evenement(I, base_tl)); finsi + afficher_erreur "/"; + si (present(champ_evenement(I, date))) alors afficher_erreur (champ_evenement(I, date)); finsi + afficher_erreur "/"; + si (present(champ_evenement(I, 2042_rect))) alors afficher_erreur (champ_evenement(I, 2042_rect)); finsi + afficher_erreur "\n"; +) cible enchainement_primitif: application: iliad; diff --git a/src/mlang/backend_compilers/bir_to_dgfip_c.ml b/src/mlang/backend_compilers/bir_to_dgfip_c.ml index 2d1a28415..67c2193a3 100644 --- a/src/mlang/backend_compilers/bir_to_dgfip_c.ml +++ b/src/mlang/backend_compilers/bir_to_dgfip_c.ml @@ -288,6 +288,10 @@ let rec generate_c_expr (e : Mir.expression Pos.marked) : D.dfun "multimax" [ bound.value_comp; D.m_var v2 PassPointer Val ] in D.build_transitive_composition { set_vars; def_test; value_comp } + | FuncCall ((NbEvents, _), _) -> + let def_test = D.dinstr "1.0" in + let value_comp = D.dinstr "nb_evenements(irdata)" in + D.build_transitive_composition { set_vars = []; def_test; value_comp } | FuncCall ((Func fn, _), args) -> let res = fresh_c_local "result" in let def_res = Pp.spr "def_%s" res in @@ -343,6 +347,33 @@ let rec generate_c_expr (e : Mir.expression Pos.marked) : (Format.sprintf "attribut_%s((T_varinfo *)%s)" (Pos.unmark a) ptr) in D.build_transitive_composition { set_vars = []; def_test; value_comp } + | EventField (me, f) -> + let fn = Format.sprintf "event_field_%s" (Pos.unmark f) in + let res = fresh_c_local "result" in + let def_res = Pp.spr "def_%s" res in + let val_res = Pp.spr "val_%s" res in + let def_res_ptr = Pp.spr "&%s" def_res in + let val_res_ptr = Pp.spr "&%s" val_res in + let set_vars, arg_exprs = + let e = generate_c_expr me in + (e.set_vars, [ e.def_test; e.value_comp ]) + in + let d_fun = + D.dfun fn + ([ + D.dlow_level "irdata"; + D.dlow_level def_res_ptr; + D.dlow_level val_res_ptr; + ] + @ arg_exprs) + in + let set_vars = + set_vars + @ [ (D.Def, def_res, d_fun); (D.Val, val_res, D.dlow_level val_res) ] + in + let def_test = D.dinstr def_res in + let value_comp = D.dinstr val_res in + D.build_transitive_composition { set_vars; def_test; value_comp } | Size var -> let ptr = VID.gen_info_ptr (Pos.unmark var) in let def_test = D.dinstr "1.0" in @@ -364,8 +395,7 @@ let rec generate_c_expr (e : Mir.expression Pos.marked) : let def_test = D.dinstr "1.0" in let value_comp = D.dinstr "nb_bloquantes(irdata)" in D.build_transitive_composition { set_vars = []; def_test; value_comp } - | NbCategory _ -> assert false - | FuncCallLoop _ | Loop _ -> assert false + | NbCategory _ | FuncCallLoop _ | Loop _ -> assert false let generate_m_assign (dgfip_flags : Dgfip_options.flags) (var : Com.Var.t) (offset : D.offset) (oc : Format.formatter) (se : D.expression_composition) @@ -517,6 +547,26 @@ let rec generate_stmt (dgfip_flags : Dgfip_options.flags) in let print_val = fresh_c_local "mpp_print" in let print_def = print_val ^ "_d" in + let print_name_or_alias name_or_alias e f = + let locals, set, def, value = D.build_expression @@ generate_c_expr e in + Format.fprintf oc "@[{%a%a%a@;%a@;@]}@;" + D.format_local_declarations locals + (D.format_set_vars dgfip_flags) + set + (D.format_assign dgfip_flags print_def) + def + (D.format_assign dgfip_flags print_val) + value; + Format.fprintf oc "@[{@;int idx = (int)floor(%s);@; /* prout */" + print_val; + Format.fprintf oc + "@[if(%s && 0 <= idx && idx < irdata->nb_events){@;" print_def; + Format.fprintf oc + "print_string(%s, %s, irdata->events[idx].field_%s_var->%s);@]@;" + print_std pr_ctx (Pos.unmark f) name_or_alias; + Format.fprintf oc "}@]@;"; + Format.fprintf oc "}@;" + in Format.fprintf oc "@[{@,char %s;@;double %s;@;" print_def print_val; List.iter (fun (arg : Com.Var.t Com.print_arg Pos.marked) -> @@ -532,6 +582,8 @@ let rec generate_stmt (dgfip_flags : Dgfip_options.flags) let ptr = VID.gen_info_ptr var in Format.fprintf oc "print_string(%s, %s, %s->alias);@;" print_std pr_ctx ptr + | PrintEventName (e, f) -> print_name_or_alias "name" e f + | PrintEventAlias (e, f) -> print_name_or_alias "alias" e f | PrintIndent e -> let locals, set, def, value = D.build_expression @@ generate_c_expr e diff --git a/src/mlang/backend_compilers/dgfip_gen_files.ml b/src/mlang/backend_compilers/dgfip_gen_files.ml index d79f345b7..62efb06ca 100644 --- a/src/mlang/backend_compilers/dgfip_gen_files.ml +++ b/src/mlang/backend_compilers/dgfip_gen_files.ml @@ -338,6 +338,22 @@ struct S_keep_discord { T_keep_discord *suivant; }; +struct S_event { +|}; + IntMap.iter + (fun _idx fname -> + let field = StrMap.find fname cprog.program_event_fields in + if field.is_var then + Format.fprintf fmt " T_varinfo *field_%s_var;\n" fname + else ( + Format.fprintf fmt " char field_%s_def;\n" fname; + Format.fprintf fmt " double field_%s_val;\n" fname)) + cprog.program_event_field_idxs; + Format.fprintf fmt + {|}; + +typedef struct S_event T_event; + struct S_irdata { double *saisie; double *calculee; @@ -370,12 +386,24 @@ struct S_irdata { int sz_err_archive; char **err_archive; int nb_err_archive; + T_event *events; + int nb_events; T_print_context ctx_pr_out; T_print_context ctx_pr_err; }; typedef struct S_irdata T_irdata; +|}; + StrMap.iter + (fun f _ -> + Format.fprintf fmt + "extern char event_field_%s(T_irdata *irdata, char *res_def, double \ + *res_val, char idx_def, double idx_val);\n" + f) + cprog.program_event_fields; + Format.fprintf fmt + {| #define S_ irdata->saisie #define C_ irdata->calculee #define B_ irdata->base @@ -389,22 +417,6 @@ typedef struct S_irdata T_irdata; /*#define IT_ irdata->info_tmps*/ /*#define IR_ irdata->info_ref*/ -struct S_event { -|}; - IntMap.iter - (fun _idx fname -> - let field = StrMap.find fname cprog.program_event_fields in - if field.is_var then - Format.fprintf fmt " T_varinfo *field_%s_var;\n" fname - else ( - Format.fprintf fmt " char field_%s_def;\n" fname; - Format.fprintf fmt " double field_%s_val;\n" fname)) - cprog.program_event_field_idxs; - Format.fprintf fmt - {|}; - -typedef struct S_event T_event; - #define EST_SAISIE 0x00000 #define EST_CALCULEE 0x04000 #define EST_BASE 0x08000 @@ -426,7 +438,6 @@ extern void free_erreur(); #define max(a,b) (((a) >= (b)) ? (a) : (b)) |}; Format.fprintf fmt "#define EPSILON %f" !Cli.comparison_error_margin; - Format.fprintf fmt {| #define GT_E(a,b) ((a) > (b) + EPSILON) @@ -576,6 +587,7 @@ extern char *lis_erreur_sous_code(T_erreur *err); extern char *lis_erreur_is_isf(T_erreur *err); extern char *lis_erreur_nom(T_erreur *err); extern int lis_erreur_type(T_erreur *err); +extern int nb_evenements(T_irdata *irdata); extern T_varinfo *cherche_varinfo(T_irdata *irdata, const char *nom); extern char lis_varinfo_def(T_irdata *irdata, T_varinfo *info); @@ -644,7 +656,7 @@ let gen_mlang_h fmt cprog flags stats_varinfos = gen_decl_targets fmt cprog; pr "#endif /* _MLANG_H_ */\n\n" -let gen_mlang_c fmt flags = +let gen_mlang_c fmt (cprog : Mir.program) flags = Format.fprintf fmt "%s" {|/****** LICENCE CECIL *****/ @@ -1424,6 +1436,11 @@ int lis_erreur_type(T_erreur *err) { return err->type; } +int nb_evenements(T_irdata *irdata) { + if (irdata == NULL) return 0; + return irdata->nb_events; +} + T_varinfo *cherche_varinfo(T_irdata *irdata, const char *nom) { T_varinfo_map *map = NULL; int res = -1; @@ -1584,7 +1601,32 @@ void pr_err_var(T_irdata *irdata, char *nom) { if (irdata == NULL) return; pr_var(&(irdata->ctx_pr_err), irdata, nom); } -|} + +|}; + StrMap.iter + (fun f (ef : Com.event_field) -> + Format.fprintf fmt + "char event_field_%s(T_irdata *irdata, char *res_def, double *res_val, \ + char idx_def, double idx_val) {\n" + f; + if ef.is_var then Format.fprintf fmt " T_varinfo *info = NULL;\n"; + Format.fprintf fmt " int idx = (int)floor(idx_val);\n"; + Format.fprintf fmt + " if (idx_def != 1 || idx < 0 || irdata->nb_events <= idx) {\n"; + Format.fprintf fmt " *res_def = 0;\n"; + Format.fprintf fmt " *res_val = 0.0;\n"; + Format.fprintf fmt " return 0;\n"; + Format.fprintf fmt " }\n"; + if ef.is_var then ( + Format.fprintf fmt " info = irdata->events[idx].field_%s_var;\n" f; + Format.fprintf fmt " *res_def = lis_varinfo_def(irdata, info);\n"; + Format.fprintf fmt " *res_val = lis_varinfo_val(irdata, info);\n") + else ( + Format.fprintf fmt " *res_def = irdata->events[idx].field_%s_def;\n" f; + Format.fprintf fmt " *res_val = irdata->events[idx].field_%s_val;\n" f); + Format.fprintf fmt " return *res_def;\n"; + Format.fprintf fmt "}\n\n") + cprog.program_event_fields let open_file filename = let oc = open_out filename in @@ -1613,5 +1655,5 @@ let generate_auxiliary_files flags (cprog : Mir.program) : unit = close_out oc; let oc, fmt = open_file (Filename.concat folder "mlang.c") in - gen_mlang_c fmt flags; + gen_mlang_c fmt cprog flags; close_out oc diff --git a/src/mlang/m_frontend/check_validity.ml b/src/mlang/m_frontend/check_validity.ml index 5aed941e3..500c04ead 100644 --- a/src/mlang/m_frontend/check_validity.ml +++ b/src/mlang/m_frontend/check_validity.ml @@ -315,6 +315,10 @@ module Err = struct Pos.format_position old_pos in Errors.raise_spanned_error msg pos + + let unknown_event_field name pos = + let msg = Format.asprintf "unknown event field \"%s\"" name in + Errors.raise_spanned_error msg pos end type syms = Com.DomainId.t Pos.marked Com.DomainIdMap.t @@ -361,7 +365,7 @@ type program = { prog_chainings : chaining StrMap.t; prog_var_cats : Com.CatVar.data Com.CatVar.Map.t; prog_vars : Com.Var.t StrMap.t; - prog_alias : Com.Var.t StrMap.t; + prog_alias : string Pos.marked StrMap.t; prog_event_fields : Com.event_field StrMap.t; prog_event_field_idxs : string IntMap.t; prog_event_pos : Pos.t; @@ -596,16 +600,19 @@ let check_global_var (var : Com.Var.t) (prog : program) : program = | Some (gvar : Com.Var.t) -> let old_pos = Pos.get_position gvar.name in Err.variable_already_declared name old_pos name_pos - | None -> StrMap.add name var prog.prog_vars + | None -> ( + match StrMap.find_opt name prog.prog_alias with + | None -> StrMap.add name var prog.prog_vars + | Some (_, old_pos) -> + Err.variable_already_declared name old_pos name_pos) in let prog_alias = match Com.Var.alias var with | Some (alias, alias_pos) -> ( match StrMap.find_opt alias prog.prog_alias with - | Some (gvar : Com.Var.t) -> - let old_pos = Pos.get_position (Option.get (Com.Var.alias gvar)) in + | Some (_, old_pos) -> Err.alias_already_declared alias old_pos alias_pos - | None -> StrMap.add alias var prog.prog_alias) + | None -> StrMap.add alias var.name prog.prog_alias) | None -> prog.prog_alias in { prog with prog_vars; prog_alias } @@ -1064,6 +1071,11 @@ let rec fold_var_expr | Some _ -> Err.tmp_vars_have_no_attrs var_pos | None -> ())); fold_var v Both env acc + | EventField (e, f) -> ( + if is_filter then Err.forbidden_expresion_in_filter expr_pos; + match StrMap.find_opt (Pos.unmark f) env.prog.prog_event_fields with + | Some _ -> fold_var_expr fold_var is_filter acc e env + | None -> Err.unknown_event_field (Pos.unmark f) (Pos.get_position f)) | Size v -> fold_var v Both env acc | NbAnomalies | NbDiscordances | NbInformatives | NbBloquantes -> if is_filter then Err.forbidden_expresion_in_filter expr_pos; @@ -1308,6 +1320,14 @@ let rec check_instructions (instrs : Mast.instruction Pos.marked list) | Com.PrintString _ -> () | Com.PrintName v | Com.PrintAlias v -> ignore (check_variable v Both env) + | Com.PrintEventName (e, f) | Com.PrintEventAlias (e, f) -> ( + match + StrMap.find_opt (Pos.unmark f) env.prog.prog_event_fields + with + | Some _ -> ignore (check_expression false e env) + | None -> + Err.unknown_event_field (Pos.unmark f) + (Pos.get_position f)) | Com.PrintIndent e -> ignore (check_expression false e env) | Com.PrintExpr (e, _min, _max) -> ignore (check_expression false e env)) @@ -2239,7 +2259,7 @@ let eval_expr_verif (prog : program) (verif : verif) in Some (if res = positive then 1.0 else 0.0)) | NbAnomalies | NbDiscordances | NbInformatives | NbBloquantes | Index _ - | FuncCallLoop _ | Loop _ -> + | FuncCallLoop _ | Loop _ | EventField _ -> assert false in aux expr @@ -2601,7 +2621,10 @@ let complete_vars_stack (prog : program) : program = match a with | Com.PrintString _ | Com.PrintName _ | Com.PrintAlias _ -> (nb, sz, nbRef, tdata) - | Com.PrintIndent me | Com.PrintExpr (me, _, _) -> + | Com.PrintEventName (me, _) + | Com.PrintEventAlias (me, _) + | Com.PrintIndent me + | Com.PrintExpr (me, _, _) -> let nb', sz', nbRef', tdata = aux_expr tdata me in (max nb nb', max sz sz', max nbRef nbRef', tdata) in @@ -2657,7 +2680,10 @@ let complete_vars_stack (prog : program) : program = assert false and aux_expr tdata (expr, _pos) = match expr with - | Com.TestInSet (_, me, _) | Com.Unop (_, me) | Com.Index (_, me) -> + | Com.TestInSet (_, me, _) + | Com.Unop (_, me) + | Com.Index (_, me) + | Com.EventField (me, _) -> aux_expr tdata me | Com.Comparison (_, me0, me1) | Com.Binop (_, me0, me1) -> let nb0, sz0, nbRef0, tdata = aux_expr tdata me0 in diff --git a/src/mlang/m_frontend/check_validity.mli b/src/mlang/m_frontend/check_validity.mli index bf50ddd13..5b5c3ab27 100644 --- a/src/mlang/m_frontend/check_validity.mli +++ b/src/mlang/m_frontend/check_validity.mli @@ -56,7 +56,7 @@ type program = { prog_chainings : chaining StrMap.t; prog_var_cats : Com.CatVar.data Com.CatVar.Map.t; prog_vars : Com.Var.t StrMap.t; - prog_alias : Com.Var.t StrMap.t; + prog_alias : string Pos.marked StrMap.t; prog_event_fields : Com.event_field StrMap.t; prog_event_field_idxs : string IntMap.t; prog_event_pos : Pos.t; diff --git a/src/mlang/m_frontend/expand_macros.ml b/src/mlang/m_frontend/expand_macros.ml index 768ed9af1..a806b4fb9 100644 --- a/src/mlang/m_frontend/expand_macros.ml +++ b/src/mlang/m_frontend/expand_macros.ml @@ -617,6 +617,9 @@ let rec expand_expression (const_map : const_context) (loop_map : loop_context) | Var v, v_pos -> (Attribut ((v, v_pos), a), expr_pos) | Literal (Float _), v_pos -> Err.constant_cannot_have_an_attribut v_pos | _ -> assert false) + | EventField (e, f) -> + let e' = expand_expression const_map loop_map e in + (EventField (e', f), expr_pos) | Size var -> ( match expand_variable const_map loop_map var with | Var v, v_pos -> (Size (v, v_pos), expr_pos) @@ -689,6 +692,12 @@ let rec expand_instruction (const_map : const_context) List.map (fun arg -> match Pos.unmark arg with + | Com.PrintEventName (expr, f) -> + let expr' = expand_expression const_map ParamsMap.empty expr in + (Com.PrintEventName (expr', f), Pos.get_position arg) + | Com.PrintEventAlias (expr, f) -> + let expr' = expand_expression const_map ParamsMap.empty expr in + (Com.PrintEventAlias (expr', f), Pos.get_position arg) | Com.PrintIndent expr -> let expr' = expand_expression const_map ParamsMap.empty expr in (Com.PrintIndent expr', Pos.get_position arg) diff --git a/src/mlang/m_frontend/mast_to_mir.ml b/src/mlang/m_frontend/mast_to_mir.ml index 0d732401b..3b4f06b51 100644 --- a/src/mlang/m_frontend/mast_to_mir.ml +++ b/src/mlang/m_frontend/mast_to_mir.ml @@ -148,6 +148,9 @@ let rec translate_expression (cats : Com.CatVar.data Com.CatVar.Map.t) | _ -> let msg = Format.sprintf "unknown variable %s" v_name in Errors.raise_spanned_error msg (Pos.get_position v)) + | EventField (e, f) -> + let new_e = translate_expression cats var_data e in + EventField (new_e, f) | Size v -> ( let v_name = match Pos.unmark v with @@ -253,6 +256,12 @@ let rec translate_prog (error_decls : Com.Error.t StrMap.t) Format.sprintf "unknown variable %s" name in Errors.raise_spanned_error msg (Pos.get_position v)) + | Com.PrintEventName (e, f) -> + let e' = translate_expression cats var_data e in + Com.PrintEventName (e', f) + | Com.PrintEventAlias (e, f) -> + let e' = translate_expression cats var_data e in + Com.PrintEventAlias (e', f) | Com.PrintIndent e -> Com.PrintIndent (translate_expression cats var_data e) | Com.PrintExpr (e, min, max) -> @@ -509,6 +518,7 @@ let translate (p : Mast.program) (main_target : string) : Mir.program = program_rule_domains = prog.prog_rdoms; program_verif_domains = prog.prog_vdoms; program_vars = var_data; + program_alias = prog.prog_alias; program_event_fields = prog.prog_event_fields; program_event_field_idxs = prog.prog_event_field_idxs; program_rules = rules; diff --git a/src/mlang/m_frontend/mlexer.mll b/src/mlang/m_frontend/mlexer.mll index 2be7658be..f4adb72d3 100644 --- a/src/mlang/m_frontend/mlexer.mll +++ b/src/mlang/m_frontend/mlexer.mll @@ -76,6 +76,7 @@ rule token = parse | "calculee" -> COMPUTED | "calculer" -> COMPUTE | "categorie" -> CATEGORY + | "champ_evenement" -> EVENT_FIELD | "cible" -> TARGET | "const" -> CONST | "dans" -> IN diff --git a/src/mlang/m_frontend/mparser.mly b/src/mlang/m_frontend/mparser.mly index 15e800768..5bb4bab0d 100644 --- a/src/mlang/m_frontend/mparser.mly +++ b/src/mlang/m_frontend/mparser.mly @@ -58,7 +58,7 @@ along with this program. If not, see . %token INFORMATIVE OUTPUT FONCTION VARIABLE ATTRIBUT %token BASE GIVEN_BACK COMPUTABLE BY_DEFAULT %token DOMAIN SPECIALIZE AUTHORIZE VERIFIABLE -%token EVENT VALUE STEP +%token EVENT VALUE STEP EVENT_FIELD %token EOF @@ -753,20 +753,25 @@ instruction_then_when_branch: print_argument: | s = STRING { Com.PrintString (parse_string s) } -| f = with_pos(print_function) LPAREN v = symbol_with_pos RPAREN - { - match Pos.unmark f with - | "nom" -> Com.PrintName (parse_variable $sloc (fst v), snd v) - | "alias" -> Com.PrintAlias (parse_variable $sloc (fst v), snd v) - | _ -> assert false - } +| f = with_pos(print_function) LPAREN v = symbol_with_pos RPAREN { + match Pos.unmark f with + | "nom" -> Com.PrintName (parse_variable $sloc (fst v), snd v) + | "alias" -> Com.PrintAlias (parse_variable $sloc (fst v), snd v) + | _ -> assert false + } +| f = with_pos(print_function) LPAREN expr = with_pos(sum_expression) + COMMA field = symbol_with_pos RPAREN { + match Pos.unmark f with + | "nom" -> Com.PrintEventName (expr, field) + | "alias" -> Com.PrintEventAlias (expr, field) + | _ -> assert false + } | INDENT LPAREN e = with_pos(expression) RPAREN { Com.PrintIndent e } -| LPAREN e = with_pos(expression) RPAREN prec = print_precision? - { - match prec with - | Some (min, max) -> Com.PrintExpr (e, min, max) - | None -> Com.PrintExpr (e, 0, 20) - } +| LPAREN e = with_pos(expression) RPAREN prec = print_precision? { + match prec with + | Some (min, max) -> Com.PrintExpr (e, min, max) + | None -> Com.PrintExpr (e, 0, 20) + } print_function: | NAME { "nom" } @@ -1172,6 +1177,9 @@ function_call: | ATTRIBUT LPAREN var = symbol_with_pos COMMA attr = symbol_with_pos RPAREN { Attribut ((parse_variable $sloc (fst var), snd var), attr) } +| EVENT_FIELD LPAREN m_expr = with_pos(sum_expression) COMMA field = symbol_with_pos RPAREN { + EventField (m_expr, field) + } | SIZE LPAREN var = symbol_with_pos RPAREN { Size (parse_variable $sloc (fst var), snd var) } diff --git a/src/mlang/m_ir/com.ml b/src/mlang/m_ir/com.ml index a2b62e7f1..dd6699f80 100644 --- a/src/mlang/m_ir/com.ml +++ b/src/mlang/m_ir/com.ml @@ -293,7 +293,7 @@ end type event_field = { name : string Pos.marked; index : int; is_var : bool } -type event_value = Numeric of float option | RefVar of string +type 'v event_value = Numeric of float option | RefVar of 'v module DomainId = StrSet @@ -413,6 +413,7 @@ type 'v expression = | NbDiscordances | NbInformatives | NbBloquantes + | EventField of 'v m_expression * string Pos.marked and 'v m_expression = 'v expression Pos.marked @@ -451,6 +452,8 @@ type 'v print_arg = | PrintString of string | PrintName of 'v Pos.marked | PrintAlias of 'v Pos.marked + | PrintEventName of 'v m_expression * string Pos.marked + | PrintEventAlias of 'v m_expression * string Pos.marked | PrintIndent of 'v m_expression | PrintExpr of 'v m_expression * int * int @@ -666,16 +669,25 @@ let rec format_expression form_var fmt = | Attribut (v, a) -> Format.fprintf fmt "attribut(%a, %s)" form_var (Pos.unmark v) (Pos.unmark a) + | EventField (e, f) -> + Format.fprintf fmt "champ_evenement(%a, %s)" form_expr (Pos.unmark e) + (Pos.unmark f) | Size v -> Format.fprintf fmt "taille(%a)" form_var (Pos.unmark v) | NbAnomalies -> Format.fprintf fmt "nb_anomalies()" | NbDiscordances -> Format.fprintf fmt "nb_discordances()" | NbInformatives -> Format.fprintf fmt "nb_informatives()" | NbBloquantes -> Format.fprintf fmt "nb_bloquantes()" -let format_print_arg form_var fmt = function +let format_print_arg form_var fmt = + let form_expr = format_expression form_var in + function | PrintString s -> Format.fprintf fmt "\"%s\"" s | PrintName v -> Format.fprintf fmt "nom(%a)" (Pp.unmark form_var) v | PrintAlias v -> Format.fprintf fmt "alias(%a)" (Pp.unmark form_var) v + | PrintEventName (e, f) -> + Format.fprintf fmt "nom(%a, %s)" form_expr (Pos.unmark e) (Pos.unmark f) + | PrintEventAlias (e, f) -> + Format.fprintf fmt "alias(%a, %s)" form_expr (Pos.unmark e) (Pos.unmark f) | PrintIndent e -> Format.fprintf fmt "indenter(%a)" (Pp.unmark (format_expression form_var)) diff --git a/src/mlang/m_ir/com.mli b/src/mlang/m_ir/com.mli index 81bb884d0..11d3e4acf 100644 --- a/src/mlang/m_ir/com.mli +++ b/src/mlang/m_ir/com.mli @@ -152,7 +152,7 @@ end type event_field = { name : string Pos.marked; index : int; is_var : bool } -type event_value = Numeric of float option | RefVar of string +type 'v event_value = Numeric of float option | RefVar of 'v module DomainId : StrSet.T @@ -271,6 +271,7 @@ type 'v expression = | NbDiscordances | NbInformatives | NbBloquantes + | EventField of 'v m_expression * string Pos.marked and 'v m_expression = 'v expression Pos.marked @@ -300,6 +301,8 @@ type 'v print_arg = | PrintString of string | PrintName of 'v Pos.marked | PrintAlias of 'v Pos.marked + | PrintEventName of 'v m_expression * string Pos.marked + | PrintEventAlias of 'v m_expression * string Pos.marked | PrintIndent of 'v m_expression | PrintExpr of 'v m_expression * int * int diff --git a/src/mlang/m_ir/mir.ml b/src/mlang/m_ir/mir.ml index 49d9bd0c3..2daef3933 100644 --- a/src/mlang/m_ir/mir.ml +++ b/src/mlang/m_ir/mir.ml @@ -66,6 +66,7 @@ type program = { program_rule_domains : Com.rule_domain Com.DomainIdMap.t; program_verif_domains : Com.verif_domain Com.DomainIdMap.t; program_vars : Com.Var.t StrMap.t; + program_alias : string Pos.marked StrMap.t; program_event_fields : Com.event_field StrMap.t; program_event_field_idxs : string IntMap.t; program_rules : string IntMap.t; @@ -238,6 +239,12 @@ let expand_functions (p : program) : program = (fun m_arg -> let arg, arg_pos = m_arg in match arg with + | Com.PrintEventName (e, f) -> + let e' = expand_functions_expr e in + (Com.PrintEventName (e', f), arg_pos) + | Com.PrintEventAlias (e, f) -> + let e' = expand_functions_expr e in + (Com.PrintEventAlias (e', f), arg_pos) | Com.PrintIndent e -> let e' = expand_functions_expr e in (Com.PrintIndent e', arg_pos) diff --git a/src/mlang/m_ir/mir.mli b/src/mlang/m_ir/mir.mli index 901e0817d..3be37e66c 100644 --- a/src/mlang/m_ir/mir.mli +++ b/src/mlang/m_ir/mir.mli @@ -56,6 +56,7 @@ type program = { program_rule_domains : Com.rule_domain Com.DomainIdMap.t; program_verif_domains : Com.verif_domain Com.DomainIdMap.t; program_vars : Com.Var.t StrMap.t; + program_alias : string Pos.marked StrMap.t; program_event_fields : Com.event_field StrMap.t; program_event_field_idxs : string IntMap.t; program_rules : string IntMap.t; diff --git a/src/mlang/m_ir/mir_interpreter.ml b/src/mlang/m_ir/mir_interpreter.ml index 274deae79..fd770f52a 100644 --- a/src/mlang/m_ir/mir_interpreter.ml +++ b/src/mlang/m_ir/mir_interpreter.ml @@ -47,7 +47,7 @@ module type S = sig mutable ctx_nb_bloquantes : int; mutable ctx_finalized_anos : (Com.Error.t * string option) list; mutable ctx_exported_anos : (Com.Error.t * string option) list; - mutable ctx_events : Com.event_value StrMap.t IntMap.t; + mutable ctx_events : Com.Var.t Com.event_value StrMap.t IntMap.t; } val empty_ctx : Mir.program -> ctx @@ -59,7 +59,7 @@ module type S = sig val update_ctx_with_inputs : ctx -> Com.literal Com.Var.Map.t -> unit val update_ctx_with_events : - ctx -> Mir.program -> Com.event_value IntMap.t list -> unit + ctx -> Mir.program -> Com.Var.t Com.event_value IntMap.t list -> unit type run_error = | NanOrInf of string * Mir.expression Pos.marked @@ -127,7 +127,7 @@ struct mutable ctx_nb_bloquantes : int; mutable ctx_finalized_anos : (Com.Error.t * string option) list; mutable ctx_exported_anos : (Com.Error.t * string option) list; - mutable ctx_events : Com.event_value StrMap.t IntMap.t; + mutable ctx_events : Com.Var.t Com.event_value StrMap.t IntMap.t; } let empty_ctx (p : Mir.program) : ctx = @@ -181,9 +181,9 @@ struct value_inputs let update_ctx_with_events (ctx : ctx) (p : Mir.program) - (events : Com.event_value IntMap.t list) : unit = + (events : Com.Var.t Com.event_value IntMap.t list) : unit = let ctx_events = - let fold (map, idx) (evt : Com.event_value IntMap.t) = + let fold (map, idx) (evt : Com.Var.t Com.event_value IntMap.t) = let foldEvt id ev map = match IntMap.find_opt id p.program_event_field_idxs with | Some fname -> ( @@ -215,7 +215,7 @@ struct let pp_ev fmt = function | Com.Numeric None -> Pp.string fmt "indefini" | Com.Numeric (Some f) -> Pp.float fmt f - | Com.RefVar v -> Pp.string fmt v + | Com.RefVar v -> Pp.string fmt (Com.Var.name_str v) in IntMap.iter (fun i m -> @@ -488,6 +488,19 @@ struct match StrMap.find_opt (Pos.unmark a) (Com.Var.attrs var) with | Some l -> Number (N.of_float (float (Pos.unmark l))) | None -> Undefined) + | EventField (e, f) -> ( + let new_e = evaluate_expr ctx p e in + match new_e with + | Number z when N.(z >=. zero ()) -> ( + let i = Int64.to_int N.(to_int z) in + match IntMap.find_opt i ctx.ctx_events with + | Some m -> ( + match StrMap.find (Pos.unmark f) m with + | Com.Numeric (Some v) -> Number N.(of_float v) + | Com.Numeric None -> Undefined + | Com.RefVar var -> get_var_value ctx var 0) + | None -> Undefined) + | _ -> Undefined) | Size var -> ( let var, _ = get_var ctx (Pos.unmark var) in match Com.Var.is_table var with @@ -497,8 +510,7 @@ struct | NbDiscordances -> Number (N.of_float (float ctx.ctx_nb_discos)) | NbInformatives -> Number (N.of_float (float ctx.ctx_nb_infos)) | NbBloquantes -> Number (N.of_float (float ctx.ctx_nb_bloquantes)) - | NbCategory _ -> assert false - | FuncCallLoop _ | Loop _ -> assert false + | NbCategory _ | FuncCallLoop _ | Loop _ -> assert false with | RuntimeError (e, ctx) -> if !exit_on_rte then raise_runtime_as_structured e @@ -649,6 +661,30 @@ struct | PrintAlias (var, _) -> let var, _ = get_var ctx var in pr_raw ctx_pr (Com.Var.alias_str var) + | PrintEventName (e, f) -> ( + match evaluate_expr ctx p e with + | Number x -> ( + let i = Int64.to_int (N.to_int x) in + match IntMap.find_opt i ctx.ctx_events with + | Some m -> ( + match StrMap.find_opt (Pos.unmark f) m with + | Some (Com.RefVar var) -> + pr_raw ctx_pr (Com.Var.name_str var) + | _ -> ()) + | None -> ()) + | Undefined -> ()) + | PrintEventAlias (e, f) -> ( + match evaluate_expr ctx p e with + | Number x -> ( + let i = Int64.to_int (N.to_int x) in + match IntMap.find_opt i ctx.ctx_events with + | Some m -> ( + match StrMap.find_opt (Pos.unmark f) m with + | Some (Com.RefVar var) -> + pr_raw ctx_pr (Com.Var.alias_str var) + | _ -> ()) + | None -> ()) + | Undefined -> ()) | PrintIndent e -> let diff = match evaluate_expr ctx p e with @@ -951,7 +987,7 @@ let prepare_interp (sort : Cli.value_sort) (roundops : Cli.round_ops) : unit = | _ -> () let evaluate_program (p : Mir.program) (inputs : Com.literal Com.Var.Map.t) - (events : Com.event_value IntMap.t list) (sort : Cli.value_sort) + (events : Com.Var.t Com.event_value IntMap.t list) (sort : Cli.value_sort) (roundops : Cli.round_ops) : float option StrMap.t * StrSet.t = prepare_interp sort roundops; let module Interp = (val get_interp sort roundops : S) in diff --git a/src/mlang/m_ir/mir_interpreter.mli b/src/mlang/m_ir/mir_interpreter.mli index 55a8aa5e5..078f18767 100644 --- a/src/mlang/m_ir/mir_interpreter.mli +++ b/src/mlang/m_ir/mir_interpreter.mli @@ -68,7 +68,7 @@ module type S = sig mutable ctx_nb_bloquantes : int; mutable ctx_finalized_anos : (Com.Error.t * string option) list; mutable ctx_exported_anos : (Com.Error.t * string option) list; - mutable ctx_events : Com.event_value StrMap.t IntMap.t; + mutable ctx_events : Com.Var.t Com.event_value StrMap.t IntMap.t; } (** Interpretation context *) @@ -81,7 +81,7 @@ module type S = sig val update_ctx_with_inputs : ctx -> Com.literal Com.Var.Map.t -> unit val update_ctx_with_events : - ctx -> Mir.program -> Com.event_value IntMap.t list -> unit + ctx -> Mir.program -> Com.Var.t Com.event_value IntMap.t list -> unit (** Interpreter runtime errors *) type run_error = @@ -160,7 +160,7 @@ val get_interp : Cli.value_sort -> Cli.round_ops -> (module S) val evaluate_program : Mir.program -> Com.literal Com.Var.Map.t -> - Com.event_value IntMap.t list -> + Com.Var.t Com.event_value IntMap.t list -> Cli.value_sort -> Cli.round_ops -> float option StrMap.t * StrSet.t diff --git a/src/mlang/test_framework/test_interpreter.ml b/src/mlang/test_framework/test_interpreter.ml index 1875a4450..e084ece05 100644 --- a/src/mlang/test_framework/test_interpreter.ml +++ b/src/mlang/test_framework/test_interpreter.ml @@ -21,7 +21,8 @@ let find_var_of_name (p : Mir.program) (name : string Pos.marked) : Com.Var.t = let to_MIR_function_and_inputs (program : Mir.program) (t : Irj_ast.irj_file) : (Com.literal Com.Var.Map.t * float StrMap.t * StrSet.t) - * (Com.event_value IntMap.t list * float StrMap.t * StrSet.t) option = + * (Com.Var.t Com.event_value IntMap.t list * float StrMap.t * StrSet.t) + option = let inputVars = let ancsded = find_var_of_name program ("V_ANCSDED", Pos.no_pos) in let ancsded_val = Com.Float (float_of_int (!Cli.income_year + 1)) in @@ -38,6 +39,18 @@ let to_MIR_function_and_inputs (program : Mir.program) (t : Irj_ast.irj_file) : t.prim.entrees in let eventsList rappels = + let from_var vn = + let name = + match StrMap.find_opt vn program.program_alias with + | Some m_name -> Pos.unmark m_name + | None -> vn + in + match StrMap.find_opt name program.program_vars with + | Some var -> var + | None -> + Cli.error_print "Variable inconnue: %s" vn; + raise (Errors.StructuredError ("Fichier de test incorrect", [], None)) + in let fromDirection = function | "R" -> Some 0.0 | "C" -> Some 1.0 @@ -49,14 +62,14 @@ let to_MIR_function_and_inputs (program : Mir.program) (t : Irj_ast.irj_file) : raise (Errors.StructuredError ("Fichier de test incorrect", [], None)) in let fromPenalty = function - | None -> None + | None -> Some 0.0 (* None *) | Some p when 0 <= p && p <= 99 -> Some (float p) | Some p -> Cli.error_print "Code de pénalité: %d, devrait être entre 0 et 99" p; raise (Errors.StructuredError ("Fichier de test incorrect", [], None)) in let from_2042_rect = function - | None -> None + | None -> Some 0.0 (* None *) | Some 0 -> Some 0.0 | Some 1 -> Some 1.0 | Some r -> @@ -68,7 +81,7 @@ let to_MIR_function_and_inputs (program : Mir.program) (t : Irj_ast.irj_file) : IntMap.empty |> IntMap.add 0 (Com.Numeric (Some (float rappel.event_nb))) |> IntMap.add 1 (Com.Numeric (Some (float rappel.rappel_nb))) - |> IntMap.add 2 (Com.RefVar rappel.variable_code) + |> IntMap.add 2 (Com.RefVar (from_var rappel.variable_code)) |> IntMap.add 3 (Com.Numeric (Some (float rappel.change_value))) |> IntMap.add 4 (Com.Numeric (fromDirection rappel.direction)) |> IntMap.add 5 (Com.Numeric (fromPenalty rappel.penalty_code))