A bool returned from C reads as its low bit on --x86 as on LLVM, and the where-and fix and the x-1 hint follow the code's own syntax rather than its file name
This commit is contained in:
parent
c3a05d7447
commit
e81191d770
@ -8868,7 +8868,7 @@ and unknown_name : 'a. ?setting:bool -> ctx -> Loc.t -> string -> 'a =
|
|||||||
and [x/2] are one name each. When the parts either side of an operator
|
and [x/2] are one name each. When the parts either side of an operator
|
||||||
character are a value in scope and a number or another value, that is
|
character are a value in scope and a number or another value, that is
|
||||||
almost certainly the arithmetic, and the sentence says how to spell it. *)
|
almost certainly the arithmetic, and the sentence says how to spell it. *)
|
||||||
(if Filename.check_suffix loc.Loc.file ".fln" then begin
|
(if Source.indented_at loc then begin
|
||||||
let known s =
|
let known s =
|
||||||
s <> ""
|
s <> ""
|
||||||
&& (String.for_all (fun c -> (c >= '0' && c <= '9') || c = '.') s
|
&& (String.for_all (fun c -> (c >= '0' && c <= '9') || c = '.') s
|
||||||
|
|||||||
@ -1209,6 +1209,22 @@ and header (s : st) w : Form.t =
|
|||||||
let wt = advance p in
|
let wt = advance p in
|
||||||
let rec preds acc =
|
let rec preds acc =
|
||||||
let e, _ = expr p in
|
let e, _ = expr p in
|
||||||
|
(* [and] is how a condition joins tests, so it is what gets written
|
||||||
|
for several predicates; the clause separates them with commas. *)
|
||||||
|
(match e.Form.v with
|
||||||
|
| Form.List ({ Form.v = Form.Sym "and"; _ } :: (_ :: _ as ps)) ->
|
||||||
|
let spell (q : Form.t) =
|
||||||
|
match q.Form.v with
|
||||||
|
| Form.List [ { Form.v = Form.Sym n; _ };
|
||||||
|
{ Form.v = Form.Sym v; _ } ] ->
|
||||||
|
Printf.sprintf "%s(%s)" n v
|
||||||
|
| _ -> Form.to_string q
|
||||||
|
in
|
||||||
|
failk "where-and" e.Form.loc
|
||||||
|
"a where clause separates its predicates with commas, not and \
|
||||||
|
— write where %s"
|
||||||
|
(String.concat ", " (List.map spell ps))
|
||||||
|
| _ -> ());
|
||||||
match (peek p).tok with
|
match (peek p).tok with
|
||||||
| COMMA -> ignore (advance p); preds (e :: acc)
|
| COMMA -> ignore (advance p); preds (e :: acc)
|
||||||
| _ -> List.rev (e :: acc)
|
| _ -> List.rev (e :: acc)
|
||||||
|
|||||||
25
lib/parse.ml
25
lib/parse.ml
@ -374,26 +374,13 @@ let constraints (body : Form.t list) : Ast.pred list * Form.t list =
|
|||||||
{ Ast.pname = name; pvar = String.sub v 1 (String.length v - 1);
|
{ Ast.pname = name; pvar = String.sub v 1 (String.length v - 1);
|
||||||
ploc = p.Form.loc }
|
ploc = p.Form.loc }
|
||||||
(* [and] is how a condition joins tests, so it is what gets written
|
(* [and] is how a condition joins tests, so it is what gets written
|
||||||
for several predicates. The fix is spelled in the file's own syntax,
|
for several predicates. The .fln reader refuses its own spelling of
|
||||||
which only the location's file name tells apart here. *)
|
this with its own fix; what reaches here is paren code. *)
|
||||||
| Form.List ({ Form.v = Form.Sym "and"; _ } :: (_ :: _ as ps)) ->
|
| Form.List ({ Form.v = Form.Sym "and"; _ } :: (_ :: _ as ps)) ->
|
||||||
let fln = Filename.check_suffix p.Form.loc.Loc.file ".fln" in
|
Loc.fail p.Form.loc
|
||||||
let fln_pred (q : Form.t) =
|
"a where clause puts several predicates in a vector, not in an and \
|
||||||
match q.Form.v with
|
— write {:where [%s]}"
|
||||||
| Form.List [ { Form.v = Form.Sym n; _ }; { Form.v = Form.Sym v; _ } ]
|
(String.concat " " (List.map Form.to_string ps))
|
||||||
-> Printf.sprintf "%s(%s)" n v
|
|
||||||
| _ -> Form.to_string q
|
|
||||||
in
|
|
||||||
if fln then
|
|
||||||
Loc.fail p.Form.loc
|
|
||||||
"a where clause separates its predicates with commas, not and — \
|
|
||||||
write where %s"
|
|
||||||
(String.concat ", " (List.map fln_pred ps))
|
|
||||||
else
|
|
||||||
Loc.fail p.Form.loc
|
|
||||||
"a where clause puts several predicates in a vector, not in an \
|
|
||||||
and — write {:where [%s]}"
|
|
||||||
(String.concat " " (List.map Form.to_string ps))
|
|
||||||
| _ ->
|
| _ ->
|
||||||
Loc.fail p.Form.loc
|
Loc.fail p.Form.loc
|
||||||
"a where predicate is (name? $t), one predicate about one type \
|
"a where predicate is (name? $t), one predicate about one type \
|
||||||
|
|||||||
@ -41,13 +41,24 @@ let syntax_of_field = function
|
|||||||
| Some ("indented" | "fln") -> Indented
|
| Some ("indented" | "fln") -> Indented
|
||||||
| _ -> Paren
|
| _ -> Paren
|
||||||
|
|
||||||
|
let in_request = ref false
|
||||||
|
|
||||||
let with_code ?indent ~syntax ~at f =
|
let with_code ?indent ~syntax ~at f =
|
||||||
let s = !code_syntax and a = !code_at and i = !code_indent in
|
let s = !code_syntax and a = !code_at and i = !code_indent
|
||||||
|
and r = !in_request in
|
||||||
code_syntax := syntax;
|
code_syntax := syntax;
|
||||||
code_at := at;
|
code_at := at;
|
||||||
code_indent := indent;
|
code_indent := indent;
|
||||||
|
in_request := true;
|
||||||
Fun.protect
|
Fun.protect
|
||||||
~finally:(fun () -> code_syntax := s; code_at := a; code_indent := i) f
|
~finally:(fun () ->
|
||||||
|
code_syntax := s; code_at := a; code_indent := i; in_request := r) f
|
||||||
|
|
||||||
|
(* Was the code at [loc] written in the indented syntax? Inside an editor
|
||||||
|
request the request says; outside one a file's name does, as
|
||||||
|
[read_file] decides. *)
|
||||||
|
let indented_at (loc : Loc.t) =
|
||||||
|
if !in_request then !code_syntax = Indented else is_indented loc.Loc.file
|
||||||
|
|
||||||
(* The paren reader started at a line and column: [Reader.read_all] always
|
(* The paren reader started at a line and column: [Reader.read_all] always
|
||||||
starts at 1:1. *)
|
starts at 1:1. *)
|
||||||
|
|||||||
@ -3244,6 +3244,11 @@ and call_native ?at f ~sym ?(chan = false) ~(args : Tast.expr list) ~rty dst =
|
|||||||
unsupported
|
unsupported
|
||||||
"%s returns %s by value, which needs SysV return classification this \
|
"%s returns %s by value, which needs SysV return classification this \
|
||||||
backend does not have" sym (Types.to_string rty);
|
backend does not have" sym (Types.to_string rty);
|
||||||
|
(* A C bool is 0 or 1 only by the callee's good faith: [(declare f [..]
|
||||||
|
bool "abs")] hands back whatever byte abs left. LLVM declares the
|
||||||
|
return [i1] and reads its low bit, so this does too, and every bool
|
||||||
|
past this point is 0 or 1 — which [=], [not] and [match] assume. *)
|
||||||
|
if Types.equal rty Types.Bool then and_imm f.b ~dst:rax 1;
|
||||||
store_loc f ~reg:(if is_float rty then xmm0 else rax) dst rty
|
store_loc f ~reg:(if is_float rty then xmm0 else rax) dst rty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
24
test/programs/ffi-bool.flan
Normal file
24
test/programs/ffi-bool.flan
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
;;;; A bool from C that is not 0 or 1 reads as its low bit on both backends:
|
||||||
|
;;;; abs(3) is 3, which is true, and equal to abs(1).
|
||||||
|
|
||||||
|
(declare two [n i32] bool "abs")
|
||||||
|
|
||||||
|
(defstruct Flag [on bool])
|
||||||
|
|
||||||
|
(defn main [] i32
|
||||||
|
(let [a (two 3)
|
||||||
|
b (two 1)
|
||||||
|
c (two 0)
|
||||||
|
f (Flag {.on a})
|
||||||
|
v [a b]]
|
||||||
|
(print (= a b)) (print " ")
|
||||||
|
(print (!= a b)) (print " ")
|
||||||
|
(print (= a true)) (print " ")
|
||||||
|
(print (= (.on f) b)) (print " ")
|
||||||
|
(print (= (at v 0) (at v 1))) (print " ")
|
||||||
|
(print (match a true "T" false "F")) (print " ")
|
||||||
|
(print (if a "t" "f")) (print " ")
|
||||||
|
(print (not a)) (print " ")
|
||||||
|
(print (= c false))
|
||||||
|
(println "")
|
||||||
|
0))
|
||||||
@ -459,6 +459,12 @@ let () =
|
|||||||
"programs/match-bool.flan" match_bool_out;
|
"programs/match-bool.flan" match_bool_out;
|
||||||
outputs ~dev:true "match over a bool and keywords, dev"
|
outputs ~dev:true "match over a bool and keywords, dev"
|
||||||
"programs/match-bool.flan" match_bool_out;
|
"programs/match-bool.flan" match_bool_out;
|
||||||
|
let ffi_bool_out = "true false true true true T t false true\n" in
|
||||||
|
outputs "a bool from C" "programs/ffi-bool.flan" ffi_bool_out;
|
||||||
|
outputs ~opt:"-O0" "a bool from C, -O0" "programs/ffi-bool.flan"
|
||||||
|
ffi_bool_out;
|
||||||
|
outputs ~x86:true "a bool from C, --x86" "programs/ffi-bool.flan"
|
||||||
|
ffi_bool_out;
|
||||||
(* update, ++ and -- evaluate their place's subexpressions once: the
|
(* update, ++ and -- evaluate their place's subexpressions once: the
|
||||||
counts are the number of calls an index or a key function got. *)
|
counts are the number of calls an index or a key function got. *)
|
||||||
let update_out = "3\n11 20 90\n1 1 3\n16\n2\n7 1\n32\n2 50\n" in
|
let update_out = "3\n11 20 90\n1 1 3\n16\n2\n7 1\n32\n2 50\n" in
|
||||||
|
|||||||
@ -287,6 +287,11 @@ let () =
|
|||||||
"(defn g [h (Fn [i32 i32] bool)] () (h 1 2))";
|
"(defn g [h (Fn [i32 i32] bool)] () (h 1 2))";
|
||||||
reads "untyped parameter is dyn" "fn id(x) -> dyn = x" "(defn id [x dyn] dyn x)";
|
reads "untyped parameter is dyn" "fn id(x) -> dyn = x" "(defn id [x dyn] dyn x)";
|
||||||
refuses "no return type" "fn f(x)\n x" "indent/return-type" "-> i32";
|
refuses "no return type" "fn f(x)\n x" "indent/return-type" "-> i32";
|
||||||
|
(* The fix is .fln's commas whatever the file is called: [read] names it
|
||||||
|
<syntax>. *)
|
||||||
|
refuses "where predicates joined with and"
|
||||||
|
"fn f(x: $t, y: $u) -> i32 where ordered?($t) and equal?($u)\n 0"
|
||||||
|
"indent/where-and" "commas, not and — write where ordered?($t), equal?($u)";
|
||||||
(* Characters, lexed before brackets and separators. *)
|
(* Characters, lexed before brackets and separators. *)
|
||||||
reads "character literals" "x = [\\( \\, \\space \\)]" "(set x [\\( \\, \\space \\)])";
|
reads "character literals" "x = [\\( \\, \\space \\)]" "(set x [\\( \\, \\space \\)])";
|
||||||
reads "character arguments" "f(\\,, \\))" "(f \\, \\))";
|
reads "character arguments" "f(\\,, \\))" "(f \\, \\))";
|
||||||
@ -534,17 +539,6 @@ let () =
|
|||||||
if not (Test_support.contains d.Loc.dmsg "Did you mean x - 1?") then
|
if not (Test_support.contains d.Loc.dmsg "Did you mean x - 1?") then
|
||||||
fail "x-1: %s" d.Loc.dmsg
|
fail "x-1: %s" d.Loc.dmsg
|
||||||
| exception e -> fail "x-1: %s" (Printexc.to_string e));
|
| exception e -> fail "x-1: %s" (Printexc.to_string e));
|
||||||
(* Several where predicates joined with and: the fix is .fln's commas. *)
|
|
||||||
let f = Filename.concat scratch "syntax-where-and.fln" in
|
|
||||||
write f "fn f(x: $t, y: $u) -> i32 where ordered?($t) and equal?($u)\n 0\n";
|
|
||||||
(match Front.checked f with
|
|
||||||
| _ -> fail "where joined with and checked"
|
|
||||||
| exception Loc.Error d ->
|
|
||||||
if not (Test_support.contains d.Loc.dmsg
|
|
||||||
"separates its predicates with commas, not and — write where \
|
|
||||||
ordered?($t), equal?($u)") then
|
|
||||||
fail "where joined with and: %s" d.Loc.dmsg
|
|
||||||
| exception e -> fail "where joined with and: %s" (Printexc.to_string e));
|
|
||||||
(* One package, one file in two syntaxes: refused naming both. *)
|
(* One package, one file in two syntaxes: refused naming both. *)
|
||||||
let dir = Filename.concat scratch "syntax-twin" in
|
let dir = Filename.concat scratch "syntax-twin" in
|
||||||
let pkg = Filename.concat dir "geo" in
|
let pkg = Filename.concat dir "geo" in
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user