A .fln let takes more bindings on the lines indented under it, a top-level one more globals, and flan convert writes runs of short bindings that way
This commit is contained in:
parent
04b29f283d
commit
12cd4feff0
@ -1362,8 +1362,53 @@ and let_lines n prs body =
|
|||||||
| first :: more -> Source_text.tag t.loc.Loc.line first :: more
|
| first :: more -> Source_text.tag t.loc.Loc.line first :: more
|
||||||
| [] -> []
|
| [] -> []
|
||||||
in
|
in
|
||||||
|
(* A let whose body starts with another is one run of bindings: the reader
|
||||||
|
merges the two back whichever way they are written. *)
|
||||||
|
let rec absorb prs body =
|
||||||
|
match body with
|
||||||
|
| x :: rest when let_sugar x && !quasi = 0 ->
|
||||||
|
(match if rest = [] then Some x else flatten x rest with
|
||||||
|
| Some { v = Form.List (_ :: { v = Form.Vec bs; _ } :: inner); _ } ->
|
||||||
|
(match pairs bs with
|
||||||
|
| Some ps -> absorb (prs @ ps) inner
|
||||||
|
| None -> (prs, body))
|
||||||
|
| _ -> (prs, body))
|
||||||
|
| _ -> (prs, body)
|
||||||
|
in
|
||||||
|
let prs, body = absorb prs body in
|
||||||
let lines n b = let p, v = bind b in tagged b (value_lines n p v) in
|
let lines n b = let p, v = bind b in tagged b (value_lines n p v) in
|
||||||
List.concat_map (lines n) prs @ block n body
|
(* A binding that fits a line with a short value joins a group: the ones
|
||||||
|
after the first go on the lines under it, lined up with its name. *)
|
||||||
|
let short n b =
|
||||||
|
let p, v = bind b in
|
||||||
|
match value_lines n p v with
|
||||||
|
| [ l ] when String.length (at 0 v) <= 40 && not (!inside v) -> Some (tagged b [ l ])
|
||||||
|
| _ -> None
|
||||||
|
in
|
||||||
|
let under b =
|
||||||
|
let p, v = bind b in
|
||||||
|
let p = String.sub p 4 (String.length p - 4) in
|
||||||
|
match value_lines (n + 4) p v with
|
||||||
|
| [ l ] when String.length (at 0 v) <= 40 && not (!inside v) -> Some (tagged b [ l ])
|
||||||
|
| _ -> None
|
||||||
|
in
|
||||||
|
let rec emit = function
|
||||||
|
| [] -> []
|
||||||
|
| b :: rest ->
|
||||||
|
(match short n b with
|
||||||
|
| None -> lines n b @ emit rest
|
||||||
|
| Some first ->
|
||||||
|
let rec group acc = function
|
||||||
|
| b' :: rest' as all ->
|
||||||
|
(match under b' with
|
||||||
|
| Some l -> group (acc @ l) rest'
|
||||||
|
| None -> (acc, all))
|
||||||
|
| [] -> (acc, [])
|
||||||
|
in
|
||||||
|
let more, rest = group [] rest in
|
||||||
|
first @ more @ emit rest)
|
||||||
|
in
|
||||||
|
emit prs @ block n body
|
||||||
|
|
||||||
(** A whole file: top-level forms with a blank line between them. [macros]
|
(** 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
|
is [Body_macros.table] of the file; without it, the prelude's and the
|
||||||
|
|||||||
@ -1474,10 +1474,27 @@ and value_line ?(block_ok = false) (s : st) ~after : Form.t =
|
|||||||
| Form.List items -> mk p e.loc (Form.List (items @ body))
|
| Form.List items -> mk p e.loc (Form.List (items @ body))
|
||||||
| _ -> mk p e.loc (Form.List (e :: body)))
|
| _ -> mk p e.loc (Form.List (e :: body)))
|
||||||
| COMMA ->
|
| COMMA ->
|
||||||
failk "one-binding" (peek p).loc
|
let c = (peek p).loc in
|
||||||
|
(* On a let's line, the fix is the let's group: the rest of the line
|
||||||
|
under the first name. *)
|
||||||
|
let group =
|
||||||
|
let file, lines = !source in
|
||||||
|
if c.Loc.file <> file || c.Loc.line > Array.length lines then None
|
||||||
|
else
|
||||||
|
let line = lines.(c.Loc.line - 1) in
|
||||||
|
let head = String.trim (String.sub line 0 (c.Loc.col - 1)) in
|
||||||
|
let rest = String.trim (String.sub line c.Loc.col (String.length line - c.Loc.col)) in
|
||||||
|
if String.length head > 4 && String.sub head 0 4 = "let " && rest <> "" then
|
||||||
|
Some (Printf.sprintf ":\n\n %s\n %s" head rest)
|
||||||
|
else None
|
||||||
|
in
|
||||||
|
failk "one-binding" c
|
||||||
"%s is followed by a comma, and one line binds one name. Put each \
|
"%s is followed by a comma, and one line binds one name. Put each \
|
||||||
binding on its own line, one after the other"
|
binding on its own line%s"
|
||||||
(text_of e)
|
(text_of e)
|
||||||
|
(match group with
|
||||||
|
| Some g -> ", the ones after the first under its name" ^ g
|
||||||
|
| None -> ", one after the other")
|
||||||
| _ -> lambda_block ~block_ok s e ~after:(text_of e)
|
| _ -> lambda_block ~block_ok s e ~after:(text_of e)
|
||||||
|
|
||||||
(* Whether this line has a [then] at depth zero: a one-line if. *)
|
(* Whether this line has a [then] at depth zero: a one-line if. *)
|
||||||
@ -1501,9 +1518,10 @@ and lambda_block ?(block_ok = false) (s : st) (e : Form.t) ~after =
|
|||||||
else expect_eol p ~after;
|
else expect_eol p ~after;
|
||||||
e
|
e
|
||||||
|
|
||||||
and let_stmt (s : st) : Form.t list =
|
(* One binding of a let, [x = v], [x: T = v] or [{a .x} = p], through the
|
||||||
|
end of its line (and the block its value takes). *)
|
||||||
|
and binding (s : st) : Form.t * Form.t =
|
||||||
let p = s.p in
|
let p = s.p in
|
||||||
let t = advance p in
|
|
||||||
let target, _ = unary p in
|
let target, _ = unary p in
|
||||||
(* [let x: T = v] is [(let [x (the T v)])]: a let binding has no type slot
|
(* [let x: T = v] is [(let [x (the T v)])]: a let binding has no type slot
|
||||||
of its own, and [the] is the form that says what a value is. *)
|
of its own, and [the] is the form that says what a value is. *)
|
||||||
@ -1524,6 +1542,72 @@ and let_stmt (s : st) : Form.t list =
|
|||||||
Form.make (Form.List [ sym tyf.loc "the"; tyf; v ]) (span p tyf.loc)
|
Form.make (Form.List [ sym tyf.loc "the"; tyf; v ]) (span p tyf.loc)
|
||||||
| None -> v
|
| None -> v
|
||||||
in
|
in
|
||||||
|
(target, v)
|
||||||
|
|
||||||
|
(* The lines indented under a let, each one more binding of it: [let a = 1]
|
||||||
|
and under it [b = a + 1], lined up with [a]. Anything else there is
|
||||||
|
refused; [first] is the let's first target, for the message. *)
|
||||||
|
and binding_lines : 'a. st -> first:Form.t -> one:(unit -> 'a) -> 'a list =
|
||||||
|
fun s ~first ~one ->
|
||||||
|
let p = s.p in
|
||||||
|
if (peek p).tok <> INDENT then []
|
||||||
|
else begin
|
||||||
|
ignore (advance p);
|
||||||
|
let rec go acc =
|
||||||
|
match (peek p).tok with
|
||||||
|
| DEDENT -> ignore (advance p); List.rev acc
|
||||||
|
| EOF -> List.rev acc
|
||||||
|
| _ when binding_line p -> go (one () :: acc)
|
||||||
|
| _ ->
|
||||||
|
failk "let-block" (where_ p)
|
||||||
|
"this line is indented under let %s, and the only lines that go \
|
||||||
|
there are more bindings of the let, lined up with its first name:\n\n\
|
||||||
|
\ let a = 1\n b = a + 1\n\n\
|
||||||
|
A let's names last to the end of the block the let is in, so any \
|
||||||
|
other line after it goes at the let's column"
|
||||||
|
(text_of first)
|
||||||
|
in
|
||||||
|
go []
|
||||||
|
end
|
||||||
|
|
||||||
|
(* Whether the line at point is a binding: a name, or a [[...]] or [{...}]
|
||||||
|
pattern, then [=] or [: T =]. [x += 1] and [f(x)] are not. *)
|
||||||
|
and binding_line p =
|
||||||
|
(* An [=] at the line's own depth, from token [k] on. *)
|
||||||
|
let rec eq k depth =
|
||||||
|
match (peek_at p k).tok with
|
||||||
|
| EOF | NEWLINE | INDENT | DEDENT -> false
|
||||||
|
| NAME "=" when depth = 0 -> true
|
||||||
|
| LP | LB | LC -> eq (k + 1) (depth + 1)
|
||||||
|
| RP | RB | RC -> eq (k + 1) (depth - 1)
|
||||||
|
| _ -> eq (k + 1) depth
|
||||||
|
in
|
||||||
|
match (peek p).tok with
|
||||||
|
| NAME s when s <> "" && s.[0] <> '.' && not (is_op_word s) ->
|
||||||
|
(match (peek_at p 1).tok with
|
||||||
|
| NAME "=" -> (peek_at p 1).sp
|
||||||
|
| COLON -> eq 2 0
|
||||||
|
| _ -> false)
|
||||||
|
(* [~g = a] in a template. *)
|
||||||
|
| UNQ -> eq 1 0
|
||||||
|
| LB | LC ->
|
||||||
|
let rec close k depth =
|
||||||
|
match (peek_at p k).tok with
|
||||||
|
| EOF | NEWLINE -> false
|
||||||
|
| LP | LB | LC -> close (k + 1) (depth + 1)
|
||||||
|
| RP | RB | RC when depth = 1 -> (peek_at p (k + 1)).tok = NAME "="
|
||||||
|
| RP | RB | RC -> close (k + 1) (depth - 1)
|
||||||
|
| _ -> close (k + 1) depth
|
||||||
|
in
|
||||||
|
close 0 0
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
and let_stmt (s : st) : Form.t list =
|
||||||
|
let p = s.p in
|
||||||
|
let t = advance p in
|
||||||
|
let (target, v) = binding s in
|
||||||
|
let more = binding_lines s ~first:target ~one:(fun () -> binding s) in
|
||||||
|
let own = List.concat_map (fun (a, b) -> [ a; b ]) ((target, v) :: more) in
|
||||||
let make bindings body =
|
let make bindings body =
|
||||||
let f =
|
let f =
|
||||||
mk p t.loc
|
mk p t.loc
|
||||||
@ -1538,17 +1622,10 @@ and let_stmt (s : st) : Form.t list =
|
|||||||
match body with
|
match body with
|
||||||
| [ ({ Form.v = Form.List (_ :: { v = Form.Vec bs; _ } :: body); _ } as inner) ]
|
| [ ({ Form.v = Form.List (_ :: { v = Form.Vec bs; _ } :: body); _ } as inner) ]
|
||||||
when List.memq inner s.lets ->
|
when List.memq inner s.lets ->
|
||||||
make (target :: v :: bs) body
|
make (own @ bs) body
|
||||||
| _ -> make [ target; v ] body
|
| _ -> make own body
|
||||||
in
|
in
|
||||||
(* A let has no block: its name lasts to the end of the block it is in. *)
|
[ merged (stmts s) ]
|
||||||
if (peek p).tok = INDENT then
|
|
||||||
failk "let-block" (peek_at p 1).loc
|
|
||||||
"this line is indented under let %s, which takes no block. A let's \
|
|
||||||
name lasts to the end of the block the let is in, so the lines after \
|
|
||||||
it go at the let's column"
|
|
||||||
(text_of target)
|
|
||||||
else [ merged (stmts s) ]
|
|
||||||
|
|
||||||
and stmt (s : st) : Form.t =
|
and stmt (s : st) : Form.t =
|
||||||
let p = s.p in
|
let p = s.p in
|
||||||
@ -1697,57 +1774,7 @@ and header (s : st) w : Form.t =
|
|||||||
in
|
in
|
||||||
named (if w = "fn" then "defn" else "defn-")
|
named (if w = "fn" then "defn" else "defn-")
|
||||||
(name :: Form.make (Form.Vec ps) lp.loc :: ret :: (where_clause @ body))
|
(name :: Form.make (Form.Vec ps) lp.loc :: ret :: (where_clause @ body))
|
||||||
| "def" | "once" | "const" ->
|
| "def" | "once" | "const" -> def_form s w t l0
|
||||||
(* A top-level [let] is read here too, as [def]: [w] is then "def" and
|
|
||||||
[t] the let. *)
|
|
||||||
let shown = match t.tok with NAME "let" -> "let" | _ -> w in
|
|
||||||
let name = name_tok p ~what:"the name being defined" in
|
|
||||||
let tyf =
|
|
||||||
match (peek p).tok with
|
|
||||||
| COLON -> ignore (advance p); Some (ty p)
|
|
||||||
| _ -> None
|
|
||||||
in
|
|
||||||
let v =
|
|
||||||
match (peek p).tok with
|
|
||||||
| NAME "=" ->
|
|
||||||
ignore (advance p);
|
|
||||||
Some (value_line s ~after:(shown ^ " " ^ text_of name ^ " ="))
|
|
||||||
| _ ->
|
|
||||||
expect_eol p ~after:(match tyf with Some f -> text_of f | None -> text_of name);
|
|
||||||
None
|
|
||||||
in
|
|
||||||
let head =
|
|
||||||
match w with "def" -> "def" | "once" -> "defonce" | _ -> "defconst"
|
|
||||||
in
|
|
||||||
if shown = "def" then
|
|
||||||
failk "def-is-let" l0
|
|
||||||
"a global is written with let, at the file's top level:\n\n let %s%s%s"
|
|
||||||
(text_of name)
|
|
||||||
(match tyf, v with
|
|
||||||
| Some t, _ -> ": " ^ text_of t
|
|
||||||
| None, None -> ": i32"
|
|
||||||
| None, Some _ -> "")
|
|
||||||
(match v, tyf with
|
|
||||||
| Some v, _ -> " = " ^ text_of v
|
|
||||||
| None, None -> " = 0"
|
|
||||||
| None, Some _ -> "");
|
|
||||||
let items =
|
|
||||||
match w, tyf, v with
|
|
||||||
| "const", None, Some v -> [ name; v ]
|
|
||||||
| "const", Some t, Some v -> [ name; t; v ]
|
|
||||||
| "const", _, None ->
|
|
||||||
failk "const-value" l0
|
|
||||||
"a const needs its value: const %s = 3" (text_of name)
|
|
||||||
| _, None, Some v -> [ name; sym name.loc "dyn"; v ]
|
|
||||||
| _, Some t, None -> [ name; t ]
|
|
||||||
| _, Some t, Some v -> [ name; t; v ]
|
|
||||||
| _, None, None ->
|
|
||||||
failk "def-empty" l0
|
|
||||||
"%s %s names neither a type nor a value. Give it one or both: %s %s: \
|
|
||||||
i32 = 0"
|
|
||||||
shown (text_of name) shown (text_of name)
|
|
||||||
in
|
|
||||||
named head items
|
|
||||||
| "struct" | "union" ->
|
| "struct" | "union" ->
|
||||||
let name = name_tok p ~what:"the type's name" in
|
let name = name_tok p ~what:"the type's name" in
|
||||||
(* [struct Pt(x: i32, y: i32)]: the fields on the header's line, as a
|
(* [struct Pt(x: i32, y: i32)]: the fields on the header's line, as a
|
||||||
@ -2268,6 +2295,65 @@ and header (s : st) w : Form.t =
|
|||||||
named "quasiquote" [ e ])
|
named "quasiquote" [ e ])
|
||||||
| _ -> assert false
|
| _ -> assert false
|
||||||
|
|
||||||
|
(* [let x = v] at the top level, [once x = v] or [const x = v], from the
|
||||||
|
name on: [t] is the word, and [l0] where the form starts. A top-level let
|
||||||
|
leaves the lines indented under it to [read_all], which reads each as one
|
||||||
|
more global. *)
|
||||||
|
and def_form (s : st) w (t : token) l0 : Form.t =
|
||||||
|
let p = s.p in
|
||||||
|
let named head items = mk p l0 (Form.List (sym l0 head :: items)) in
|
||||||
|
(* A top-level [let] is read here too, as [def]: [w] is then "def" and
|
||||||
|
[t] the let. *)
|
||||||
|
let shown = match t.tok with NAME "let" -> "let" | _ -> w in
|
||||||
|
let name = name_tok p ~what:"the name being defined" in
|
||||||
|
let tyf =
|
||||||
|
match (peek p).tok with
|
||||||
|
| COLON -> ignore (advance p); Some (ty p)
|
||||||
|
| _ -> None
|
||||||
|
in
|
||||||
|
let v =
|
||||||
|
match (peek p).tok with
|
||||||
|
| NAME "=" ->
|
||||||
|
ignore (advance p);
|
||||||
|
Some (value_line ~block_ok:(shown = "let") s
|
||||||
|
~after:(shown ^ " " ^ text_of name ^ " ="))
|
||||||
|
| _ ->
|
||||||
|
expect_eol p ~after:(match tyf with Some f -> text_of f | None -> text_of name);
|
||||||
|
None
|
||||||
|
in
|
||||||
|
let head =
|
||||||
|
match w with "def" -> "def" | "once" -> "defonce" | _ -> "defconst"
|
||||||
|
in
|
||||||
|
if shown = "def" then
|
||||||
|
failk "def-is-let" l0
|
||||||
|
"a global is written with let, at the file's top level:\n\n let %s%s%s"
|
||||||
|
(text_of name)
|
||||||
|
(match tyf, v with
|
||||||
|
| Some t, _ -> ": " ^ text_of t
|
||||||
|
| None, None -> ": i32"
|
||||||
|
| None, Some _ -> "")
|
||||||
|
(match v, tyf with
|
||||||
|
| Some v, _ -> " = " ^ text_of v
|
||||||
|
| None, None -> " = 0"
|
||||||
|
| None, Some _ -> "");
|
||||||
|
let items =
|
||||||
|
match w, tyf, v with
|
||||||
|
| "const", None, Some v -> [ name; v ]
|
||||||
|
| "const", Some t, Some v -> [ name; t; v ]
|
||||||
|
| "const", _, None ->
|
||||||
|
failk "const-value" l0
|
||||||
|
"a const needs its value: const %s = 3" (text_of name)
|
||||||
|
| _, None, Some v -> [ name; sym name.loc "dyn"; v ]
|
||||||
|
| _, Some t, None -> [ name; t ]
|
||||||
|
| _, Some t, Some v -> [ name; t; v ]
|
||||||
|
| _, None, None ->
|
||||||
|
failk "def-empty" l0
|
||||||
|
"%s %s names neither a type nor a value. Give it one or both: %s %s: \
|
||||||
|
i32 = 0"
|
||||||
|
shown (text_of name) shown (text_of name)
|
||||||
|
in
|
||||||
|
named head items
|
||||||
|
|
||||||
(* handler-case, handler-bind and restart-case take nothing on their own line. *)
|
(* handler-case, handler-bind and restart-case take nothing on their own line. *)
|
||||||
and clause_header_end p w =
|
and clause_header_end p w =
|
||||||
match (peek p).tok with
|
match (peek p).tok with
|
||||||
@ -2340,8 +2426,25 @@ let read_all ?(line = 1) ?col ?indent ?(global_let = true) ~file src =
|
|||||||
| EOF -> []
|
| EOF -> []
|
||||||
| DEDENT -> ignore (advance s.p); []
|
| DEDENT -> ignore (advance s.p); []
|
||||||
| NAME "let" when header_follow s.p "let" ->
|
| NAME "let" when header_follow s.p "let" ->
|
||||||
|
let t = peek s.p in
|
||||||
let f = header s "def" in
|
let f = header s "def" in
|
||||||
f :: top ()
|
(* The lines indented under it are more globals, one each: a global
|
||||||
|
is one name, so a pattern there is refused. *)
|
||||||
|
let first = match f.v with Form.List (_ :: n :: _) -> n | _ -> f in
|
||||||
|
let more =
|
||||||
|
binding_lines s ~first ~one:(fun () ->
|
||||||
|
let l = peek s.p in
|
||||||
|
(match l.tok with
|
||||||
|
| LB | LC ->
|
||||||
|
failk "global-pattern" l.loc
|
||||||
|
"a global binds one name, and this line under let %s is a \
|
||||||
|
pattern. Bind the value to a name, and take it apart inside \
|
||||||
|
the function that uses it"
|
||||||
|
(text_of first)
|
||||||
|
| _ -> ());
|
||||||
|
def_form s "def" t l.loc)
|
||||||
|
in
|
||||||
|
f :: more @ top ()
|
||||||
| _ -> let f = stmt s in f :: top ()
|
| _ -> let f = stmt s in f :: top ()
|
||||||
in
|
in
|
||||||
let fs = if global_let then top () else stmts s in
|
let fs = if global_let then top () else stmts s in
|
||||||
|
|||||||
@ -187,9 +187,23 @@ Each item: the proposal, then the reason in one line.
|
|||||||
|
|
||||||
- **`let x = v`** scopes to the end of its block and reads as
|
- **`let x = v`** scopes to the end of its block and reads as
|
||||||
`(let [x v] rest…)`. Consecutive `let`s merge into one binding vector.
|
`(let [x v] rest…)`. Consecutive `let`s merge into one binding vector.
|
||||||
A `let` is always flat: a line indented deeper under `let x = v` is
|
A `let` takes more bindings on the lines indented under it, lined up with
|
||||||
refused. To end a `let`'s scope early, put it in a `do:` block.
|
its first name, each seeing the ones above:
|
||||||
The printer writes every `let` flat. A `let` with statements after it
|
|
||||||
|
```
|
||||||
|
let row = r + 1
|
||||||
|
col: i32 = c - 1
|
||||||
|
{x .x} = p
|
||||||
|
```
|
||||||
|
|
||||||
|
is `(let [row (+ r 1) col (the i32 (- c 1)) {x .x} p] rest…)`. Any other
|
||||||
|
line indented there is refused. At the top level each such line is one
|
||||||
|
more global, `(def col i32 …)`; a pattern there is refused, since a global
|
||||||
|
binds one name. A `let` is otherwise flat: its scope is the rest of its
|
||||||
|
block. To end it early, put it in a `do:` block.
|
||||||
|
The printer writes every `let` flat, and a run of bindings whose values
|
||||||
|
are short (one line, 40 characters or fewer) as one `let` with the rest
|
||||||
|
under the first name; top-level globals stay one `let` each. A `let` with statements after it
|
||||||
takes them into its body; when one of them means an outer name the `let`
|
takes them into its body; when one of them means an outer name the `let`
|
||||||
rebinds, the `let`'s is renamed (`x` to `x-2`, a name the top-level form
|
rebinds, the `let`'s is renamed (`x` to `x-2`, a name the top-level form
|
||||||
does not use; a struct pattern is written as `{x-2 .x}` pairs). A macro's
|
does not use; a struct pattern is written as `{x-2 .x}` pairs). A macro's
|
||||||
|
|||||||
@ -25,8 +25,8 @@ fn flush(field: Ptr(Vec(u8)), row: Ptr(Vec(str))) -> ()
|
|||||||
|
|
||||||
fn parse-line(line: [const u8]) -> Vec(str)
|
fn parse-line(line: [const u8]) -> Vec(str)
|
||||||
let row = vec-new(str)
|
let row = vec-new(str)
|
||||||
let field = vec-new(u8)
|
field = vec-new(u8)
|
||||||
let state = State.start
|
state = State.start
|
||||||
for i in range(length(line))
|
for i in range(length(line))
|
||||||
let c = line[i]
|
let c = line[i]
|
||||||
match state
|
match state
|
||||||
|
|||||||
@ -61,7 +61,7 @@ fn eval-form(e, env) -> dyn
|
|||||||
last
|
last
|
||||||
_ ->
|
_ ->
|
||||||
let f = eval(op, env)
|
let f = eval(op, env)
|
||||||
let arg = eval(e[1], env)
|
arg = eval(e[1], env)
|
||||||
eval(get(f, :body), extend(get(f, :env), get(f, :param), arg))
|
eval(get(f, :body), extend(get(f, :env), get(f, :param), arg))
|
||||||
|
|
||||||
fn run(program) -> ()
|
fn run(program) -> ()
|
||||||
|
|||||||
@ -40,8 +40,8 @@ fn show(l: Light) -> str
|
|||||||
; whoever handles it may reset the light to red.
|
; whoever handles it may reset the light to red.
|
||||||
fn run(ticks: i32, presses: [const i32], fault-at: i32) -> ()
|
fn run(ticks: i32, presses: [const i32], fault-at: i32) -> ()
|
||||||
let l = Light.Red{.left 1, .walk false}
|
let l = Light.Red{.left 1, .walk false}
|
||||||
let p = 0
|
p = 0
|
||||||
let t = 0
|
t = 0
|
||||||
until :clock t >= ticks
|
until :clock t >= ticks
|
||||||
let pressed = p < length(presses)
|
let pressed = p < length(presses)
|
||||||
and presses[p] == t
|
and presses[p] == t
|
||||||
|
|||||||
@ -18,9 +18,9 @@ fn letter?(c: u8) -> bool
|
|||||||
; The words of text, lowercased, in order.
|
; The words of text, lowercased, in order.
|
||||||
fn words(text: [const u8]) -> Vec([const u8])
|
fn words(text: [const u8]) -> Vec([const u8])
|
||||||
let out = vec-new([const u8])
|
let out = vec-new([const u8])
|
||||||
let lower = to-lower(text)
|
lower = to-lower(text)
|
||||||
let i = 0
|
i = 0
|
||||||
let n = length(lower)
|
n = length(lower)
|
||||||
while :scan i < n
|
while :scan i < n
|
||||||
until i >= n or letter?(lower[i])
|
until i >= n or letter?(lower[i])
|
||||||
i += 1
|
i += 1
|
||||||
@ -67,11 +67,11 @@ fn main() -> i32
|
|||||||
let {.word .n} = counts[i]
|
let {.word .n} = counts[i]
|
||||||
println(str(word), n)
|
println(str(word), n)
|
||||||
let top: [3 i32] = [counts[0].n counts[1].n counts[2].n]
|
let top: [3 i32] = [counts[0].n counts[1].n counts[2].n]
|
||||||
let [most & others] = top
|
[most & others] = top
|
||||||
println("most frequent seen", most, "times, then", others)
|
println("most frequent seen", most, "times, then", others)
|
||||||
let total = i32(length(ws))
|
let total = i32(length(ws))
|
||||||
let distinct = i32(length(counts))
|
distinct = i32(length(counts))
|
||||||
let g = grade(distinct, total)
|
g = grade(distinct, total)
|
||||||
println(distinct, "of", total, "distinct:", describe(g))
|
println(distinct, "of", total, "distinct:", describe(g))
|
||||||
let longest = reduce(slice(ws), slice(ws[0], 0, 0), fn(a, b) =>
|
let longest = reduce(slice(ws), slice(ws[0], 0, 0), fn(a, b) =>
|
||||||
if length(b) > length(a) then b else a)
|
if length(b) > length(a) then b else a)
|
||||||
|
|||||||
@ -539,7 +539,7 @@ let () =
|
|||||||
(* Statements. *)
|
(* Statements. *)
|
||||||
reads "lets merge" "fn f() -> i32\n let a = 1\n let b = 2\n a + b"
|
reads "lets merge" "fn f() -> i32\n let a = 1\n let b = 2\n a + b"
|
||||||
"(defn f [] i32 (let [a 1 b 2] (+ a b)))";
|
"(defn f [] i32 (let [a 1 b 2] (+ a b)))";
|
||||||
refuses ~global:false "let with a block" "let a = 1\n a\nb" "indent/let-block" "go at the let's column";
|
refuses ~global:false "let with a block" "let a = 1\n a\nb" "indent/let-block" "goes at the let's column";
|
||||||
reads ~global:false "flat let" "let a = 1\na\nb" "(let [a 1] a b)";
|
reads ~global:false "flat let" "let a = 1\na\nb" "(let [a 1] a b)";
|
||||||
reads "elif" "if a\n 1\nelif b\n 2\nelse\n 3" "(cond a 1 b 2 :else 3)";
|
reads "elif" "if a\n 1\nelif b\n 2\nelse\n 3" "(cond a 1 b 2 :else 3)";
|
||||||
reads "one-line if" "x = if a then 1 else 2" "(set x (if a 1 2))";
|
reads "one-line if" "x = if a then 1 else 2" "(set x (if a 1 2))";
|
||||||
@ -643,6 +643,8 @@ let () =
|
|||||||
refuses "two assignments" "if a then b = c = d" "indent/assign-in-test" "if a then b = c,";
|
refuses "two assignments" "if a then b = c = d" "indent/assign-in-test" "if a then b = c,";
|
||||||
refuses "a let-bound if with no block" "let r = if a > 1\nr" "indent/expected-block" "if a > 1 takes";
|
refuses "a let-bound if with no block" "let r = if a > 1\nr" "indent/expected-block" "if a > 1 takes";
|
||||||
refuses "two bindings on a line" "let v: i32 = a, w = b" "indent/one-binding" "a is followed by a comma";
|
refuses "two bindings on a line" "let v: i32 = a, w = b" "indent/one-binding" "a is followed by a comma";
|
||||||
|
refuses "two bindings on a let's line" "fn f()\n let v = a, w = b\n v" "indent/one-binding"
|
||||||
|
"under its name:\n\n let v = a\n w = b";
|
||||||
reads ~global:false "a let-bound match" "let r = match a\n 1 -> 2\n _ -> 3\nr" "(let [r (match a 1 2 _ 3)] r)";
|
reads ~global:false "a let-bound match" "let r = match a\n 1 -> 2\n _ -> 3\nr" "(let [r (match a 1 2 _ 3)] r)";
|
||||||
reads ~global:false "a let-bound if" "let q = if a\n 1\nelse\n 2\nq" "(let [q (if a 1 2)] q)";
|
reads ~global:false "a let-bound if" "let q = if a\n 1\nelse\n 2\nq" "(let [q (if a 1 2)] q)";
|
||||||
reads ~global:false "a let-bound call with a block" "let v = foo(a):\n x\nv" "(let [v (foo a x)] v)";
|
reads ~global:false "a let-bound call with a block" "let v = foo(a):\n x\nv" "(let [v (foo a x)] v)";
|
||||||
@ -659,7 +661,7 @@ let () =
|
|||||||
"(defmacro m [x] (quasiquote (+ (unquote x) 1)))";
|
"(defmacro m [x] (quasiquote (+ (unquote x) 1)))";
|
||||||
reads ~global:false "typed let" "let x: i32 = 5\nx" "(let [x (the i32 5)] x)";
|
reads ~global:false "typed let" "let x: i32 = 5\nx" "(let [x (the i32 5)] x)";
|
||||||
refuses "a let takes no block" "fn f() -> ()\n let x = 1\n g(x)\n h(x)"
|
refuses "a let takes no block" "fn f() -> ()\n let x = 1\n g(x)\n h(x)"
|
||||||
"indent/let-block" "go at the let's column";
|
"indent/let-block" "goes at the let's column";
|
||||||
(* Mistakes carried over from other languages, answered in this one. *)
|
(* Mistakes carried over from other languages, answered in this one. *)
|
||||||
refuses "a block without the colon names the call" "with-allocator(a, b)\n g()"
|
refuses "a block without the colon names the call" "with-allocator(a, b)\n g()"
|
||||||
"indent/stray-indent" "as in with-allocator(a, b):";
|
"indent/stray-indent" "as in with-allocator(a, b):";
|
||||||
@ -693,6 +695,29 @@ let () =
|
|||||||
"indent/lambda-block-left" "Indent it into the block";
|
"indent/lambda-block-left" "Indent it into the block";
|
||||||
refuses "a block lambda's brackets left open" "f(fn(a) =>\n a\n"
|
refuses "a block lambda's brackets left open" "f(fn(a) =>\n a\n"
|
||||||
"indent/unclosed" "ends where this bracket closes";
|
"indent/unclosed" "ends where this bracket closes";
|
||||||
|
(* A let's bindings on the lines under it. *)
|
||||||
|
reads ~global:false "a let's bindings on indented lines" "let a = 1\n b = a + 1\n c: i32 = b\ng(c)"
|
||||||
|
"(let [a 1 b (+ a 1) c (the i32 b)] (g c))";
|
||||||
|
reads ~global:false "patterns among them" "let p = q()\n {x .x} = p\n [h & t] = xs\ng(x, h)"
|
||||||
|
"(let [p (q) {x .x} p [h & t] xs] (g x h))";
|
||||||
|
reads ~global:false "a binding with a block value" "let a = 1\n b =\n f()\n a\n c = match b\n 1 -> 2\n _ -> 3\ng(c)"
|
||||||
|
"(let [a 1 b (do (f) a) c (match b 1 2 _ 3)] (g c))";
|
||||||
|
reads ~global:false "a let after a group merges into it" "let a = 1\n b = 2\nlet c = 3\ng(c)"
|
||||||
|
"(let [a 1 b 2 c 3] (g c))";
|
||||||
|
reads ~global:false "a group in a body" "fn f()\n let a = 1\n b = 2\n a + b"
|
||||||
|
"(defn f [] _ (let [a 1 b 2] (+ a b)))";
|
||||||
|
refuses ~global:false "a statement under a let" "let a = 1\n g(a)\nh()"
|
||||||
|
"indent/let-block" "b = a + 1";
|
||||||
|
refuses ~global:false "an assignment to a field under a let" "let a = p()\n a.x = 1\nh()"
|
||||||
|
"indent/let-block" "only lines that go there are more bindings";
|
||||||
|
refuses ~global:false "a compound assignment under a let" "let a = 1\n a += 1\nh()"
|
||||||
|
"indent/let-block" "let's column";
|
||||||
|
reads "a top-level group is several globals" "let a = 1\n b: i32 = 2\nfn f() = a"
|
||||||
|
"(def a dyn 1)\n(def b i32 2)\n(defn f [] _ a)";
|
||||||
|
refuses "a global group binds names" "let a = 1\n {x .x} = p"
|
||||||
|
"indent/global-pattern" "a global binds one name";
|
||||||
|
refuses "a statement under a global" "let a = 1\n f(a)"
|
||||||
|
"indent/let-block" "more bindings of the let";
|
||||||
(* Indices separate as a vector's elements do. *)
|
(* Indices separate as a vector's elements do. *)
|
||||||
reads "indices separated by spaces" "x = grid[row col].color-idx"
|
reads "indices separated by spaces" "x = grid[row col].color-idx"
|
||||||
"(set x (.color-idx (at grid row col)))";
|
"(set x (.color-idx (at grid row col)))";
|
||||||
@ -786,18 +811,18 @@ let () =
|
|||||||
(* A let is always flat: it takes in the rest of its block. *)
|
(* A let is always flat: it takes in the rest of its block. *)
|
||||||
prints "flat let" "(defn f [] () (let [j 1] (g j)) (h))" " let j = 1\n g(j)\n h()";
|
prints "flat let" "(defn f [] () (let [j 1] (g j)) (h))" " let j = 1\n g(j)\n h()";
|
||||||
prints "a chain of lets, all flat" "(defn f [] () (let [a 1] (let [b 2] (g b)) (k a)) (h))"
|
prints "a chain of lets, all flat" "(defn f [] () (let [a 1] (let [b 2] (g b)) (k a)) (h))"
|
||||||
" let a = 1\n let b = 2\n g(b)\n k(a)\n h()";
|
" let a = 1\n b = 2\n g(b)\n k(a)\n h()";
|
||||||
(* A later statement that means an outer name of the same spelling: the
|
(* A later statement that means an outer name of the same spelling: the
|
||||||
let's own is renamed. *)
|
let's own is renamed. *)
|
||||||
prints "a later outer name of the same spelling renames the let's"
|
prints "a later outer name of the same spelling renames the let's"
|
||||||
"(defn f [x i32] () (let [x 1] (g x)) (h x))" " let x-2 = 1\n g(x-2)\n h(x)";
|
"(defn f [x i32] () (let [x 1] (g x)) (h x))" " let x-2 = 1\n g(x-2)\n h(x)";
|
||||||
prints "the inner let of a chain renamed"
|
prints "the inner let of a chain renamed"
|
||||||
"(defn f [] () (let [a 1] (let [b 2] (g b)) (h b)))" " let a = 1\n let b-2 = 2\n g(b-2)\n h(b)";
|
"(defn f [] () (let [a 1] (let [b 2] (g b)) (h b)))" " let a = 1\n b-2 = 2\n g(b-2)\n h(b)";
|
||||||
prints "the binding's own value keeps the outer name"
|
prints "the binding's own value keeps the outer name"
|
||||||
"(defn f [x i32] () (let [x (+ x 1)] (g x)) (h x))" " let x-2 = x + 1\n g(x-2)\n h(x)";
|
"(defn f [x i32] () (let [x (+ x 1)] (g x)) (h x))" " let x-2 = x + 1\n g(x-2)\n h(x)";
|
||||||
prints "a later binding's value takes the new name"
|
prints "a later binding's value takes the new name"
|
||||||
"(defn f [x i32] () (let [x 1 y (+ x 1)] (g y)) (h x))"
|
"(defn f [x i32] () (let [x 1 y (+ x 1)] (g y)) (h x))"
|
||||||
" let x-2 = 1\n let y = x-2 + 1\n g(y)\n h(x)";
|
" let x-2 = 1\n y = x-2 + 1\n g(y)\n h(x)";
|
||||||
prints "the new name is one the function does not use"
|
prints "the new name is one the function does not use"
|
||||||
"(defn f [x i32] () (let [x 1] (g x x-2)) (h x))" " let x-3 = 1\n g(x-3, x-2)\n h(x)";
|
"(defn f [x i32] () (let [x 1] (g x x-2)) (h x))" " let x-3 = 1\n g(x-3, x-2)\n h(x)";
|
||||||
prints "a later let of the same name is no mention"
|
prints "a later let of the same name is no mention"
|
||||||
@ -838,10 +863,10 @@ let () =
|
|||||||
prints "comment is a body in order" "(comment (let [a 1] (g a)) (h))" "comment:\n let a = 1\n g(a)\n h()";
|
prints "comment is a body in order" "(comment (let [a 1] (g a)) (h))" "comment:\n let a = 1\n g(a)\n h()";
|
||||||
prints "a later lambda keeps the outer name"
|
prints "a later lambda keeps the outer name"
|
||||||
"(defn f [] i32 (let [x 1] (let [x 5] (g x)) (app (fn [y] (+ x y)) 2)))"
|
"(defn f [] i32 (let [x 1] (let [x 5] (g x)) (app (fn [y] (+ x y)) 2)))"
|
||||||
" let x = 1\n let x-2 = 5\n g(x-2)\n app(fn(y) => x + y, 2)";
|
" let x = 1\n x-2 = 5\n g(x-2)\n app(fn(y) => x + y, 2)";
|
||||||
prints "a renamed name renamed again counts on"
|
prints "a renamed name renamed again counts on"
|
||||||
"(defn f [] () (let [x 1] (let [x 2] (let [x 3] (g x)) (g x)) (g x)))"
|
"(defn f [] () (let [x 1] (let [x 2] (let [x 3] (g x)) (g x)) (g x)))"
|
||||||
" let x = 1\n let x-2 = 2\n let x-3 = 3\n g(x-3)\n g(x-2)\n g(x)";
|
" let x = 1\n x-2 = 2\n x-3 = 3\n g(x-3)\n g(x-2)\n g(x)";
|
||||||
prints "a macro that names the let's name keeps its scope"
|
prints "a macro that names the let's name keeps its scope"
|
||||||
"(defmacro show-it [] `(println it))\n(defn f [] () (let [it 1] (let [it 2] (show-it)) (show-it)))"
|
"(defmacro show-it [] `(println it))\n(defn f [] () (let [it 1] (let [it 2] (show-it)) (show-it)))"
|
||||||
" let it = 1\n do:\n let it = 2\n show-it()\n show-it()";
|
" let it = 1\n do:\n let it = 2\n show-it()\n show-it()";
|
||||||
@ -898,7 +923,19 @@ let () =
|
|||||||
"(let [a 1 ; first\n b 2] ; second";
|
"(let [a 1 ; first\n b 2] ; second";
|
||||||
prints "each binding keeps its comment, indented"
|
prints "each binding keeps its comment, indented"
|
||||||
"(defn f [] i32\n (let [a 1 ; first\n b 2] ; second\n (+ a b)))"
|
"(defn f [] i32\n (let [a 1 ; first\n b 2] ; second\n (+ a b)))"
|
||||||
" let a = 1 ; first\n let b = 2 ; second";
|
" let a = 1 ; first\n b = 2 ; second";
|
||||||
|
prints "a comment line between grouped bindings"
|
||||||
|
"(defn f [] i32\n (let [a 1\n ;; why b\n b 2]\n (+ a b)))"
|
||||||
|
" let a = 1\n ;; why b\n b = 2\n";
|
||||||
|
prints "a long value starts a let of its own"
|
||||||
|
"(defn f [] i32 (let [a 1 b (some-function-with-a-long-name alpha beta gamma) c 2] (+ a b c)))"
|
||||||
|
" let a = 1\n let b = some-function-with-a-long-name(alpha, beta, gamma)\n let c = 2\n";
|
||||||
|
prints "a block value ends the group"
|
||||||
|
"(defn f [] i32 (let [a 1 b 2 c (do (g) a) d 4 e 5] (+ a b c d e)))"
|
||||||
|
" let a = 1\n b = 2\n let c =\n g()\n a\n let d = 4\n e = 5\n";
|
||||||
|
prints "typed and pattern bindings in a group"
|
||||||
|
"(defn f [p dyn] i32 (let [a (the i32 1) {x .x} p [h & t] xs] (+ a x h)))"
|
||||||
|
" let a: i32 = 1\n {x .x} = p\n [h & t] = xs\n";
|
||||||
back "comments to parens" "; head\n\nfn main() -> i32\n ; why\n g() ; note\n 0"
|
back "comments to parens" "; head\n\nfn main() -> i32\n ; why\n g() ; note\n 0"
|
||||||
"; head\n\n(defn main [] i32\n ; why\n (g) ; note\n 0)";
|
"; head\n\n(defn main [] i32\n ; why\n (g) ; note\n 0)";
|
||||||
(* Written the way the corpus writes them. *)
|
(* Written the way the corpus writes them. *)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user