A .fln file writes a type alias as type Row = Vec(i32), and flan check prints nothing for a file that checks unless given --defs.
This commit is contained in:
parent
1a97dfff77
commit
72c73117d6
17
TODO.org
17
TODO.org
@ -650,27 +650,10 @@ Decided 2026-09-26: a lambda's body follows ~=>~, and ~=>~ is its only spelling
|
|||||||
takes an indented block even inside brackets, closing where the brackets close:
|
takes an indented block even inside brackets, closing where the brackets close:
|
||||||
~sort-by(xs, fn(a, b) =>~ plus a block.
|
~sort-by(xs, fn(a, b) =>~ plus a block.
|
||||||
|
|
||||||
** NEXT A type alias is written type Row = Vec(i32)
|
|
||||||
Decided 2026-09-26: .fln reads ~type Name = T~ as ~(defalias Name T)~, and the printer
|
|
||||||
writes it back.
|
|
||||||
|
|
||||||
** TODO flan check prints every definition of a file that checks
|
|
||||||
A clean =flan check= lists the whole prelude (about 170 lines). Clean should print
|
|
||||||
nothing, or only the file's own definitions behind a flag.
|
|
||||||
|
|
||||||
** NEXT Classes and methods have .fln syntax
|
|
||||||
Decided 2026-09-26: ~class Lambda(param, body, env)~, ~generic describe(v) -> dyn~,
|
|
||||||
~method describe(f: Lambda)~ plus a block (the class as the parameter's type),
|
|
||||||
~multi kind(v) -> dyn = type-of(v)~, ~method kind(v) when :int~ plus a block.
|
|
||||||
|
|
||||||
** NEXT A top-level let is a global
|
** NEXT A top-level let is a global
|
||||||
Decided 2026-09-26: in .fln ~let x = v~ at column 0 reads ~(def x v)~ and replaces
|
Decided 2026-09-26: in .fln ~let x = v~ at column 0 reads ~(def x v)~ and replaces
|
||||||
~def~, which is refused with that fix; ~once~ and ~const~ stay.
|
~def~, which is refused with that fix; ~once~ and ~const~ stay.
|
||||||
|
|
||||||
** NEXT A struct fits on one line
|
|
||||||
Decided 2026-09-26: ~struct Pt(x: i32, y: i32)~ beside the block form, like a data
|
|
||||||
case; union and a struct with a parent too.
|
|
||||||
|
|
||||||
** TODO Hard-coded code in messages is still paren syntax in a .fln file
|
** TODO Hard-coded code in messages is still paren syntax in a .fln file
|
||||||
Types follow the code's syntax now (=Types.spell=). Hints written into a message's
|
Types follow the code's syntax now (=Types.spell=). Hints written into a message's
|
||||||
text — =(Ptr %s)=, =(clone v)=, =(the T x)= in most of =check.ml= and =parse.ml=, the
|
text — =(Ptr %s)=, =(clone v)=, =(the T x)= in most of =check.ml= and =parse.ml=, the
|
||||||
|
|||||||
52
bin/main.ml
52
bin/main.ml
@ -226,9 +226,14 @@ let no_gc_flag = "--no-gc"
|
|||||||
downstream that it ran. *)
|
downstream that it ran. *)
|
||||||
let warn_memory_flag = "--warn-memory"
|
let warn_memory_flag = "--warn-memory"
|
||||||
|
|
||||||
|
(* [flan check --defs]: every definition the checked program holds, prelude
|
||||||
|
included. Off by default, so a file that checks prints nothing. *)
|
||||||
|
let defs_flag = "--defs"
|
||||||
|
|
||||||
let flags =
|
let flags =
|
||||||
[ no_checks_flag; dev_flag; debug_flag; sanitize_flag; two_process_flag;
|
[ no_checks_flag; dev_flag; debug_flag; sanitize_flag; two_process_flag;
|
||||||
x86_flag; llvm_flag; no_annotate_flag; no_gc_flag; warn_memory_flag ]
|
x86_flag; llvm_flag; no_annotate_flag; no_gc_flag; warn_memory_flag;
|
||||||
|
defs_flag ]
|
||||||
|
|
||||||
(* The warnings, where errors go. Printed one to a location in the repo's
|
(* The warnings, where errors go. Printed one to a location in the repo's
|
||||||
standard [file:line:col:] shape, with the squiggle [Loc.entry] draws, so
|
standard [file:line:col:] shape, with the squiggle [Loc.entry] draws, so
|
||||||
@ -355,6 +360,7 @@ let () =
|
|||||||
files
|
files
|
||||||
| _ :: "check" :: args when List.exists (fun a -> not (is_flag a)) args ->
|
| _ :: "check" :: args when List.exists (fun a -> not (is_flag a)) args ->
|
||||||
let warn_memory = List.mem warn_memory_flag args in
|
let warn_memory = List.mem warn_memory_flag args in
|
||||||
|
let defs = List.mem defs_flag args in
|
||||||
let files = List.filter (fun a -> not (is_flag a)) args in
|
let files = List.filter (fun a -> not (is_flag a)) args in
|
||||||
List.iter
|
List.iter
|
||||||
(fun path ->
|
(fun path ->
|
||||||
@ -366,26 +372,28 @@ let () =
|
|||||||
program that checked, which is what leaves the exit status
|
program that checked, which is what leaves the exit status
|
||||||
alone. *)
|
alone. *)
|
||||||
if warn_memory then print_memory_warnings ~file:path p;
|
if warn_memory then print_memory_warnings ~file:path p;
|
||||||
List.iter
|
if defs then begin
|
||||||
(fun (g : Flan.Tast.global) ->
|
List.iter
|
||||||
Printf.printf "%s %s %s\n"
|
(fun (g : Flan.Tast.global) ->
|
||||||
(* The three defining forms, told apart the way the compiler
|
Printf.printf "%s %s %s\n"
|
||||||
tells them apart: [gconst] is the image, and [grerun] is
|
(* The three defining forms, told apart the way the compiler
|
||||||
what a re-run does to the storage. A listing that called
|
tells them apart: [gconst] is the image, and [grerun] is
|
||||||
both mutable forms one name could not answer the question
|
what a re-run does to the storage. A listing that called
|
||||||
someone runs [flan check] on a dev file to ask. *)
|
both mutable forms one name could not answer the question
|
||||||
(if g.gconst then "defconst"
|
someone runs [flan check] on a dev file to ask. *)
|
||||||
else if g.grerun then "def" else "defonce")
|
(if g.gconst then "defconst"
|
||||||
g.gname (Flan.Types.to_string g.gty))
|
else if g.grerun then "def" else "defonce")
|
||||||
p.globals;
|
g.gname (Flan.Types.to_string g.gty))
|
||||||
List.iter
|
p.globals;
|
||||||
(fun (f : Flan.Tast.fn) ->
|
List.iter
|
||||||
if not (Flan.Check.internal_name f.name) then
|
(fun (f : Flan.Tast.fn) ->
|
||||||
Printf.printf "defn %s : (Fn [%s] %s) %d slots\n" f.name
|
if not (Flan.Check.internal_name f.name) then
|
||||||
(String.concat " "
|
Printf.printf "defn %s : (Fn [%s] %s) %d slots\n" f.name
|
||||||
(List.map Flan.Types.to_string f.params))
|
(String.concat " "
|
||||||
(Flan.Types.to_string f.ret) (Array.length f.slots))
|
(List.map Flan.Types.to_string f.params))
|
||||||
p.fns))
|
(Flan.Types.to_string f.ret) (Array.length f.slots))
|
||||||
|
p.fns
|
||||||
|
end))
|
||||||
files
|
files
|
||||||
(* The generated C, for looking at. A wrong FFI binding is wrong in the
|
(* The generated C, for looking at. A wrong FFI binding is wrong in the
|
||||||
wrapper, and the wrapper is not on disk anywhere — [Build] hands the text
|
wrapper, and the wrapper is not on disk anywhere — [Build] hands the text
|
||||||
@ -982,7 +990,7 @@ let () =
|
|||||||
| None -> code))
|
| None -> code))
|
||||||
| _ ->
|
| _ ->
|
||||||
prerr_endline
|
prerr_endline
|
||||||
"usage: flan (read|parse|check|emit|shim) <file.flan>...\n flan check <file.flan>... [--warn-memory]\n flan emit <file.flan> [--x86] [--dev] [--debug] [--no-bounds-checks]\n\
|
"usage: flan (read|parse|check|emit|shim) <file.flan>...\n flan check <file.flan>... [--warn-memory] [--defs]\n flan emit <file.flan> [--x86] [--dev] [--debug] [--no-bounds-checks]\n\
|
||||||
\ flan import-c <header.h> [package.flan...] [clang flags...]\n\
|
\ flan import-c <header.h> [package.flan...] [clang flags...]\n\
|
||||||
\ flan generate-c <package-dir>\n\
|
\ flan generate-c <package-dir>\n\
|
||||||
\ flan build <file.flan> [-o out] [-O0|-O1|-O2|-O3] \
|
\ flan build <file.flan> [-o out] [-O0|-O1|-O2|-O3] \
|
||||||
|
|||||||
@ -97,7 +97,7 @@ fine here. Brackets and strings are still paired."
|
|||||||
'("fn" "fn-" "def" "once" "const" "struct" "union" "data" "enum" "import"
|
'("fn" "fn-" "def" "once" "const" "struct" "union" "data" "enum" "import"
|
||||||
"if" "elif" "else" "while" "until" "for" "match" "let" "return" "break"
|
"if" "elif" "else" "while" "until" "for" "match" "let" "return" "break"
|
||||||
"continue" "defer" "handler-case" "handler-bind" "restart-case" "on"
|
"continue" "defer" "handler-case" "handler-bind" "restart-case" "on"
|
||||||
"restart" "quote" "macro" "loop"))
|
"restart" "quote" "macro" "loop" "type"))
|
||||||
|
|
||||||
;; The headers whose block follows on the lines under them. `defer' and
|
;; The headers whose block follows on the lines under them. `defer' and
|
||||||
;; `quote' open one only when nothing follows them on the line; `fn' does not
|
;; `quote' open one only when nothing follows them on the line; `fn' does not
|
||||||
@ -112,7 +112,7 @@ fine here. Brackets and strings are still paired."
|
|||||||
'(("fn" . "defn") ("fn-" . "defn-") ("def" . "def") ("once" . "defonce")
|
'(("fn" . "defn") ("fn-" . "defn-") ("def" . "def") ("once" . "defonce")
|
||||||
("const" . "defconst") ("struct" . "defstruct") ("data" . "defdata")
|
("const" . "defconst") ("struct" . "defstruct") ("data" . "defdata")
|
||||||
("enum" . "defenum") ("union" . "defunion") ("import" . "import")
|
("enum" . "defenum") ("union" . "defunion") ("import" . "import")
|
||||||
("macro" . "defmacro"))
|
("macro" . "defmacro") ("type" . "defalias"))
|
||||||
"Each declaration header word, and the paren head it reads as.")
|
"Each declaration header word, and the paren head it reads as.")
|
||||||
|
|
||||||
;;; Syntax
|
;;; Syntax
|
||||||
@ -1560,7 +1560,10 @@ lambda or a `Fn(...)' type, and not after a match arm's."
|
|||||||
1 font-lock-keyword-face)
|
1 font-lock-keyword-face)
|
||||||
(,(concat "^\\(fn-?\\|macro\\)[ \t]+" flan-fln--name-re)
|
(,(concat "^\\(fn-?\\|macro\\)[ \t]+" flan-fln--name-re)
|
||||||
2 font-lock-function-name-face)
|
2 font-lock-function-name-face)
|
||||||
(,(concat "^\\(?:struct\\|data\\|union\\|enum\\)[ \t]+" flan-fln--name-re)
|
(,(concat "^\\(?:struct\\|data\\|union\\|enum\\|type\\)[ \t]+" flan-fln--name-re)
|
||||||
|
1 font-lock-type-face)
|
||||||
|
;; An alias's type, `type Row = Vec(i32)'.
|
||||||
|
(,(concat "^type[ \t]+[^][ \t\n(){},;\":]+[ \t]+=[ \t]+" flan-fln--name-re)
|
||||||
1 font-lock-type-face)
|
1 font-lock-type-face)
|
||||||
;; A condition's parent, `struct DiskFull :parent IoError'.
|
;; A condition's parent, `struct DiskFull :parent IoError'.
|
||||||
(,(concat "^struct[ \t]+[^][ \t\n(){},;\":]+[ \t]+:parent[ \t]+" flan-fln--name-re)
|
(,(concat "^struct[ \t]+[^][ \t\n(){},;\":]+[ \t]+:parent[ \t]+" flan-fln--name-re)
|
||||||
@ -1600,7 +1603,7 @@ lambda or a `Fn(...)' type, and not after a match arm's."
|
|||||||
(defvar flan-fln-imenu-generic-expression
|
(defvar flan-fln-imenu-generic-expression
|
||||||
`(("Functions" ,(concat "^fn-?[ \t]+" flan-fln--name-re) 1)
|
`(("Functions" ,(concat "^fn-?[ \t]+" flan-fln--name-re) 1)
|
||||||
("Macros" ,(concat "^\\(?:macro[ \t]+\\|defmacro(\\)" flan-fln--name-re) 1)
|
("Macros" ,(concat "^\\(?:macro[ \t]+\\|defmacro(\\)" flan-fln--name-re) 1)
|
||||||
("Types" ,(concat "^\\(?:struct\\|data\\|union\\|enum\\)[ \t]+" flan-fln--name-re) 1)
|
("Types" ,(concat "^\\(?:struct\\|data\\|union\\|enum\\|type\\)[ \t]+" flan-fln--name-re) 1)
|
||||||
("Variables" ,(concat "^\\(?:def\\|once\\|const\\)[ \t]+" flan-fln--name-re) 1))
|
("Variables" ,(concat "^\\(?:def\\|once\\|const\\)[ \t]+" flan-fln--name-re) 1))
|
||||||
"Imenu index for `flan-fln-mode'.")
|
"Imenu index for `flan-fln-mode'.")
|
||||||
|
|
||||||
@ -1610,7 +1613,7 @@ lambda or a `Fn(...)' type, and not after a match arm's."
|
|||||||
(when s
|
(when s
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char s)
|
(goto-char s)
|
||||||
(and (looking-at (concat "\\(?:fn-?\\|macro\\|def\\|once\\|const\\|struct\\|data\\|union\\|enum\\)[ \t]+"
|
(and (looking-at (concat "\\(?:fn-?\\|macro\\|def\\|once\\|const\\|struct\\|data\\|union\\|enum\\|type\\)[ \t]+"
|
||||||
flan-fln--name-re))
|
flan-fln--name-re))
|
||||||
(match-string-no-properties 1))))))
|
(match-string-no-properties 1))))))
|
||||||
|
|
||||||
|
|||||||
@ -88,6 +88,10 @@ fn dir(d: Dir) -> i64
|
|||||||
struct Oops :parent Error
|
struct Oops :parent Error
|
||||||
code: i64
|
code: i64
|
||||||
|
|
||||||
|
type Count = i64
|
||||||
|
|
||||||
|
fn counted(n: Count) -> Count = n + 1
|
||||||
|
|
||||||
fn oops-code() -> i64
|
fn oops-code() -> i64
|
||||||
handler-case
|
handler-case
|
||||||
error(Oops{.code 7})
|
error(Oops{.code 7})
|
||||||
@ -235,6 +239,8 @@ comment():
|
|||||||
("fn rs" "(rs)" "3")
|
("fn rs" "(rs)" "3")
|
||||||
("fn dir" "(dir :north)" "7")
|
("fn dir" "(dir :north)" "7")
|
||||||
("struct Oops" "(oops-code)" "7")
|
("struct Oops" "(oops-code)" "7")
|
||||||
|
("type Count" "(counted 1)" "2")
|
||||||
|
("fn counted" "(counted 1)" "2")
|
||||||
("fn oops-code" "(oops-code)" "7")
|
("fn oops-code" "(oops-code)" "7")
|
||||||
("macro dbl-of" "(use-mac 5)" "10")
|
("macro dbl-of" "(use-mac 5)" "10")
|
||||||
("fn use-mac" "(use-mac 5)" "10")
|
("fn use-mac" "(use-mac 5)" "10")
|
||||||
|
|||||||
@ -714,6 +714,8 @@ of its line with AT-END."
|
|||||||
(test-flan-fln--in "struct DiskFull :parent IoError
|
(test-flan-fln--in "struct DiskFull :parent IoError
|
||||||
free: i64
|
free: i64
|
||||||
|
|
||||||
|
type Row = Vec(i64)
|
||||||
|
|
||||||
macro repeat(i, n, & body)
|
macro repeat(i, n, & body)
|
||||||
quote
|
quote
|
||||||
for ~i in range(~n)
|
for ~i in range(~n)
|
||||||
@ -731,7 +733,14 @@ fn gcd(a: i32, b: i32) -> i32
|
|||||||
(test-flan-fln--is "and :parent a keyword" (funcall face ":parent") 'font-lock-constant-face)
|
(test-flan-fln--is "and :parent a keyword" (funcall face ":parent") 'font-lock-constant-face)
|
||||||
(test-flan-fln--is "macro is a keyword" (funcall face "macro") 'font-lock-keyword-face)
|
(test-flan-fln--is "macro is a keyword" (funcall face "macro") 'font-lock-keyword-face)
|
||||||
(test-flan-fln--is "and its name a function's" (funcall face "repeat") 'font-lock-function-name-face)
|
(test-flan-fln--is "and its name a function's" (funcall face "repeat") 'font-lock-function-name-face)
|
||||||
(test-flan-fln--is "loop is a keyword" (funcall face "loop") 'font-lock-keyword-face))
|
(test-flan-fln--is "loop is a keyword" (funcall face "loop") 'font-lock-keyword-face)
|
||||||
|
(test-flan-fln--is "type is a keyword" (funcall face "type") 'font-lock-keyword-face)
|
||||||
|
(test-flan-fln--is "an alias's name is a type" (funcall face "Row") 'font-lock-type-face)
|
||||||
|
(test-flan-fln--is "and so is what it names" (funcall face "Vec(i64)") 'font-lock-type-face))
|
||||||
|
(goto-char (point-min))
|
||||||
|
(search-forward "Row")
|
||||||
|
(test-flan-fln--is "an alias installs as a defalias"
|
||||||
|
(flan-fln--declaration-head-at (line-beginning-position)) "defalias")
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(search-forward "~@body")
|
(search-forward "~@body")
|
||||||
(test-flan-fln--is "a macro is one top-level form"
|
(test-flan-fln--is "a macro is one top-level form"
|
||||||
|
|||||||
@ -26,7 +26,7 @@ let reserved =
|
|||||||
[ "fn"; "fn-"; "def"; "once"; "const"; "struct"; "union"; "data"; "enum";
|
[ "fn"; "fn-"; "def"; "once"; "const"; "struct"; "union"; "data"; "enum";
|
||||||
"import"; "if"; "elif"; "else"; "while"; "until"; "match"; "let"; "for";
|
"import"; "if"; "elif"; "else"; "while"; "until"; "match"; "let"; "for";
|
||||||
"return"; "break"; "continue"; "defer"; "handler-case"; "handler-bind";
|
"return"; "break"; "continue"; "defer"; "handler-case"; "handler-bind";
|
||||||
"restart-case"; "quote"; "on"; "restart"; "macro"; "loop" ]
|
"restart-case"; "quote"; "on"; "restart"; "macro"; "loop"; "type" ]
|
||||||
|
|
||||||
(* A symbol the reader gives back as itself when it is written bare. *)
|
(* A symbol the reader gives back as itself when it is written bare. *)
|
||||||
let name_ok s =
|
let name_ok s =
|
||||||
@ -1062,6 +1062,9 @@ and sugar n (f : Form.t) : string list option =
|
|||||||
(ind (n + 2) ^ if is_sym "dyn" t then fname else fname ^ ": " ^ ty t))
|
(ind (n + 2) ^ if is_sym "dyn" t then fname else fname ^ ": " ^ ty t))
|
||||||
prs)
|
prs)
|
||||||
| _ -> None)
|
| _ -> None)
|
||||||
|
| Form.List [ { v = Form.Sym "defalias"; _ }; { v = Form.Sym name; _ }; t ]
|
||||||
|
when def_name name && type_shaped t ->
|
||||||
|
Some [ i ^ "type " ^ name ^ " = " ^ ty t ]
|
||||||
| Form.List [ { v = Form.Sym "defdata"; _ }; { v = Form.Sym name; _ }; { v = Form.Vec cs; _ } ]
|
| Form.List [ { v = Form.Sym "defdata"; _ }; { v = Form.Sym name; _ }; { v = Form.Vec cs; _ } ]
|
||||||
when def_name name ->
|
when def_name name ->
|
||||||
let case (c : Form.t) =
|
let case (c : Form.t) =
|
||||||
|
|||||||
@ -1070,6 +1070,8 @@ let header_follow p s =
|
|||||||
| "macro" ->
|
| "macro" ->
|
||||||
n.sp && plain_name n.tok
|
n.sp && plain_name n.tok
|
||||||
&& (let a = peek_at p 2 in a.tok = LP && not a.sp)
|
&& (let a = peek_at p 2 in a.tok = LP && not a.sp)
|
||||||
|
(* [type Row = Vec(i32)]: a name and its [=]. *)
|
||||||
|
| "type" -> n.sp && plain_name n.tok && (peek_at p 2).tok = NAME "="
|
||||||
(* [loop x = a, ...]: a name and its [=]. A name and a comma or the end
|
(* [loop x = a, ...]: a name and its [=]. A name and a comma or the end
|
||||||
of the line, or [loop] alone over a block, is a loop missing its first
|
of the line, or [loop] alone over a block, is a loop missing its first
|
||||||
values, which [header] answers. *)
|
values, which [header] answers. *)
|
||||||
@ -1551,6 +1553,12 @@ and header (s : st) w : Form.t =
|
|||||||
(match parent with
|
(match parent with
|
||||||
| None -> [ name; fv ]
|
| None -> [ name; fv ]
|
||||||
| Some (k, pt) -> name :: k :: pt :: (if fields = [] then [] else [ fv ]))
|
| Some (k, pt) -> name :: k :: pt :: (if fields = [] then [] else [ fv ]))
|
||||||
|
| "type" ->
|
||||||
|
let name = name_tok p ~what:"the alias's name" in
|
||||||
|
expect_name p "=" ~what:"= and the type it names";
|
||||||
|
let t = ty p in
|
||||||
|
expect_eol p ~after:(text_of t);
|
||||||
|
named "defalias" [ name; t ]
|
||||||
| "macro" ->
|
| "macro" ->
|
||||||
let name = name_tok p ~what:"the macro's name" in
|
let name = name_tok p ~what:"the macro's name" in
|
||||||
let lp = glued_lp p ~what:"the parameters, in parentheses glued to the name" in
|
let lp = glued_lp p ~what:"the parameters, in parentheses glued to the name" in
|
||||||
|
|||||||
@ -291,6 +291,7 @@ Each item: the proposal, then the reason in one line.
|
|||||||
`struct DiskFull :parent IoError` with its field lines, reading
|
`struct DiskFull :parent IoError` with its field lines, reading
|
||||||
`(defstruct DiskFull :parent IoError [free i64])`; with no field lines it
|
`(defstruct DiskFull :parent IoError [free i64])`; with no field lines it
|
||||||
reads `(defstruct IoError :parent Error)`. **Built.**
|
reads `(defstruct IoError :parent Error)`. **Built.**
|
||||||
|
- `type Row = Vec(i32)` reads `(defalias Row (Vec i32))`. **Built.**
|
||||||
- `macro repeat(i, n, & body)` plus a block reads
|
- `macro repeat(i, n, & body)` plus a block reads
|
||||||
`(defmacro repeat [i n & body] …)`. A parameter is a bare name, a
|
`(defmacro repeat [i n & body] …)`. A parameter is a bare name, a
|
||||||
destructuring vector `[a b]`, or `& rest`, last. **Built.**
|
destructuring vector `[a b]`, or `& rest`, last. **Built.**
|
||||||
@ -300,7 +301,7 @@ Each item: the proposal, then the reason in one line.
|
|||||||
- `import rl "vendor:raylib"`. **Built.**
|
- `import rl "vendor:raylib"`. **Built.**
|
||||||
- **Every other form uses the fallback** (next item) until someone asks for
|
- **Every other form uses the fallback** (next item) until someone asks for
|
||||||
sugar: `defclass`, `defgeneric`, `defmulti`, `defmethod`, `declare`,
|
sugar: `defclass`, `defgeneric`, `defmulti`, `defmethod`, `declare`,
|
||||||
`declare-c`, `defalias`, `array-fill`. **Built.**
|
`declare-c`, `array-fill`. **Built.**
|
||||||
The class forms keep the fallback for good (2026-09-26):
|
The class forms keep the fallback for good (2026-09-26):
|
||||||
`defmethod(area, point, [p]):` reads well enough.
|
`defmethod(area, point, [p]):` reads well enough.
|
||||||
|
|
||||||
|
|||||||
@ -7314,6 +7314,14 @@ level "1"
|
|||||||
cli_case "check on a file that is not there"
|
cli_case "check on a file that is not there"
|
||||||
"check no-such-file.flan" ~code:1
|
"check no-such-file.flan" ~code:1
|
||||||
~says:[ "no-such-file.flan"; "No such file or directory" ];
|
~says:[ "no-such-file.flan"; "No such file or directory" ];
|
||||||
|
(* A file that checks prints nothing; --defs lists what it defined. *)
|
||||||
|
(match cli "check programs/recur.flan" with
|
||||||
|
| 0, "" -> ()
|
||||||
|
| code, text ->
|
||||||
|
incr failures;
|
||||||
|
Printf.printf "FAIL a clean check prints nothing\n got: %S (exit %d)\n" text code);
|
||||||
|
cli_case "check --defs lists the definitions" "check programs/recur.flan --defs" ~code:0
|
||||||
|
~says:[ "defn gcd : (Fn [i32 i32] i32)" ];
|
||||||
(* And every other front end takes the same route, since the arm is on the
|
(* And every other front end takes the same route, since the arm is on the
|
||||||
one wrapper they all go through. *)
|
one wrapper they all go through. *)
|
||||||
cli_case "build on a file that is not there"
|
cli_case "build on a file that is not there"
|
||||||
|
|||||||
@ -555,6 +555,9 @@ let () =
|
|||||||
reads "struct" "struct Cell\n row: i32\n tag" "(defstruct Cell [row i32 tag dyn])";
|
reads "struct" "struct Cell\n row: i32\n tag" "(defstruct Cell [row i32 tag dyn])";
|
||||||
reads "struct with a parent" "struct DiskFull :parent IoError\n free: i64"
|
reads "struct with a parent" "struct DiskFull :parent IoError\n free: i64"
|
||||||
"(defstruct DiskFull :parent IoError [free i64])";
|
"(defstruct DiskFull :parent IoError [free i64])";
|
||||||
|
reads "type alias" "type Row = Vec(i32)" "(defalias Row (Vec i32))";
|
||||||
|
reads "type alias of an array" "type V2 = [2 f32]" "(defalias V2 [2 f32])";
|
||||||
|
reads "a local named type" "type = 3" "(set type 3)";
|
||||||
reads "a parent and no fields" "struct Io :parent Error" "(defstruct Io :parent Error)";
|
reads "a parent and no fields" "struct Io :parent Error" "(defstruct Io :parent Error)";
|
||||||
reads "macro" "macro repeat(i, n, & body)\n quote\n f(~i)\n ~@body"
|
reads "macro" "macro repeat(i, n, & body)\n quote\n f(~i)\n ~@body"
|
||||||
"(defmacro repeat [i n & body] (quasiquote (do (f (unquote i)) (unquote-splicing body))))";
|
"(defmacro repeat [i n & body] (quasiquote (do (f (unquote i)) (unquote-splicing body))))";
|
||||||
@ -824,6 +827,7 @@ let () =
|
|||||||
prints "a template's for keeps its unquotes"
|
prints "a template's for keeps its unquotes"
|
||||||
"(defmacro m [i n & body] `(dotimes [~i ~n] ~@body))" "for ~i in range(~n)";
|
"(defmacro m [i n & body] `(dotimes [~i ~n] ~@body))" "for ~i in range(~n)";
|
||||||
prints "a macro" "(defmacro m [[a b] n & body] `(do ~@body))" "macro m([a b], n, & body)\n quote";
|
prints "a macro" "(defmacro m [[a b] n & body] `(do ~@body))" "macro m([a b], n, & body)\n quote";
|
||||||
|
prints "a type alias" "(defalias Row (Vec i32))" "type Row = Vec(i32)";
|
||||||
prints "a struct with a parent" "(defstruct D :parent Io [free i64])"
|
prints "a struct with a parent" "(defstruct D :parent Io [free i64])"
|
||||||
"struct D :parent Io\n free: i64";
|
"struct D :parent Io\n free: i64";
|
||||||
prints "a parent with no fields" "(defstruct D :parent Io)" "struct D :parent Io";
|
prints "a parent with no fields" "(defstruct D :parent Io)" "struct D :parent Io";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user