Compiling simple program correctly to C

This commit is contained in:
Denis Merigoux 2023-12-13 11:07:08 +01:00
parent 827fcef469
commit 5c49581207
No known key found for this signature in database
GPG Key ID: EE99DCFA365C3EE3
2 changed files with 73 additions and 25 deletions

View File

@ -81,6 +81,21 @@ let rec translate_expr (ctxt : 'm ctxt) (expr : 'm L.expr) : A.block * A.expr =
(* In C89, struct literates have to be initialized at variable (* In C89, struct literates have to be initialized at variable
definition... *) definition... *)
raise (NotAnExpr { needs_a_local_decl = false }) raise (NotAnExpr { needs_a_local_decl = false })
| EInj { e = e1; cons; name } when not ctxt.config.no_struct_literals ->
let e1_stmts, new_e1 = translate_expr ctxt e1 in
( e1_stmts,
( A.EInj
{
e1 = new_e1;
cons;
name;
expr_typ = Expr.maybe_ty (Mark.get expr);
},
Expr.pos expr ) )
| EInj _ when ctxt.config.no_struct_literals ->
(* In C89, struct literates have to be initialized at variable
definition... *)
raise (NotAnExpr { needs_a_local_decl = false })
| ETuple args -> | ETuple args ->
let args_stmts, new_args = let args_stmts, new_args =
List.fold_left List.fold_left
@ -98,17 +113,6 @@ let rec translate_expr (ctxt : 'm ctxt) (expr : 'm L.expr) : A.block * A.expr =
| ETupleAccess { e = e1; index; _ } -> | ETupleAccess { e = e1; index; _ } ->
let e1_stmts, new_e1 = translate_expr ctxt e1 in let e1_stmts, new_e1 = translate_expr ctxt e1 in
e1_stmts, (A.ETupleAccess { e1 = new_e1; index }, Expr.pos expr) e1_stmts, (A.ETupleAccess { e1 = new_e1; index }, Expr.pos expr)
| EInj { e = e1; cons; name } ->
let e1_stmts, new_e1 = translate_expr ctxt e1 in
( e1_stmts,
( A.EInj
{
e1 = new_e1;
cons;
name;
expr_typ = Expr.maybe_ty (Mark.get expr);
},
Expr.pos expr ) )
| EApp | EApp
{ {
f = EOp { op = Op.HandleDefaultOpt; tys = _ }, _binder_mark; f = EOp { op = Op.HandleDefaultOpt; tys = _ }, _binder_mark;
@ -204,11 +208,7 @@ and translate_statements (ctxt : 'm ctxt) (block_expr : 'm L.expr) : A.block =
([], []) exceptions ([], []) exceptions
in in
let just_stmts, new_just = translate_expr ctxt just in let just_stmts, new_just = translate_expr ctxt just in
let new_cons = translate_statements ctxt cons in let cons_stmts, new_cons = translate_expr ctxt cons in
(* Be careful ! Here, [new_cons]'s last statement is the definition of the
final value we want from this expression. However, this final value is of
type [tau] instead of type [option tau]. We need to inject it
correctly... *)
exceptions_stmts exceptions_stmts
@ just_stmts @ just_stmts
@ [ @ [
@ -217,7 +217,20 @@ and translate_statements (ctxt : 'm ctxt) (block_expr : 'm L.expr) : A.block =
{ {
exceptions = new_exceptions; exceptions = new_exceptions;
just = new_just; just = new_just;
cons = new_cons; cons =
cons_stmts
@ [
( (match ctxt.inside_definition_of with
| None -> A.SReturn (Mark.remove new_cons)
| Some x ->
A.SLocalDef
{
name = Mark.copy new_cons x;
expr = new_cons;
typ = Expr.maybe_ty (Mark.get block_expr);
}),
Expr.pos block_expr );
];
return_typ = Expr.maybe_ty (Mark.get block_expr); return_typ = Expr.maybe_ty (Mark.get block_expr);
}), }),
Expr.pos block_expr ); Expr.pos block_expr );
@ -395,6 +408,37 @@ and translate_statements (ctxt : 'm ctxt) (block_expr : 'm L.expr) : A.block =
] ]
| _ -> []) | _ -> [])
@ [A.SRaise except, Expr.pos block_expr] @ [A.SRaise except, Expr.pos block_expr]
| EInj { e = e1; cons; name } when ctxt.config.no_struct_literals ->
let e1_stmts, new_e1 = translate_expr ctxt e1 in
let tmp_struct_var_name =
match ctxt.inside_definition_of with
| None ->
failwith "should not happen"
(* [translate_expr] should create this [inside_definition_of]*)
| Some x -> x, Expr.pos block_expr
in
let inj_expr =
( A.EInj
{
e1 = new_e1;
cons;
name;
expr_typ = Expr.maybe_ty (Mark.get block_expr);
},
Expr.pos block_expr )
in
e1_stmts
@ [
( A.SLocalInit
{
name = tmp_struct_var_name;
expr = inj_expr;
typ =
( Mark.remove (Expr.maybe_ty (Mark.get block_expr)),
Expr.pos block_expr );
},
Expr.pos block_expr );
]
| EStruct { fields; name } when ctxt.config.no_struct_literals -> | EStruct { fields; name } when ctxt.config.no_struct_literals ->
let args_stmts, new_args = let args_stmts, new_args =
StructField.Map.fold StructField.Map.fold

