Where a program starts, how a big array clears, and which key folds
flan-dev's start command proposed the last program it had started, so invoking it from a fresh project's buffer offered the previous project's file. It now proposes the buffer it was called from; restarting the previous program is what flan-dev-restart-program is for. Zeroing a fixed array wrote one typed store per element. Above 64 bytes that becomes a memset, which LLVM can lower as a bulk clear; below it the inline stores are still cheaper than a call. Outline's minor-mode map owned TAB in the lowering buffer, so the folding keys that buffer defines never ran. A buffer-local overriding map gives them back without touching Outline anywhere else. FIX.org collects the rough edges found while using the dev loop.
This commit is contained in:
parent
65d14f42f0
commit
798c852934
26
FIX.org
Normal file
26
FIX.org
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
* Stuff I've found
|
||||||
|
** Why do I need to call flan-dev to open another window?
|
||||||
|
let: flan: the program exited; restart flan dev
|
||||||
|
** I can't eval a toplevel defvar, need to eval-defun (C-c C-c)
|
||||||
|
For Flan’s intended live-program workflow, C-x C-e on any complete top-level form should do the natural thing:
|
||||||
|
|
||||||
|
- expression → compile/run temporary thunk; print its value
|
||||||
|
- defn, defvar, defmacro, etc. → compile/install it; report what changed
|
||||||
|
|
||||||
|
The compiler already has both paths. The current split is an editor/UI artifact: C-x C-e is wired directly to eval-expr, while C-c C-c is wired to declaration reload. It is not a fundamental limitation.
|
||||||
|
|
||||||
|
A good fix would make C-x C-e context-aware: if the enclosing form is top-level, send it through the declaration evaluator; otherwise use expression evaluation. Then C-c C-c can remain a convenient explicit “reload this definition” alias, but not the only way defvar works.
|
||||||
|
** I can't eval a top level Vec
|
||||||
|
slurp returns (Vec u8), an owning, move-only buffer. Flan currently forbids every move-only global because it has no global ownership/lifetime model: any function could read and free it, while ownership tracking only exists within one function.
|
||||||
|
|
||||||
|
For data that is fixed at build time, use an embedded immutable array instead:
|
||||||
|
|
||||||
|
(defconst the-data (embed "game-data.edn"))
|
||||||
|
|
||||||
|
That produces a fixed [u8], not a heap-owning Vec, so it can live globally. It also resolves relative to sand.flan.
|
||||||
|
|
||||||
|
If game-data.edn genuinely must be loaded at runtime, then today it has to be owned by a local—typically load it in main and pass it through the functions that need it. For a game-wide runtime-owned data asset, that is a missing language/runtime feature, not a bad use case on your part.
|
||||||
|
** The edn module seems to need a struct declaration, it should do both; go into a struct but also return a Map with Vecs and Sets when we don't provide a type
|
||||||
|
** defenum needs optional autoincrementing discriminants
|
||||||
|
** We need a javascript backend so we can reach the world
|
||||||
|
** We need to have C-style unions, maybe those are called defunion, and then sum types are defdata or deftype
|
||||||
@ -1,4 +1 @@
|
|||||||
* Additional things
|
* Additional things
|
||||||
** Why do we have prints dedicted per type? That's terrible, what do we need to have proper (println) work for everything?
|
|
||||||
** The current std is suffering from the same problem, functions should be generic? Why is it like this?
|
|
||||||
** Why do we have =at= and =nth= if they're the same? Pick one, maybe =at=. For all STD functions make sure we don't have redundancy, even if it matches clojure or lisp
|
|
||||||
|
|||||||
@ -570,13 +570,19 @@ When called interactively while a daemon this Emacs started is alive, asks
|
|||||||
before stopping it and switching programs. A noninteractive call still
|
before stopping it and switching programs. A noninteractive call still
|
||||||
refuses: callers cannot silently discard a running program's state."
|
refuses: callers cannot silently discard a running program's state."
|
||||||
(interactive
|
(interactive
|
||||||
;; The program last started, where there was one: a restart after a quit is
|
;; Starting a program is about the buffer the command was called from.
|
||||||
;; the common case, and it is rarely the buffer point happens to be in —
|
;; Keeping [flan-dev--file] as DEFAULT here made a previous project win
|
||||||
;; you quit from wherever you were reading when you decided to.
|
;; over the current buffer: after working on sand.flan, invoking this from
|
||||||
(list (read-file-name "flan dev: " nil flan-dev--file t
|
;; ~/Development/gameboy/gameboy.flan still proposed (and could start)
|
||||||
(and buffer-file-name
|
;; sand.flan. [flan-dev-restart-program] is the deliberate way to restart
|
||||||
(string-suffix-p ".flan" buffer-file-name)
|
;; the previous program; an ordinary M-x command must not do that.
|
||||||
(file-name-nondirectory buffer-file-name)))))
|
(let ((file (and buffer-file-name
|
||||||
|
(string-suffix-p ".flan" buffer-file-name)
|
||||||
|
(expand-file-name buffer-file-name))))
|
||||||
|
(list (read-file-name "flan dev: "
|
||||||
|
(and file (file-name-directory file))
|
||||||
|
file t
|
||||||
|
(and file (file-name-nondirectory file))))))
|
||||||
(when (process-live-p flan-dev--daemon)
|
(when (process-live-p flan-dev--daemon)
|
||||||
;; `interactive' has already read FILE. Refusing only here used to make
|
;; `interactive' has already read FILE. Refusing only here used to make
|
||||||
;; that selection look as though it had been ignored: the old daemon kept
|
;; that selection look as though it had been ignored: the old daemon kept
|
||||||
|
|||||||
@ -562,6 +562,16 @@ that is felt."
|
|||||||
(setq-local outline-regexp "[▸▾] ")
|
(setq-local outline-regexp "[▸▾] ")
|
||||||
(setq-local outline-level (lambda () 1))
|
(setq-local outline-level (lambda () 1))
|
||||||
(outline-minor-mode 1)
|
(outline-minor-mode 1)
|
||||||
|
;; Minor-mode bindings take precedence over this mode's map. Outline owns
|
||||||
|
;; TAB by default, so give this buffer its intended folding keys back
|
||||||
|
;; without changing Outline's bindings anywhere else.
|
||||||
|
(let ((map (copy-keymap outline-minor-mode-map)))
|
||||||
|
(define-key map (kbd "TAB") #'flan-lower-toggle)
|
||||||
|
(define-key map [backtab] #'flan-lower-cycle-all)
|
||||||
|
(setq-local minor-mode-overriding-map-alist
|
||||||
|
(cons (cons 'outline-minor-mode map)
|
||||||
|
(assq-delete-all 'outline-minor-mode
|
||||||
|
minor-mode-overriding-map-alist))))
|
||||||
(add-hook 'kill-buffer-hook #'flan-lower--clean nil t))
|
(add-hook 'kill-buffer-hook #'flan-lower--clean nil t))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
|
|||||||
@ -853,6 +853,8 @@ is written instead — the real `message' call the real command makes."
|
|||||||
(with-current-buffer flan-lower-buffer
|
(with-current-buffer flan-lower-buffer
|
||||||
(test-flan--check "C-c C-l opens a lowering buffer in its own mode"
|
(test-flan--check "C-c C-l opens a lowering buffer in its own mode"
|
||||||
(derived-mode-p 'flan-lower-mode))
|
(derived-mode-p 'flan-lower-mode))
|
||||||
|
(test-flan--check "TAB is the lowering buffer's toggle, not Outline's"
|
||||||
|
(eq (key-binding (kbd "TAB")) #'flan-lower-toggle))
|
||||||
;; The claim the header makes, which is the opposite of the one
|
;; The claim the header makes, which is the opposite of the one
|
||||||
;; `flan-disassemble' makes, and the reason both commands exist.
|
;; `flan-disassemble' makes, and the reason both commands exist.
|
||||||
(test-flan--check "whose header says it is the file and not the program"
|
(test-flan--check "whose header says it is the file and not the program"
|
||||||
|
|||||||
27
lib/emit.ml
27
lib/emit.ml
@ -577,6 +577,25 @@ let ins f fmt =
|
|||||||
Printf.ksprintf
|
Printf.ksprintf
|
||||||
(fun s -> if f.live then Buffer.add_string f.b (" " ^ s ^ f.dloc ^ "\n")) fmt
|
(fun s -> if f.live then Buffer.add_string f.b (" " ^ s ^ f.dloc ^ "\n")) fmt
|
||||||
|
|
||||||
|
(* A fixed array has no padding between elements, so its zero value is exactly
|
||||||
|
a run of zero bytes. Naming that operation lets LLVM choose its bulk-clear
|
||||||
|
implementation instead of expanding a large aggregate store into one store
|
||||||
|
per element. Keep small arrays as typed stores: their inline code is
|
||||||
|
cheaper than a call on targets which do not inline the intrinsic. *)
|
||||||
|
let bulk_zero_min_bytes = 64
|
||||||
|
|
||||||
|
let emit_bulk_zero f ptr ty =
|
||||||
|
match ty with
|
||||||
|
| Types.Array _ ->
|
||||||
|
let size, align = lay f.md ty in
|
||||||
|
if size >= bulk_zero_min_bytes then begin
|
||||||
|
ins f
|
||||||
|
"call void @llvm.memset.p0.i64(ptr align %d %s, i8 0, i64 %d, i1 false)"
|
||||||
|
align ptr size;
|
||||||
|
true
|
||||||
|
end else false
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
let term f fmt =
|
let term f fmt =
|
||||||
Printf.ksprintf
|
Printf.ksprintf
|
||||||
(fun s ->
|
(fun s ->
|
||||||
@ -1084,8 +1103,11 @@ and value_at f (e : Tast.expr) : string =
|
|||||||
"zeroinitializer"
|
"zeroinitializer"
|
||||||
| Tast.Set (p, v) ->
|
| Tast.Set (p, v) ->
|
||||||
let ptr, ty = place f p in
|
let ptr, ty = place f p in
|
||||||
let v' = value f v in
|
(match v.Tast.e with
|
||||||
ins f "store %s %s, ptr %s" (ll ty) v' ptr;
|
| Tast.Zero _ when emit_bulk_zero f ptr ty -> ()
|
||||||
|
| _ ->
|
||||||
|
let v' = value f v in
|
||||||
|
ins f "store %s %s, ptr %s" (ll ty) v' ptr);
|
||||||
"zeroinitializer"
|
"zeroinitializer"
|
||||||
| Tast.Make (_, fields) -> aggregate f e.Tast.ty fields
|
| Tast.Make (_, fields) -> aggregate f e.Tast.ty fields
|
||||||
| Tast.MakeCase (uname, case, fields) ->
|
| Tast.MakeCase (uname, case, fields) ->
|
||||||
@ -2602,6 +2624,7 @@ let header = {|; Generated by flan. The layout is C's: no object headers anywher
|
|||||||
%flanframe = type { ptr, ptr, ptr }
|
%flanframe = type { ptr, ptr, ptr }
|
||||||
@flan_frame_head = external global ptr
|
@flan_frame_head = external global ptr
|
||||||
|
|
||||||
|
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
|
||||||
declare void @flan_rt_init(i32, ptr)
|
declare void @flan_rt_init(i32, ptr)
|
||||||
declare void @flan_argv(ptr)
|
declare void @flan_argv(ptr)
|
||||||
declare void @flan_write_stdout(ptr, i64)
|
declare void @flan_write_stdout(ptr, i64)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user