Skip to content

Commit

Permalink
Merge pull request #94 from MLanguage/improve-anomaly-handling
Browse files Browse the repository at this point in the history
Improve anomaly handling
  • Loading branch information
denismerigoux authored Nov 15, 2021
2 parents d994b4c + 8f9d90a commit 066141e
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 112 deletions.
4 changes: 2 additions & 2 deletions examples/dgfip_c/backend_tests/test_harness.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ int main(int argc, char *argv[])
int num_outputs = m_num_inputs();
m_value *outputs_array_for_m = malloc(num_outputs * sizeof(m_value));
m_output *output_for_m = malloc(sizeof(m_input));
m_error *errors;
m_error_occurrence *errors;

char *name;
char *value_s;
Expand Down Expand Up @@ -89,7 +89,7 @@ int main(int argc, char *argv[])
// Here we move to controlling the outputs, so we
// have to run the computation!
m_input_from_array(input_for_m, input_array_for_m);
errors = malloc(sizeof(Errors));
errors = malloc(sizeof(error_occurrences));
output_for_m->errors = errors;
m_extracted(output_for_m, input_for_m);
free(output_for_m->errors);
Expand Down
19 changes: 16 additions & 3 deletions examples/dgfip_c/m_error.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
/* Copyright (C) 2021 Inria, contributor: James Barnes <[email protected]>
This program is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If
not, see <https://www.gnu.org/licenses/>. */

#include "m_error.h"

