Skip to content

Commit b02fdbe

Browse files
committed
C backend: generate .h files and use them for imported modules
Also includes some fixes to the propagation of visibility info of types.
1 parent dd6ef8b commit b02fdbe

File tree

5 files changed

+116
-73
lines changed

5 files changed

+116
-73
lines changed

compiler/dcalc/from_scopelang.ml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,14 @@ let translate_program (prgm : 'm S.program) : 'm Ast.program =
921921
StructName.Map.add scope_sig_ctx.scope_sig_input_struct fields acc)
922922
scopes_parameters decl_ctx.ctx_structs
923923
in
924-
let decl_ctx = { decl_ctx with ctx_structs } in
924+
let ctx_public_types =
925+
ScopeName.Map.fold (fun scope sig_ctx acc ->
926+
if (ScopeName.Map.find scope decl_ctx.ctx_scopes).visibility = Public
927+
then TypeIdent.Set.add (Struct sig_ctx.scope_sig_input_struct) acc
928+
else acc)
929+
scopes_parameters decl_ctx.ctx_public_types
930+
in
931+
let decl_ctx = { decl_ctx with ctx_structs; ctx_public_types } in
925932
let toplevel_vars =
926933
TopdefName.Map.mapi
927934
(fun name (_, ty, _vis) ->

compiler/driver.ml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -996,10 +996,21 @@ module Commands = struct
996996
~renaming:(Some Scalc.To_c.renaming)
997997
in
998998
let output_file, with_output = get_output_format options ~ext:".c" output in
999+
let out_intf, with_output_intf =
1000+
match output_file with
1001+
| Some f when prg.module_name <> None ->
1002+
let f = File.(f -.- "h") in
1003+
File.get_formatter_of_out_channel ~source_file:options.Global.input_src ~output_file:(Some f)
1004+
~ext:".h" ()
1005+
| _ -> None, fun pp -> pp (Format.make_formatter (fun _ _ _ -> ()) ignore)
1006+
in
9991007
Message.debug "Compiling program into C...";
1000-
Message.debug "Writing to %s..."
1001-
(Option.value ~default:"stdout" output_file);
1002-
with_output @@ fun fmt -> Scalc.To_c.format_program fmt prg type_ordering
1008+
Message.debug "Writing to %s / %s..."
1009+
(Option.value ~default:"stdout" output_file)
1010+
(Option.value ~default:"no interface output" out_intf);
1011+
with_output @@ fun ppf_src ->
1012+
with_output_intf @@ fun ppf_intf ->
1013+
Scalc.To_c.format_program ~ppf_src ~ppf_intf prg type_ordering
10031014

10041015
let c_cmd =
10051016
Cmd.v

compiler/scalc/to_c.ml

Lines changed: 86 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ let rec format_typ
147147

148148
let format_ctx
149149
(type_ordering : TypeIdent.t list)
150-
(fmt : Format.formatter)
150+
~ppc ~pph
151151
(ctx : decl_ctx) : unit =
152152
let format_struct_decl fmt (struct_name, struct_fields) =
153153
let fields = StructField.Map.bindings struct_fields in
@@ -171,16 +171,15 @@ let format_ctx
171171
if EnumConstructor.Map.is_empty enum_cons then
172172
failwith "no constructors in the enum"
173173
else
174-
Format.fprintf fmt "@,@[<v 2>enum %s_code {@,%a@;<0 -2>}@] %s__code;@,"
174+
Format.fprintf fmt "@,@[<v 2>enum %s__code {@,%a@;<0 -2>}@];@,"
175175
(EnumName.base enum_name)
176176
(Format.pp_print_list
177177
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@ ")
178178
(fun fmt (enum_cons, _) -> EnumConstructor.format fmt enum_cons))
179-
(EnumConstructor.Map.bindings enum_cons)
180-
(EnumName.base enum_name);
179+
(EnumConstructor.Map.bindings enum_cons);
181180
Format.fprintf fmt
182181
"@,\
183-
@[<v 2>typedef struct %s {@ enum %s_code code;@ @[<v 2>union {@ %a@]@,\
182+
@[<v 2>typedef struct %s {@ enum %s__code code;@ @[<v 2>union {@ %a@]@,\
184183
} payload;@]@,\
185184
} %s;" (EnumName.base enum_name) (EnumName.base enum_name)
186185
(Format.pp_print_list
@@ -194,36 +193,32 @@ let format_ctx
194193
(EnumConstructor.Map.bindings enum_cons)
195194
(EnumName.base enum_name)
196195
in
197-
198-
let is_in_type_ordering s =
199-
List.exists
200-
(fun struct_or_enum ->
201-
match struct_or_enum with
202-
| TypeIdent.Enum _ -> false
203-
| TypeIdent.Struct s' -> s = s')
204-
type_ordering
205-
in
206196
let scope_structs =
207-
List.map
208-
(fun (s, _) -> TypeIdent.Struct s)
209-
(StructName.Map.bindings
210-
(StructName.Map.filter
211-
(fun s _ -> not (is_in_type_ordering s))
212-
ctx.ctx_structs))
197+
List.fold_left (fun acc -> function
198+
| TypeIdent.Struct s -> StructName.Map.remove s acc
199+
| _ -> acc)
200+
ctx.ctx_structs type_ordering
201+
|> StructName.Map.keys
202+
|> List.map (fun s -> TypeIdent.Struct s)
213203
in
214-
Format.pp_print_list
215-
~pp_sep:(fun _ () -> ())
216-
(fun fmt struct_or_enum ->
204+
List.iter
205+
(fun struct_or_enum ->
217206
match struct_or_enum with
218-
| TypeIdent.Struct s ->
207+
| TypeIdent.Struct s as tid ->
219208
if StructName.path s = [] then
220-
Format.fprintf fmt "@,%a" format_struct_decl
221-
(s, StructName.Map.find s ctx.ctx_structs)
222-
| TypeIdent.Enum e ->
209+
let def = StructName.Map.find s ctx.ctx_structs in
210+
Format.fprintf ppc "@,%a" format_struct_decl (s, def);
211+
if TypeIdent.Set.mem tid ctx.ctx_public_types
212+
then Format.fprintf pph "@,%a" format_struct_decl (s, def)
213+
else Format.eprintf "NOT PUB: %a (pub: %a)@."
214+
StructName.format s
215+
(Format.pp_print_seq ~pp_sep:Format.pp_print_space TypeIdent.format) (TypeIdent.Set.to_seq ctx.ctx_public_types)
216+
| TypeIdent.Enum e as tid ->
223217
if EnumName.path e = [] then
224-
Format.fprintf fmt "@,%a" format_enum_decl
225-
(e, EnumName.Map.find e ctx.ctx_enums))
226-
fmt
218+
let def = EnumName.Map.find e ctx.ctx_enums in
219+
Format.fprintf ppc "@,%a" format_enum_decl (e, def);
220+
if TypeIdent.Set.mem tid ctx.ctx_public_types
221+
then Format.fprintf pph "@,%a" format_enum_decl (e, def))
227222
(type_ordering @ scope_structs)
228223

229224
let format_lit (fmt : Format.formatter) (l : lit Mark.pos) : unit =
@@ -714,26 +709,36 @@ let format_main (fmt : Format.formatter) (p : Ast.program) =
714709
Format.fprintf fmt "@,return 0;@;<1 -2>}@]"
715710

716711
let format_program
717-
(fmt : Format.formatter)
712+
~ppf_src:ppc
713+
~ppf_intf:pph
718714
(p : Ast.program)
719715
(type_ordering : TypeIdent.t list) : unit =
720-
Fun.protect ~finally:(Format.pp_print_newline fmt)
716+
let ppboth f = f ppc; f pph in
717+
let ppboth_if condition f = f ppc; if condition then f pph in
718+
Fun.protect ~finally:(fun () -> ppboth (fun ppf -> Format.pp_print_newline ppf ()))
721719
@@ fun () ->
722-
Format.pp_open_vbox fmt 0;
723-
Format.fprintf fmt
724-
"/* This file has been generated by the Catala compiler, do not edit! */@,\
725-
@,\
726-
#include <stdio.h>@,\
720+
ppboth (fun ppf -> Format.pp_open_vbox ppf 0);
721+
ppboth (fun ppf -> Format.fprintf ppf
722+
"/* This file has been generated by the Catala compiler, do not edit! */@,@,");
723+
Format.fprintf ppc
724+
"#include <stdio.h>@,\
727725
#include <stdlib.h>@,\
728726
#include <catala_runtime.h>@,\
729727
@,";
728+
let module_id =
729+
match p.module_name with
730+
| None -> "MAIN"
731+
| Some (m, _) -> String.uppercase_ascii (String.to_ascii (ModuleName.to_string m))
732+
in
733+
Format.fprintf pph "#ifndef __%s_H__@,#define __%s_H__@," module_id module_id;
730734
List.iter
731735
(fun (m, _intf_id) ->
732-
Format.fprintf fmt "#include \"%s.c\"@,"
733-
(String.uncapitalize_ascii (ModuleName.to_string m)))
736+
ppboth @@ fun ppf -> Format.fprintf ppf "@,#include \"%s.h\""
737+
(String.uncapitalize_ascii (ModuleName.to_string m)))
734738
(Program.modules_to_list p.ctx.decl_ctx.ctx_modules);
735-
format_ctx type_ordering fmt p.ctx.decl_ctx;
736-
Format.pp_print_cut fmt ();
739+
(* TODO: check the module hash ? *)
740+
format_ctx type_ordering ~ppc ~pph p.ctx.decl_ctx;
741+
ppboth (fun ppf -> Format.pp_print_cut ppf ());
737742
let ctx = { decl_ctx = p.ctx.decl_ctx } in
738743
let _env =
739744
List.fold_left
@@ -744,21 +749,27 @@ let format_program
744749
parameters that perform lazy evaluation: {[ inline foo_type foo() {
745750
static foo_type foo = NULL; return (foo ? foo : foo = foo_init());
746751
} ]} NOTE: "inline" is not defined in C89 *)
747-
Format.fprintf fmt "@[<v 2>@[<hov 4>%a () {@]@,"
748-
(format_typ ~const:true p.ctx.decl_ctx (fun fmt ->
749-
Format.pp_print_space fmt ();
750-
VarName.format fmt var))
751-
typ;
752-
Format.fprintf fmt "@[<hov 2>static %a = NULL;@]@,"
752+
let public = (* TODO: Ugh! Pass this info into scalc ! *)
753+
Re.(execp (compile (seq [str "__"; diff any digit])) (VarName.to_string var))
754+
in
755+
ppboth_if public (fun ppf ->
756+
Format.fprintf ppf "@,@[<v 2>@[<hov 4>%a"
757+
(format_typ ~const:true p.ctx.decl_ctx (fun fmt ->
758+
Format.pp_print_space fmt ();
759+
VarName.format fmt var))
760+
typ);
761+
if public then Format.fprintf pph ";@]@]@,";
762+
Format.fprintf ppc " () {@]@,";
763+
Format.fprintf ppc "@[<hov 2>static %a = NULL;@]@,"
753764
(format_typ ~const:true p.ctx.decl_ctx (fun fmt ->
754765
Format.pp_print_space fmt ();
755766
VarName.format fmt var))
756767
typ;
757-
Format.fprintf fmt "@[<hov 2>return (%a ? %a : (%a = %a));@]"
768+
Format.fprintf ppc "@[<hov 2>return (%a ? %a : (%a = %a));@]"
758769
VarName.format var VarName.format var VarName.format var
759770
(format_expression ctx env)
760771
expr;
761-
Format.fprintf fmt "@;<1 -2>}@]@,@,";
772+
Format.fprintf ppc "@;<1 -2>}@]@,";
762773
{ env with global_vars = VarName.Set.add var env.global_vars }
763774
| SFunc { var; func }
764775
| SScope { scope_body_var = var; scope_body_func = func; _ } ->
@@ -767,29 +778,36 @@ let format_program
767778
VarName.Set.of_list
768779
(List.map (fun (v, _) -> Mark.remove v) func_params)
769780
in
770-
Format.fprintf fmt
771-
"@,@[<v 2>@[<hov 4>%a@ @[<hv 1>(%a)@]@]@;<1 -2>{%a@]@,}@,"
772-
(format_typ ~const:true ctx.decl_ctx (fun fmt ->
773-
Format.pp_print_space fmt ();
774-
FuncName.format fmt var))
775-
func_return_typ
776-
(Format.pp_print_list
777-
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@ ")
778-
(fun fmt (var, typ) ->
779-
Format.pp_open_hovbox fmt 2;
780-
(format_typ ~const:true p.ctx.decl_ctx (fun fmt ->
781-
Format.pp_print_space fmt ();
782-
VarName.format fmt (Mark.remove var)))
783-
fmt typ;
784-
Format.pp_close_box fmt ()))
785-
func_params
781+
let public = (* TODO: Ugh! Pass this info into scalc ! *)
782+
Re.(execp (compile (seq [str "__"; diff any digit])) (FuncName.to_string var))
783+
in
784+
ppboth_if public (fun ppf ->
785+
Format.fprintf ppf
786+
"@,@[<v 2>@[<hov 4>%a@ @[<hv 1>(%a)@]@]"
787+
(format_typ ~const:true ctx.decl_ctx (fun fmt ->
788+
Format.pp_print_space fmt ();
789+
FuncName.format fmt var))
790+
func_return_typ
791+
(Format.pp_print_list
792+
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@ ")
793+
(fun fmt (var, typ) ->
794+
Format.pp_open_hovbox fmt 2;
795+
(format_typ ~const:true p.ctx.decl_ctx (fun fmt ->
796+
Format.pp_print_space fmt ();
797+
VarName.format fmt (Mark.remove var)))
798+
fmt typ;
799+
Format.pp_close_box fmt ()))
800+
func_params);
801+
if public then Format.fprintf pph "@];@,";
802+
Format.fprintf ppc "@;<1 -2>{%a@]@,}@,"
786803
(format_block ctx { env with local_vars })
787804
func_body;
788805
env)
789806
{ global_vars = VarName.Set.empty; local_vars = VarName.Set.empty }
790807
p.code_items
791808
in
792809
if p.module_name = None then (
793-
Format.pp_print_cut fmt ();
794-
format_main fmt p);
795-
Format.pp_close_box fmt ()
810+
Format.pp_print_cut ppc ();
811+
format_main ppc p);
812+
Format.fprintf pph "@,#endif /* __%s_H__ */" module_id;
813+
ppboth (fun ppf -> Format.pp_close_box ppf ())

compiler/scalc/to_c.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ open Shared_ast
2020

2121
val renaming : Renaming.t
2222

23-
val format_program : Format.formatter -> Ast.program -> TypeIdent.t list -> unit
23+
val format_program : ppf_src:Format.formatter -> ppf_intf:Format.formatter -> Ast.program -> TypeIdent.t list -> unit
2424
(** Usage [format_program fmt p type_dependencies_ordering] *)

compiler/shared_ast/renaming.ml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,13 +652,20 @@ let program
652652
~constrs:(fun n ->
653653
EnumConstructor.Map.find n type_renaming_ctx.constrs_map)
654654
in
655+
let ctx_public_types =
656+
TypeIdent.Set.map (function
657+
| Struct s -> Struct (StructName.Map.find s type_renaming_ctx.structs_map)
658+
| Enum s -> Enum (EnumName.Map.find s type_renaming_ctx.enums_map))
659+
p.decl_ctx.ctx_public_types
660+
in
655661
let decl_ctx =
656662
{
657663
p.decl_ctx with
658664
ctx_enums = type_renaming_ctx.ctx_enums;
659665
ctx_structs = type_renaming_ctx.ctx_structs;
660666
ctx_scopes;
661667
ctx_topdefs;
668+
ctx_public_types;
662669
}
663670
in
664671
let decl_ctx = Program.map_decl_ctx ~f:(typ ctx) decl_ctx in

0 commit comments

Comments
 (0)