View File

@ -355,7 +355,8 @@ let rec format_expression (ctx : decl_ctx) (fmt : Format.formatter) (e : expr) :
| EStructFieldAccess { e1; field; _ } -> | EStructFieldAccess { e1; field; _ } ->
Format.fprintf fmt "%a.%a" (format_expression ctx) e1 Format.fprintf fmt "%a.%a" (format_expression ctx) e1
format_struct_field_name field format_struct_field_name field
| EInj { e1 = _e; cons; name = e_name; expr_typ } | EInj { e1 = e; cons; name = e_name; expr_typ }
(* These should only appear when initializing a variable definition *)
when EnumName.equal e_name Expr.option_enum -> when EnumName.equal e_name Expr.option_enum ->
let e_name = let e_name =
TypMap.find TypMap.find
@ -368,14 +369,17 @@ let rec format_expression (ctx : decl_ctx) (fmt : Format.formatter) (e : expr) :
List.map fst List.map fst
(EnumConstructor.Map.bindings (EnumName.Map.find e_name ctx.ctx_enums)) (EnumConstructor.Map.bindings (EnumName.Map.find e_name ctx.ctx_enums))
in in
let _some_cons, _none_cons = let some_cons, none_cons =
match option_config with match option_config with
| [some_cons; none_cons] -> some_cons, none_cons | [some_cons; none_cons] -> some_cons, none_cons
| _ -> failwith "should not happen" | _ -> failwith "should not happen"
in in
if EnumConstructor.equal cons Expr.none_constr then if EnumConstructor.equal cons Expr.none_constr then
Format.fprintf fmt "NONE" Format.fprintf fmt "{%a_%a,@ {none_cons: NULL}}" format_enum_name e_name
else Format.fprintf fmt "SOME" format_enum_cons_name none_cons
else
Format.fprintf fmt "{%a_%a,@ {some_cons: %a}}" format_enum_name e_name
format_enum_cons_name some_cons (format_expression ctx) e
| EInj { e1 = e; cons; name = enum_name; _ } -> | EInj { e1 = e; cons; name = enum_name; _ } ->
Format.fprintf fmt "new(\"catala_enum_%a\", code = \"%a\",@ value = %a)" Format.fprintf fmt "new(\"catala_enum_%a\", code = \"%a\",@ value = %a)"
format_enum_name enum_name format_enum_cons_name cons format_enum_name enum_name format_enum_cons_name cons
@ -582,7 +586,7 @@ let rec format_statement
List.map fst List.map fst
(EnumConstructor.Map.bindings (EnumName.Map.find e_name ctx.ctx_enums)) (EnumConstructor.Map.bindings (EnumName.Map.find e_name ctx.ctx_enums))
in in
let some_cons, _none_cons = let some_cons, none_cons =
match option_config with match option_config with
| [some_cons; none_cons] -> some_cons, none_cons | [some_cons; none_cons] -> some_cons, none_cons
| _ -> failwith "should not happen" | _ -> failwith "should not happen"
@ -594,12 +598,12 @@ let rec format_statement
let variable_defined_in_cons = let variable_defined_in_cons =
match List.hd (List.rev cons) with match List.hd (List.rev cons) with
| SReturn (EVar v), _ -> v | SReturn (EVar v), _ -> v
| SLocalDef { name; _ }, _ -> Mark.remove name | SLocalDef { name; _ }, _ | SLocalInit { name; _ }, _ -> Mark.remove name
| _ -> failwith "should not happen" | _ -> failwith "should not happen"
in in
Format.fprintf fmt "%a = {0,{NULL}};@," Format.fprintf fmt "@[<hov 2>%a = {%a_%a,@ {none_cons: NULL}};@]@,"
(format_typ ctx (fun fmt -> format_var fmt exception_acc_var)) (format_typ ctx (fun fmt -> format_var fmt exception_acc_var))
return_typ; return_typ format_enum_name e_name format_enum_cons_name none_cons;
Format.fprintf fmt "%a;@," Format.fprintf fmt "%a;@,"
(format_typ ctx (fun fmt -> format_var fmt exception_current)) (format_typ ctx (fun fmt -> format_var fmt exception_current))
return_typ; return_typ;