int get_occurred_errors_count(m_error *errors, int size) {
int get_occurred_errors_count(m_error_occurrence* errors, int size) {
int count = 0;

for (int i = 0; i < size; i++) {
Expand All @@ -12,8 +25,8 @@ int get_occurred_errors_count(m_error *errors, int size) {
return count;
}

m_error *get_occurred_errors_items(int full_list_count, m_error *full_list,
m_error *filtered_errors) {
m_error_occurrence* get_occurred_errors_items(int full_list_count, m_error_occurrence* full_list,
m_error_occurrence* filtered_errors) {
int count = 0;

for (int i = 0; i < full_list_count; i++) {
Expand Down
36 changes: 27 additions & 9 deletions examples/dgfip_c/m_error.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
/* Copyright (C) 2021 Inria, contributor: James Barnes <[email protected]>
This program is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If
not, see <https://www.gnu.org/licenses/>. */

#ifndef M_ERROR_
#define M_ERROR_

Expand All @@ -9,17 +22,22 @@
typedef enum error_kind { Anomaly, Discordance, Information } error_kind;

typedef struct m_error {
char kind[2];
char major_code[4];
char minor_code[7];
char description[81];
char isisf[2];
bool has_occurred;
const char* kind;
const char* major_code;
const char* minor_code;
const char* description;
const char* isisf;
const char* code_information;
} m_error;

int get_occurred_errors(m_error *errors, int size);
typedef struct m_error_occurrence {
const m_error *error;
bool has_occurred;
} m_error_occurrence;

int get_occurred_errors(m_error_occurrence *errors, int size);

m_error *get_occurred_errors_items(int full_list_count, m_error *full_list,
m_error *filtered_errors);
m_error_occurrence* get_occurred_errors_items(int full_list_count, m_error_occurrence *full_list,
m_error_occurrence *filtered_errors);

#endif /* M_ERROR_ */
170 changes: 72 additions & 98 deletions src/mlang/backend_compilers/bir_to_dgfip_c.ml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ open Mir

let none_value = "m_undefined"

module ErrorSet = Set.Make (Error)

let generate_comp_op (op : Mast.comp_op) : string =
match op with
| Mast.Gt -> "m_gt"
Expand Down Expand Up @@ -167,53 +165,36 @@ let generate_var_def (var_indexes : int Mir.VariableMap.t) (var : Mir.Variable.t
defs
(generate_variable var_indexes (GetValueVar "generic_index"))
var sv
(* Errors.raise_spanned_error "generic index table definitions not supported in C the backend"
* (Pos.get_position e) *)
| InputVar -> assert false

let generate_var_cond (var_indexes : int Mir.VariableMap.t) (cond : condition_data)
(oc : Format.formatter) =
let scond, defs = generate_c_expr cond.cond_expr var_indexes in
let percent = Re.Pcre.regexp "%" in
Format.fprintf oc
{|
%acond = %s;
if (m_is_defined_true(cond))
{%a%a
}
|}
Format.fprintf oc "@[<hv 0>%acond = %s;@,@[<hv 2>if (m_is_defined_true(cond)){@,%a@]@,}@,@,@]"
(format_local_vars_defs var_indexes)
defs scond
(* A019:anomalie :"A":"019":"00":"ATTENTION CALCUL NON EFFECTUE PAR L'ESI":"N"; *)
(fun fmt err ->
let error_descr =
(Pos.unmark @@ err.Mir.Error.descr.kind)
^ (Pos.unmark @@ err.Mir.Error.descr.major_code)
^ Pos.unmark @@ err.Mir.Error.descr.minor_code
in
let error_descr = Re.Pcre.substitute ~rex:percent ~subst:(fun _ -> "%%") error_descr in
Format.fprintf fmt
{|
output->errors[m_get_error_index("%s")].has_occurred = true;|}
error_descr)
(fst cond.cond_error)
(fun oc () ->
let error, _ = cond.cond_error in
let error_pos = error.id in
Format.fprintf oc
"@[<hv 0>m_error_occurrence occurrence = output->errors[%d]; @,\
occurrence.error = &m_errors[%d]; @,\
occurrence.has_occurred = true;@]@,"
error_pos error_pos;
if (fst cond.cond_error).Mir.Error.typ = Mast.Anomaly then
Format.fprintf oc
{|
output->is_error = true;
#ifndef ANOMALY_LIMIT
free(TGV);
free(LOCAL);
return -1;
#else /* ANOMALY_LIMIT */
if (anomaly_count >= max_anomalies) {
free(TGV);
free(LOCAL);
return -1;
}
#endif /* ANOMALY_LIMIT */
|})
"output->is_error = true;@,\
#ifndef ANOMALY_LIMIT @,\
free(TGV); @,\
free(LOCAL); @,\
return -1; @,\
#else /* ANOMALY_LIMIT */ @,\
@[<hv 2>if (anomaly_count >= max_anomalies) {@,\
\ free(TGV); @,\
\ free(LOCAL);@,\
\ return -1;@]@,\
}@,\
#endif /* ANOMALY_LIMIT */")
()

let fresh_cond_counter = ref 0
Expand Down Expand Up @@ -339,11 +320,11 @@ let generate_main_function_signature_and_var_decls (p : Bir.program)
Format.fprintf oc "m_value cond;@\n@\n";
Format.fprintf oc
{|
#ifdef ANOMALY_LIMIT
int anomaly_count = 0;
int max_anomalies = ANOMALY_LIMIT;
#endif /* ANOMALY_LIMIT */
|}
#ifdef ANOMALY_LIMIT
int anomaly_count = 0;
int max_anomalies = ANOMALY_LIMIT;
#endif /* ANOMALY_LIMIT */
|}

let generate_return (var_indexes : int Mir.VariableMap.t) (oc : Format.formatter)
(function_spec : Bir_interface.bir_function) =
Expand All @@ -369,39 +350,6 @@ let generate_header (oc : Format.formatter) () : unit =
let generate_footer (oc : Format.formatter) () : unit =
Format.fprintf oc "\n#endif /* IR_HEADER_ */"

let generate_get_error_index_prototype (oc : Format.formatter) (add_semicolon : bool) =
Format.fprintf oc "int m_get_error_index(char *name)%s" (if add_semicolon then ";\n\n" else "")

let generate_get_error_index_func (oc : Format.formatter) (errors : ErrorSet.t) =
let error_counter = ref 0 in
Format.fprintf oc
"%a {@\n%a @\n printf(\"Error %%s not found!\", name);@\n exit(-1); @\n}@\n"
generate_get_error_index_prototype false
(fun oc () ->
ErrorSet.iter
(fun (error : Error.t) ->
Format.fprintf oc " if (strcmp(\"%s%s%s\", name) == 0) { return %d; } \n"
(Pos.unmark error.descr.kind)
(Pos.unmark error.descr.major_code)
(Pos.unmark error.descr.minor_code)
!error_counter;
error_counter := !error_counter + 1)
errors)
()

let generate_get_error_count_prototype (oc : Format.formatter) (add_semicolon : bool) =
Format.fprintf oc "int m_num_errors()%s" (if add_semicolon then ";\n\n" else "")

let generate_get_error_count_func (oc : Format.formatter) (errors : ErrorSet.t) =
Format.fprintf oc
{|
%a {
return %d;
}

|}
generate_get_error_count_prototype false (ErrorSet.cardinal errors)

let generate_empty_input_prototype (oc : Format.formatter) (add_semicolon : bool) =
Format.fprintf oc "void m_empty_input(m_input *input)%s" (if add_semicolon then ";\n\n" else "")

Expand Down Expand Up @@ -474,7 +422,7 @@ let generate_get_input_num_func (oc : Format.formatter) (function_spec : Bir_int

let generate_input_type (oc : Format.formatter) (function_spec : Bir_interface.bir_function) =
let input_vars = List.map fst (VariableMap.bindings function_spec.func_variable_inputs) in
Format.fprintf oc "typedef struct m_input {@[<h 2>%a@]@\n} m_input;@\n@\n"
Format.fprintf oc "@[<h 2>typedef struct m_input {@,%a@]@\n} m_input;@\n@\n"
(Format.pp_print_list
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
(fun fmt var ->
Expand Down Expand Up @@ -565,7 +513,7 @@ let generate_output_type (oc : Format.formatter) (function_spec : Bir_interface.
let output_vars = List.map fst (VariableMap.bindings function_spec.func_outputs) in
Format.fprintf oc
"@[<v 2>typedef struct m_output {@,\
m_error *errors;@,\
m_error_occurrence *errors;@,\
bool is_error;@,\
%a@.@[<h>}@ m_output;@]@]@\n\
@\n"
Expand All @@ -575,13 +523,47 @@ let generate_output_type (oc : Format.formatter) (function_spec : Bir_interface.
Format.fprintf fmt "m_value %s; // %s" (generate_name var) (Pos.unmark var.Variable.descr)))
output_vars

let error_table_definitions (oc : Format.formatter) (program : Bir.program) =
let error_set_size = VariableMap.cardinal program.mir_program.program_conds in
Format.fprintf oc "typedef m_error_occurrence error_occurrences[%d];\n" error_set_size;
Format.fprintf oc "typedef m_error errors[%d];\n" error_set_size

let print_error_line (oc : Format.formatter) (cond_data : condition_data) =
let err, var = cond_data.cond_error in
Format.fprintf oc
"{.kind = \"%s\", .major_code = \"%s\", .minor_code = \"%s\", .isisf = \"%s\",.description = \
\"%s\", .code_information = %s},@,"
(Strings.sanitize_str err.descr.kind)
(Strings.sanitize_str err.descr.major_code)
(Strings.sanitize_str err.descr.minor_code)
(Strings.sanitize_str err.descr.isisf)
(Strings.sanitize_str err.descr.description)
(match var with
| None -> "\"\""
| Some v -> ( match v.alias with Some alias -> "\"" ^ alias ^ "\"" | None -> assert false))

let generate_errors_table (oc : Format.formatter) (program : Bir.program) =
Format.fprintf oc "@[<hv 2>static const errors m_errors = {@,%a@]};"
(fun oc conds -> VariableMap.iter (fun _ cond_data -> print_error_line oc cond_data) conds)
program.mir_program.program_conds

let generate_get_error_count_prototype (oc : Format.formatter) (add_semicolon : bool) =
Format.fprintf oc "int m_num_errors()%s" (if add_semicolon then ";\n\n" else "")

let generate_get_error_count_func (oc : Format.formatter) (program : Bir.program) =
Format.fprintf oc {|
%a {
return %d;
}

|} generate_get_error_count_prototype false
(VariableMap.cardinal program.mir_program.program_conds)

let generate_implem_header oc header_filename =
Format.fprintf oc "// File generated by the Mlang compiler\n\n";
Format.fprintf oc "#include \"%s\"\n\n" header_filename;
Format.fprintf oc "#include <string.h>\n"

let generate_cond_table _ v error_set = ErrorSet.add (fst v.cond_error) error_set

let generate_c_program (program : Bir.program) (function_spec : Bir_interface.bir_function)
(filename : string) : unit =
if Filename.extension filename <> ".c" then
Expand All @@ -591,32 +573,24 @@ let generate_c_program (program : Bir.program) (function_spec : Bir_interface.bi
let _oc = open_out header_filename in
let var_indexes, var_table_size = get_variables_indexes program function_spec in
let oc = Format.formatter_of_out_channel _oc in
let error_set =
VariableMap.fold generate_cond_table program.mir_program.program_conds ErrorSet.empty
in
let conds oc () =
Format.fprintf oc "typedef m_error Errors[%d]; @\n@\n" (ErrorSet.cardinal error_set)
in
Format.fprintf oc "%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a" generate_header () conds ()
generate_input_type function_spec generate_empty_input_prototype true
Format.fprintf oc "%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a" generate_header () error_table_definitions
program generate_input_type function_spec generate_empty_input_prototype true
generate_input_from_array_prototype true generate_get_input_index_prototype true
generate_get_input_num_prototype true generate_get_input_name_from_index_prototype true
generate_output_type function_spec generate_output_to_array_prototype true
generate_get_output_index_prototype true generate_get_output_name_from_index_prototype true
generate_get_output_num_prototype true generate_empty_output_prototype true
generate_get_error_index_prototype true generate_get_error_count_prototype true
generate_main_function_signature true generate_footer ();
generate_get_error_count_prototype true generate_main_function_signature true generate_footer ();
close_out _oc;
let _oc = open_out filename in
let oc = Format.formatter_of_out_channel _oc in
Format.fprintf oc "%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a" generate_implem_header header_filename
generate_get_error_index_func error_set generate_get_error_count_func error_set
generate_empty_input_func function_spec generate_input_from_array_func function_spec
generate_get_input_index_func function_spec generate_get_input_name_from_index_func
function_spec generate_get_input_num_func function_spec generate_output_to_array_func
function_spec generate_get_output_index_func function_spec
generate_get_output_name_from_index_func function_spec generate_get_output_num_func
function_spec generate_empty_output_func function_spec
generate_errors_table program generate_get_error_count_func program generate_empty_input_func
function_spec generate_input_from_array_func function_spec generate_get_input_index_func
function_spec generate_get_input_name_from_index_func function_spec generate_get_input_num_func
function_spec generate_output_to_array_func function_spec generate_get_output_index_func
function_spec generate_get_output_name_from_index_func function_spec
generate_get_output_num_func function_spec generate_empty_output_func function_spec
(generate_rule_functions program var_indexes)
program.rules
(generate_main_function_signature_and_var_decls program var_indexes var_table_size)
Expand Down

0 comments on commit 066141e

Please sign in to comment.