The .fln reader takes loop and recur as names wherever the Lisp loop's spellings are not written, and the convert refusal lists its lines in a sentence of their own.
This commit is contained in:
parent
fc463cf320
commit
17a7afb297
@ -1355,7 +1355,7 @@ let refuse_loops (fs : Form.t list) =
|
||||
let lines = List.sort_uniq compare (List.map (fun (f : Form.t) -> f.loc.Loc.line) uses) in
|
||||
let notes = List.map (fun (f : Form.t) -> Loc.note f.loc (word f ^ " is here")) rest in
|
||||
Loc.failk ~notes "convert/no-loop" first.loc
|
||||
"this file uses loop or recur on line%s %s, and the indented syntax \
|
||||
"this file uses loop or recur on line%s %s. The indented syntax \
|
||||
has neither. Rewrite each one in the .flan file as a while or until \
|
||||
over let variables it changes, then convert again:\n\n\
|
||||
\ (let [i 0 total 0]\n\
|
||||
@ -1363,7 +1363,10 @@ let refuse_loops (fs : Form.t list) =
|
||||
\ (set total (+ total i))\n\
|
||||
\ (set i (+ i 1))))"
|
||||
(if List.length lines = 1 then "" else "s")
|
||||
(String.concat ", " (List.map string_of_int lines))
|
||||
(match List.rev_map string_of_int lines with
|
||||
| last :: (_ :: _ as before) ->
|
||||
String.concat ", " (List.rev before) ^ " and " ^ last
|
||||
| ls -> String.concat "" ls)
|
||||
|
||||
(** A whole file: top-level forms with a blank line between them. [macros]
|
||||
is [Body_macros.table] of the file; without it, the prelude's and the
|
||||
|
||||
@ -776,13 +776,20 @@ and primary p : Form.t * int =
|
||||
let glued_lp = nxt.tok = LP && not nxt.sp in
|
||||
if s = "if" && nxt.sp && starts_value nxt.tok then if_expr p
|
||||
else if s = "fn" && glued_lp then fn_expr p
|
||||
else if (s = "loop" || s = "recur")
|
||||
&& (glued_lp || nxt.tok = COLON
|
||||
|| (nxt.sp && starts_value nxt.tok
|
||||
&& (match nxt.tok with
|
||||
| NAME x -> not (x = "=" || List.mem_assoc x assign_ops || is_op_word x)
|
||||
| _ -> true))
|
||||
|| (nxt.tok = NEWLINE && (peek_at p 2).tok = INDENT)) then
|
||||
(* Only the Lisp loop's spellings are refused here, for a message at the
|
||||
word: [loop x = a, ...], [loop([...]):], a bare [loop] over a block
|
||||
where a statement or a let's value starts, and [recur(...)]. Anywhere
|
||||
else [loop] and [recur] are names; [refuse_loops] catches the rest. *)
|
||||
else if glued_lp && (s = "loop" || s = "recur") then no_loop l0 s
|
||||
else if s = "loop"
|
||||
&& ((nxt.sp
|
||||
&& (match nxt.tok with NAME x -> not (is_op_word x) | _ -> false)
|
||||
&& (match (peek_at p 2).tok with NAME "=" | COMMA -> true | _ -> false))
|
||||
|| (nxt.tok = NEWLINE && (peek_at p 2).tok = INDENT
|
||||
&& (p.i = 0
|
||||
|| (match (last p).tok with
|
||||
| NEWLINE | INDENT | DEDENT | NAME "=" -> true
|
||||
| _ -> false)))) then
|
||||
no_loop l0 s
|
||||
else if is_op_word s then begin
|
||||
if glued_lp || ends_value nxt.tok then begin
|
||||
|
||||
@ -628,6 +628,14 @@ let () =
|
||||
"indent/no-loop" "loop is not";
|
||||
refuses "a quoted loop" "f('(loop [i 0] (recur i)))" "indent/no-loop" "loop is not";
|
||||
reads "loop as a name" "loop = 4" "(set loop 4)";
|
||||
reads "if over loop" "if loop\n 1" "(when loop 1)";
|
||||
reads "while over loop" "while loop\n g()" "(while loop (g))";
|
||||
reads "until over loop" "until loop\n g()" "(until loop (g))";
|
||||
reads "elif over loop" "if recur\n 1\nelif loop\n 2" "(cond recur 1 loop 2)";
|
||||
reads "a one-line if over loop" "if loop then 1 else 2" "(if loop 1 2)";
|
||||
reads "a one-line if over recur" "if recur > 0 then recur else 0" "(if (> recur 0) recur 0)";
|
||||
reads ~global:false "a typed let of loop" "let loop: i32 = 1\nloop" "(let [loop (the i32 1)] loop)";
|
||||
reads "a match over loop, and an arm of it" "match loop\n loop -> loop" "(match loop loop loop)";
|
||||
reads "read-only pointer" "let p: Ptr(const u8) = uninit" "(def p (Ptr const u8) uninit)";
|
||||
(* Statements that fit on a line, in one-line slots. *)
|
||||
reads "arm statements" "match s\n 1 -> break\n 2 -> continue :outer\n _ -> x += 1"
|
||||
@ -1013,7 +1021,7 @@ let () =
|
||||
(fun n ->
|
||||
if not (Test_support.contains d.Loc.dmsg n) then
|
||||
fail "the loop refusal does not say %S: %s" n d.Loc.dmsg)
|
||||
[ "on lines 2, 3, 5"; "(while (< i 10)" ];
|
||||
[ "on lines 2, 3 and 5. The indented syntax"; "(while (< i 10)" ];
|
||||
if List.length d.Loc.notes <> 2 then
|
||||
fail "the loop refusal points at %d more places, wanted 2" (List.length d.Loc.notes))
|
||||
| exception e -> fail "a loop: %s" (diag_text e))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user