The config is tested by what it is for, not by its parser alone
Exclusion says why rather than going quiet, a pattern matches by prefix, an override changes the Flan face and leaves the C symbol verbatim, and a rename dissolves a kebab collision instead of leaving both halves refused — that last one is why the kebab rule is consulted in exactly one place. The file itself too: a line that is neither directive is an error, because a typo in a name override would otherwise land a binding under the wrong name.
This commit is contained in:
parent
85ef56f657
commit
ecfe180d2e
@ -1378,6 +1378,105 @@ let () =
|
||||
check "nor is the other half of the collision"
|
||||
(not (List.exists (fun l -> contains l "\"spin2d\"") produced));
|
||||
|
||||
(* ── The config beside the header (Cimport.read_config) ────────── *)
|
||||
|
||||
(* Why there is a config at all: the generated declarations are committed, so
|
||||
a hand-edit to them is destroyed by the next regeneration and the edit has
|
||||
to live somewhere regeneration reads instead. These are the two things it
|
||||
can say. *)
|
||||
let with_config config =
|
||||
let taken = Hashtbl.create 16 in
|
||||
List.iter
|
||||
(fun d ->
|
||||
match Ast.declared_name d with
|
||||
| Some n -> Hashtbl.replace taken n ()
|
||||
| None -> ())
|
||||
fixture_ds;
|
||||
let known_structs =
|
||||
List.filter_map
|
||||
(fun (d : Ast.decl) ->
|
||||
match d.Ast.d with Ast.Defstruct (n, _) -> Some n | _ -> None)
|
||||
fixture_ds
|
||||
and known_enums =
|
||||
List.filter_map
|
||||
(fun (d : Ast.decl) ->
|
||||
match d.Ast.d with Ast.Defenum (n, _) -> Some n | _ -> None)
|
||||
fixture_ds
|
||||
in
|
||||
let i, _, _ =
|
||||
Cimport.header ~loc:Loc.unknown ~header:"headers/sample.h" ~flags:[]
|
||||
~known_structs ~known_enums ~taken ~bound_syms:[] ~config
|
||||
in
|
||||
(List.map Cimport.decl_source i.Cimport.decls, i.Cimport.hidden)
|
||||
in
|
||||
|
||||
let lines, hidden =
|
||||
with_config { Cimport.excludes = [ "set_seed" ]; renames = [] }
|
||||
in
|
||||
check "an excluded symbol is not generated"
|
||||
(not (List.exists (fun l -> contains l "\"set_seed\"") lines));
|
||||
(* Not silently absent. "there is no such binding" and "the package decided
|
||||
against this binding" are different answers and a reader gets the second,
|
||||
which is what [hidden] is for. *)
|
||||
check "and it says it was excluded rather than going quiet"
|
||||
(List.exists
|
||||
(fun (n, why) -> n = "set-seed" && contains why "excluded by the package")
|
||||
hidden);
|
||||
|
||||
let lines, _ =
|
||||
with_config { Cimport.excludes = [ "add_*" ]; renames = [] }
|
||||
in
|
||||
check "an exclude pattern matches by prefix"
|
||||
(not (List.exists (fun l -> contains l "\"add_ints\"") lines));
|
||||
check "and leaves everything it does not match"
|
||||
(List.exists (fun l -> contains l "\"set_seed\"") lines);
|
||||
|
||||
let lines, _ =
|
||||
with_config
|
||||
{ Cimport.excludes = []; renames = [ ("set_seed", "seed!") ] }
|
||||
in
|
||||
(* The C symbol is kept verbatim, so an override changes the Flan face and
|
||||
nothing else — which is what makes it safe to spell a predicate the way
|
||||
Lisp spells one. *)
|
||||
check "a name override is the Flan name, and the C symbol is untouched"
|
||||
(List.mem "(declare-c seed! [seed u32] \"set_seed\")" lines);
|
||||
|
||||
(* The collision above is refused because neither Spin2D nor spin2d may take
|
||||
[spin-2d] by an accident of header order. Naming one of them is the way
|
||||
out, and it is the reason the kebab rule is consulted in exactly one
|
||||
place: the groups are computed on the name a function will really take,
|
||||
so the rename dissolves the group rather than leaving both refused. *)
|
||||
let lines, hidden =
|
||||
with_config
|
||||
{ Cimport.excludes = []; renames = [ ("Spin2D", "spin-2d-upper") ] }
|
||||
in
|
||||
check "a rename resolves a collision for both halves"
|
||||
(List.exists (fun l -> contains l "\"Spin2D\"") lines
|
||||
&& List.exists (fun l -> contains l "\"spin2d\"") lines);
|
||||
check "and the collision is no longer refused"
|
||||
(not (List.mem_assoc "spin-2d" hidden));
|
||||
|
||||
(* The file, since a typo in it would otherwise show up as a binding under
|
||||
the wrong name. A line that is neither directive is an error rather than a
|
||||
line quietly skipped. *)
|
||||
let config_file text =
|
||||
let f = Filename.temp_file "flan-bindings" "" in
|
||||
let ch = open_out f in
|
||||
output_string ch text;
|
||||
close_out ch;
|
||||
f
|
||||
in
|
||||
let c = Cimport.read_config (config_file "# a comment\n\nexclude Mem*\nname IsWindowReady window-ready?\n") in
|
||||
check "read_config reads an exclude" (c.Cimport.excludes = [ "Mem*" ]);
|
||||
check "read_config reads a name override"
|
||||
(c.Cimport.renames = [ ("IsWindowReady", "window-ready?") ]);
|
||||
check "a missing config is no exclusions and no overrides"
|
||||
(Cimport.read_config "no-such-bindings-file" = Cimport.no_config);
|
||||
check "a line that is neither directive is refused"
|
||||
(match Cimport.read_config (config_file "rename Foo bar\n") with
|
||||
| _ -> false
|
||||
| exception Loc.Error (_, m) -> contains m "and this is neither");
|
||||
|
||||
(* A refused name is a name that exists and cannot be had — Zig's failDecl,
|
||||
which Load.refuse_hidden already implements for main. Nothing may be in
|
||||
both lists, or asking for a name that works would report that it does
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user