Merge branch 'master' into worktree-agent-ae8e466a60e7cf35a
This commit is contained in:
commit
895828992e
@ -182,7 +182,7 @@ problems:
|
|||||||
$ flan import-c test/headers/sample.h
|
$ flan import-c test/headers/sample.h
|
||||||
(declare-c set-seed [seed u32] "set_seed")
|
(declare-c set-seed [seed u32] "set_seed")
|
||||||
(declare-c add-ints [a i32 b i32] i32 "add_ints")
|
(declare-c add-ints [a i32 b i32] i32 "add_ints")
|
||||||
(declare-c name-length [text string] i32 "name_length")
|
(declare-c name-length [text str] i32 "name_length")
|
||||||
...
|
...
|
||||||
;; 9 imported, 12 refused, of 22 functions in test/headers/sample.h
|
;; 9 imported, 12 refused, of 22 functions in test/headers/sample.h
|
||||||
;; refused owned-text: owned_text returns char *, which the caller owns and
|
;; refused owned-text: owned_text returns char *, which the caller owns and
|
||||||
|
|||||||
6
TODO.org
6
TODO.org
@ -12,8 +12,8 @@ rejected without a record is an idea that gets re-proposed.
|
|||||||
* Language surface
|
* Language surface
|
||||||
|
|
||||||
** NEXT str and String
|
** NEXT str and String
|
||||||
Decided 2026-09-25: the typed read-only text is =str= (renamed from =string=); =String=
|
Decided 2026-09-25: the typed read-only text is =str= (the rename from =string= is
|
||||||
is new, owned, growable, always valid UTF-8, through an allocator. The prelude's text
|
done; =string= is refused with the fix); =String= is new, owned, growable, always valid UTF-8, through an allocator. The prelude's text
|
||||||
builders return =String=; =(Vec u8)= stays for raw bytes. Text is UTF-8 everywhere and
|
builders return =String=; =(Vec u8)= stays for raw bytes. Text is UTF-8 everywhere and
|
||||||
a character is a code point; dyn gets a character tag, so \\I prints as \\I.
|
a character is a code point; dyn gets a character tag, so \\I prints as \\I.
|
||||||
Dyn text stays immutable, with chars and text converting to and from a dyn
|
Dyn text stays immutable, with chars and text converting to and from a dyn
|
||||||
@ -2076,7 +2076,7 @@ an unannotated two-name parameter vector compiles as two dyn parameters, and a
|
|||||||
=defn= named after a builtin stopped being unreachable.
|
=defn= named after a builtin stopped being unreachable.
|
||||||
|
|
||||||
** WAIT Every diagnostic carries a stable kind at the end of its first line
|
** WAIT Every diagnostic carries a stable kind at the end of its first line
|
||||||
Decided 2026-09-25: wanted, in the shape =... found string [type-mismatch]=. Waits
|
Decided 2026-09-25: wanted, in the shape =... found str [type-mismatch]=. Waits
|
||||||
for the documentation rewrite, which is what a kind would link to. The clause
|
for the documentation rewrite, which is what a kind would link to. The clause
|
||||||
order — understood, then the conflict, then the fix — is a rule in =CLAUDE.md=,
|
order — understood, then the conflict, then the fix — is a rule in =CLAUDE.md=,
|
||||||
and reporting every error in a form is its own entry under the Editor heading.
|
and reporting every error in a form is its own entry under the Editor heading.
|
||||||
|
|||||||
@ -118,7 +118,7 @@
|
|||||||
;; print and println are compiler-provided and structural: the walk over the
|
;; print and println are compiler-provided and structural: the walk over the
|
||||||
;; argument's concrete type happens at compile time, so there is nothing to
|
;; argument's concrete type happens at compile time, so there is nothing to
|
||||||
;; dispatch on at run time and no type to name at the call site.
|
;; dispatch on at run time and no type to name at the call site.
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(if (< (length args) 2)
|
(if (< (length args) 2)
|
||||||
(do (println "usage: calc-me \"1 + 2 * 3\"") 1)
|
(do (println "usage: calc-me \"1 + 2 * 3\"") 1)
|
||||||
(match (evaluate (bytes-view (at args 1)))
|
(match (evaluate (bytes-view (at args 1)))
|
||||||
|
|||||||
@ -676,8 +676,8 @@ exercised by running `sand.flan` and looking, which is the whole of what can be
|
|||||||
|
|
||||||
### A string returned from C is copied into the context allocator
|
### A string returned from C is copied into the context allocator
|
||||||
|
|
||||||
A `declare-c` may return `string`. The C wrapper answers the pointer and its length, and the generated Flan wrapper is
|
A `declare-c` may return `str`. The C wrapper answers the pointer and its length, and the generated Flan wrapper is
|
||||||
`(string (bytes (string (slice-from-ptr p n))))`: a view of C's bytes, copied by `bytes` into the context allocator. The
|
`(str (bytes (str (slice-from-ptr p n))))`: a view of C's bytes, copied by `bytes` into the context allocator. The
|
||||||
copy is Flan's rather than C's so that it goes through the same allocation guard (`StorageExhausted` with `retry`) and
|
copy is Flan's rather than C's so that it goes through the same allocation guard (`StorageExhausted` with `retry`) and
|
||||||
the same registry note every other allocation does, and `with-allocator` picks where it lands. The string lives until
|
the same registry note every other allocation does, and `with-allocator` picks where it lands. The string lives until
|
||||||
that allocator's `free-all` or destroy, which is the lifetime `(bytes s)` already has; a caller calling one every frame
|
that allocator's `free-all` or destroy, which is the lifetime `(bytes s)` already has; a caller calling one every frame
|
||||||
@ -689,7 +689,7 @@ in that case the wrapper first moves the text into one scratch buffer the shim o
|
|||||||
there. Without a string argument the pointer is the library's own and nothing is moved twice. A null is the empty
|
there. Without a string argument the pointer is the library's own and nothing is moved twice. A null is the empty
|
||||||
string.
|
string.
|
||||||
|
|
||||||
The importer follows `const`. `const char *` returned is text the caller only reads, so it becomes `string`; `char *`
|
The importer follows `const`. `const char *` returned is text the caller only reads, so it becomes `str`; `char *`
|
||||||
without `const` is text the caller owns and releases through the library (`LoadFileText` and `UnloadFileText`), and a
|
without `const` is text the caller owns and releases through the library (`LoadFileText` and `UnloadFileText`), and a
|
||||||
copy would leave the original with nothing to release it through, so that one stays refused and a hand-written
|
copy would leave the original with nothing to release it through, so that one stays refused and a hand-written
|
||||||
`declare-c` saying `(Ptr u8)` binds it. `TextFormat` stays unbound because it is variadic. Eighteen raylib functions came
|
`declare-c` saying `(Ptr u8)` binds it. `TextFormat` stays unbound because it is variadic. Eighteen raylib functions came
|
||||||
@ -711,7 +711,7 @@ over a mesh built in Flan and a model translated by its `transform`.
|
|||||||
|
|
||||||
`FilePathList` is a `char **` raylib owns until the matching `Unload`. It crosses by the returned-string rule:
|
`FilePathList` is a `char **` raylib owns until the matching `Unload`. It crosses by the returned-string rule:
|
||||||
`dropped-files`, `directory-files` and `directory-files-ex` copy each path into the context allocator, release raylib's
|
`dropped-files`, `directory-files` and `directory-files-ex` copy each path into the context allocator, release raylib's
|
||||||
list before returning, and answer a `(Vec string)`. There is nothing of raylib's left for the caller to unload, which is
|
list before returning, and answer a `(Vec str)`. There is nothing of raylib's left for the caller to unload, which is
|
||||||
why they are not named `load-`.
|
why they are not named `load-`.
|
||||||
|
|
||||||
### rlgl is its own package
|
### rlgl is its own package
|
||||||
@ -1167,7 +1167,7 @@ i8..i64 / u8..u64 i8..i64 signedness lives in the ops
|
|||||||
f32 f64 float double
|
f32 f64 float double
|
||||||
bool i1
|
bool i1
|
||||||
an enum i32
|
an enum i32
|
||||||
[T] and string { ptr, i64 } ptr+len, non-owning
|
[T] and str { ptr, i64 } ptr+len, non-owning
|
||||||
[n T] [n x T] inline, a value
|
[n T] [n x T] inline, a value
|
||||||
(Ptr T) ptr opaque pointers
|
(Ptr T) ptr opaque pointers
|
||||||
(Option T) { i8, T } tag 0 None, 1 Some
|
(Option T) { i8, T } tag 0 None, 1 Some
|
||||||
@ -2962,7 +2962,7 @@ as the shape of the whole feature: the answer is a Flan expression, and there is
|
|||||||
program.
|
program.
|
||||||
|
|
||||||
**Lookup stayed by name, and the signature is checked against what it found.** `flan_find_restart` matches the name
|
**Lookup stayed by name, and the signature is checked against what it found.** `flan_find_restart` matches the name
|
||||||
hash and nothing else, so an inner `(use-value [s string] ...)` shadows an outer `(use-value [v i32] ...)` and an i32
|
hash and nothing else, so an inner `(use-value [s str] ...)` shadows an outer `(use-value [v i32] ...)` and an i32
|
||||||
is refused there — the outer frame that would have taken it is never consulted. That is §4 read straight ("the first
|
is refused there — the outer frame that would have taken it is never consulted. That is §4 read straight ("the first
|
||||||
frame offering the name") and it is the thing a reader will assume works the other way, so `restarts.flan` has a case
|
frame offering the name") and it is the thing a reader will assume works the other way, so `restarts.flan` has a case
|
||||||
for it. Searching outward for a frame whose signature fits would make which restart runs depend on the arguments,
|
for it. Searching outward for a frame whose signature fits would make which restart runs depend on the arguments,
|
||||||
@ -3002,7 +3002,7 @@ function values and the work doubles.
|
|||||||
None of the four is anywhere near this. All four are about *surface syntax*, and a value the compiler builds that no
|
None of the four is anywhere near this. All four are about *surface syntax*, and a value the compiler builds that no
|
||||||
surface form names trips none of them:
|
surface form names trips none of them:
|
||||||
|
|
||||||
- `Allocator` is a `Types.t` case with no user-writable constructor, the way `string` is a builtin ptr+len. No Flan
|
- `Allocator` is a `Types.t` case with no user-writable constructor, the way `str` is a builtin ptr+len. No Flan
|
||||||
type names its procedure.
|
type names its procedure.
|
||||||
- The procedure is a C symbol the emitter names.
|
- The procedure is a C symbol the emitter names.
|
||||||
- `vec-new`, `push`, `free`, `free-all` and the rest are ordinary named calls, which `check_call` already routes
|
- `vec-new`, `push`, `free`, `free-all` and the rest are ordinary named calls, which `check_call` already routes
|
||||||
@ -3564,7 +3564,7 @@ the payload at offset 8, and 40/8 for a struct holding one.
|
|||||||
[Empty
|
[Empty
|
||||||
(Dot [x f64 y f64])
|
(Dot [x f64 y f64])
|
||||||
(Rect [w i32 h i32])
|
(Rect [w i32 h i32])
|
||||||
(Tag [name string n u8])])
|
(Tag [name str n u8])])
|
||||||
|
|
||||||
(Shape.Rect {.w 3 .h 3}) ; a value: the type and the case, then the fields
|
(Shape.Rect {.w 3 .h 3}) ; a value: the type and the case, then the fields
|
||||||
(Shape.Rect {.w 3}) ; ZII, exactly as in a struct literal — .h is 0
|
(Shape.Rect {.w 3}) ; ZII, exactly as in a struct literal — .h is 0
|
||||||
@ -3614,7 +3614,7 @@ is a layout change, the same way reordering a struct's fields is.
|
|||||||
- **`(.x u)`.** A union's fields belong to a case, and which case is being held is what the tag says. `match` is how
|
- **`(.x u)`.** A union's fields belong to a case, and which case is being held is what the tag says. `match` is how
|
||||||
one is opened, and its arms bind the fields of the case they matched.
|
one is opened, and its arms bind the fields of the case they matched.
|
||||||
- **A global initialised with a case.** `(defonce g U (U.B {.x 1}))` would mean serialising the fields into the payload
|
- **A global initialised with a case.** `(defonce g U (U.B {.x 1}))` would mean serialising the fields into the payload
|
||||||
blob at link time, which is a byte-level encoder this compiler does not have and which could not express a `string`
|
blob at link time, which is a byte-level encoder this compiler does not have and which could not express a `str`
|
||||||
field at all — that is a pointer the linker has to relocate and a byte array has nowhere to put a relocation. A
|
field at all — that is a pointer the linker has to relocate and a byte array has nowhere to put a relocation. A
|
||||||
*zeroed* global is fine and needs none of it: it is the first declared case.
|
*zeroed* global is fine and needs none of it: it is the first declared case.
|
||||||
|
|
||||||
@ -3771,7 +3771,7 @@ macro returns. That is the structural answer to "keep the source location of the
|
|||||||
produces", and it is what the queued structured-error work reads.
|
produces", and it is what the queued structured-error work reads.
|
||||||
|
|
||||||
Case order is tag order, so the list in the prelude is a layout contract and says so. The widest cases are
|
Case order is tag order, so the list in the prelude is a layout contract and says so. The widest cases are
|
||||||
`(Str [s string])` and `(List [xs [Form]])`; a string and a slice are both `%slice` = `{ptr, i64}`, 16 bytes at
|
`(Str [s str])` and `(List [xs [Form]])`; a string and a slice are both `%slice` = `{ptr, i64}`, 16 bytes at
|
||||||
align 8. So the image is `{ i32 tag, [2 x i64] payload }`: **24 bytes, align 8, payload at offset 8**, and every case
|
align 8. So the image is `{ i32 tag, [2 x i64] payload }`: **24 bytes, align 8, payload at offset 8**, and every case
|
||||||
holds its one member at the payload's start, so there is no third offset anywhere in the marshaller.
|
holds its one member at the payload's start, so there is no third offset anywhere in the marshaller.
|
||||||
|
|
||||||
@ -4310,8 +4310,8 @@ be wrong in a way worth being able to see: the prelude *was* reaching the expand
|
|||||||
|
|
||||||
The list at the foot of `prelude.ml` used to be one sentence — every entry needed to produce bytes that did not exist
|
The list at the foot of `prelude.ml` used to be one sentence — every entry needed to produce bytes that did not exist
|
||||||
in its input, and there was no allocator. `join`, `concat`, `split`, `to-lower`, `to-upper`, `repeat` and `replace`
|
in its input, and there was no allocator. `join`, `concat`, `split`, `to-lower`, `to-upper`, `repeat` and `replace`
|
||||||
have moved up into the code; `string-from-bytes` turned out to be the `string` builtin all along, and
|
have moved up into the code; `string-from-bytes` turned out to be the `str` builtin all along, and
|
||||||
`(string (slice v))` is the round trip, free precisely because the layouts are identical.
|
`(str (slice v))` is the round trip, free precisely because the layouts are identical.
|
||||||
|
|
||||||
What remains is refused for four different reasons, and is now written that way: `pad`/`center` for *nothing at all*
|
What remains is refused for four different reasons, and is now written that way: `pad`/`center` for *nothing at all*
|
||||||
except that no caller has asked; `format`/`sprintf` for variadics of mixed type; `map`/`filter`/`reduce`/`sort-by`
|
except that no caller has asked; `format`/`sprintf` for variadics of mixed type; `map`/`filter`/`reduce`/`sort-by`
|
||||||
@ -4879,7 +4879,7 @@ and the rule is easier to state and to trust with one construct in it.
|
|||||||
|
|
||||||
## Assets are baked in, and the reason it is a compiler feature
|
## Assets are baked in, and the reason it is a compiler feature
|
||||||
|
|
||||||
TODO.org, "Assets are embedded at compile time". `(embed "brush.png")` is a `[const u8]`, `(embed "brush.png" string)` is a `string`, and
|
TODO.org, "Assets are embedded at compile time". `(embed "brush.png")` is a `[const u8]`, `(embed "brush.png" str)` is a `str`, and
|
||||||
`(embed-dir "assets")` is a `[n EmbedFile]` sorted by name. Odin's `#load` and `#load_directory` are the model
|
`(embed-dir "assets")` is a `[n EmbedFile]` sorted by name. Odin's `#load` and `#load_directory` are the model
|
||||||
(`src/parser.cpp`, and `check_load_directive` / `check_load_directory_directive` in `src/check_builtin.cpp`); Odin's
|
(`src/parser.cpp`, and `check_load_directive` / `check_load_directory_directive` in `src/check_builtin.cpp`); Odin's
|
||||||
`#` is not imported, because an s-expression language already has a head position for a name and these resolve as
|
`#` is not imported, because an s-expression language already has a head position for a name and these resolve as
|
||||||
@ -4897,16 +4897,16 @@ into the same `private unnamed_addr constant` every string literal already becom
|
|||||||
across the whole 0–255 range, so a PNG survives the round trip through the `.ll`. Bound with `defconst` at top level an
|
across the whole 0–255 range, so a PNG survives the round trip through the `.ll`. Bound with `defconst` at top level an
|
||||||
`embed-dir` is an LLVM constant outright, through emit.ml's `const`.
|
`embed-dir` is an LLVM constant outright, through emit.ml's `const`.
|
||||||
|
|
||||||
**A `Str` node typed `[const u8]`, not a `Bytes` prim over a `string`.** This is the one non-obvious choice. `Bytes` is
|
**A `Str` node typed `[const u8]`, not a `Bytes` prim over a `str`.** This is the one non-obvious choice. `Bytes` is
|
||||||
identity — emit.ml lowers `Types.String` and `Types.Slice _` to the same `%slice` — but wrapping the literal in a prim
|
identity — emit.ml lowers `Types.String` and `Types.Slice _` to the same `%slice` — but wrapping the literal in a prim
|
||||||
makes the node non-constant, and `const` then refuses an `embed-dir` in a `defconst` with *a global's value must be a
|
makes the node non-constant, and `const` then refuses an `embed-dir` in a `defconst` with *a global's value must be a
|
||||||
compile-time constant*. Both of emit.ml's string emitters take the bytes and ignore the node's type, so it is the same
|
compile-time constant*. Both of emit.ml's string emitters take the bytes and ignore the node's type, so it is the same
|
||||||
constant either way and this one is a constant a global can hold.
|
constant either way and this one is a constant a global can hold.
|
||||||
|
|
||||||
**Two spellings, not one form that changes type with its context.** Odin threads a `type_hint` everywhere and can
|
**Two spellings, not one form that changes type with its context.** Odin threads a `type_hint` everywhere and can
|
||||||
afford `#load("p")` to mean a `string` here and a `[]u8` there. With structural equality and no conversion between one
|
afford `#load("p")` to mean a `str` here and a `[]u8` there. With structural equality and no conversion between one
|
||||||
container and another — implicit widening is numbers only — the same text meaning two types would be a wart, so
|
container and another — implicit widening is numbers only — the same text meaning two types would be a wart, so
|
||||||
`string` is written down when it is wanted. The
|
`str` is written down when it is wanted. The
|
||||||
site's expectation is a fallback only and nothing depends on it.
|
site's expectation is a fallback only and nothing depends on it.
|
||||||
|
|
||||||
**The path is a literal and resolves relative to the file the form is written in.** Both are Odin's rules and for
|
**The path is a literal and resolves relative to the file the form is written in.** Both are Odin's rules and for
|
||||||
@ -5702,7 +5702,7 @@ Measured on a 200-million-iteration loop at `-O2`: 0.53s with the call, 0.00s wi
|
|||||||
Four entry points a program can reach through `declare-c` write a scalar:
|
Four entry points a program can reach through `declare-c` write a scalar:
|
||||||
|
|
||||||
```flan
|
```flan
|
||||||
(declare-c watch-i64 [name string x i64] i32 "flan_dev_watch_i64")
|
(declare-c watch-i64 [name str x i64] i32 "flan_dev_watch_i64")
|
||||||
(watch-i64 "ticks" ticks)
|
(watch-i64 "ticks" ticks)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -7079,7 +7079,7 @@ expression the checker walks can live.
|
|||||||
### The rules it derives, and the one the game file decided
|
### The rules it derives, and the one the game file decided
|
||||||
|
|
||||||
A map with keyword keys is a struct, one field per key. An integer is `i64`, a float
|
A map with keyword keys is a struct, one field per key. An integer is `i64`, a float
|
||||||
`f64`, a boolean `bool`, a string `string` — *copied*, which is `read.flan`'s contract and
|
`f64`, a boolean `bool`, a string `str` — *copied*, which is `read.flan`'s contract and
|
||||||
not the tokenizer's: a `Token`'s text points into the buffer and a struct that outlives
|
not the tokenizer's: a `Token`'s text points into the buffer and a struct that outlives
|
||||||
the buffer cannot hold one. A vector of one repeated shape is `(Vec T)`. A nested map is a
|
the buffer cannot hold one. A vector of one repeated shape is `(Vec T)`. A nested map is a
|
||||||
struct named for the path that reaches it, `Tileset-selected-cells`, with a hyphen because
|
struct named for the path that reaches it, `Tileset-selected-cells`, with a hyphen because
|
||||||
@ -7403,7 +7403,7 @@ it: an assignment that *completed* before the signal stands, and rolling those b
|
|||||||
restart is not a transaction"). What no longer happens is a single assignment left halfway.
|
restart is not a transaction"). What no longer happens is a single assignment left halfway.
|
||||||
|
|
||||||
**A `def` whose type changed** is refused before anything is stored, by `Session.compatible`, which already said the
|
**A `def` whose type changed** is refused before anything is stored, by `Session.compatible`, which already said the
|
||||||
right sentence for this path: *`speed` changes type, from `i64` to `string`; the running program already laid that
|
right sentence for this path: *`speed` changes type, from `i64` to `str`; the running program already laid that
|
||||||
storage out. Restart to change it.*
|
storage out. Restart to change it.*
|
||||||
|
|
||||||
**`defonce` is untouched**, and that is its contract: `kind = Once` never reaches the store list, so re-evaluating one
|
**`defonce` is untouched**, and that is its contract: `kind = Once` never reaches the store list, so re-evaluating one
|
||||||
|
|||||||
@ -255,7 +255,7 @@ host does:
|
|||||||
1. Hold the state in a `let` in `main` and pass `(Ptr Game)` to update and draw. Costs
|
1. Hold the state in a `let` in `main` and pass `(Ptr Game)` to update and draw. Costs
|
||||||
one parameter on three functions.
|
one parameter on three functions.
|
||||||
2. For the texture cache specifically, a `[8 CacheEntry]` fixed array with a count beats a
|
2. For the texture cache specifically, a `[8 CacheEntry]` fixed array with a count beats a
|
||||||
`(Map string Texture2D)` outright — the game loads five textures, and a linear scan of
|
`(Map str Texture2D)` outright — the game loads five textures, and a linear scan of
|
||||||
five path comparisons at load time is not worth a hash table. This is a case where the
|
five path comparisons at load time is not worth a hash table. This is a case where the
|
||||||
restriction pushes toward the right answer.
|
restriction pushes toward the right answer.
|
||||||
|
|
||||||
@ -692,7 +692,7 @@ each finding in §A names the command that produced the failure.
|
|||||||
> differences it accepted. `vendor/raylib/raylib.flan` carries
|
> differences it accepted. `vendor/raylib/raylib.flan` carries
|
||||||
> `get-codepoint-previous-raw` — the exact declaration this section says it wanted — and
|
> `get-codepoint-previous-raw` — the exact declaration this section says it wanted — and
|
||||||
> a `get-codepoint-previous` wrapper over it that takes the bytes and an offset;
|
> a `get-codepoint-previous` wrapper over it that takes the bytes and an offset;
|
||||||
> `generated.flan` no longer carries the `string`-faced version at all, because a binding
|
> `generated.flan` no longer carries the `str`-faced version at all, because a binding
|
||||||
> that is wrong for the only direction it reads in is worse than no binding. The example's
|
> that is wrong for the only direction it reads in is worse than no binding. The example's
|
||||||
> `step-back` is one call to it, the continuation-byte walk is gone, and the expression
|
> `step-back` is one call to it, the continuation-byte walk is gone, and the expression
|
||||||
> below now prints 12356 and 3. The section is kept as written; the reasoning is the part
|
> below now prints 12356 and 3. The section is kept as written; the reasoning is the part
|
||||||
@ -700,7 +700,7 @@ each finding in §A names the command that produced the failure.
|
|||||||
|
|
||||||
|
|
||||||
This is the real find of the round, and it is general: **a C function that reads
|
This is the real find of the round, and it is general: **a C function that reads
|
||||||
*backwards* from the pointer it is handed cannot be given a Flan `string`.**
|
*backwards* from the pointer it is handed cannot be given a Flan `str`.**
|
||||||
|
|
||||||
`lib/shim.ml` is explicit about why — `Pstr` is "ptr+len in, a NUL-terminated copy out",
|
`lib/shim.ml` is explicit about why — `Pstr` is "ptr+len in, a NUL-terminated copy out",
|
||||||
and the wrapper builds that copy for the duration of the call. Forwards, that is invisible
|
and the wrapper builds that copy for the duration of the call. Forwards, that is invisible
|
||||||
@ -714,7 +714,7 @@ It does not crash, which is the bad part. Run headless:
|
|||||||
(let [text "いろはに"
|
(let [text "いろはに"
|
||||||
b (bytes text)
|
b (bytes text)
|
||||||
sz 0]
|
sz 0]
|
||||||
(println (rl/get-codepoint-previous (string (slice b 3 (length b))) (addr sz)))
|
(println (rl/get-codepoint-previous (str (slice b 3 (length b))) (addr sz)))
|
||||||
(println sz))
|
(println sz))
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -735,15 +735,15 @@ and means it, as `load-image-from-memory-raw` and `load-font-ex-raw` do:
|
|||||||
```
|
```
|
||||||
|
|
||||||
with `(addr (at b i))` for the interior pointer. It does not work, and the reason is not
|
with `(addr (at b i))` for the interior pointer. It does not work, and the reason is not
|
||||||
the FFI. `lib/cimport.ml` maps `const char *` to `string`, and `agrees` — the function that
|
the FFI. `lib/cimport.ml` maps `const char *` to `str`, and `agrees` — the function that
|
||||||
decides whether a hand-written declaration and the header say the same thing — accepts
|
decides whether a hand-written declaration and the header say the same thing — accepts
|
||||||
exactly one difference, an enum against a 32-bit integer. `(Ptr u8)` against `string` is not
|
exactly one difference, an enum against a 32-bit integer. `(Ptr u8)` against `str` is not
|
||||||
it. Adding the line above and building *anything*, not only regenerating, gives:
|
it. Adding the line above and building *anything*, not only regenerating, gives:
|
||||||
|
|
||||||
```
|
```
|
||||||
vendor/raylib/generated.flan:233:12: the declare-c of get-codepoint-previous-raw
|
vendor/raylib/generated.flan:233:12: the declare-c of get-codepoint-previous-raw
|
||||||
disagrees with vendor/raylib/raylib-5.5.h: parameter text is (Ptr u8) and the
|
disagrees with vendor/raylib/raylib-5.5.h: parameter text is (Ptr u8) and the
|
||||||
header says string (const char *)
|
header says str (const char *)
|
||||||
```
|
```
|
||||||
|
|
||||||
`headers` is read on every build, so the binding cannot be added without relaxing the
|
`headers` is read on every build, so the binding cannot be added without relaxing the
|
||||||
@ -823,12 +823,12 @@ something with a length, and it was reached for three times across the two files
|
|||||||
open question and the answer is clean. The reader takes the bytes, the object file carries
|
open question and the answer is clean. The reader takes the bytes, the object file carries
|
||||||
them, the shim hands them over, and `LoadCodepoints` decodes the 54 codepoints of the Iroha
|
them, the shim hands them over, and `LoadCodepoints` decodes the 54 codepoints of the Iroha
|
||||||
into the 49 distinct ones the atlas is built from. Nothing in Flan claims to know what a
|
into the 49 distinct ones the atlas is built from. Nothing in Flan claims to know what a
|
||||||
character is — a `string` is bytes and `(bytes s)` / `(string b)` say so in both directions
|
character is — a `str` is bytes and `(bytes s)` / `(str b)` say so in both directions
|
||||||
at no cost — and for this job that is exactly the right amount of opinion. There is a
|
at no cost — and for this job that is exactly the right amount of opinion. There is a
|
||||||
`valid-utf8?` in the prelude and this example never needs it.
|
`valid-utf8?` in the prelude and this example never needs it.
|
||||||
|
|
||||||
**An interior pointer into a string has an idiom already.** `(string (slice b off (length b)))`
|
**An interior pointer into a string has an idiom already.** `(str (slice b off (length b)))`
|
||||||
is the C's `char *ptr` and compiles to nothing: a `string` and a `[u8]` are the same two
|
is the C's `char *ptr` and compiles to nothing: a `str` and a `[u8]` are the same two
|
||||||
words. Every forward-reading `const char *` entry point is reachable that way.
|
words. Every forward-reading `const char *` entry point is reachable that way.
|
||||||
|
|
||||||
**`load-font-ex` needed nothing.** It takes a `[i32]` of codepoints, takes the
|
**`load-font-ex` needed nothing.** It takes a `[i32]` of codepoints, takes the
|
||||||
@ -852,7 +852,7 @@ example.
|
|||||||
> test rather than a raylib example, and there is not one.
|
> test rather than a raylib example, and there is not one.
|
||||||
|
|
||||||
**Fixed arrays were the right shape for both.** A codepoint table with a count, a
|
**Fixed arrays were the right shape for both.** A codepoint table with a count, a
|
||||||
`[9 Rectangle]` of toggle buttons, a `[9 string]` of labels. The §3 finding from the
|
`[9 Rectangle]` of toggle buttons, a `[9 str]` of labels. The §3 finding from the
|
||||||
siam-farmer report — a global cannot hold a `Vec`, and fixed arrays with counts are usually
|
siam-farmer report — a global cannot hold a `Vec`, and fixed arrays with counts are usually
|
||||||
the better answer anyway — held again, in two more programs, with no friction at all.
|
the better answer anyway — held again, in two more programs, with no friction at all.
|
||||||
|
|
||||||
|
|||||||
@ -429,7 +429,7 @@ frames that have no file.
|
|||||||
know which restart you want and do not need the buffer.
|
know which restart you want and do not need the buffer.
|
||||||
|
|
||||||
**The condition's fields are named and typed, and have no values.** Under the
|
**The condition's fields are named and typed, and have no values.** Under the
|
||||||
condition you get the struct it is — `:path string`, `:tried i32` — because the
|
condition you get the struct it is — `:path str`, `:tried i32` — because the
|
||||||
daemon compiled the program and knows what that type looks like without asking
|
daemon compiled the program and knows what that type looks like without asking
|
||||||
the program anything. What is beside each field is a note saying the value is
|
the program anything. What is beside each field is a note saying the value is
|
||||||
not available, not a blank: a value lives in the stopped frame, and nothing yet
|
not available, not a blank: a value lives in the stopped frame, and nothing yet
|
||||||
@ -551,7 +551,7 @@ answers a different question — it answers what the **next** run does.
|
|||||||
now, and what you type is a Flan **expression**, evaluated in the program and
|
now, and what you type is a Flan **expression**, evaluated in the program and
|
||||||
checked against the type of the place it is going into. `(+ 1 2)`, a string
|
checked against the type of the place it is going into. `(+ 1 2)`, a string
|
||||||
literal, a whole struct literal all work; one that does not fit comes back with
|
literal, a whole struct literal all work; one that does not fit comes back with
|
||||||
the checker's own sentence — *expected f32, found string* — and nothing is
|
the checker's own sentence — *expected f32, found str* — and nothing is
|
||||||
stored. A literal arrives at the place's width, so `3` into an `f32` field is
|
stored. A literal arrives at the place's width, so `3` into an `f32` field is
|
||||||
three point oh and not a refusal you would have had to write `3.0` to avoid.
|
three point oh and not a refusal you would have had to write `3.0` to avoid.
|
||||||
Point on no field line at all sets the whole value, which is how a data type's
|
Point on no field line at all sets the whole value, which is how a data type's
|
||||||
@ -772,8 +772,8 @@ last. These two are the other half. A slot keeps **count, min, max, last and
|
|||||||
mean**, and the buffer renders them as one line:
|
mean**, and the buffer renders them as one line:
|
||||||
|
|
||||||
```flan
|
```flan
|
||||||
(declare-c watch-num-i64 [name string x i64] i32 "flan_dev_watch_num_i64")
|
(declare-c watch-num-i64 [name str x i64] i32 "flan_dev_watch_num_i64")
|
||||||
(declare-c watch-num-f64 [name string x f64] i32 "flan_dev_watch_num_f64")
|
(declare-c watch-num-f64 [name str x f64] i32 "flan_dev_watch_num_f64")
|
||||||
|
|
||||||
(watch-num-i64 "cell" (at grid i))
|
(watch-num-i64 "cell" (at grid i))
|
||||||
```
|
```
|
||||||
@ -795,9 +795,9 @@ table is also reachable as plain C functions, one per scalar type, which a
|
|||||||
program declares like any other:
|
program declares like any other:
|
||||||
|
|
||||||
```flan
|
```flan
|
||||||
(declare-c watch-i64 [name string x i64] i32 "flan_dev_watch_i64")
|
(declare-c watch-i64 [name str x i64] i32 "flan_dev_watch_i64")
|
||||||
(declare-c watch-f64 [name string x f64] i32 "flan_dev_watch_f64")
|
(declare-c watch-f64 [name str x f64] i32 "flan_dev_watch_f64")
|
||||||
(declare-c watch-str [name string s string] i32 "flan_dev_watch_str")
|
(declare-c watch-str [name str s str] i32 "flan_dev_watch_str")
|
||||||
```
|
```
|
||||||
|
|
||||||
Each returns 1 if the value was written and 0 if nobody is watching or the
|
Each returns 1 if the value was written and 0 if nobody is watching or the
|
||||||
|
|||||||
@ -717,7 +717,7 @@ visits the source of the one it lands on."
|
|||||||
|
|
||||||
(defun flan-cnr-param-types (params)
|
(defun flan-cnr-param-types (params)
|
||||||
"The types in PARAMS, a restart's parameters as the program spells them.
|
"The types in PARAMS, a restart's parameters as the program spells them.
|
||||||
PARAMS is a parenthesised list such as \"(i64 (Option string))\"; the result
|
PARAMS is a parenthesised list such as \"(i64 (Option str))\"; the result
|
||||||
is one string per type, or nil when it takes none or cannot be read."
|
is one string per type, or nil when it takes none or cannot be read."
|
||||||
(let ((form (and (stringp params)
|
(let ((form (and (stringp params)
|
||||||
(condition-case nil (car (read-from-string params))
|
(condition-case nil (car (read-from-string params))
|
||||||
|
|||||||
@ -1647,7 +1647,7 @@ lambda or a `Fn(...)' type, and not after a match arm's."
|
|||||||
(flan-fln--return-type-matcher 1 font-lock-type-face)
|
(flan-fln--return-type-matcher 1 font-lock-type-face)
|
||||||
;; The package half of a qualified name, as `flan-mode' draws it.
|
;; The package half of a qualified name, as `flan-mode' draws it.
|
||||||
("\\_<\\([a-zA-Z][a-zA-Z0-9!?*+=<>._-]*/\\)" 1 font-lock-type-face)
|
("\\_<\\([a-zA-Z][a-zA-Z0-9!?*+=<>._-]*/\\)" 1 font-lock-type-face)
|
||||||
("\\_<\\(?:[iu]\\(?:8\\|16\\|32\\|64\\)\\|f\\(?:32\\|64\\)\\|bool\\|string\\|dyn\\|Never\\|Allocator\\|Ptr\\|Option\\|Vec\\|Map\\|C?Fn\\)\\_>"
|
("\\_<\\(?:[iu]\\(?:8\\|16\\|32\\|64\\)\\|f\\(?:32\\|64\\)\\|bool\\|str\\|dyn\\|Never\\|Allocator\\|Ptr\\|Option\\|Vec\\|Map\\|C?Fn\\)\\_>"
|
||||||
. font-lock-type-face)
|
. font-lock-type-face)
|
||||||
("\\_<\\$[^][ \t\n(){},;\":]*" . font-lock-type-face)
|
("\\_<\\$[^][ \t\n(){},;\":]*" . font-lock-type-face)
|
||||||
;; A character literal, `\c' or `\space'.
|
;; A character literal, `\c' or `\space'.
|
||||||
|
|||||||
@ -175,15 +175,15 @@ face says.")
|
|||||||
;; containers and memory
|
;; containers and memory
|
||||||
"length" "at" "slice" "slice-from" "addr" "deref"
|
"length" "at" "slice" "slice-from" "addr" "deref"
|
||||||
;; options, bytes, the host
|
;; options, bytes, the host
|
||||||
"Some" "bytes" "bytes-view" "string"
|
"Some" "bytes" "bytes-view" "str"
|
||||||
"bytes->f64" "bytes->i64" "f64->bytes" "i64->bytes"
|
"bytes->f64" "bytes->i64" "f64->bytes" "i64->bytes"
|
||||||
"write-stdout" "print" "println" "exit" "argv")
|
"write-stdout" "print" "println" "exit" "argv")
|
||||||
"The functions the compiler provides, from `lib/check.ml''s `builtins' table.
|
"The functions the compiler provides, from `lib/check.ml''s `builtins' table.
|
||||||
|
|
||||||
Ordinary calls — nothing here is special to the parser — so they are drawn as
|
Ordinary calls — nothing here is special to the parser — so they are drawn as
|
||||||
builtins and not as keywords. `string' is in this list and in the type rule
|
builtins and not as keywords. `str' is in this list and in the type rule
|
||||||
below and means a different thing in each: `(string b)' converts and a bare
|
below and means a different thing in each: `(str b)' converts and a bare
|
||||||
`string' names a type, which the rules tell apart by the paren.
|
`str' names a type, which the rules tell apart by the paren.
|
||||||
|
|
||||||
`destructure~nth' is in the table and not here: the compiler writes it into a
|
`destructure~nth' is in the table and not here: the compiler writes it into a
|
||||||
destructuring `let' and nobody types it.
|
destructuring `let' and nobody types it.
|
||||||
@ -253,7 +253,7 @@ reason and is the odd one — it is legal only as the last item of a `def' or a
|
|||||||
;; word outright — unit is spelled `()'. Drawing it as a valid type would
|
;; word outright — unit is spelled `()'. Drawing it as a valid type would
|
||||||
;; advertise a spelling the parser rejects, which is the same reason
|
;; advertise a spelling the parser rejects, which is the same reason
|
||||||
;; `find-restart' and `await' are left out of `flan--special'.
|
;; `find-restart' and `await' are left out of `flan--special'.
|
||||||
("\\_<\\(?:[iu]\\(?:8\\|16\\|32\\|64\\)\\|f\\(?:32\\|64\\)\\|bool\\|string\\|dyn\\|const\\|int\\|float\\|Never\\|Allocator\\|Ptr\\|Option\\|Vec\\|Map\\|C?Fn\\)\\_>"
|
("\\_<\\(?:[iu]\\(?:8\\|16\\|32\\|64\\)\\|f\\(?:32\\|64\\)\\|bool\\|str\\|dyn\\|const\\|int\\|float\\|Never\\|Allocator\\|Ptr\\|Option\\|Vec\\|Map\\|C?Fn\\)\\_>"
|
||||||
. font-lock-type-face)
|
. font-lock-type-face)
|
||||||
;; A type variable, `$t', which is what a generic `defn' names its
|
;; A type variable, `$t', which is what a generic `defn' names its
|
||||||
;; parameter types with and what `{:where (ordered? $t)}' constrains.
|
;; parameter types with and what `{:where (ordered? $t)}' constrains.
|
||||||
|
|||||||
@ -1093,7 +1093,7 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
:at "/src/files.flan:12:3" :arity 0 :params "()")
|
:at "/src/files.flan:12:3" :arity 0 :params "()")
|
||||||
(:report "Try again with another path"
|
(:report "Try again with another path"
|
||||||
:at "/src/files.flan:12:3" :arity 1
|
:at "/src/files.flan:12:3" :arity 1
|
||||||
:params "(string)")
|
:params "(str)")
|
||||||
(:report "" :at nil :arity 0 :params "()")))))
|
(:report "" :at nil :arity 0 :params "()")))))
|
||||||
(text (with-current-buffer buf (buffer-string))))
|
(text (with-current-buffer buf (buffer-string))))
|
||||||
(test-flan--check "a restart's report is beside its name"
|
(test-flan--check "a restart's report is beside its name"
|
||||||
@ -1101,7 +1101,7 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
(test-flan--check "and where its clause is written"
|
(test-flan--check "and where its clause is written"
|
||||||
(string-match-p "again (/src/files.flan:12:3)" text))
|
(string-match-p "again (/src/files.flan:12:3)" text))
|
||||||
(test-flan--check "a restart taking values shows their types"
|
(test-flan--check "a restart taking values shows their types"
|
||||||
(string-match-p "\\[use-value\\] +(string) Try again with another path"
|
(string-match-p "\\[use-value\\] +(str) Try again with another path"
|
||||||
text))
|
text))
|
||||||
(test-flan--check "one with no report and no source shows its name alone"
|
(test-flan--check "one with no report and no source shows its name alone"
|
||||||
(string-match-p " 2: \\[plain\\] *\n" text))
|
(string-match-p " 2: \\[plain\\] *\n" text))
|
||||||
@ -1117,8 +1117,8 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
|
|
||||||
;; A restart that takes values asks for one per parameter and sends them.
|
;; A restart that takes values asks for one per parameter and sends them.
|
||||||
(test-flan--check "a restart's parameter types are read from their spelling"
|
(test-flan--check "a restart's parameter types are read from their spelling"
|
||||||
(equal (flan-cnr-param-types "(i64 (Option string))")
|
(equal (flan-cnr-param-types "(i64 (Option str))")
|
||||||
'("i64" "(Option string)")))
|
'("i64" "(Option str)")))
|
||||||
(let ((sent nil) (asked nil))
|
(let ((sent nil) (asked nil))
|
||||||
(let ((flan-cnr-request-function
|
(let ((flan-cnr-request-function
|
||||||
(lambda (form) (setq sent form) (list :status "ok" :note "accepted"))))
|
(lambda (form) (setq sent form) (list :status "ok" :note "accepted"))))
|
||||||
@ -1613,12 +1613,12 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
;; blame is even a field of this condition.
|
;; blame is even a field of this condition.
|
||||||
(let ((text (with-current-buffer
|
(let ((text (with-current-buffer
|
||||||
(test-flan--cnr (list :condition "Missing" :restarts '("retry")
|
(test-flan--cnr (list :condition "Missing" :restarts '("retry")
|
||||||
:fields '(("path" "string" nil)
|
:fields '(("path" "str" nil)
|
||||||
("tried" "i32" "3"))
|
("tried" "i32" "3"))
|
||||||
:fields-why "the stop's value was not readable"))
|
:fields-why "the stop's value was not readable"))
|
||||||
(buffer-string))))
|
(buffer-string))))
|
||||||
(test-flan--check "a field is named and typed even with no value"
|
(test-flan--check "a field is named and typed even with no value"
|
||||||
(string-match-p ":path *string *not read" text))
|
(string-match-p ":path *str *not read" text))
|
||||||
(test-flan--check "and the reason is one sentence, said once above the rows"
|
(test-flan--check "and the reason is one sentence, said once above the rows"
|
||||||
(and (string-match-p "not read — the stop's value" text)
|
(and (string-match-p "not read — the stop's value" text)
|
||||||
(= 1 (seq-count
|
(= 1 (seq-count
|
||||||
@ -1696,7 +1696,7 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
(let ((text (with-current-buffer
|
(let ((text (with-current-buffer
|
||||||
(test-flan--cnr
|
(test-flan--cnr
|
||||||
(list :condition "Missing" :restarts '("retry" "a" "retry")
|
(list :condition "Missing" :restarts '("retry" "a" "retry")
|
||||||
:fields '(("path" "string" nil))
|
:fields '(("path" "str" nil))
|
||||||
:stack (list (list :fn "f" :fetched t :locals nil))))
|
:stack (list (list :fn "f" :fetched t :locals nil))))
|
||||||
(buffer-string))))
|
(buffer-string))))
|
||||||
(test-flan--check "no bracketed implementation note leaks into the buffer"
|
(test-flan--check "no bracketed implementation note leaks into the buffer"
|
||||||
@ -1731,7 +1731,7 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
("break" '(:status "ok" :stopped t :condition "sim/Missing"
|
("break" '(:status "ok" :stopped t :condition "sim/Missing"
|
||||||
:restarts ("retry")))
|
:restarts ("retry")))
|
||||||
("layout" '(:status "ok" :type "sim/Missing"
|
("layout" '(:status "ok" :type "sim/Missing"
|
||||||
:fields (("path" "string") ("tried" "i32"))))))))
|
:fields (("path" "str") ("tried" "i32"))))))))
|
||||||
(let ((text (with-current-buffer (save-window-excursion (flan-cnr-show))
|
(let ((text (with-current-buffer (save-window-excursion (flan-cnr-show))
|
||||||
(buffer-string))))
|
(buffer-string))))
|
||||||
(test-flan--check "the condition's name is what `layout' is asked for"
|
(test-flan--check "the condition's name is what `layout' is asked for"
|
||||||
@ -1747,7 +1747,7 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
:type)
|
:type)
|
||||||
"sim/Missing"))
|
"sim/Missing"))
|
||||||
(test-flan--check "the fields are drawn, named and typed"
|
(test-flan--check "the fields are drawn, named and typed"
|
||||||
(string-match-p ":path *string" text))
|
(string-match-p ":path *str\\_>" text))
|
||||||
;; Shape and contents are two different questions, and this stub's
|
;; Shape and contents are two different questions, and this stub's
|
||||||
;; daemon answers only the first — so the values fall back to the
|
;; daemon answers only the first — so the values fall back to the
|
||||||
;; layout, each row saying in one sentence why it is empty.
|
;; layout, each row saying in one sentence why it is empty.
|
||||||
@ -1783,7 +1783,7 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
;; that touches each one.
|
;; that touches each one.
|
||||||
:globals '(("grid" "[4 i32]" "[7 5 0 0]" (0 1))
|
:globals '(("grid" "[4 i32]" "[7 5 0 0]" (0 1))
|
||||||
("pressure" "i64" "12" (0))
|
("pressure" "i64" "12" (0))
|
||||||
("label" "string" "\"running\"" (1)))))
|
("label" "str" "\"running\"" (1)))))
|
||||||
(buf (test-flan--cnr state))
|
(buf (test-flan--cnr state))
|
||||||
(text (with-current-buffer buf (buffer-string))))
|
(text (with-current-buffer buf (buffer-string))))
|
||||||
(test-flan--check "a global is named, typed and valued"
|
(test-flan--check "a global is named, typed and valued"
|
||||||
@ -1825,7 +1825,7 @@ would be overwritten. Look again and re-do the edit")
|
|||||||
(test-flan--cnr
|
(test-flan--cnr
|
||||||
(list :condition "Boom" :restarts '("retry")
|
(list :condition "Boom" :restarts '("retry")
|
||||||
:stack (list (list :fn "f"))
|
:stack (list (list :fn "f"))
|
||||||
:globals '(("label" "string" "\"x\"" (1)))
|
:globals '(("label" "str" "\"x\"" (1)))
|
||||||
:globals-refused '(("weird" "no printer for (Map i64 i64)"))
|
:globals-refused '(("weird" "no printer for (Map i64 i64)"))
|
||||||
:globals-skipped
|
:globals-skipped
|
||||||
'(("0: sim/inner" "this frame's body was redefined since it was entered"))))
|
'(("0: sim/inner" "this frame's body was redefined since it was entered"))))
|
||||||
|
|||||||
@ -111,13 +111,13 @@
|
|||||||
;; there.
|
;; there.
|
||||||
(test-flan-mode--check
|
(test-flan-mode--check
|
||||||
"a defn with a return type indents its body by two"
|
"a defn with a return type indents its body by two"
|
||||||
"(defn look [n i64 label string] i64
|
"(defn look [n i64 label str] i64
|
||||||
(print label)
|
(print label)
|
||||||
n)")
|
n)")
|
||||||
|
|
||||||
(test-flan-mode--check
|
(test-flan-mode--check
|
||||||
"and a defn without one indents it the same"
|
"and a defn without one indents it the same"
|
||||||
"(defn show-trim [s string] ()
|
"(defn show-trim [s str] ()
|
||||||
(print s)
|
(print s)
|
||||||
(println \"\"))")
|
(println \"\"))")
|
||||||
|
|
||||||
|
|||||||
@ -67,7 +67,7 @@
|
|||||||
(defconst gesture-log-size 20)
|
(defconst gesture-log-size 20)
|
||||||
(defconst max-touch-count 32)
|
(defconst max-touch-count 32)
|
||||||
|
|
||||||
(defonce gesture-log [gesture-log-size string])
|
(defonce gesture-log [gesture-log-size str])
|
||||||
;; The C's inverted circular queue: the index counts DOWN and wraps at the top,
|
;; The C's inverted circular queue: the index counts DOWN and wraps at the top,
|
||||||
;; so the newest entry is always at gesture-log-index and the draw loop walks
|
;; so the newest entry is always at gesture-log-index and the draw loop walks
|
||||||
;; forward from there. Starting at the size rather than at size-1 is the C's
|
;; forward from there. Starting at the size rather than at size-1 is the C's
|
||||||
@ -103,7 +103,7 @@
|
|||||||
;; belongs under a :gesture-none guard. The C's switch over single members
|
;; belongs under a :gesture-none guard. The C's switch over single members
|
||||||
;; hides both; a range test cannot.
|
;; hides both; a range test cannot.
|
||||||
|
|
||||||
(defn gesture-name [g rl/Gesture] string
|
(defn gesture-name [g rl/Gesture] str
|
||||||
(cond
|
(cond
|
||||||
(= g :gesture-none) "None"
|
(= g :gesture-none) "None"
|
||||||
(= g :gesture-tap) "Tap"
|
(= g :gesture-tap) "Tap"
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
(defconst max-gesture-strings 20)
|
(defconst max-gesture-strings 20)
|
||||||
|
|
||||||
(defonce gesture-log [max-gesture-strings string])
|
(defonce gesture-log [max-gesture-strings str])
|
||||||
(defonce gestures-count i32)
|
(defonce gestures-count i32)
|
||||||
(defonce current-gesture rl/Gesture)
|
(defonce current-gesture rl/Gesture)
|
||||||
(defonce last-gesture rl/Gesture)
|
(defonce last-gesture rl/Gesture)
|
||||||
@ -38,7 +38,7 @@
|
|||||||
;; The C's switch, as a function. `:else` is its `default:` — an unnamed
|
;; The C's switch, as a function. `:else` is its `default:` — an unnamed
|
||||||
;; gesture logs the empty string, which draws nothing, which is what falling
|
;; gesture logs the empty string, which draws nothing, which is what falling
|
||||||
;; through the C's switch without a TextCopy leaves in the slot.
|
;; through the C's switch without a TextCopy leaves in the slot.
|
||||||
(defn gesture-name [g rl/Gesture] string
|
(defn gesture-name [g rl/Gesture] str
|
||||||
(cond
|
(cond
|
||||||
(= g :gesture-tap) "GESTURE TAP"
|
(= g :gesture-tap) "GESTURE TAP"
|
||||||
(= g :gesture-double-tap) "GESTURE DOUBLETAP"
|
(= g :gesture-double-tap) "GESTURE DOUBLETAP"
|
||||||
|
|||||||
@ -60,7 +60,7 @@
|
|||||||
;; and a table of one-character strings; (string b) makes the
|
;; and a table of one-character strings; (string b) makes the
|
||||||
;; number a string with no instructions, so it is one draw-text and
|
;; number a string with no instructions, so it is one draw-text and
|
||||||
;; this file imports nothing but raylib.
|
;; this file imports nothing but raylib.
|
||||||
(rl/draw-text (string (i64->bytes (i64 i)))
|
(rl/draw-text (str (i64->bytes (i64 i)))
|
||||||
(- (i32 (.x p)) 10) (- (i32 (.y p)) 70) 40
|
(- (i32 (.x p)) 10) (- (i32 (.y p)) 70) 40
|
||||||
rl/black))))
|
rl/black))))
|
||||||
|
|
||||||
|
|||||||
@ -188,7 +188,7 @@
|
|||||||
;; Not in the C: which button the search picked, as a number, so the
|
;; Not in the C: which button the search picked, as a number, so the
|
||||||
;; headless case and the window agree about the same thing.
|
;; headless case and the window agree about the same thing.
|
||||||
(rl/draw-text "button: " 10 34 20 rl/lightgray)
|
(rl/draw-text "button: " 10 34 20 rl/lightgray)
|
||||||
(rl/draw-text (string (i64->bytes (i64 pressed)))
|
(rl/draw-text (str (i64->bytes (i64 pressed)))
|
||||||
(+ 10 (rl/measure-text "button: " 20)) 34 20
|
(+ 10 (rl/measure-text "button: " 20)) 34 20
|
||||||
rl/lightgray))
|
rl/lightgray))
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
;; One line of the state list: the label, then "on" or "off" in lime or
|
;; One line of the state list: the label, then "on" or "off" in lime or
|
||||||
;; maroon, at the x the label ended. The C writes two whole DrawText calls per
|
;; maroon, at the x the label ended. The C writes two whole DrawText calls per
|
||||||
;; flag with the text repeated; this says it once.
|
;; flag with the text repeated; this says it once.
|
||||||
(defn draw-flag [label string flag u32 y i32] ()
|
(defn draw-flag [label str flag u32 y i32] ()
|
||||||
(rl/draw-text label 10 y 10 rl/gray)
|
(rl/draw-text label 10 y 10 rl/gray)
|
||||||
(let [x (+ 10 (rl/measure-text label 10))]
|
(let [x (+ 10 (rl/measure-text label 10))]
|
||||||
(if (rl/window-state? flag)
|
(if (rl/window-state? flag)
|
||||||
|
|||||||
@ -45,7 +45,7 @@
|
|||||||
;;
|
;;
|
||||||
;; Nothing may be formatted between the draw and the measure: `s` may be a view
|
;; Nothing may be formatted between the draw and the measure: `s` may be a view
|
||||||
;; of the shared buffer, and both calls have to see the same bytes.
|
;; of the shared buffer, and both calls have to see the same bytes.
|
||||||
(defn draw-piece [s string x i32 y i32 size i32 color rl/Color] i32
|
(defn draw-piece [s str x i32 y i32 size i32 color rl/Color] i32
|
||||||
(rl/draw-text s x y size color)
|
(rl/draw-text s x y size color)
|
||||||
(rl/measure-text s size))
|
(rl/measure-text s size))
|
||||||
|
|
||||||
@ -74,7 +74,7 @@
|
|||||||
;; the old note about i32's most negative value — it is widened to i64 before
|
;; the old note about i32's most negative value — it is widened to i64 before
|
||||||
;; formatting, so there is no negation to wrap.
|
;; formatting, so there is no negation to wrap.
|
||||||
(defn draw-int [n i32 x i32 y i32 size i32 color rl/Color] i32
|
(defn draw-int [n i32 x i32 y i32 size i32 color rl/Color] i32
|
||||||
(draw-piece (string (i64->bytes (i64 n))) x y size color))
|
(draw-piece (str (i64->bytes (i64 n))) x y size color))
|
||||||
|
|
||||||
;; The same with a fixed minimum number of digits — the C's "%03i". A number
|
;; The same with a fixed minimum number of digits — the C's "%03i". A number
|
||||||
;; wider than `width` is drawn in full rather than truncated, which is what
|
;; wider than `width` is drawn in full rather than truncated, which is what
|
||||||
|
|||||||
@ -135,7 +135,7 @@
|
|||||||
(let [b (bytes-view text)]
|
(let [b (bytes-view text)]
|
||||||
(if (>= off (length b))
|
(if (>= off (length b))
|
||||||
0
|
0
|
||||||
(rl/get-codepoint-next (string (slice b off (length b))) size-out))))
|
(rl/get-codepoint-next (str (slice b off (length b))) size-out))))
|
||||||
|
|
||||||
;; One codepoint forward, clamped at the end.
|
;; One codepoint forward, clamped at the end.
|
||||||
;;
|
;;
|
||||||
|
|||||||
@ -122,7 +122,7 @@
|
|||||||
(i32 (.width text-box)) (i32 (.height text-box))
|
(i32 (.width text-box)) (i32 (.height text-box))
|
||||||
(if mouse-on-text rl/red rl/darkgray))
|
(if mouse-on-text rl/red rl/darkgray))
|
||||||
|
|
||||||
(let [typed (string (slice name 0 letter-count))]
|
(let [typed (str (slice name 0 letter-count))]
|
||||||
(rl/draw-text typed (+ (i32 (.x text-box)) 5) (+ (i32 (.y text-box)) 8)
|
(rl/draw-text typed (+ (i32 (.x text-box)) 5) (+ (i32 (.y text-box)) 8)
|
||||||
40 rl/maroon)
|
40 rl/maroon)
|
||||||
|
|
||||||
|
|||||||
@ -82,7 +82,7 @@
|
|||||||
i 0]
|
i 0]
|
||||||
(while (< i length)
|
(while (< i length)
|
||||||
(let [size 0
|
(let [size 0
|
||||||
cp (rl/get-codepoint (string (slice text i length)) (addr size))]
|
cp (rl/get-codepoint (str (slice text i length)) (addr size))]
|
||||||
;; A byte that decodes to nothing answers '?' and raylib would normally
|
;; A byte that decodes to nothing answers '?' and raylib would normally
|
||||||
;; stop; this walks on one byte at a time so the bad bytes get drawn.
|
;; stop; this walks on one byte at a time so the bad bytes get drawn.
|
||||||
(when (= cp (i32 \?)) (set size 1))
|
(when (= cp (i32 \?)) (set size 1))
|
||||||
|
|||||||
@ -68,7 +68,7 @@
|
|||||||
;; the C — see the header comment.
|
;; the C — see the header comment.
|
||||||
(let [b (bytes-view message)
|
(let [b (bytes-view message)
|
||||||
n (min (i32 (length b)) (/ frames-counter 10))]
|
n (min (i32 (length b)) (/ frames-counter 10))]
|
||||||
(rl/draw-text (string (slice b 0 n)) 210 160 20 rl/maroon))
|
(rl/draw-text (str (slice b 0 n)) 210 160 20 rl/maroon))
|
||||||
|
|
||||||
(rl/draw-text "PRESS [ENTER] to RESTART!" 240 260 20 rl/lightgray)
|
(rl/draw-text "PRESS [ENTER] to RESTART!" 240 260 20 rl/lightgray)
|
||||||
(rl/draw-text "HOLD [SPACE] to SPEED UP!" 239 300 20 rl/lightgray))))
|
(rl/draw-text "HOLD [SPACE] to SPEED UP!" 239 300 20 rl/lightgray))))
|
||||||
|
|||||||
@ -80,7 +80,7 @@
|
|||||||
(defconst proc-flip-vertical 7)
|
(defconst proc-flip-vertical 7)
|
||||||
(defconst proc-flip-horizontal 8)
|
(defconst proc-flip-horizontal 8)
|
||||||
|
|
||||||
(defonce process-names [num-processes string])
|
(defonce process-names [num-processes str])
|
||||||
|
|
||||||
;; The nine toggle buttons down the left-hand side, laid out once at startup.
|
;; The nine toggle buttons down the left-hand side, laid out once at startup.
|
||||||
(defonce toggle-recs [num-processes rl/Rectangle])
|
(defonce toggle-recs [num-processes rl/Rectangle])
|
||||||
|
|||||||
@ -293,7 +293,7 @@ and decl_kind =
|
|||||||
(* The same, but written in the C library's own terms — structs by value,
|
(* The same, but written in the C library's own terms — structs by value,
|
||||||
strings as strings. [Shim] generates the C that flattens it and rewrites
|
strings as strings. [Shim] generates the C that flattens it and rewrites
|
||||||
this into a [Declare] plus an ordinary [Defn], so nothing downstream sees
|
this into a [Declare] plus an ordinary [Defn], so nothing downstream sees
|
||||||
one. Two forms and not one because [(declare f [p string] ...)] already
|
one. Two forms and not one because [(declare f [p str] ...)] already
|
||||||
means "the symbol takes ptr+len", which is the opposite of what this
|
means "the symbol takes ptr+len", which is the opposite of what this
|
||||||
means. *)
|
means. *)
|
||||||
| DeclareC of fn * string
|
| DeclareC of fn * string
|
||||||
|
|||||||
125
lib/check.ml
125
lib/check.ml
@ -570,7 +570,7 @@ let foreign_spelling = function
|
|||||||
| "byte" -> Some "u8"
|
| "byte" -> Some "u8"
|
||||||
| "double" -> Some "f64"
|
| "double" -> Some "f64"
|
||||||
| "boolean" -> Some "bool"
|
| "boolean" -> Some "bool"
|
||||||
| "str" -> Some "string"
|
| "string" -> Some "str"
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
|
||||||
(* The builtin names, for the did-you-mean at a call — [prinltn] is a typo for
|
(* The builtin names, for the did-you-mean at a call — [prinltn] is a typo for
|
||||||
@ -1953,7 +1953,7 @@ and resolve_name env ~seen loc n =
|
|||||||
| None ->
|
| None ->
|
||||||
match n with
|
match n with
|
||||||
| "bool" -> Types.Bool
|
| "bool" -> Types.Bool
|
||||||
| "string" -> Types.String
|
| "str" -> Types.String
|
||||||
(* Lowercase and concrete, which the rule three screens down says is a
|
(* Lowercase and concrete, which the rule three screens down says is a
|
||||||
type variable. It is spelled this way because it is a primitive and
|
type variable. It is spelled this way because it is a primitive and
|
||||||
every other primitive is lowercase — [dyn] beside [i64] and [bool]
|
every other primitive is lowercase — [dyn] beside [i64] and [bool]
|
||||||
@ -2077,16 +2077,14 @@ and array_len env loc = function
|
|||||||
another name that is not a type, or by nothing, takes one and is [dyn]. That
|
another name that is not a type, or by nothing, takes one and is [dyn]. That
|
||||||
is the whole rule, and it reads the way the vector reads.
|
is the whole rule, and it reads the way the vector reads.
|
||||||
|
|
||||||
A name that *is* a type name is refused rather than paired. [(defn f [i64 x]
|
A name that *is* a type name pairs only when a type follows it: [[str str]]
|
||||||
...)] has no good reading: taken as written it is a parameter called [i64],
|
has one reading. [(defn f [i64 x] ...)] has two — a dyn parameter called
|
||||||
which shadows nothing but confuses everything, and the likelier intent is a
|
[i64], or a pair written backwards — so it is refused rather than handed
|
||||||
pair written backwards. Refusing here costs a rename in the one program that
|
back as a signature nobody wrote. *)
|
||||||
meant it and closes the one place where this rule could still hand somebody
|
|
||||||
a signature they did not write. *)
|
|
||||||
let is_type_name env n =
|
let is_type_name env n =
|
||||||
Types.ikind_of_name n <> None
|
Types.ikind_of_name n <> None
|
||||||
|| Types.fkind_of_name n <> None
|
|| Types.fkind_of_name n <> None
|
||||||
|| List.mem n [ "bool"; "string"; "dyn"; "Unit"; "Never"; "Allocator" ]
|
|| List.mem n [ "bool"; "str"; "dyn"; "Unit"; "Never"; "Allocator" ]
|
||||||
|| Hashtbl.mem env.aliases n
|
|| Hashtbl.mem env.aliases n
|
||||||
|| Hashtbl.mem env.structs n
|
|| Hashtbl.mem env.structs n
|
||||||
|| Hashtbl.mem env.gstructs n
|
|| Hashtbl.mem env.gstructs n
|
||||||
@ -2188,6 +2186,16 @@ let dyn_param_or_typo env n loc =
|
|||||||
(* In a .fln file the type sits after [name:], so it cannot be read as a
|
(* In a .fln file the type sits after [name:], so it cannot be read as a
|
||||||
second parameter and needs no word about parameter vectors. *)
|
second parameter and needs no word about parameter vectors. *)
|
||||||
let fln = Source.indented_at loc in
|
let fln = Source.indented_at loc in
|
||||||
|
(* [string] is what most languages call the text type, so [[s string]] is
|
||||||
|
far likelier one parameter of a misspelled type than two dyn ones. The
|
||||||
|
other foreign spellings ([long], [byte], [double]) are ordinary parameter
|
||||||
|
names and keep the dyn reading. *)
|
||||||
|
if n = "string" then
|
||||||
|
Loc.failk "check/unknown-type" loc
|
||||||
|
"unknown type string — Flan spells it str%s"
|
||||||
|
(if fln then ""
|
||||||
|
else ". Otherwise string reads as a second parameter, because a \
|
||||||
|
parameter with no type is dyn, and wants another name");
|
||||||
match suggestion with
|
match suggestion with
|
||||||
| Some m when fln ->
|
| Some m when fln ->
|
||||||
Loc.failk "check/unknown-type" loc "unknown type %s — did you mean %s?" n m
|
Loc.failk "check/unknown-type" loc "unknown type %s — did you mean %s?" n m
|
||||||
@ -2245,11 +2253,20 @@ let pair_params ?(also = fun _ -> false) ?(declared = fun _ -> None)
|
|||||||
Loc.failk "check/parameter-name-expected" t.Ast.tloc
|
Loc.failk "check/parameter-name-expected" t.Ast.tloc
|
||||||
"a parameter's name was expected here, and this is a type. Parameters \
|
"a parameter's name was expected here, and this is a type. Parameters \
|
||||||
are [name Type ...]"
|
are [name Type ...]"
|
||||||
| Ast.Pname (n, loc) :: rest when is_type_name env n ->
|
(* A parameter may share a type's name — [str] is a common name for text —
|
||||||
ignore rest;
|
when a type follows it: [[str str]] and [str: str] can only be a name
|
||||||
|
then a type. Without a type after it, [[i64 x]] is a pair written
|
||||||
|
backwards as likely as a dyn parameter called [i64], so that one is
|
||||||
|
refused with both fixes. *)
|
||||||
|
| Ast.Pname (n, loc) :: Ast.Ptype t :: rest when is_type_name env n ->
|
||||||
|
{ Ast.fname = n; fty = t; floc = loc } :: go rest
|
||||||
|
| Ast.Pname (n, loc) :: Ast.Pname (t, tloc) :: rest
|
||||||
|
when is_type_name env n && is_type_name env t ->
|
||||||
|
{ Ast.fname = n; fty = { Ast.t = Ast.Tname t; tloc }; floc = loc } :: go rest
|
||||||
|
| Ast.Pname (n, loc) :: _ when is_type_name env n ->
|
||||||
Loc.failk "check/parameter-named-type" loc
|
Loc.failk "check/parameter-named-type" loc
|
||||||
"%s names a type, so it cannot also be this parameter's name. Write \
|
"%s names a type, and no type follows this parameter called %s. Give \
|
||||||
[name %s], or rename the parameter" n n
|
it one, as [%s %s], or if the pair is backwards write [name %s]" n n n n n
|
||||||
(* [_] reads a type off a body, and a parameter has none to read. *)
|
(* [_] reads a type off a body, and a parameter has none to read. *)
|
||||||
| Ast.Pname (n, _) :: Ast.Pname ("_", tloc) :: _ ->
|
| Ast.Pname (n, _) :: Ast.Pname ("_", tloc) :: _ ->
|
||||||
Loc.failk "check/infer-misplaced" tloc
|
Loc.failk "check/infer-misplaced" tloc
|
||||||
@ -10397,12 +10414,27 @@ and type_named ctx n =
|
|||||||
mistake, instead of this form reporting a missing element type. *)
|
mistake, instead of this form reporting a missing element type. *)
|
||||||
|| n <> tyvar_bare n
|
|| n <> tyvar_bare n
|
||||||
|| List.mem n Types.primitive_names
|
|| List.mem n Types.primitive_names
|
||||||
|
(* Answered as a type so [resolve_name] says it is spelled [str], rather
|
||||||
|
than this form saying no element type was written. *)
|
||||||
|
|| n = "string"
|
||||||
|| Hashtbl.mem ctx.env.structs n
|
|| Hashtbl.mem ctx.env.structs n
|
||||||
|| Hashtbl.mem ctx.env.datas n
|
|| Hashtbl.mem ctx.env.datas n
|
||||||
|| Hashtbl.mem ctx.env.unions n
|
|| Hashtbl.mem ctx.env.unions n
|
||||||
|| Hashtbl.mem ctx.env.enums n
|
|| Hashtbl.mem ctx.env.enums n
|
||||||
|| Hashtbl.mem ctx.env.aliases n
|
|| Hashtbl.mem ctx.env.aliases n
|
||||||
|
|
||||||
|
(* A local or global that shares a type's name — [str] is a common name for
|
||||||
|
text — is the binding in (vec-new str), and then nothing names the type.
|
||||||
|
Said here so the refusal names the binding rather than a missing type. *)
|
||||||
|
and shadowed_type_arg ctx loc what args =
|
||||||
|
match args with
|
||||||
|
| { Ast.e = Ast.Var n; _ } :: _
|
||||||
|
when type_named ctx n && (lookup ctx n <> None || global_value ctx n) ->
|
||||||
|
fail loc
|
||||||
|
"%s here is the value named %s and not the type, so nothing says what \
|
||||||
|
(%s) makes — rename that binding to write the type" n n what
|
||||||
|
| _ -> ()
|
||||||
|
|
||||||
(* The element type for [vec-new]: a leading bare symbol naming a type, a
|
(* The element type for [vec-new]: a leading bare symbol naming a type, a
|
||||||
leading type expression — [(vec-new [u8])], [(vec-new (Ptr Cell))], which
|
leading type expression — [(vec-new [u8])], [(vec-new (Ptr Cell))], which
|
||||||
Parse has already read as one — or the expectation at the site. A bare
|
Parse has already read as one — or the expectation at the site. A bare
|
||||||
@ -10427,6 +10459,7 @@ and vec_new_elem ctx ~want loc args =
|
|||||||
(match want with
|
(match want with
|
||||||
| Some (Types.Vec t) -> t, args
|
| Some (Types.Vec t) -> t, args
|
||||||
| _ ->
|
| _ ->
|
||||||
|
shadowed_type_arg ctx loc "vec-new" args;
|
||||||
fail loc
|
fail loc
|
||||||
"nothing here says what (vec-new) is a Vec of — write the element \
|
"nothing here says what (vec-new) is a Vec of — write the element \
|
||||||
type, as (vec-new i32)")
|
type, as (vec-new i32)")
|
||||||
@ -10488,7 +10521,7 @@ and map_kv loc what (t : Types.t) =
|
|||||||
(* The key and value for [map-new]: two leading bare symbols naming types, or
|
(* The key and value for [map-new]: two leading bare symbols naming types, or
|
||||||
the expectation at the site. The same rule [vec-new] uses, with the same
|
the expectation at the site. The same rule [vec-new] uses, with the same
|
||||||
escape for a symbol that is really a binding — an allocator, in practice —
|
escape for a symbol that is really a binding — an allocator, in practice —
|
||||||
and the pair is written together or not at all, because (map-new string)
|
and the pair is written together or not at all, because (map-new str)
|
||||||
says half of a type and half is not a type. *)
|
says half of a type and half is not a type. *)
|
||||||
and map_new_types ctx ~want loc args =
|
and map_new_types ctx ~want loc args =
|
||||||
let is_type n =
|
let is_type n =
|
||||||
@ -10507,7 +10540,7 @@ and map_new_types ctx ~want loc args =
|
|||||||
Option.get (as_type k), Option.get (as_type v), rest
|
Option.get (as_type k), Option.get (as_type v), rest
|
||||||
| a :: _ when type_of_expr ~generic:(Hashtbl.mem ctx.env.gstructs) a <> None ->
|
| a :: _ when type_of_expr ~generic:(Hashtbl.mem ctx.env.gstructs) a <> None ->
|
||||||
fail loc
|
fail loc
|
||||||
"(map-new) names a key and no value — write both, as (map-new string \
|
"(map-new) names a key and no value — write both, as (map-new str \
|
||||||
i32)"
|
i32)"
|
||||||
| { Ast.e = Ast.Var k; _ } :: rest when is_type k && rest = [] ->
|
| { Ast.e = Ast.Var k; _ } :: rest when is_type k && rest = [] ->
|
||||||
fail loc
|
fail loc
|
||||||
@ -10517,9 +10550,10 @@ and map_new_types ctx ~want loc args =
|
|||||||
(match want with
|
(match want with
|
||||||
| Some (Types.Map (k, v)) -> k, v, args
|
| Some (Types.Map (k, v)) -> k, v, args
|
||||||
| _ ->
|
| _ ->
|
||||||
|
shadowed_type_arg ctx loc "map-new" args;
|
||||||
fail loc
|
fail loc
|
||||||
"nothing here says what (map-new) maps — write the key and value \
|
"nothing here says what (map-new) maps — write the key and value \
|
||||||
types, as (map-new string i32)")
|
types, as (map-new str i32)")
|
||||||
|
|
||||||
(* The element type, or the reason this is not a Vec. *)
|
(* The element type, or the reason this is not a Vec. *)
|
||||||
and vec_elem loc what (t : Types.t) =
|
and vec_elem loc what (t : Types.t) =
|
||||||
@ -12066,10 +12100,10 @@ and named_call ?(qualified = false) ctx ~want loc name args =
|
|||||||
being told the file is missing and left to discover the other half
|
being told the file is missing and left to discover the other half
|
||||||
after fixing it. *)
|
after fixing it. *)
|
||||||
(match args with
|
(match args with
|
||||||
| [ _; { Ast.e = Ast.Var "string"; _ } ] | [ _ ] -> ()
|
| [ _; { Ast.e = Ast.Var "str"; _ } ] | [ _ ] -> ()
|
||||||
| [ _; t ] ->
|
| [ _; t ] ->
|
||||||
fail t.Ast.loc
|
fail t.Ast.loc
|
||||||
"embed's second argument is string, or nothing for a [const u8]"
|
"embed's second argument is str, or nothing for a [const u8]"
|
||||||
| _ -> ());
|
| _ -> ());
|
||||||
let data = read_embed_file (embed_path loc p) p.Ast.loc in
|
let data = read_embed_file (embed_path loc p) p.Ast.loc in
|
||||||
let as_string () = mk loc Types.String (Tast.Str data) in
|
let as_string () = mk loc Types.String (Tast.Str data) in
|
||||||
@ -12088,7 +12122,7 @@ and named_call ?(qualified = false) ctx ~want loc name args =
|
|||||||
two types would be a wart. [want] is a fallback only, and nothing
|
two types would be a wart. [want] is a fallback only, and nothing
|
||||||
depends on it. *)
|
depends on it. *)
|
||||||
(match args with
|
(match args with
|
||||||
| [ _; { Ast.e = Ast.Var "string"; _ } ] ->
|
| [ _; { Ast.e = Ast.Var "str"; _ } ] ->
|
||||||
expect ctx loc ~want (as_string ())
|
expect ctx loc ~want (as_string ())
|
||||||
| _ ->
|
| _ ->
|
||||||
(match want with
|
(match want with
|
||||||
@ -12096,7 +12130,7 @@ and named_call ?(qualified = false) ctx ~want loc name args =
|
|||||||
| _ -> expect ctx loc ~want (as_bytes ())))
|
| _ -> expect ctx loc ~want (as_bytes ())))
|
||||||
| _ ->
|
| _ ->
|
||||||
fail loc
|
fail loc
|
||||||
"embed is (embed \"path\") for a [const u8], or (embed \"path\" string)")
|
"embed is (embed \"path\") for a [const u8], or (embed \"path\" str)")
|
||||||
(* ── What a macro says when it has to refuse ───────────────────
|
(* ── What a macro says when it has to refuse ───────────────────
|
||||||
The one thing a macro could not do, written down in the prelude where
|
The one thing a macro could not do, written down in the prelude where
|
||||||
[unless] settles for it: "a macro has no error facility: it runs inside
|
[unless] settles for it: "a macro has no error facility: it runs inside
|
||||||
@ -12666,7 +12700,7 @@ and named_call ?(qualified = false) ctx ~want loc name args =
|
|||||||
expect ctx loc ~want (dup_elems ctx loc (Types.Int Types.U8) s a)
|
expect ctx loc ~want (dup_elems ctx loc (Types.Int Types.U8) s a)
|
||||||
| _ -> fail loc "bytes is (bytes s) or (bytes s allocator)")
|
| _ -> fail loc "bytes is (bytes s) or (bytes s allocator)")
|
||||||
|
|
||||||
(* (string b): a [u8] seen as a string. The mirror of (bytes-view s),
|
(* (str b): a [u8] seen as a str. The mirror of (bytes-view s),
|
||||||
spelled the same way — a type name in head position, like (bytes s) and
|
spelled the same way — a type name in head position, like (bytes s) and
|
||||||
unlike the numeric casts, which go through [is_cast] and really do
|
unlike the numeric casts, which go through [is_cast] and really do
|
||||||
convert.
|
convert.
|
||||||
@ -12680,7 +12714,7 @@ and named_call ?(qualified = false) ctx ~want loc name args =
|
|||||||
|
|
||||||
Two decisions are baked in here.
|
Two decisions are baked in here.
|
||||||
|
|
||||||
1. It does NOT check UTF-8, because `string` does not claim UTF-8. The
|
1. It does NOT check UTF-8, because `str` does not claim UTF-8. The
|
||||||
prelude settles this: valid-utf8? is an ordinary function you call when
|
prelude settles this: valid-utf8? is an ordinary function you call when
|
||||||
you care, decode-rune/rune-at/rune-count all take [u8] rather than
|
you care, decode-rune/rune-at/rune-count all take [u8] rather than
|
||||||
string, and decode-rune answers {.ok false .width 1} on a malformed
|
string, and decode-rune answers {.ok false .width 1} on a malformed
|
||||||
@ -12694,13 +12728,13 @@ and named_call ?(qualified = false) ctx ~want loc name args =
|
|||||||
|
|
||||||
2. It takes a [const u8], so a [u8] and a (bytes-view s) are both
|
2. It takes a [const u8], so a [u8] and a (bytes-view s) are both
|
||||||
accepted. This direction only loses the ability to write — a string
|
accepted. This direction only loses the ability to write — a string
|
||||||
is read-only everywhere — so the result of (string b) can reach
|
is read-only everywhere — so the result of (str b) can reach
|
||||||
strictly fewer stores than b could.
|
strictly fewer stores than b could.
|
||||||
|
|
||||||
The text i64->bytes and f64->bytes answer lives in the temp allocator
|
The text i64->bytes and f64->bytes answer lives in the temp allocator
|
||||||
until the next (free-temp); calling it a string does not copy it, so text
|
until the next (free-temp); calling it a string does not copy it, so text
|
||||||
kept past the frame is cloned first. *)
|
kept past the frame is cloned first. *)
|
||||||
| "string" ->
|
| "str" ->
|
||||||
arity ctx loc name 1 args;
|
arity ctx loc name 1 args;
|
||||||
prim Tast.StrOfBytes Types.String [ byte_slice ctx (List.hd args) ]
|
prim Tast.StrOfBytes Types.String [ byte_slice ctx (List.hd args) ]
|
||||||
| "bytes->f64" ->
|
| "bytes->f64" ->
|
||||||
@ -13362,6 +13396,13 @@ and ordinary_call ctx ~want loc name args =
|
|||||||
not (List.mem m [ "true"; "false"; "nil"; "None";
|
not (List.mem m [ "true"; "false"; "nil"; "None";
|
||||||
"context/allocator"; "context/temp" ])
|
"context/allocator"; "context/temp" ])
|
||||||
in
|
in
|
||||||
|
(* [(string b)], [(byte x)]: another language's name for a type, used
|
||||||
|
as the conversion, which Flan spells with its own type name. *)
|
||||||
|
(match foreign_spelling name with
|
||||||
|
| Some m ->
|
||||||
|
Loc.failk "check/unknown-function" loc
|
||||||
|
"unknown function %s — Flan spells it %s" name m
|
||||||
|
| None -> ());
|
||||||
match guess with
|
match guess with
|
||||||
| Some m when not (callable m) ->
|
| Some m when not (callable m) ->
|
||||||
if args = [] then
|
if args = [] then
|
||||||
@ -14507,15 +14548,15 @@ let builtins : (string * string * string) list =
|
|||||||
:keyword :map — or, for a value built by a defclass constructor, the \
|
:keyword :map — or, for a value built by a defclass constructor, the \
|
||||||
class's name as class-of answers it. A typed value answers the kind it \
|
class's name as class-of answers it. A typed value answers the kind it \
|
||||||
has as a dyn value: an i32 is :int.");
|
has as a dyn value: an i32 is :int.");
|
||||||
("keyword", "keyword [string|[const u8]] dyn",
|
("keyword", "keyword [str|[const u8]] dyn",
|
||||||
"The interned dyn keyword named by the bytes, for a name that only \
|
"The interned dyn keyword named by the bytes, for a name that only \
|
||||||
exists at run time — a reader building :texture-path out of a token's \
|
exists at run time — a reader building :texture-path out of a token's \
|
||||||
text. A literal :foo is already one.");
|
text. A literal :foo is already one.");
|
||||||
|
|
||||||
(* assets, embedded at compile time *)
|
(* assets, embedded at compile time *)
|
||||||
("embed", "embed [\"path\" string?] [const u8]",
|
("embed", "embed [\"path\" str?] [const u8]",
|
||||||
"The file's bytes, read at compile time and baked in as a constant; \
|
"The file's bytes, read at compile time and baked in as a constant; \
|
||||||
(embed \"p\" string) reads it as a string instead. The path is \
|
(embed \"p\" str) reads it as a str instead. The path is \
|
||||||
relative to the file the form is written in, and the slice points into \
|
relative to the file the form is written in, and the slice points into \
|
||||||
read-only data.");
|
read-only data.");
|
||||||
("embed-dir", "embed-dir [\"path\"] [n EmbedFile]",
|
("embed-dir", "embed-dir [\"path\"] [n EmbedFile]",
|
||||||
@ -14527,27 +14568,27 @@ let builtins : (string * string * string) list =
|
|||||||
carries a name, and this carries a sentence.");
|
carries a name, and this carries a sentence.");
|
||||||
|
|
||||||
(* files *)
|
(* files *)
|
||||||
("slurp", "slurp [string Allocator?] (Vec u8)",
|
("slurp", "slurp [str Allocator?] (Vec u8)",
|
||||||
"Reads a whole file. No Result and no out-parameter: a failure to read \
|
"Reads a whole file. No Result and no out-parameter: a failure to read \
|
||||||
signals FileError under retry and use-value, and a failure to allocate \
|
signals FileError under retry and use-value, and a failure to allocate \
|
||||||
signals StorageExhausted.");
|
signals StorageExhausted.");
|
||||||
("barf", "barf [string [const u8]] ()",
|
("barf", "barf [str [const u8]] ()",
|
||||||
"Writes a whole file. On the web target it signals FileError every \
|
"Writes a whole file. On the web target it signals FileError every \
|
||||||
time, with the path — there is no conditional compilation, so the \
|
time, with the path — there is no conditional compilation, so the \
|
||||||
program decides rather than the build.");
|
program decides rather than the build.");
|
||||||
("delete-file", "delete-file [string] ()",
|
("delete-file", "delete-file [str] ()",
|
||||||
"Removes the file, or signals FileError with retry and use-value. It \
|
"Removes the file, or signals FileError with retry and use-value. It \
|
||||||
answers () and not a bool, because the failure is the condition.");
|
answers () and not a bool, because the failure is the condition.");
|
||||||
("make-directory", "make-directory [string] ()",
|
("make-directory", "make-directory [str] ()",
|
||||||
"Creates the directory, or signals FileError. () for the reason \
|
"Creates the directory, or signals FileError. () for the reason \
|
||||||
delete-file answers one.");
|
delete-file answers one.");
|
||||||
("rename-file", "rename-file [string string] ()",
|
("rename-file", "rename-file [str str] ()",
|
||||||
"Renames the first path to the second, or signals FileError. A \
|
"Renames the first path to the second, or signals FileError. A \
|
||||||
use-value names a different source for the same destination, which is \
|
use-value names a different source for the same destination, which is \
|
||||||
the direction a handler can act on.");
|
the direction a handler can act on.");
|
||||||
|
|
||||||
(* containers *)
|
(* containers *)
|
||||||
("length", "length [[n T]|[T]|string|(Vec T)|(Map K V)] i32",
|
("length", "length [[n T]|[T]|str|(Vec T)|(Map K V)] i32",
|
||||||
"How many elements. One question and one word across an array, a slice, \
|
"How many elements. One question and one word across an array, a slice, \
|
||||||
a string, a Vec and a Map.");
|
a string, a Vec and a Map.");
|
||||||
("at", "at [collection i32 ...] T",
|
("at", "at [collection i32 ...] T",
|
||||||
@ -14555,7 +14596,7 @@ let builtins : (string * string * string) list =
|
|||||||
allocator's epoch checked first. On a string it is the byte, a u8. It \
|
allocator's epoch checked first. On a string it is the byte, a u8. It \
|
||||||
is also a place, so (set (at v i) x) goes through the same check; a \
|
is also a place, so (set (at v i) x) goes through the same check; a \
|
||||||
string is the exception, being a view it does not own.");
|
string is the exception, being a view it does not own.");
|
||||||
("slice", "slice [[n T]|[T]|string|(Vec T) i32? i32?] [T]|string",
|
("slice", "slice [[n T]|[T]|str|(Vec T) i32? i32?] [T]|str",
|
||||||
"The half-open range [lo hi) as a non-owning view. lo defaults to 0 and \
|
"The half-open range [lo hi) as a non-owning view. lo defaults to 0 and \
|
||||||
hi to the length, so (slice a) is the whole of it and (slice a n) is \
|
hi to the length, so (slice a) is the whole of it and (slice a n) is \
|
||||||
the tail from n. A bound may sit one past the end; a literal pair that \
|
the tail from n. A bound may sit one past the end; a literal pair that \
|
||||||
@ -14580,20 +14621,20 @@ let builtins : (string * string * string) list =
|
|||||||
written as a name rather than as a call.");
|
written as a name rather than as a call.");
|
||||||
|
|
||||||
(* the host primitives *)
|
(* the host primitives *)
|
||||||
("bytes", "bytes [string Allocator?] [u8]",
|
("bytes", "bytes [str Allocator?] [u8]",
|
||||||
"A writable copy of the string's bytes, from the current allocator or \
|
"A writable copy of the string's bytes, from the current allocator or \
|
||||||
one named. It allocates like vec-new does — a failure signals \
|
one named. It allocates like vec-new does — a failure signals \
|
||||||
StorageExhausted with retry — and (free b) releases it, through the \
|
StorageExhausted with retry — and (free b) releases it, through the \
|
||||||
current allocator or (free b a) through the one it came from. For reading without a copy, \
|
current allocator or (free b a) through the one it came from. For reading without a copy, \
|
||||||
bytes-view.");
|
bytes-view.");
|
||||||
("bytes-view", "bytes-view [string] [const u8]",
|
("bytes-view", "bytes-view [str] [const u8]",
|
||||||
"The string's own storage seen as a read-only byte slice. It costs \
|
"The string's own storage seen as a read-only byte slice. It costs \
|
||||||
nothing — both are a ptr and a length at run time — and it decodes \
|
nothing — both are a ptr and a length at run time — and it decodes \
|
||||||
nothing. A store through it is a compile error; bytes is the writable \
|
nothing. A store through it is a compile error; bytes is the writable \
|
||||||
copy.");
|
copy.");
|
||||||
("string", "string [[const u8]] string",
|
("str", "str [[const u8]] str",
|
||||||
"A byte slice seen as a string, and free at run time. It does not check \
|
"A byte slice seen as a str, and free at run time. It does not check \
|
||||||
UTF-8, because `string` does not claim UTF-8 — valid-utf8? is an \
|
UTF-8, because `str` does not claim UTF-8 — valid-utf8? is an \
|
||||||
ordinary function you call when you care.");
|
ordinary function you call when you care.");
|
||||||
("bytes->f64", "bytes->f64 [[const u8]] f64", "Parses a float out of the bytes.");
|
("bytes->f64", "bytes->f64 [[const u8]] f64", "Parses a float out of the bytes.");
|
||||||
("bytes->i64", "bytes->i64 [[const u8]] i64",
|
("bytes->i64", "bytes->i64 [[const u8]] i64",
|
||||||
@ -14615,7 +14656,7 @@ let builtins : (string * string * string) list =
|
|||||||
is a read, so it does not consume the value.");
|
is a read, so it does not consume the value.");
|
||||||
("println", "println [T ...] ()",
|
("println", "println [T ...] ()",
|
||||||
"print, with a newline after it — (println) alone is the newline.");
|
"print, with a newline after it — (println) alone is the newline.");
|
||||||
("watch", "watch [string T] ()",
|
("watch", "watch [str T] ()",
|
||||||
"Writes the value, rendered as print renders it, into the dev session's \
|
"Writes the value, rendered as print renders it, into the dev session's \
|
||||||
watch table under the name, where M-x flan-watch shows it. Does nothing \
|
watch table under the name, where M-x flan-watch shows it. Does nothing \
|
||||||
when no watch buffer is open. Outside a dev build it only evaluates \
|
when no watch buffer is open. Outside a dev build it only evaluates \
|
||||||
@ -14623,7 +14664,7 @@ let builtins : (string * string * string) list =
|
|||||||
("exit", "exit [i32] never",
|
("exit", "exit [i32] never",
|
||||||
"Ends the process with this status. It has no value, so nothing written \
|
"Ends the process with this status. It has no value, so nothing written \
|
||||||
after it runs.");
|
after it runs.");
|
||||||
("argv", "argv [] [string]", "The command line, as a slice of strings.");
|
("argv", "argv [] [str]", "The command line, as a slice of strings.");
|
||||||
|
|
||||||
(* the names rather than calls — [var]'s arms. Their
|
(* the names rather than calls — [var]'s arms. Their
|
||||||
signature is the [name type] shape [Dev.defs] gives a global, because
|
signature is the [name type] shape [Dev.defs] gives a global, because
|
||||||
@ -16507,7 +16548,7 @@ let check_main env decls =
|
|||||||
in
|
in
|
||||||
if not ok_params then
|
if not ok_params then
|
||||||
fail at
|
fail at
|
||||||
"main takes no parameters or one [string], not (%s)"
|
"main takes no parameters or one [str], not (%s)"
|
||||||
(String.concat (if Source.indented_at at then ", " else " ")
|
(String.concat (if Source.indented_at at then ", " else " ")
|
||||||
(List.map (tyname at) params));
|
(List.map (tyname at) params));
|
||||||
if not (Types.equal ret Types.Unit || Types.equal ret (Types.Int Types.I32))
|
if not (Types.equal ret Types.Unit || Types.equal ret (Types.Int Types.I32))
|
||||||
|
|||||||
@ -552,7 +552,7 @@ let param_ty env (s : string) : Ast.texpr =
|
|||||||
let inner = String.trim (String.sub s 0 (String.length s - 1)) in
|
let inner = String.trim (String.sub s 0 (String.length s - 1)) in
|
||||||
let is_const = strip_prefix "const " inner <> None in
|
let is_const = strip_prefix "const " inner <> None in
|
||||||
match bare inner with
|
match bare inner with
|
||||||
| "char" when is_const -> tname "string"
|
| "char" when is_const -> tname "str"
|
||||||
| "char" ->
|
| "char" ->
|
||||||
refuse
|
refuse
|
||||||
"char * is a parameter C may write through, and a Flan string crosses \
|
"char * is a parameter C may write through, and a Flan string crosses \
|
||||||
@ -573,7 +573,7 @@ let param_ty env (s : string) : Ast.texpr =
|
|||||||
|
|
||||||
[const char *] is text the caller only reads — a static buffer, a pointer
|
[const char *] is text the caller only reads — a static buffer, a pointer
|
||||||
into an argument, a string literal — and [Shim] copies it into the context
|
into an argument, a string literal — and [Shim] copies it into the context
|
||||||
allocator, so it becomes a [string]. [char *] without the const is text the
|
allocator, so it becomes a [str]. [char *] without the const is text the
|
||||||
caller owns and must hand back through the library's own release function
|
caller owns and must hand back through the library's own release function
|
||||||
([LoadFileText] and [UnloadFileText]); copying it would leak the original
|
([LoadFileText] and [UnloadFileText]); copying it would leak the original
|
||||||
with nothing left to release it through, so it is refused and a
|
with nothing left to release it through, so it is refused and a
|
||||||
@ -585,7 +585,7 @@ let ret_ty env (s : string) : Ast.texpr option =
|
|||||||
let inner = String.trim (String.sub s 0 (String.length s - 1)) in
|
let inner = String.trim (String.sub s 0 (String.length s - 1)) in
|
||||||
let is_const = strip_prefix "const " inner <> None in
|
let is_const = strip_prefix "const " inner <> None in
|
||||||
match bare inner with
|
match bare inner with
|
||||||
| "char" when is_const -> Some (tname "string")
|
| "char" when is_const -> Some (tname "str")
|
||||||
| "char" ->
|
| "char" ->
|
||||||
refuse
|
refuse
|
||||||
"returns char *, which the caller owns and releases through the \
|
"returns char *, which the caller owns and releases through the \
|
||||||
@ -927,7 +927,7 @@ let agrees env (a : Ast.texpr) (b : Ast.texpr) =
|
|||||||
|
|
||||||
The second tolerance, and the one [agrees] cannot express on its own. By the
|
The second tolerance, and the one [agrees] cannot express on its own. By the
|
||||||
time a C parameter has become a Flan type, what the header actually said
|
time a C parameter has become a Flan type, what the header actually said
|
||||||
about it is gone: [param_ty] renders [const char *] as [string] and
|
about it is gone: [param_ty] renders [const char *] as [str] and
|
||||||
[value_ty] renders [void *] as [(Ptr u8)], and both of those are the
|
[value_ty] renders [void *] as [(Ptr u8)], and both of those are the
|
||||||
importer's own choice rather than the header's word. A hand-written line
|
importer's own choice rather than the header's word. A hand-written line
|
||||||
that says [(Ptr u8)] over a [const char *] is not disagreeing with the
|
that says [(Ptr u8)] over a [const char *] is not disagreeing with the
|
||||||
@ -966,7 +966,7 @@ let ptr_agrees_elem env ~inner (elem : Ast.texpr) =
|
|||||||
reporting [value_ty]'s guess of [u8] back at the author as if the header
|
reporting [value_ty]'s guess of [u8] back at the author as if the header
|
||||||
had said it. What is *not* given up is that it is a pointer at all: the
|
had said it. What is *not* given up is that it is a pointer at all: the
|
||||||
match above requires [(Ptr _)] on the Flan side, so an [i32] or a
|
match above requires [(Ptr _)] on the Flan side, so an [i32] or a
|
||||||
[string] declared against a [void *] is still a finding. That
|
[str] declared against a [void *] is still a finding. That
|
||||||
asymmetry is the point — raylib spells thirty-odd parameters [void *]
|
asymmetry is the point — raylib spells thirty-odd parameters [void *]
|
||||||
and none of them is a scalar. *)
|
and none of them is a scalar. *)
|
||||||
let b = bare inner in
|
let b = bare inner in
|
||||||
@ -1580,7 +1580,7 @@ let decl_source (d : Ast.decl) =
|
|||||||
- a [(Ptr T)] where the header says [T *] and the hand-written line chose
|
- a [(Ptr T)] where the header says [T *] and the hand-written line chose
|
||||||
something more specific for a reason it recorded. That is [ptr_agrees],
|
something more specific for a reason it recorded. That is [ptr_agrees],
|
||||||
and it needs the C spelling because the rendering has already thrown the
|
and it needs the C spelling because the rendering has already thrown the
|
||||||
answer away: [param_ty] turns [const char *] into [string] and [value_ty]
|
answer away: [param_ty] turns [const char *] into [str] and [value_ty]
|
||||||
turns [void *] into [(Ptr u8)], neither of which is what the header said.
|
turns [void *] into [(Ptr u8)], neither of which is what the header said.
|
||||||
[(Ptr u8)] over a [char *], and [(Ptr] anything[)] over a [void *], now
|
[(Ptr u8)] over a [char *], and [(Ptr] anything[)] over a [void *], now
|
||||||
agree; [(Ptr A)] over a [B *] does not.
|
agree; [(Ptr A)] over a [B *] does not.
|
||||||
@ -1642,15 +1642,15 @@ let diff_bound ~env ~(bound : (Ast.fn * string) list) (d : dump) =
|
|||||||
| None ->
|
| None ->
|
||||||
(match (try Ok (ret_ty env c.cret) with Refused w -> Error w) with
|
(match (try Ok (ret_ty env c.cret) with Refused w -> Error w) with
|
||||||
(* A return the importer refuses says nothing, as a parameter
|
(* A return the importer refuses says nothing, as a parameter
|
||||||
does — except a [string] over a [char *] without const. That
|
does — except a [str] over a [char *] without const. That
|
||||||
one is a real disagreement: the shim would copy the text and
|
one is a real disagreement: the shim would copy the text and
|
||||||
leave the library's buffer with no owner. *)
|
leave the library's buffer with no owner. *)
|
||||||
| Error _ ->
|
| Error _ ->
|
||||||
(match fn.Ast.ret with
|
(match fn.Ast.ret with
|
||||||
| Some { Ast.t = Ast.Tname "string"; _ } ->
|
| Some { Ast.t = Ast.Tname "str"; _ } ->
|
||||||
say
|
say
|
||||||
(Printf.sprintf
|
(Printf.sprintf
|
||||||
"returns string and the header says %s, which the \
|
"returns str and the header says %s, which the \
|
||||||
caller owns and releases through the library — \
|
caller owns and releases through the library — \
|
||||||
declare it (Ptr u8)"
|
declare it (Ptr u8)"
|
||||||
c.cret)
|
c.cret)
|
||||||
|
|||||||
@ -1092,7 +1092,7 @@ let rec dty m d (t : Types.t) : int =
|
|||||||
(* ptr+len, and shown as ptr+len. There is no hidden owner and no
|
(* ptr+len, and shown as ptr+len. There is no hidden owner and no
|
||||||
capacity, so two members are the whole truth about a slice. *)
|
capacity, so two members are the whole truth about a slice. *)
|
||||||
| Types.String ->
|
| Types.String ->
|
||||||
composite "string"
|
composite "str"
|
||||||
[ ("ptr", Types.Ptr (Types.Mut, (Types.Int Types.U8))); ("len", Types.Int Types.I64) ]
|
[ ("ptr", Types.Ptr (Types.Mut, (Types.Int Types.U8))); ("len", Types.Int Types.I64) ]
|
||||||
| Types.Slice (_, e) ->
|
| Types.Slice (_, e) ->
|
||||||
composite (Types.to_string t)
|
composite (Types.to_string t)
|
||||||
@ -3989,7 +3989,7 @@ and prim f (e : Tast.expr) (p : Tast.prim) (args : Tast.expr list) =
|
|||||||
no copy (plan.org, Milestone-2 primitives). *)
|
no copy (plan.org, Milestone-2 primitives). *)
|
||||||
| Tast.Bytes, [ x ] -> value f x
|
| Tast.Bytes, [ x ] -> value f x
|
||||||
(* (string b), and the same non-instruction for the same reason: String and
|
(* (string b), and the same non-instruction for the same reason: String and
|
||||||
Slice _ are both %slice. See check.ml's "string" case. *)
|
Slice _ are both %slice. See check.ml's "str" case. *)
|
||||||
| Tast.StrOfBytes, [ x ] -> value f x
|
| Tast.StrOfBytes, [ x ] -> value f x
|
||||||
| Tast.BytesToF64, [ x ] -> shim_in f "@flan_bytes_to_f64" "double" x
|
| Tast.BytesToF64, [ x ] -> shim_in f "@flan_bytes_to_f64" "double" x
|
||||||
| Tast.BytesToI64, [ x ] -> shim_in f "@flan_bytes_to_i64" "i64" x
|
| Tast.BytesToI64, [ x ] -> shim_in f "@flan_bytes_to_i64" "i64" x
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
- A struct — a plain object, [{x: 1, y: 2}], keyed by the field's own name.
|
- A struct — a plain object, [{x: 1, y: 2}], keyed by the field's own name.
|
||||||
Readable output is a goal, and this is most of it.
|
Readable output is a goal, and this is most of it.
|
||||||
- [[n T]], a fixed array — a JS array, or a [Uint8Array] when [T] is [u8].
|
- [[n T]], a fixed array — a JS array, or a [Uint8Array] when [T] is [u8].
|
||||||
- [[T]], a slice, and [string] — [{a, o, n}]: the backing store, an offset
|
- [[T]], a slice, and [str] — [{a, o, n}]: the backing store, an offset
|
||||||
into it and a length. A slice is a non-owning view in Flan and this is a
|
into it and a length. A slice is a non-owning view in Flan and this is a
|
||||||
non-owning view here: writing through one writes the original, and a
|
non-owning view here: writing through one writes the original, and a
|
||||||
copy of a slice shares its storage, both of which are what the other two
|
copy of a slice shares its storage, both of which are what the other two
|
||||||
@ -47,11 +47,11 @@
|
|||||||
- [(Fn [..] R)] — a JS function. Function {e values} come along; they carry
|
- [(Fn [..] R)] — a JS function. Function {e values} come along; they carry
|
||||||
no capture in Flan either.
|
no capture in Flan either.
|
||||||
|
|
||||||
{b [string] and [[u8]] are the same representation, and that is not a
|
{b [str] and [[u8]] are the same representation, and that is not a
|
||||||
shortcut.} [Tast.Bytes] and [Tast.StrOfBytes] are documented there as
|
shortcut.} [Tast.Bytes] and [Tast.StrOfBytes] are documented there as
|
||||||
non-instructions — in both existing backends a [string] {e is} a (ptr, len)
|
non-instructions — in both existing backends a [str] {e is} a (ptr, len)
|
||||||
pair over bytes, and the two prims reinterpret rather than convert. Making
|
pair over bytes, and the two prims reinterpret rather than convert. Making
|
||||||
[string] a JS string would make [(length s)] count UTF-16 code units where
|
[str] a JS string would make [(length s)] count UTF-16 code units where
|
||||||
every other backend counts bytes, and the prelude is byte-oriented
|
every other backend counts bytes, and the prelude is byte-oriented
|
||||||
throughout ([rune-count], [valid-utf8?], [decode-rune] all take [[u8]]).
|
throughout ([rune-count], [valid-utf8?], [decode-rune] all take [[u8]]).
|
||||||
So the JS string appears in exactly one place: the argument of
|
So the JS string appears in exactly one place: the argument of
|
||||||
|
|||||||
@ -1507,7 +1507,7 @@ let rec decl (f : Form.t) : Ast.decl =
|
|||||||
(* An empty field vector is the same category as none. *)
|
(* An empty field vector is the same category as none. *)
|
||||||
| [ n; { v = Kw "parent"; _ }; p ] | [ n; { v = Kw "parent"; _ }; p; { v = Vec []; _ } ] ->
|
| [ n; { v = Kw "parent"; _ }; p ] | [ n; { v = Kw "parent"; _ }; p; { v = Vec []; _ } ] ->
|
||||||
let str name =
|
let str name =
|
||||||
{ Ast.fname = name; fty = { Ast.t = Ast.Tname "string"; tloc = f.loc };
|
{ Ast.fname = name; fty = { Ast.t = Ast.Tname "str"; tloc = f.loc };
|
||||||
floc = f.loc }
|
floc = f.loc }
|
||||||
in
|
in
|
||||||
mk (Ast.Defstruct (tname n, [ str "name"; str "message" ], Some (texpr p)))
|
mk (Ast.Defstruct (tname n, [ str "name"; str "message" ], Some (texpr p)))
|
||||||
@ -1765,8 +1765,8 @@ let rec decl (f : Form.t) : Ast.decl =
|
|||||||
[declare]'s signature IS the C signature, already flattened by whoever
|
[declare]'s signature IS the C signature, already flattened by whoever
|
||||||
wrote the C; [declare-c]'s is the *library's* — structs by value — and
|
wrote the C; [declare-c]'s is the *library's* — structs by value — and
|
||||||
[Shim] generates the flattening. The two cannot be one form, because
|
[Shim] generates the flattening. The two cannot be one form, because
|
||||||
(declare f [p string] ...) already means the symbol takes ptr+len and
|
(declare f [p str] ...) already means the symbol takes ptr+len and
|
||||||
(declare-c f [p string] ...) means it takes a NUL-terminated char *. *)
|
(declare-c f [p str] ...) means it takes a NUL-terminated char *. *)
|
||||||
let mkd fn csym =
|
let mkd fn csym =
|
||||||
if String.equal which "declare-c" then Ast.DeclareC (fn, csym)
|
if String.equal which "declare-c" then Ast.DeclareC (fn, csym)
|
||||||
else Ast.Declare (fn, csym)
|
else Ast.Declare (fn, csym)
|
||||||
|
|||||||
@ -60,7 +60,7 @@ let source = {flan|
|
|||||||
;; condition has an empty sentence, since its fields say what it is.
|
;; condition has an empty sentence, since its fields say what it is.
|
||||||
;;
|
;;
|
||||||
;; (pause) and warnings are not under Error: a breakpoint is not a failure.
|
;; (pause) and warnings are not under Error: a breakpoint is not a failure.
|
||||||
(defstruct Error [name string message string])
|
(defstruct Error [name str message str])
|
||||||
|
|
||||||
;; The condition every allocating operation signals when the allocator cannot
|
;; The condition every allocating operation signals when the allocator cannot
|
||||||
;; satisfy a request — spec-memory.md, "Allocation failure". It is here rather
|
;; satisfy a request — spec-memory.md, "Allocation failure". It is here rather
|
||||||
@ -195,7 +195,7 @@ let source = {flan|
|
|||||||
;; agreement flan_bounds_cond keeps with BoundsError. No restart is
|
;; agreement flan_bounds_cond keeps with BoundsError. No restart is
|
||||||
;; established at the call, BoundsError's decision for BoundsError's reason:
|
;; established at the call, BoundsError's decision for BoundsError's reason:
|
||||||
;; nothing a handler supplies makes the old arguments fit the new body.
|
;; nothing a handler supplies makes the old arguments fit the new body.
|
||||||
(defstruct StaleCall :parent Error [callee string compiled string current string])
|
(defstruct StaleCall :parent Error [callee str compiled str current str])
|
||||||
|
|
||||||
;; A call through a (CFn ...) that holds no function. A CFn may be a struct
|
;; A call through a (CFn ...) that holds no function. A CFn may be a struct
|
||||||
;; field, a fixed array's element or a global, and each of those starts out
|
;; field, a fixed array's element or a global, and each of those starts out
|
||||||
@ -206,7 +206,7 @@ let source = {flan|
|
|||||||
;; Signalled from the runtime — flan_null_call in runtime/flan_rt.c — so
|
;; Signalled from the runtime — flan_null_call in runtime/flan_rt.c — so
|
||||||
;; **this field is a C struct that has to agree with this one**. No restart is
|
;; **this field is a C struct that has to agree with this one**. No restart is
|
||||||
;; established at the call, BoundsError's decision for BoundsError's reason.
|
;; established at the call, BoundsError's decision for BoundsError's reason.
|
||||||
(defstruct NullCall :parent Error [type string])
|
(defstruct NullCall :parent Error [type str])
|
||||||
|
|
||||||
;; What a generic function signals when no method answers. `generic` is the
|
;; What a generic function signals when no method answers. `generic` is the
|
||||||
;; name written at the defgeneric or defmulti, and `value` is what the
|
;; name written at the defgeneric or defmulti, and `value` is what the
|
||||||
@ -228,7 +228,7 @@ let source = {flan|
|
|||||||
;;
|
;;
|
||||||
;; No restart is established at the miss, which is BoundsError's decision
|
;; No restart is established at the miss, which is BoundsError's decision
|
||||||
;; taken for BoundsError's reason -- see the note above it.
|
;; taken for BoundsError's reason -- see the note above it.
|
||||||
(defstruct NoMethod :parent Error [generic string value dyn])
|
(defstruct NoMethod :parent Error [generic str value dyn])
|
||||||
|
|
||||||
;; A breakpoint. (pause) stops the program where it stands and hands it to the
|
;; A breakpoint. (pause) stops the program where it stands and hands it to the
|
||||||
;; break loop, with the whole stack under it readable — C-c C-b lists the
|
;; break loop, with the whole stack under it readable — C-c C-b lists the
|
||||||
@ -1282,9 +1282,9 @@ let source = {flan|
|
|||||||
;; something. flan_getenv answers a length of -1 and a pointer at a valid empty
|
;; something. flan_getenv answers a length of -1 and a pointer at a valid empty
|
||||||
;; string, so the test below is arithmetic and the pointer is never dereferenced
|
;; string, so the test below is arithmetic and the pointer is never dereferenced
|
||||||
;; on the absent path.
|
;; on the absent path.
|
||||||
(declare getenv-raw [name string out-len (Ptr i64)] (Ptr u8) "flan_getenv")
|
(declare getenv-raw [name str out-len (Ptr i64)] (Ptr u8) "flan_getenv")
|
||||||
|
|
||||||
(defn getenv [name string] (Option [u8])
|
(defn getenv [name str] (Option [u8])
|
||||||
(let [n (i64 0)
|
(let [n (i64 0)
|
||||||
p (getenv-raw name (addr n))]
|
p (getenv-raw name (addr n))]
|
||||||
(if (< n 0)
|
(if (< n 0)
|
||||||
@ -1951,7 +1951,7 @@ let source = {flan|
|
|||||||
;; stopped being true when `Vec` landed, and most of the list has moved up into
|
;; stopped being true when `Vec` landed, and most of the list has moved up into
|
||||||
;; the building section above: join, concat, split, to-lower, to-upper, repeat
|
;; the building section above: join, concat, split, to-lower, to-upper, repeat
|
||||||
;; and replace are all written now, and `string-from-bytes` turned out to be
|
;; and replace are all written now, and `string-from-bytes` turned out to be
|
||||||
;; the `string` builtin all along — (string (slice v)) is the round trip,
|
;; the `str` builtin all along — (str (slice v)) is the round trip,
|
||||||
;; and the layouts being identical is exactly why it is free.
|
;; and the layouts being identical is exactly why it is free.
|
||||||
;;
|
;;
|
||||||
;; What is left is refused for four *different* reasons, which is why they are
|
;; What is left is refused for four *different* reasons, which is why they are
|
||||||
@ -1992,7 +1992,7 @@ let source = {flan|
|
|||||||
;; does, so an embed costs nothing at run time and nothing at startup. It is
|
;; does, so an embed costs nothing at run time and nothing at startup. It is
|
||||||
;; also read-only, so `data` is a [const u8] and a store through it is refused
|
;; also read-only, so `data` is a [const u8] and a store through it is refused
|
||||||
;; at compile time. To get a writable copy, copy the bytes into a Vec.
|
;; at compile time. To get a writable copy, copy the bytes into a Vec.
|
||||||
(defstruct EmbedFile [name string data [const u8]])
|
(defstruct EmbedFile [name str data [const u8]])
|
||||||
|
|
||||||
;; A linear scan, deliberately. A directory embed is tens of entries, the scan
|
;; A linear scan, deliberately. A directory embed is tens of entries, the scan
|
||||||
;; is over names already in cache-warm .rodata, and the alternative — a
|
;; is over names already in cache-warm .rodata, and the alternative — a
|
||||||
@ -2003,7 +2003,7 @@ let source = {flan|
|
|||||||
;; It takes a slice rather than the array (embed-dir) answers, because an array
|
;; It takes a slice rather than the array (embed-dir) answers, because an array
|
||||||
;; length is part of its type and there are no generics: write
|
;; length is part of its type and there are no generics: write
|
||||||
;; (embed-find (slice assets 0 (length assets)) "brush.png").
|
;; (embed-find (slice assets 0 (length assets)) "brush.png").
|
||||||
(defn embed-find [files [EmbedFile] name string] (Option [const u8])
|
(defn embed-find [files [EmbedFile] name str] (Option [const u8])
|
||||||
(dotimes [i (length files)]
|
(dotimes [i (length files)]
|
||||||
(when (bytes=? (bytes-view (.name (at files i))) (bytes-view name))
|
(when (bytes=? (bytes-view (.name (at files i))) (bytes-view name))
|
||||||
(return (Some (.data (at files i))))))
|
(return (Some (.data (at files i))))))
|
||||||
@ -2021,7 +2021,7 @@ let source = {flan|
|
|||||||
;; parent link, not class inheritance", decides on is the
|
;; parent link, not class inheritance", decides on is the
|
||||||
;; answer to that, and it is not built; when it is, these reasons can become
|
;; answer to that, and it is not built; when it is, these reasons can become
|
||||||
;; types without any call site changing.
|
;; types without any call site changing.
|
||||||
(defstruct FileError :parent Error [path string op i32 reason i32])
|
(defstruct FileError :parent Error [path str op i32 reason i32])
|
||||||
|
|
||||||
(defconst file-op-read i32 0)
|
(defconst file-op-read i32 0)
|
||||||
(defconst file-op-write i32 1)
|
(defconst file-op-write i32 1)
|
||||||
@ -2051,7 +2051,7 @@ let source = {flan|
|
|||||||
;; each signals FileError with those two restarts. "Is it there" and "how big
|
;; each signals FileError with those two restarts. "Is it there" and "how big
|
||||||
;; is it" have no such answer: absence is the reply, not a fault, and a
|
;; is it" have no such answer: absence is the reply, not a fault, and a
|
||||||
;; condition would make the ordinary case cost a handler search.
|
;; condition would make the ordinary case cost a handler search.
|
||||||
(declare file-stat-raw [path string out-size (Ptr i64)] i8 "flan_file_stat")
|
(declare file-stat-raw [path str out-size (Ptr i64)] i8 "flan_file_stat")
|
||||||
|
|
||||||
;; True for anything the path resolves to — a file, a directory, a device —
|
;; True for anything the path resolves to — a file, a directory, a device —
|
||||||
;; because that is what the question asks and a caller wanting "and it is a
|
;; because that is what the question asks and a caller wanting "and it is a
|
||||||
@ -2063,7 +2063,7 @@ let source = {flan|
|
|||||||
;; first. Reach for it when the answer is the point — choosing a config path,
|
;; first. Reach for it when the answer is the point — choosing a config path,
|
||||||
;; deciding whether to write a default — and not as a guard in front of an
|
;; deciding whether to write a default — and not as a guard in front of an
|
||||||
;; operation that already reports its own failure properly.
|
;; operation that already reports its own failure properly.
|
||||||
(defn file-exists? [path string] bool
|
(defn file-exists? [path str] bool
|
||||||
(let [n (i64 0)]
|
(let [n (i64 0)]
|
||||||
(= (file-stat-raw path (addr n)) 1)))
|
(= (file-stat-raw path (addr n)) 1)))
|
||||||
|
|
||||||
@ -2071,7 +2071,7 @@ let source = {flan|
|
|||||||
;; answer — that is the trade a caller makes by asking a question with no
|
;; answer — that is the trade a caller makes by asking a question with no
|
||||||
;; restart on it. A caller that needs to tell "missing" from "denied" wants
|
;; restart on it. A caller that needs to tell "missing" from "denied" wants
|
||||||
;; `slurp`, whose FileError carries the reason.
|
;; `slurp`, whose FileError carries the reason.
|
||||||
(defn file-size [path string] (Option i64)
|
(defn file-size [path str] (Option i64)
|
||||||
(let [n (i64 0)]
|
(let [n (i64 0)]
|
||||||
(if (= (file-stat-raw path (addr n)) 1) (Some n) None)))
|
(if (= (file-stat-raw path (addr n)) 1) (Some n) None)))
|
||||||
|
|
||||||
@ -2100,10 +2100,10 @@ let source = {flan|
|
|||||||
;; process rather than to any source file — nothing else knows better, and
|
;; process rather than to any source file — nothing else knows better, and
|
||||||
;; every program links this runtime. It is not a file API and `slurp` is; this
|
;; every program links this runtime. It is not a file API and `slurp` is; this
|
||||||
;; exists so a macro can look at data at compile time.
|
;; exists so a macro can look at data at compile time.
|
||||||
(declare macro-slurp-raw [path string out-len (Ptr i64)] (Ptr u8)
|
(declare macro-slurp-raw [path str out-len (Ptr i64)] (Ptr u8)
|
||||||
"flan_macro_slurp")
|
"flan_macro_slurp")
|
||||||
|
|
||||||
(defn macro-slurp [path string] (Option [u8])
|
(defn macro-slurp [path str] (Option [u8])
|
||||||
(let [n (i64 0)
|
(let [n (i64 0)
|
||||||
p (macro-slurp-raw path (addr n))]
|
p (macro-slurp-raw path (addr n))]
|
||||||
(if (< n 0)
|
(if (< n 0)
|
||||||
@ -2131,11 +2131,11 @@ let source = {flan|
|
|||||||
;; Case order is the tag order (docs/BUILT.md, data types), so this list is a layout
|
;; Case order is the tag order (docs/BUILT.md, data types), so this list is a layout
|
||||||
;; contract with lib/expand.ml's marshaller and may not be reordered.
|
;; contract with lib/expand.ml's marshaller and may not be reordered.
|
||||||
(defdata Form
|
(defdata Form
|
||||||
[(Sym [s string])
|
[(Sym [s str])
|
||||||
(Kw [s string])
|
(Kw [s str])
|
||||||
(Int [i i64])
|
(Int [i i64])
|
||||||
(Float [x f64])
|
(Float [x f64])
|
||||||
(Str [s string])
|
(Str [s str])
|
||||||
(Byte [b i32])
|
(Byte [b i32])
|
||||||
(List [xs [Form]])
|
(List [xs [Form]])
|
||||||
(Vec [xs [Form]])
|
(Vec [xs [Form]])
|
||||||
@ -2182,7 +2182,7 @@ let source = {flan|
|
|||||||
|
|
||||||
;; (head x) for every x, which is what ~~@xs splices into an inner template:
|
;; (head x) for every x, which is what ~~@xs splices into an inner template:
|
||||||
;; one unquote per element, as SBCL's unquote* builds (src/code/backq.lisp).
|
;; one unquote per element, as SBCL's unquote* builds (src/code/backq.lisp).
|
||||||
(defn form-wrap-each [head string xs [Form]] [Form]
|
(defn form-wrap-each [head str xs [Form]] [Form]
|
||||||
(let [v (vec-new Form)]
|
(let [v (vec-new Form)]
|
||||||
(dotimes [i (length xs)]
|
(dotimes [i (length xs)]
|
||||||
(push v (Form.List {.xs (form-pair (Form.Sym {.s head}) (at xs i))})))
|
(push v (Form.List {.xs (form-pair (Form.Sym {.s head}) (at xs i))})))
|
||||||
@ -2219,7 +2219,7 @@ let source = {flan|
|
|||||||
(let [d (i64->bytes (gensym-next))]
|
(let [d (i64->bytes (gensym-next))]
|
||||||
(dotimes [i (length d)]
|
(dotimes [i (length d)]
|
||||||
(push v (at d i))))
|
(push v (at d i))))
|
||||||
(Form.Sym {.s (string (slice v))})))
|
(Form.Sym {.s (str (slice v))})))
|
||||||
|
|
||||||
;; ── The first special form to stop being one ──────────────────────────
|
;; ── The first special form to stop being one ──────────────────────────
|
||||||
;;
|
;;
|
||||||
@ -2443,7 +2443,7 @@ let source = {flan|
|
|||||||
(Form.List xs) xs
|
(Form.List xs) xs
|
||||||
_ (form-nil)))
|
_ (form-nil)))
|
||||||
|
|
||||||
(defn form-sym? [f Form name string] bool
|
(defn form-sym? [f Form name str] bool
|
||||||
(match f
|
(match f
|
||||||
(Form.Sym s) (bytes=? (bytes-view s) (bytes-view name))
|
(Form.Sym s) (bytes=? (bytes-view s) (bytes-view name))
|
||||||
_ false))
|
_ false))
|
||||||
|
|||||||
@ -307,7 +307,7 @@ let rec render ?(refuse = print_refusal) c depth (e : Tast.expr) : Tast.expr lis
|
|||||||
Not squeamishness about indeterminate bytes — a printer that showed a
|
Not squeamishness about indeterminate bytes — a printer that showed a
|
||||||
number nobody stored would be fine, and every member of a union is a
|
number nobody stored would be fine, and every member of a union is a
|
||||||
legal read by this language's own rule. It is that one of those members
|
legal read by this language's own rule. It is that one of those members
|
||||||
may be a [string] or a [Ptr], and rendering it would dereference
|
may be a [str] or a [Ptr], and rendering it would dereference
|
||||||
whatever bytes happen to be in the union's storage. A tagged data type
|
whatever bytes happen to be in the union's storage. A tagged data type
|
||||||
is safe to print because its tag says which case is live; there is no
|
is safe to print because its tag says which case is live; there is no
|
||||||
such fact here, so the printer would be following a pointer it invented.
|
such fact here, so the printer would be following a pointer it invented.
|
||||||
|
|||||||
16
lib/shim.ml
16
lib/shim.ml
@ -9,8 +9,8 @@
|
|||||||
[declare-c] says the other thing: the signature is the *library's*, structs
|
[declare-c] says the other thing: the signature is the *library's*, structs
|
||||||
by value and all, and the compiler is to produce whatever flattening makes
|
by value and all, and the compiler is to produce whatever flattening makes
|
||||||
it crossable. The two cannot be one form —
|
it crossable. The two cannot be one form —
|
||||||
[(declare start-raw [path string] i32 "flan_agent_start")] and
|
[(declare start-raw [path str] i32 "flan_agent_start")] and
|
||||||
[(declare-c init-window [w i32 h i32 title string] "InitWindow")] are the
|
[(declare-c init-window [w i32 h i32 title str] "InitWindow")] are the
|
||||||
same shape and mean opposite things about who NUL-terminates the string.
|
same shape and mean opposite things about who NUL-terminates the string.
|
||||||
|
|
||||||
Why the crossing is still C, and not [emit.ml]: a small aggregate's calling
|
Why the crossing is still C, and not [emit.ml]: a small aggregate's calling
|
||||||
@ -320,7 +320,7 @@ let rec cty env ~needed ~loc ~what (t : Ast.texpr) : string =
|
|||||||
"%s is %s, a union, and the shim generator writes structs only. \
|
"%s is %s, a union, and the shim generator writes structs only. \
|
||||||
Pass (Ptr %s) and let the C side read it"
|
Pass (Ptr %s) and let the C side read it"
|
||||||
what n n
|
what n n
|
||||||
else if String.equal n "string" then
|
else if String.equal n "str" then
|
||||||
fail loc
|
fail loc
|
||||||
"%s is a string, and a string crosses only as a parameter or a \
|
"%s is a string, and a string crosses only as a parameter or a \
|
||||||
return value — declare (Ptr u8) and read it in Flan"
|
return value — declare (Ptr u8) and read it in Flan"
|
||||||
@ -379,7 +379,7 @@ type pkind =
|
|||||||
let classify env ~needed ~loc ~what (t : Ast.texpr) =
|
let classify env ~needed ~loc ~what (t : Ast.texpr) =
|
||||||
let t' = unalias env t in
|
let t' = unalias env t in
|
||||||
match t'.Ast.t with
|
match t'.Ast.t with
|
||||||
| Ast.Tname "string" -> (Pstr, "const char *")
|
| Ast.Tname "str" -> (Pstr, "const char *")
|
||||||
(* A copy crosses behind a pointer only: by value, the Flan half this
|
(* A copy crosses behind a pointer only: by value, the Flan half this
|
||||||
generator writes would have to spell the copy's type, and it builds its
|
generator writes would have to spell the copy's type, and it builds its
|
||||||
wrapper from struct names. *)
|
wrapper from struct names. *)
|
||||||
@ -891,7 +891,7 @@ let flan_wrapper ?track (fn : Ast.fn) (s : shim) raw : Ast.decl_kind =
|
|||||||
out ],
|
out ],
|
||||||
Some (ty loc (Ast.Tname n)) )
|
Some (ty loc (Ast.Tname n)) )
|
||||||
| `Str ->
|
| `Str ->
|
||||||
(* (string (bytes (string (slice-from p n)))): a view of C's bytes,
|
(* (str (bytes (str (slice-from p n)))): a view of C's bytes,
|
||||||
copied by [bytes] into the context allocator, and seen as a string
|
copied by [bytes] into the context allocator, and seen as a string
|
||||||
again. The length is bound before the pointer is, so its address
|
again. The length is bound before the pointer is, so its address
|
||||||
exists to be written through. *)
|
exists to be written through. *)
|
||||||
@ -903,9 +903,9 @@ let flan_wrapper ?track (fn : Ast.fn) (s : shim) raw : Ast.decl_kind =
|
|||||||
bval = ex loc (Ast.Int 0L); bloc = loc };
|
bval = ex loc (Ast.Int 0L); bloc = loc };
|
||||||
{ Ast.bname = ptr_tmp; bty = None;
|
{ Ast.bname = ptr_tmp; bty = None;
|
||||||
bval = call (args @ [ app "addr" [ v len_tmp ] ]); bloc = loc } ];
|
bval = call (args @ [ app "addr" [ v len_tmp ] ]); bloc = loc } ];
|
||||||
( [ app "string"
|
( [ app "str"
|
||||||
[ app "bytes"
|
[ app "bytes"
|
||||||
[ app "string"
|
[ app "str"
|
||||||
[ app "slice-from" [ v ptr_tmp; v len_tmp ] ] ] ] ],
|
[ app "slice-from" [ v ptr_tmp; v len_tmp ] ] ] ] ],
|
||||||
fn.Ast.ret )
|
fn.Ast.ret )
|
||||||
| _ -> ([ call args ], fn.Ast.ret)
|
| _ -> ([ call args ], fn.Ast.ret)
|
||||||
@ -957,7 +957,7 @@ let one env ~taken ~tracks (fn : Ast.fn) csym loc =
|
|||||||
let t' = unalias env t in
|
let t' = unalias env t in
|
||||||
(match t'.Ast.t with
|
(match t'.Ast.t with
|
||||||
| Ast.Tname "Unit" -> `Void
|
| Ast.Tname "Unit" -> `Void
|
||||||
| Ast.Tname "string" -> `Str
|
| Ast.Tname "str" -> `Str
|
||||||
| Ast.Tname n when Hashtbl.mem env.structs n ->
|
| Ast.Tname n when Hashtbl.mem env.structs n ->
|
||||||
ignore (cty env ~needed ~loc ~what t');
|
ignore (cty env ~needed ~loc ~what t');
|
||||||
`Struct (n, ctype_name n)
|
`Struct (n, ctype_name n)
|
||||||
|
|||||||
@ -36,7 +36,7 @@ type prim =
|
|||||||
calc-me's tokenizer and the prelude's printers each need. *)
|
calc-me's tokenizer and the prelude's printers each need. *)
|
||||||
| Bytes | BytesToF64 | BytesToI64 | F64ToBytes | I64ToBytes
|
| Bytes | BytesToF64 | BytesToI64 | F64ToBytes | I64ToBytes
|
||||||
(* (string b): the other direction of [Bytes], and the same non-instruction.
|
(* (string b): the other direction of [Bytes], and the same non-instruction.
|
||||||
See check.ml's "string" case for why it is unchecked. *)
|
See check.ml's "str" case for why it is unchecked. *)
|
||||||
| StrOfBytes
|
| StrOfBytes
|
||||||
(* No surface name: the structural printer is the only thing that builds
|
(* No surface name: the structural printer is the only thing that builds
|
||||||
these. U64ToBytes because u64 is not i64 with a flag, EscapeBytes for a
|
these. U64ToBytes because u64 is not i64 with a flag, EscapeBytes for a
|
||||||
|
|||||||
@ -44,7 +44,7 @@ type t =
|
|||||||
| Array of int64 * t (* [n T] inline, a value, copies *)
|
| Array of int64 * t (* [n T] inline, a value, copies *)
|
||||||
| Map of t * t (* (Map K V) *)
|
| Map of t * t (* (Map K V) *)
|
||||||
| Ptr of access * t (* (Ptr T) (Ptr const T) *)
|
| Ptr of access * t (* (Ptr T) (Ptr const T) *)
|
||||||
(* [Allocator]: a builtin opaque type, the way [string] is a builtin
|
(* [Allocator]: a builtin opaque type, the way [str] is a builtin
|
||||||
ptr+len. It is a [Types.t] case with no user-writable constructor, which
|
ptr+len. It is a [Types.t] case with no user-writable constructor, which
|
||||||
is what lets spec-memory.md's "procedure plus an opaque data pointer" be
|
is what lets spec-memory.md's "procedure plus an opaque data pointer" be
|
||||||
expressed with none of milestone 5's function values — the procedure is a
|
expressed with none of milestone 5's function values — the procedure is a
|
||||||
@ -145,7 +145,7 @@ let bits_f = function F32 -> 32 | F64 -> 64
|
|||||||
that already accepts [i32] accepts [int] without learning the word.
|
that already accepts [i32] accepts [int] without learning the word.
|
||||||
|
|
||||||
Only these two. The rest of the foreign spellings — [long], [double],
|
Only these two. The rest of the foreign spellings — [long], [double],
|
||||||
[uint], [str] — stay refusals that teach the Flan name; see
|
[uint], [string] — stay refusals that teach the Flan name; see
|
||||||
[Check.foreign_spelling] for why the line is drawn where it is.
|
[Check.foreign_spelling] for why the line is drawn where it is.
|
||||||
|
|
||||||
The mapping is one-way on purpose: [ikind_name] and [fkind_name] below
|
The mapping is one-way on purpose: [ikind_name] and [fkind_name] below
|
||||||
@ -175,7 +175,7 @@ let fkind_of_name = function
|
|||||||
and the identity is a half one. *)
|
and the identity is a half one. *)
|
||||||
let primitive_names =
|
let primitive_names =
|
||||||
[ "i8"; "i16"; "i32"; "i64"; "u8"; "u16"; "u32"; "u64";
|
[ "i8"; "i16"; "i32"; "i64"; "u8"; "u16"; "u32"; "u64";
|
||||||
"f32"; "f64"; "bool"; "string"; "dyn"; "Unit"; "Never"; "Allocator";
|
"f32"; "f64"; "bool"; "str"; "dyn"; "Unit"; "Never"; "Allocator";
|
||||||
"int"; "float" ]
|
"int"; "float" ]
|
||||||
|
|
||||||
let ikind_name k =
|
let ikind_name k =
|
||||||
@ -272,7 +272,7 @@ and to_string = function
|
|||||||
| Int k -> ikind_name k
|
| Int k -> ikind_name k
|
||||||
| Float k -> fkind_name k
|
| Float k -> fkind_name k
|
||||||
| Bool -> "bool"
|
| Bool -> "bool"
|
||||||
| String -> "string"
|
| String -> "str"
|
||||||
| Unit -> "()"
|
| Unit -> "()"
|
||||||
| Never -> "Never"
|
| Never -> "Never"
|
||||||
| Named n -> (match Hashtbl.find_opt display n with Some d -> d | None -> n)
|
| Named n -> (match Hashtbl.find_opt display n with Some d -> d | None -> n)
|
||||||
|
|||||||
@ -778,7 +778,7 @@ void flan_dev_watch_end(void) {
|
|||||||
/* These are the whole feature for a scalar, and they are what a program can
|
/* These are the whole feature for a scalar, and they are what a program can
|
||||||
* use today:
|
* use today:
|
||||||
*
|
*
|
||||||
* (declare-c watch-i64 [name string x i64] i32 "flan_dev_watch_i64")
|
* (declare-c watch-i64 [name str x i64] i32 "flan_dev_watch_i64")
|
||||||
* ...
|
* ...
|
||||||
* (watch-i64 "ticks" ticks)
|
* (watch-i64 "ticks" ticks)
|
||||||
*
|
*
|
||||||
@ -901,7 +901,7 @@ void flan_dev_watch_reset(void) {
|
|||||||
/* Reachable from a program by [declare-c], the same as the four scalars and
|
/* Reachable from a program by [declare-c], the same as the four scalars and
|
||||||
* for the same reason — no arm in the checker, nothing the compiler learns:
|
* for the same reason — no arm in the checker, nothing the compiler learns:
|
||||||
*
|
*
|
||||||
* (declare-c watch-num-i64 [name string x i64] i32 "flan_dev_watch_num_i64")
|
* (declare-c watch-num-i64 [name str x i64] i32 "flan_dev_watch_num_i64")
|
||||||
* ...
|
* ...
|
||||||
* (watch-num-i64 "cell" (at grid i))
|
* (watch-num-i64 "cell" (at grid i))
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1716,7 +1716,7 @@ static slot_type slot_type_of(const uint8_t *w, int64_t n) {
|
|||||||
const char *w; uint8_t kind, fbits; int64_t lo, hi;
|
const char *w; uint8_t kind, fbits; int64_t lo, hi;
|
||||||
} known[] = {
|
} known[] = {
|
||||||
{ "bool", ST_BOOL, 0, 0, 0 },
|
{ "bool", ST_BOOL, 0, 0, 0 },
|
||||||
{ "string", ST_TEXT, 0, 0, 0 },
|
{ "str", ST_TEXT, 0, 0, 0 },
|
||||||
{ "f32", ST_FLOAT, 24, 0, 0 },
|
{ "f32", ST_FLOAT, 24, 0, 0 },
|
||||||
{ "f64", ST_FLOAT, 53, 0, 0 },
|
{ "f64", ST_FLOAT, 53, 0, 0 },
|
||||||
{ "i8", ST_INT, 0, INT8_MIN, INT8_MAX },
|
{ "i8", ST_INT, 0, INT8_MIN, INT8_MAX },
|
||||||
@ -2682,7 +2682,7 @@ flan_dyn flan_dyn_rem(flan_dyn a, flan_dyn b, const uint8_t *loc,
|
|||||||
*
|
*
|
||||||
* Numbers against numbers, text against text, and nothing else. Text orders
|
* Numbers against numbers, text against text, and nothing else. Text orders
|
||||||
* bytewise, which is [memcmp] with the shorter one first on a tie — the same
|
* bytewise, which is [memcmp] with the shorter one first on a tie — the same
|
||||||
* order a sort of a [(Vec string)] would want and the only order that needs no
|
* order a sort of a [(Vec str)] would want and the only order that needs no
|
||||||
* locale, no collation table and no argument.
|
* locale, no collation table and no argument.
|
||||||
*
|
*
|
||||||
* A number against a text traps rather than answering. The temptation is to
|
* A number against a text traps rather than answering. The temptation is to
|
||||||
|
|||||||
@ -71,7 +71,7 @@ void flan_handler_pop(flan_handler *h) {
|
|||||||
*
|
*
|
||||||
* A handler that matched through a parent link is not handed the condition,
|
* A handler that matched through a parent link is not handed the condition,
|
||||||
* whose layout is its own type's, but a view laid out as the prelude's
|
* whose layout is its own type's, but a view laid out as the prelude's
|
||||||
* (defstruct Error [name string message string]) — the parent's type is
|
* (defstruct Error [name str message str]) — the parent's type is
|
||||||
* Error-shaped, which the checker requires. The view's message is the
|
* Error-shaped, which the checker requires. The view's message is the
|
||||||
* condition with its values: [message] for the runtime's own conditions,
|
* condition with its values: [message] for the runtime's own conditions,
|
||||||
* which format their sentence before signalling; what [render] prints for a
|
* which format their sentence before signalling; what [render] prints for a
|
||||||
@ -388,7 +388,7 @@ typedef struct { const uint8_t *ptr; int64_t len; } flan_slice;
|
|||||||
|
|
||||||
static int rt_argc;
|
static int rt_argc;
|
||||||
static char **rt_argv;
|
static char **rt_argv;
|
||||||
static flan_slice *rt_args; /* argv as [string], built once, never freed */
|
static flan_slice *rt_args; /* argv as [str], built once, never freed */
|
||||||
|
|
||||||
void flan_rt_init(int32_t argc, char **argv) {
|
void flan_rt_init(int32_t argc, char **argv) {
|
||||||
rt_argc = (int)argc;
|
rt_argc = (int)argc;
|
||||||
@ -1487,7 +1487,7 @@ void flan_arith_error(const uint8_t *loc, int64_t loclen, int32_t op,
|
|||||||
* is the price of never pinning a module for it.
|
* is the price of never pinning a module for it.
|
||||||
*
|
*
|
||||||
* The condition must agree field for field with the prelude's
|
* The condition must agree field for field with the prelude's
|
||||||
* (defstruct StaleCall [callee string compiled string current string]),
|
* (defstruct StaleCall [callee str compiled str current str]),
|
||||||
* the same hand-kept agreement flan_bounds_cond has with BoundsError. */
|
* the same hand-kept agreement flan_bounds_cond has with BoundsError. */
|
||||||
|
|
||||||
typedef struct { flan_slice callee, compiled, current; } flan_stale_cond;
|
typedef struct { flan_slice callee, compiled, current; } flan_stale_cond;
|
||||||
@ -1551,7 +1551,7 @@ void flan_stale_call(const char *site, const char *callee, const char *want,
|
|||||||
* `type` is copied and never freed, for flan_stale_call's reason: the text
|
* `type` is copied and never freed, for flan_stale_call's reason: the text
|
||||||
* lives in the image of the module that compiled the call, which may be a
|
* lives in the image of the module that compiled the call, which may be a
|
||||||
* thunk that is unloaded once it returns. Must agree with the prelude's
|
* thunk that is unloaded once it returns. Must agree with the prelude's
|
||||||
* (defstruct NullCall :parent Error [type string]). */
|
* (defstruct NullCall :parent Error [type str]). */
|
||||||
|
|
||||||
typedef struct { flan_slice type; } flan_nullcall_cond;
|
typedef struct { flan_slice type; } flan_nullcall_cond;
|
||||||
|
|
||||||
@ -3529,7 +3529,7 @@ int8_t flan_map_init(flan_map *m, flan_allocator *a, int64_t ksize,
|
|||||||
m->alloc = a;
|
m->alloc = a;
|
||||||
m->epoch = (int64_t)a->epoch;
|
m->epoch = (int64_t)a->epoch;
|
||||||
/* No block until something is put in it: an empty map that is never written
|
/* No block until something is put in it: an empty map that is never written
|
||||||
* costs nothing, which is what makes a (defonce m (Map string i32)) free. */
|
* costs nothing, which is what makes a (defonce m (Map str i32)) free. */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ The consequence is visible in the syntax. A `restart-case` in value position
|
|||||||
must produce its type on the *fall-through* path too:
|
must produce its type on the *fall-through* path too:
|
||||||
|
|
||||||
```
|
```
|
||||||
(defn load-texture [path string] (Handle Texture)
|
(defn load-texture [path str] (Handle Texture)
|
||||||
(if (file-exists? path)
|
(if (file-exists? path)
|
||||||
(rl/load-texture path)
|
(rl/load-texture path)
|
||||||
(restart-case
|
(restart-case
|
||||||
|
|||||||
@ -53,7 +53,7 @@ it is usually written in — a `let` binding — has no type slot for it to take
|
|||||||
them from:
|
them from:
|
||||||
|
|
||||||
```
|
```
|
||||||
(let [enemies (map-new string Enemy)]
|
(let [enemies (map-new str Enemy)]
|
||||||
...)
|
...)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -134,7 +134,7 @@
|
|||||||
|
|
||||||
;; `try` unwraps Ok, else early-returns Err, widening this function's error
|
;; `try` unwraps Ok, else early-returns Err, widening this function's error
|
||||||
;; set. Option→Result conversion is explicit — no implicit From, no anyhow.
|
;; set. Option→Result conversion is explicit — no implicit From, no anyhow.
|
||||||
(defn load-config [path string] (Result Config)
|
(defn load-config [path str] (Result Config)
|
||||||
(let [text (try (read-file path))
|
(let [text (try (read-file path))
|
||||||
table (try (parse-toml text))
|
table (try (parse-toml text))
|
||||||
port (try (ok-or (get table "port")
|
port (try (ok-or (get table "port")
|
||||||
@ -143,7 +143,7 @@
|
|||||||
|
|
||||||
;; errdefer runs only on the Result failure path — NOT on a restart transfer
|
;; errdefer runs only on the Result failure path — NOT on a restart transfer
|
||||||
;; (spec-conditions.md §5). Pairs with explicit allocation.
|
;; (spec-conditions.md §5). Pairs with explicit allocation.
|
||||||
(defn load-atlas [path string] (Result Atlas)
|
(defn load-atlas [path str] (Result Atlas)
|
||||||
(let [buf (alloc-image context/allocator)]
|
(let [buf (alloc-image context/allocator)]
|
||||||
(errdefer (free buf))
|
(errdefer (free buf))
|
||||||
(try (decode-png path buf))
|
(try (decode-png path buf))
|
||||||
@ -155,13 +155,13 @@
|
|||||||
;; file is fixed on disk. So it offers a menu and the caller chooses.
|
;; file is fixed on disk. So it offers a menu and the caller chooses.
|
||||||
;; A condition type is an ordinary struct — there is no defcondition, and no
|
;; A condition type is an ordinary struct — there is no defcondition, and no
|
||||||
;; class hierarchy to put one in. Matching is by type plus a predicate.
|
;; class hierarchy to put one in. Matching is by type plus a predicate.
|
||||||
(defstruct AssetMissing [path string])
|
(defstruct AssetMissing [path str])
|
||||||
|
|
||||||
;; `signal` has type () and RETURNS if every handler returns normally, so the
|
;; `signal` has type () and RETURNS if every handler returns normally, so the
|
||||||
;; fall-through path of a restart-case in value position must still produce the
|
;; fall-through path of a restart-case in value position must still produce the
|
||||||
;; type. `abort` has type Never, which unifies with (Handle Texture).
|
;; type. `abort` has type Never, which unifies with (Handle Texture).
|
||||||
;; Every clause body and the restart-case body share one type.
|
;; Every clause body and the restart-case body share one type.
|
||||||
(defn load-texture [path string] (Handle Texture)
|
(defn load-texture [path str] (Handle Texture)
|
||||||
(if (file-exists? path)
|
(if (file-exists? path)
|
||||||
(rl/load-texture path)
|
(rl/load-texture path)
|
||||||
(restart-case
|
(restart-case
|
||||||
@ -176,7 +176,7 @@
|
|||||||
;; then the body. It is not a type paired with an `fn`, and a handler closes
|
;; then the body. It is not a type paired with an `fn`, and a handler closes
|
||||||
;; over nothing: it is lifted into its own function, so a value it wants to keep
|
;; over nothing: it is lifted into its own function, so a value it wants to keep
|
||||||
;; goes on the condition or into a global.
|
;; goes on the condition or into a global.
|
||||||
(defn load-level [path string] Level
|
(defn load-level [path str] Level
|
||||||
(handler-bind [(AssetMissing [c]
|
(handler-bind [(AssetMissing [c]
|
||||||
(log "missing asset:" (.path c))
|
(log "missing asset:" (.path c))
|
||||||
(invoke-restart 'use-placeholder))]
|
(invoke-restart 'use-placeholder))]
|
||||||
@ -195,7 +195,7 @@
|
|||||||
(skip-form [] (skip-to-next-delimiter p))))
|
(skip-form [] (skip-to-next-delimiter p))))
|
||||||
forms))
|
forms))
|
||||||
|
|
||||||
(defn collect-parse-errors [src string] (Result Ast)
|
(defn collect-parse-errors [src str] (Result Ast)
|
||||||
(let [errors (make-vec ParseError)]
|
(let [errors (make-vec ParseError)]
|
||||||
(handler-bind [(ParseError [c]
|
(handler-bind [(ParseError [c]
|
||||||
(push errors c) ; value struct: copies out of
|
(push errors c) ; value struct: copies out of
|
||||||
@ -218,7 +218,7 @@
|
|||||||
|
|
||||||
;; ── defer for explicit resources ──────────────────────────────────────
|
;; ── defer for explicit resources ──────────────────────────────────────
|
||||||
;; defer DOES run when a restart transfer passes through this frame.
|
;; defer DOES run when a restart transfer passes through this frame.
|
||||||
(defn save-world [w (Ptr World) path string] ()
|
(defn save-world [w (Ptr World) path str] ()
|
||||||
(let [f (open path :write)]
|
(let [f (open path :write)]
|
||||||
(defer (close f))
|
(defer (close f))
|
||||||
(write-bytes f (serialize w))))
|
(write-bytes f (serialize w))))
|
||||||
@ -235,7 +235,7 @@
|
|||||||
;; An imperative loop, not (each (fn [p] (try ...))): `try` and `return` inside a
|
;; An imperative loop, not (each (fn [p] (try ...))): `try` and `return` inside a
|
||||||
;; `fn` exit the FN, so a callback would swallow the Err instead of propagating
|
;; `fn` exit the FN, so a callback would swallow the Err instead of propagating
|
||||||
;; it out of preload.
|
;; it out of preload.
|
||||||
(defn ^:async preload [paths [string]] (Result ())
|
(defn ^:async preload [paths [str]] (Result ())
|
||||||
(for [p paths]
|
(for [p paths]
|
||||||
(try (await (load-texture-async p))))
|
(try (await (load-texture-async p))))
|
||||||
(Ok unit))
|
(Ok unit))
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
(set ticks (+ ticks 1))
|
(set ticks (+ ticks 1))
|
||||||
ticks)
|
ticks)
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(if (< (length args) 2)
|
(if (< (length args) 2)
|
||||||
(do (println "usage: agent-queue <socket>") 2)
|
(do (println "usage: agent-queue <socket>") 2)
|
||||||
(do
|
(do
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
(set ticks (+ ticks 1))
|
(set ticks (+ ticks 1))
|
||||||
ticks)
|
ticks)
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(if (< (length args) 2)
|
(if (< (length args) 2)
|
||||||
(do (println "usage: agent <socket>") 2)
|
(do (println "usage: agent <socket>") 2)
|
||||||
(do
|
(do
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
(defn show-fields [s [[const u8]]] ()
|
(defn show-fields [s [[const u8]]] ()
|
||||||
(dotimes [i (length s)]
|
(dotimes [i (length s)]
|
||||||
(print (string (at s i)))
|
(print (str (at s i)))
|
||||||
(print " "))
|
(print " "))
|
||||||
(println ""))
|
(println ""))
|
||||||
|
|
||||||
@ -114,7 +114,7 @@
|
|||||||
(let [f (split (bytes-view "delta,alpha,charlie,bravo") \,)]
|
(let [f (split (bytes-view "delta,alpha,charlie,bravo") \,)]
|
||||||
(sort-bytes (slice f))
|
(sort-bytes (slice f))
|
||||||
(let [j (join (slice f) (bytes-view " < "))]
|
(let [j (join (slice f) (bytes-view " < "))]
|
||||||
(println (string (slice j))) ; alpha < bravo < charlie < delta
|
(println (str (slice j))) ; alpha < bravo < charlie < delta
|
||||||
(free j))
|
(free j))
|
||||||
(free f))
|
(free f))
|
||||||
0)
|
0)
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
(defdata Value [Nil (Int [n i64]) (List [items (Vec Value)])])
|
(defdata Value [Nil (Int [n i64]) (List [items (Vec Value)])])
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(set frame (arena-new 4096))
|
(set frame (arena-new 4096))
|
||||||
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)]
|
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)]
|
||||||
(cond
|
(cond
|
||||||
|
|||||||
@ -19,9 +19,9 @@
|
|||||||
(defdata Value
|
(defdata Value
|
||||||
[(Nil [])
|
[(Nil [])
|
||||||
(Int [n i64])
|
(Int [n i64])
|
||||||
(Text [s string])
|
(Text [s str])
|
||||||
(List [items (Vec Value)])
|
(List [items (Vec Value)])
|
||||||
(Table [entries (Map string Value)])])
|
(Table [entries (Map str Value)])])
|
||||||
|
|
||||||
;; [0 1 .. n-1] as a dynamic list. No allocator is named: with-allocator in
|
;; [0 1 .. n-1] as a dynamic list. No allocator is named: with-allocator in
|
||||||
;; main has rebound the context, and spec-memory.md puts the allocator in the
|
;; main has rebound the context, and spec-memory.md puts the allocator in the
|
||||||
@ -36,7 +36,7 @@
|
|||||||
;; A table whose values are themselves lists, so the graph is three levels
|
;; A table whose values are themselves lists, so the graph is three levels
|
||||||
;; deep before it reaches a leaf: Table -> Vec -> List -> Vec -> Int.
|
;; deep before it reaches a leaf: Table -> Vec -> List -> Vec -> Int.
|
||||||
(defn a-table [] Value
|
(defn a-table [] Value
|
||||||
(let [entries (map-new string Value)]
|
(let [entries (map-new str Value)]
|
||||||
(put entries "xs" (number-list 3))
|
(put entries "xs" (number-list 3))
|
||||||
(put entries "ys" (number-list 5))
|
(put entries "ys" (number-list 5))
|
||||||
(put entries "name" (Value.Text {.s "edn"}))
|
(put entries "name" (Value.Text {.s "edn"}))
|
||||||
|
|||||||
@ -61,7 +61,7 @@
|
|||||||
(defonce small f64 -1e300)
|
(defonce small f64 -1e300)
|
||||||
(defonce uz u32)
|
(defonce uz u32)
|
||||||
|
|
||||||
(defn show [name string n i64] ()
|
(defn show [name str n i64] ()
|
||||||
(print name) (print " ") (print n) (println ""))
|
(print name) (print " ") (print n) (println ""))
|
||||||
|
|
||||||
;;; Two frames deep with a defer on the way, so the transfer has something to
|
;;; Two frames deep with a defer on the way, so the transfer has something to
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
(defonce m1-32 i32 -1)
|
(defonce m1-32 i32 -1)
|
||||||
(defonce wide f32 1e30)
|
(defonce wide f32 1e30)
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [n (i32 (bytes->i64 (bytes-view (at args 1))))
|
(let [n (i32 (bytes->i64 (bytes-view (at args 1))))
|
||||||
;; The most negative i64. No literal spells it — the reader parses the
|
;; The most negative i64. No literal spells it — the reader parses the
|
||||||
;; digits and then negates, and the positive half does not fit — so it
|
;; digits and then negates, and the positive half does not fit — so it
|
||||||
|
|||||||
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
;;; Two frames deep, with a defer on the way, so the transfer has something to
|
;;; Two frames deep, with a defer on the way, so the transfer has something to
|
||||||
;;; cross and something to run on its way out.
|
;;; cross and something to run on its way out.
|
||||||
(defn show [name string n i64] ()
|
(defn show [name str n i64] ()
|
||||||
(print name) (print " ") (print n) (println ""))
|
(print name) (print " ") (print n) (println ""))
|
||||||
|
|
||||||
(defn read-cell [i i32] i32
|
(defn read-cell [i i32] i32
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
;;;; (that is a separate job) and lets LLVM fold the branch away here.
|
;;;; (that is a separate job) and lets LLVM fold the branch away here.
|
||||||
(defonce arr [3 i32])
|
(defonce arr [3 i32])
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [n (i32 (bytes->i64 (bytes-view (at args 1))))
|
(let [n (i32 (bytes->i64 (bytes-view (at args 1))))
|
||||||
s (bytes-view "hello")] ; len 5
|
s (bytes-view "hello")] ; len 5
|
||||||
(cond
|
(cond
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
;;; one.
|
;;; one.
|
||||||
;;; Both additions are qualified too, since + is shadowed below and this
|
;;; Both additions are qualified too, since + is shadowed below and this
|
||||||
;;; function wants the arithmetic and not the 99.
|
;;; function wants the arithmetic and not the 99.
|
||||||
(defn length [s string] i32 (builtin/+ 1 (builtin/length s)))
|
(defn length [s str] i32 (builtin/+ 1 (builtin/length s)))
|
||||||
|
|
||||||
(defn + [a i32 b i32] i32 99)
|
(defn + [a i32 b i32] i32 99)
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
(let [s "INSERTIONSORT"
|
(let [s "INSERTIONSORT"
|
||||||
b (bytes s)]
|
b (bytes s)]
|
||||||
(set (at b 0) \Z)
|
(set (at b 0) \Z)
|
||||||
(println (string b)) ; ZNSERTIONSORT
|
(println (str b)) ; ZNSERTIONSORT
|
||||||
(println s) ; INSERTIONSORT
|
(println s) ; INSERTIONSORT
|
||||||
;; The copy's block came from the context allocator, and free hands it
|
;; The copy's block came from the context allocator, and free hands it
|
||||||
;; back there — which is what keeps this program leak-free.
|
;; back there — which is what keeps this program leak-free.
|
||||||
@ -23,7 +23,7 @@
|
|||||||
;; at -O0 and silently do nothing at -O2.
|
;; at -O0 and silently do nothing at -O2.
|
||||||
(let [b (bytes "hi")]
|
(let [b (bytes "hi")]
|
||||||
(set (at b 0) \H)
|
(set (at b 0) \H)
|
||||||
(println (string b)) ; Hi
|
(println (str b)) ; Hi
|
||||||
(free b))
|
(free b))
|
||||||
|
|
||||||
;; 3. The view still costs nothing and reads the string's own storage.
|
;; 3. The view still costs nothing and reads the string's own storage.
|
||||||
@ -36,7 +36,7 @@
|
|||||||
(set frame (arena-new 4096))
|
(set frame (arena-new 4096))
|
||||||
(let [b (bytes "arena" frame)]
|
(let [b (bytes "arena" frame)]
|
||||||
(set (at b 4) \A)
|
(set (at b 4) \A)
|
||||||
(println (string b))) ; arenA
|
(println (str b))) ; arenA
|
||||||
(free-all frame)
|
(free-all frame)
|
||||||
(arena-destroy frame)
|
(arena-destroy frame)
|
||||||
|
|
||||||
|
|||||||
@ -7,5 +7,5 @@
|
|||||||
(defn main [] i32
|
(defn main [] i32
|
||||||
(let [v (bytes-view "INSERTIONSORT")]
|
(let [v (bytes-view "INSERTIONSORT")]
|
||||||
(set (at v 0) \Z)
|
(set (at v 0) \Z)
|
||||||
(print (string v))
|
(print (str v))
|
||||||
0))
|
0))
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
;; Brackets around the result so an empty trim is visible as [] rather than
|
;; Brackets around the result so an empty trim is visible as [] rather than
|
||||||
;; as nothing at all — the all-whitespace case is otherwise indistinguishable
|
;; as nothing at all — the all-whitespace case is otherwise indistinguishable
|
||||||
;; from a trim that printed the wrong slice of length zero.
|
;; from a trim that printed the wrong slice of length zero.
|
||||||
(defn show-trim [s string] ()
|
(defn show-trim [s str] ()
|
||||||
(print "[")
|
(print "[")
|
||||||
(print (trim (bytes-view s)))
|
(print (trim (bytes-view s)))
|
||||||
(print "]"))
|
(print "]"))
|
||||||
|
|||||||
@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
;; Prints its tag and answers its value. Every operand below is one of these,
|
;; Prints its tag and answers its value. Every operand below is one of these,
|
||||||
;; so the tag line is a transcript of the evaluation.
|
;; so the tag line is a transcript of the evaluation.
|
||||||
(defn mark [tag string v i32] i32
|
(defn mark [tag str v i32] i32
|
||||||
(set calls (+ calls 1))
|
(set calls (+ calls 1))
|
||||||
(print tag)
|
(print tag)
|
||||||
v)
|
v)
|
||||||
|
|
||||||
(defn markf [tag string v f64] f64
|
(defn markf [tag str v f64] f64
|
||||||
(print tag)
|
(print tag)
|
||||||
v)
|
v)
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
;;;; before 1100 two-byte characters, so a cut at a fixed byte count would
|
;;;; before 1100 two-byte characters, so a cut at a fixed byte count would
|
||||||
;;;; land inside one.
|
;;;; land inside one.
|
||||||
|
|
||||||
(defstruct Wide :parent Error [code i32 why string])
|
(defstruct Wide :parent Error [code i32 why str])
|
||||||
(defstruct Longs :parent Error)
|
(defstruct Longs :parent Error)
|
||||||
|
|
||||||
(defn main [] i32
|
(defn main [] i32
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
(defstruct IoError :parent Error)
|
(defstruct IoError :parent Error)
|
||||||
(defstruct Empty :parent Error [])
|
(defstruct Empty :parent Error [])
|
||||||
(defstruct MyErr :parent Error [code i32 why string])
|
(defstruct MyErr :parent Error [code i32 why str])
|
||||||
|
|
||||||
(defonce zero i64)
|
(defonce zero i64)
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
(defstruct MyErr :parent Error [code i32])
|
(defstruct MyErr :parent Error [code i32])
|
||||||
|
|
||||||
(defn why [] string
|
(defn why [] str
|
||||||
(handler-case (do (error (MyErr {.code 3})) "")
|
(handler-case (do (error (MyErr {.code 3})) "")
|
||||||
[(Error [e] (.message e))]))
|
[(Error [e] (.message e))]))
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
(sort w)
|
(sort w)
|
||||||
(println (total w) (total (slice w 1)))
|
(println (total w) (total (slice w 1)))
|
||||||
(println (first-of w) (first-of (bytes-view "z")))
|
(println (first-of w) (first-of (bytes-view "z")))
|
||||||
(println (string head) (string tail) (length head))
|
(println (str head) (str tail) (length head))
|
||||||
(println (bytes=? head (bytes-view "hello")) (starts-with? r head))
|
(println (bytes=? head (bytes-view "hello")) (starts-with? r head))
|
||||||
(push names head)
|
(push names head)
|
||||||
(push names tail)
|
(push names tail)
|
||||||
@ -51,15 +51,15 @@
|
|||||||
both [a b]]
|
both [a b]]
|
||||||
(println (widths (slice both)))
|
(println (widths (slice both)))
|
||||||
(set (at a 0) \A)
|
(set (at a 0) \A)
|
||||||
(println (string a)))
|
(println (str a)))
|
||||||
(let [f (split (bytes-view "b,a,c") \,)]
|
(let [f (split (bytes-view "b,a,c") \,)]
|
||||||
(sort-bytes (slice f))
|
(sort-bytes (slice f))
|
||||||
(println (string (slice (join (slice f) (bytes-view "-"))))))
|
(println (str (slice (join (slice f) (bytes-view "-"))))))
|
||||||
(println (at r 0))
|
(println (at r 0))
|
||||||
(println (call-rd rd) (call-bare rd) (call-mk mk))
|
(println (call-rd rd) (call-bare rd) (call-mk mk))
|
||||||
(let [b (bytes "q")]
|
(let [b (bytes "q")]
|
||||||
(println (peek (addr (at r 1))) (peek (addr (at "abc" 2)))
|
(println (peek (addr (at r 1))) (peek (addr (at "abc" 2)))
|
||||||
(peek (addr (at b 0)))
|
(peek (addr (at b 0)))
|
||||||
(string (slice-from (addr (at r 7)) 5))))
|
(str (slice-from (addr (at r 7)) 5))))
|
||||||
(free names))
|
(free names))
|
||||||
0)
|
0)
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
;;;; destroyed arena's record. Allocating from the context must then trap,
|
;;;; destroyed arena's record. Allocating from the context must then trap,
|
||||||
;;;; not quietly allocate from the new arena. Argument 1 reads context/allocator
|
;;;; not quietly allocate from the new arena. Argument 1 reads context/allocator
|
||||||
;;;; as a value first and uses that instead, which traps the same way.
|
;;;; as a value first and uses that instead, which traps the same way.
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [which (if (> (length args) 1) (bytes->i64 (bytes-view (at args 1))) 0)
|
(let [which (if (> (length args) 1) (bytes->i64 (bytes-view (at args 1))) 0)
|
||||||
a (arena-new 4096)]
|
a (arena-new 4096)]
|
||||||
(with-allocator a
|
(with-allocator a
|
||||||
|
|||||||
@ -19,8 +19,8 @@
|
|||||||
(let [path (vec-new u8)]
|
(let [path (vec-new u8)]
|
||||||
(append (addr path) (bytes-view "dir/"))
|
(append (addr path) (bytes-view "dir/"))
|
||||||
(dotimes [i 300] (push path \x))
|
(dotimes [i 300] (push path \x))
|
||||||
(let [tail (cret/after-slash (string (slice path)))
|
(let [tail (cret/after-slash (str (slice path)))
|
||||||
long-name (string (slice path 4))]
|
long-name (str (slice path 4))]
|
||||||
(println (length tail))
|
(println (length tail))
|
||||||
(println (= tail long-name))))
|
(println (= tail long-name))))
|
||||||
(println (length (cret/nothing)))
|
(println (length (cret/nothing)))
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
[Empty
|
[Empty
|
||||||
(Dot [x f64 y f64])
|
(Dot [x f64 y f64])
|
||||||
(Rect [w i32 h i32])
|
(Rect [w i32 h i32])
|
||||||
(Tag [name string n u8])])
|
(Tag [name str n u8])])
|
||||||
|
|
||||||
;; A union crosses a call boundary in both directions, as a parameter and as a
|
;; A union crosses a call boundary in both directions, as a parameter and as a
|
||||||
;; return type -- a value that cannot do that is not a value.
|
;; return type -- a value that cannot do that is not a value.
|
||||||
@ -29,7 +29,7 @@
|
|||||||
;; alignment visible to something other than a slot.
|
;; alignment visible to something other than a slot.
|
||||||
(defstruct Cell [id i32 s Shape])
|
(defstruct Cell [id i32 s Shape])
|
||||||
|
|
||||||
(defn describe [s Shape] string
|
(defn describe [s Shape] str
|
||||||
(match s
|
(match s
|
||||||
Empty "empty"
|
Empty "empty"
|
||||||
(Dot x y) (if (= x y) "dot on the diagonal" "dot")
|
(Dot x y) (if (= x y) "dot on the diagonal" "dot")
|
||||||
@ -100,7 +100,7 @@
|
|||||||
;; and not unions, so (vec-new Shape) was refused for not saying what it
|
;; and not unions, so (vec-new Shape) was refused for not saying what it
|
||||||
;; held -- by a program that had said.
|
;; held -- by a program that had said.
|
||||||
(let [vs (vec-new Shape)
|
(let [vs (vec-new Shape)
|
||||||
ms (map-new string Shape)]
|
ms (map-new str Shape)]
|
||||||
(push vs (Shape.Rect {.w 2 .h 3}))
|
(push vs (Shape.Rect {.w 2 .h 3}))
|
||||||
(push vs Shape.Empty)
|
(push vs Shape.Empty)
|
||||||
(put ms "only" (Shape.Tag {.name "in a map" .n 1}))
|
(put ms "only" (Shape.Tag {.name "in a map" .n 1}))
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
;;;; members here, which is what makes the pair a test rather than an
|
;;;; members here, which is what makes the pair a test rather than an
|
||||||
;;;; observation.
|
;;;; observation.
|
||||||
|
|
||||||
(defstruct Cell [name string id i32 alive bool heat f64])
|
(defstruct Cell [name str id i32 alive bool heat f64])
|
||||||
|
|
||||||
(defn tick [c (Ptr Cell) n i32] i32
|
(defn tick [c (Ptr Cell) n i32] i32
|
||||||
(let [bump (+ n 1)]
|
(let [bump (+ n 1)]
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
;;;; wrong, because it is the only one whose own alignment exceeds its first
|
;;;; wrong, because it is the only one whose own alignment exceeds its first
|
||||||
;;;; member's size.
|
;;;; member's size.
|
||||||
|
|
||||||
(defstruct Cell [alive bool heat f64 id i32 name string])
|
(defstruct Cell [alive bool heat f64 id i32 name str])
|
||||||
|
|
||||||
(defn tick [c (Ptr Cell) n i32] i32
|
(defn tick [c (Ptr Cell) n i32] i32
|
||||||
(let [bump (+ n 1)]
|
(let [bump (+ n 1)]
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
;;;; Argument 3 makes and destroys arenas in a loop, as many times as the
|
;;;; Argument 3 makes and destroys arenas in a loop, as many times as the
|
||||||
;;;; second argument says. A retired allocator is reused rather than kept, so
|
;;;; second argument says. A retired allocator is reused rather than kept, so
|
||||||
;;;; the loop's memory stays flat however long it runs.
|
;;;; the loop's memory stays flat however long it runs.
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)
|
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)
|
||||||
a (arena-new 4096)]
|
a (arena-new 4096)]
|
||||||
(cond
|
(cond
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
(set calls (+ calls 1))
|
(set calls (+ calls 1))
|
||||||
(Point {.x 3 .y 4}))
|
(Point {.x 3 .y 4}))
|
||||||
|
|
||||||
(defn show2 [label string a i32 b i32] ()
|
(defn show2 [label str a i32 b i32] ()
|
||||||
(print label)
|
(print label)
|
||||||
(print " ")
|
(print " ")
|
||||||
(print a)
|
(print a)
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
(defstruct Boom [why i32])
|
(defstruct Boom [why i32])
|
||||||
|
|
||||||
(defonce label string)
|
(defonce label str)
|
||||||
(defonce grid [4 i32])
|
(defonce grid [4 i32])
|
||||||
(defonce pressure i64)
|
(defonce pressure i64)
|
||||||
(defonce untouched i64 99)
|
(defonce untouched i64 99)
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
(defstruct Point [x f32 y f32])
|
(defstruct Point [x f32 y f32])
|
||||||
(defstruct Boom [why i32])
|
(defstruct Boom [why i32])
|
||||||
|
|
||||||
(defn look [n i64 label string] i64
|
(defn look [n i64 label str] i64
|
||||||
(let [p (Point {.x 1.5 .y 2.5})
|
(let [p (Point {.x 1.5 .y 2.5})
|
||||||
xs [10 20 30]
|
xs [10 20 30]
|
||||||
flag (> n 0)
|
flag (> n 0)
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
(defonce ticks i64)
|
(defonce ticks i64)
|
||||||
|
|
||||||
(defn parity [n i64] string
|
(defn parity [n i64] str
|
||||||
(let [out "even"]
|
(let [out "even"]
|
||||||
(unless (= 0 (% n 2))
|
(unless (= 0 (% n 2))
|
||||||
(set out "odd"))
|
(set out "odd"))
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
(defonce odd f64)
|
(defonce odd f64)
|
||||||
(defonce yes bool)
|
(defonce yes bool)
|
||||||
(defonce byte u8)
|
(defonce byte u8)
|
||||||
(defonce text string)
|
(defonce text str)
|
||||||
(defonce colour Colour)
|
(defonce colour Colour)
|
||||||
(defonce stray Colour)
|
(defonce stray Colour)
|
||||||
(defonce some (Option Point))
|
(defonce some (Option Point))
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
(defn hold [] i32
|
(defn hold [] i32
|
||||||
(set tv context/temp)
|
(set tv context/temp)
|
||||||
(let [r (fetch)]
|
(let [r (fetch)]
|
||||||
(println (string (i64->bytes 31)))
|
(println (str (i64->bytes 31)))
|
||||||
r))
|
r))
|
||||||
|
|
||||||
(defn main [] i32
|
(defn main [] i32
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
(defn hold [] i32
|
(defn hold [] i32
|
||||||
(set keep (vec-new u8 context/temp))
|
(set keep (vec-new u8 context/temp))
|
||||||
(push keep (u8 5))
|
(push keep (u8 5))
|
||||||
(let [s (string (i64->bytes 4242))
|
(let [s (str (i64->bytes 4242))
|
||||||
r (fetch)]
|
r (fetch)]
|
||||||
(println s)
|
(println s)
|
||||||
(println (length keep))
|
(println (length keep))
|
||||||
|
|||||||
@ -10,13 +10,13 @@
|
|||||||
;;;; at frame rate and the editor reads memory.
|
;;;; at frame rate and the editor reads memory.
|
||||||
(import agent "vendor:agent")
|
(import agent "vendor:agent")
|
||||||
|
|
||||||
(declare-c watch-i64 [name string x i64] i32 "flan_dev_watch_i64")
|
(declare-c watch-i64 [name str x i64] i32 "flan_dev_watch_i64")
|
||||||
(declare-c watch-f64 [name string x f64] i32 "flan_dev_watch_f64")
|
(declare-c watch-f64 [name str x f64] i32 "flan_dev_watch_f64")
|
||||||
(declare-c watch-str [name string s string] i32 "flan_dev_watch_str")
|
(declare-c watch-str [name str s str] i32 "flan_dev_watch_str")
|
||||||
;; The accumulator, for a value sampled from inside a hot loop. A scalar watch
|
;; The accumulator, for a value sampled from inside a hot loop. A scalar watch
|
||||||
;; there shows whichever iteration happened to run last, which is the case this
|
;; there shows whichever iteration happened to run last, which is the case this
|
||||||
;; exists for; see flan_dev.c, "A number sampled thousands of times a frame".
|
;; exists for; see flan_dev.c, "A number sampled thousands of times a frame".
|
||||||
(declare-c watch-num-i64 [name string x i64] i32 "flan_dev_watch_num_i64")
|
(declare-c watch-num-i64 [name str x i64] i32 "flan_dev_watch_num_i64")
|
||||||
|
|
||||||
(defonce ticks i64)
|
(defonce ticks i64)
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
;;;; exists and (get s :pause) is a place, where a plain map's absent key is
|
;;;; exists and (get s :pause) is a place, where a plain map's absent key is
|
||||||
;;;; not. dyn-slot-trap.flan has the refusals.
|
;;;; not. dyn-slot-trap.flan has the refusals.
|
||||||
|
|
||||||
(defclass state [pause bool step i32 speed f64 name string tag])
|
(defclass state [pause bool step i32 speed f64 name str tag])
|
||||||
|
|
||||||
;; A class is a slot type, and (Option T) admits nil beside a T.
|
;; A class is a slot type, and (Option T) admits nil beside a T.
|
||||||
(defclass node [owner state next (Option node) weight (Option f32)])
|
(defclass node [owner state next (Option node) weight (Option f32)])
|
||||||
|
|||||||
@ -45,7 +45,7 @@
|
|||||||
(defn pick [x dyn n i64] dyn x)
|
(defn pick [x dyn n i64] dyn x)
|
||||||
(defn pick-t [t T n i64] dyn (.d t))
|
(defn pick-t [t T n i64] dyn (.d t))
|
||||||
|
|
||||||
(defn show [label string v dyn] ()
|
(defn show [label str v dyn] ()
|
||||||
(churn)
|
(churn)
|
||||||
(println label (at v 0) (at v 1)))
|
(println label (at v 0) (at v 1)))
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
(defonce tv (Vec i64))
|
(defonce tv (Vec i64))
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)
|
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)
|
||||||
v (vec-new dyn)
|
v (vec-new dyn)
|
||||||
ar (arena-new 4096)]
|
ar (arena-new 4096)]
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
;;
|
;;
|
||||||
;; With an argument, the last slice runs past the end and traps.
|
;; With an argument, the last slice runs past the end and traps.
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [d (the dyn "hello")]
|
(let [d (the dyn "hello")]
|
||||||
(println (slice d))
|
(println (slice d))
|
||||||
(println (slice d 1))
|
(println (slice d 1))
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
(defn as-dyn [d dyn] dyn d)
|
(defn as-dyn [d dyn] dyn d)
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)
|
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)
|
||||||
s (state false 3 nil)]
|
s (state false 3 nil)]
|
||||||
(println "before")
|
(println "before")
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
(let [n (the i32 7)
|
(let [n (the i32 7)
|
||||||
f (the f32 1.5)
|
f (the f32 1.5)
|
||||||
b (the bool true)
|
b (the bool true)
|
||||||
s (the string "typed")]
|
s (the str "typed")]
|
||||||
(println (type-of nil))
|
(println (type-of nil))
|
||||||
(println (type-of true))
|
(println (type-of true))
|
||||||
(println (type-of 42))
|
(println (type-of 42))
|
||||||
|
|||||||
@ -54,7 +54,7 @@
|
|||||||
;; carries that pair, because a refusal cannot run.
|
;; carries that pair, because a refusal cannot run.
|
||||||
(defonce rows [2 (Vec i64)])
|
(defonce rows [2 (Vec i64)])
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [n (i32 (bytes->i64 (bytes-view (at args 1))))]
|
(let [n (i32 (bytes->i64 (bytes-view (at args 1))))]
|
||||||
(cond
|
(cond
|
||||||
(= n 0)
|
(= n 0)
|
||||||
|
|||||||
@ -66,7 +66,7 @@
|
|||||||
;; The struct says :name :hp :speed :boss? :drops :hitbox. These bytes have no
|
;; The struct says :name :hp :speed :boss? :drops :hitbox. These bytes have no
|
||||||
;; :speed and have a :level the struct has never heard of, which is what a
|
;; :speed and have a :level the struct has never heard of, which is what a
|
||||||
;; tuning file looks like a month after the program was built.
|
;; tuning file looks like a month after the program was built.
|
||||||
(defconst drifted string
|
(defconst drifted str
|
||||||
"{:name \"imp\" :hp 3 :level 7 :boss? true :drops [1] :hitbox {:w 1 :h 1 :offset {:x 0 :y 0}}}")
|
"{:name \"imp\" :hp 3 :level 7 :boss? true :drops [1] :hitbox {:w 1 :h 1 :offset {:x 0 :y 0}}}")
|
||||||
|
|
||||||
(defn show-drift [a Allocator] ()
|
(defn show-drift [a Allocator] ()
|
||||||
@ -93,7 +93,7 @@
|
|||||||
;; that — read-file answers an Option so that a malformed document is
|
;; that — read-file answers an Option so that a malformed document is
|
||||||
;; distinguishable from one that is literally nil — and a derived reader has to
|
;; distinguishable from one that is literally nil — and a derived reader has to
|
||||||
;; be at least as honest.
|
;; be at least as honest.
|
||||||
(defconst broken string "{:name \"orc\" :hp }")
|
(defconst broken str "{:name \"orc\" :hp }")
|
||||||
|
|
||||||
(defn show-broken [a Allocator] ()
|
(defn show-broken [a Allocator] ()
|
||||||
(handler-bind
|
(handler-bind
|
||||||
|
|||||||
@ -54,12 +54,12 @@
|
|||||||
|
|
||||||
;; The size of a set after the dedup, which is the whole of what the dedup can
|
;; The size of a set after the dedup, which is the whole of what the dedup can
|
||||||
;; be asked for.
|
;; be asked for.
|
||||||
(defn set-size [src string] ()
|
(defn set-size [src str] ()
|
||||||
(println (length (edn/read (bytes-view src)))))
|
(println (length (edn/read (bytes-view src)))))
|
||||||
|
|
||||||
;; Malformed input, told apart from the document `nil` by the cursor — the
|
;; Malformed input, told apart from the document `nil` by the cursor — the
|
||||||
;; return value alone cannot say it, and this is the spelling that can.
|
;; return value alone cannot say it, and this is the spelling that can.
|
||||||
(defn malformed? [src string] bool
|
(defn malformed? [src str] bool
|
||||||
(let [c (edn/cursor (bytes-view src))
|
(let [c (edn/cursor (bytes-view src))
|
||||||
t (edn/next (addr c))
|
t (edn/next (addr c))
|
||||||
v (edn/read-value (addr c) t)] ; the value is not the question here
|
v (edn/read-value (addr c) t)] ; the value is not the question here
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
;; wrong — off by the quote, off by the colon — would pass on the letters
|
;; wrong — off by the quote, off by the colon — would pass on the letters
|
||||||
;; alone.
|
;; alone.
|
||||||
|
|
||||||
(defn kind-letter [k i32] string
|
(defn kind-letter [k i32] str
|
||||||
(cond
|
(cond
|
||||||
(= k edn/tok-eof) "."
|
(= k edn/tok-eof) "."
|
||||||
(= k edn/tok-error) "!"
|
(= k edn/tok-error) "!"
|
||||||
@ -40,7 +40,7 @@
|
|||||||
(= k edn/tok-set-open) "#"
|
(= k edn/tok-set-open) "#"
|
||||||
:else "?"))
|
:else "?"))
|
||||||
|
|
||||||
(defn dump [src string] ()
|
(defn dump [src str] ()
|
||||||
(let [b (bytes-view src)
|
(let [b (bytes-view src)
|
||||||
c (edn/cursor b)
|
c (edn/cursor b)
|
||||||
t (edn/next (addr c))]
|
t (edn/next (addr c))]
|
||||||
@ -58,7 +58,7 @@
|
|||||||
;; The refusals. Asserted on the *reason*, not on the fact of failing: a
|
;; The refusals. Asserted on the *reason*, not on the fact of failing: a
|
||||||
;; tokenizer that answered err-unexpected-byte for every one of these would
|
;; tokenizer that answered err-unexpected-byte for every one of these would
|
||||||
;; pass a test that only checked that it failed.
|
;; pass a test that only checked that it failed.
|
||||||
(defn refusal [src string] ()
|
(defn refusal [src str] ()
|
||||||
(let [b (bytes-view src)
|
(let [b (bytes-view src)
|
||||||
c (edn/cursor b)]
|
c (edn/cursor b)]
|
||||||
(while (and (edn/ok? (addr c))
|
(while (and (edn/ok? (addr c))
|
||||||
@ -121,7 +121,7 @@
|
|||||||
(return e)))))
|
(return e)))))
|
||||||
e))
|
e))
|
||||||
|
|
||||||
(defn show-enemy [src string] ()
|
(defn show-enemy [src str] ()
|
||||||
(let [b (bytes-view src)
|
(let [b (bytes-view src)
|
||||||
c (edn/cursor b)
|
c (edn/cursor b)
|
||||||
e (read-enemy (addr c))]
|
e (read-enemy (addr c))]
|
||||||
|
|||||||
@ -20,13 +20,13 @@
|
|||||||
;; The default answer is a [u8]: bytes, because that is what an asset is.
|
;; The default answer is a [u8]: bytes, because that is what an asset is.
|
||||||
(let [a (embed "assets/a.txt")]
|
(let [a (embed "assets/a.txt")]
|
||||||
(println (length a)) ; 13
|
(println (length a)) ; 13
|
||||||
(print (string a))) ; hello from a
|
(print (str a))) ; hello from a
|
||||||
|
|
||||||
;; `string` is the second spelling, not a different meaning for the same
|
;; `string` is the second spelling, not a different meaning for the same
|
||||||
;; text. With structural equality and nothing that converts one container
|
;; text. With structural equality and nothing that converts one container
|
||||||
;; into another -- implicit widening is numbers only -- one form that changes
|
;; into another -- implicit widening is numbers only -- one form that changes
|
||||||
;; type with its context would be a wart.
|
;; type with its context would be a wart.
|
||||||
(println (embed "assets/b.bin" string)) ; BBB
|
(println (embed "assets/b.bin" str)) ; BBB
|
||||||
|
|
||||||
;; Byte-exact, including bytes no text encoding would survive: emit.ml's
|
;; Byte-exact, including bytes no text encoding would survive: emit.ml's
|
||||||
;; escape hex-escapes everything outside printable ASCII, so a PNG makes the
|
;; escape hex-escapes everything outside printable ASCII, so a PNG makes the
|
||||||
@ -50,7 +50,7 @@
|
|||||||
;; there are no generics.
|
;; there are no generics.
|
||||||
(let [all (slice assets 0 (length assets))]
|
(let [all (slice assets 0 (length assets))]
|
||||||
(match (embed-find all "b.bin")
|
(match (embed-find all "b.bin")
|
||||||
(Some b) (println (string b)) ; BBB
|
(Some b) (println (str b)) ; BBB
|
||||||
None (println "missing"))
|
None (println "missing"))
|
||||||
(match (embed-find all "nope.txt")
|
(match (embed-find all "nope.txt")
|
||||||
(Some _) (println "found")
|
(Some _) (println "found")
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
;; An enum parameter driven by a loop variable, which is the shape this exists
|
;; An enum parameter driven by a loop variable, which is the shape this exists
|
||||||
;; for: the caller has an index, not a member.
|
;; for: the caller has an index, not a member.
|
||||||
(defn name-at [i i32] string
|
(defn name-at [i i32] str
|
||||||
(let [k (K i)]
|
(let [k (K i)]
|
||||||
(cond (= k :lo) "lo"
|
(cond (= k :lo) "lo"
|
||||||
(= k :mid) "mid"
|
(= k :mid) "mid"
|
||||||
|
|||||||
@ -10,13 +10,13 @@
|
|||||||
(defn double [x i32] i32 (* x 2))
|
(defn double [x i32] i32 (* x 2))
|
||||||
(defn negate [x i32] i32 (- 0 x))
|
(defn negate [x i32] i32 (- 0 x))
|
||||||
|
|
||||||
(defstruct Ops [name string run (CFn [i32] i32)])
|
(defstruct Ops [name str run (CFn [i32] i32)])
|
||||||
|
|
||||||
(defonce table [3 (CFn [i32] i32)])
|
(defonce table [3 (CFn [i32] i32)])
|
||||||
(defonce hook (CFn [i32] i32))
|
(defonce hook (CFn [i32] i32))
|
||||||
(defonce evaluated i32 0)
|
(defonce evaluated i32 0)
|
||||||
(defonce caught i32 0)
|
(defonce caught i32 0)
|
||||||
(defonce seen string "")
|
(defonce seen str "")
|
||||||
|
|
||||||
(defn arg [x i32] i32
|
(defn arg [x i32] i32
|
||||||
(set evaluated (+ evaluated 1))
|
(set evaluated (+ evaluated 1))
|
||||||
@ -27,7 +27,7 @@
|
|||||||
(do (print (f (arg x))) (println ""))
|
(do (print (f (arg x))) (println ""))
|
||||||
(continue [] (println "empty"))))
|
(continue [] (println "empty"))))
|
||||||
|
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(set (at table 0) double)
|
(set (at table 0) double)
|
||||||
(set (at table 2) negate)
|
(set (at table 2) negate)
|
||||||
(let [ops (Ops {.name "half-built"})]
|
(let [ops (Ops {.name "half-built"})]
|
||||||
|
|||||||
@ -51,7 +51,7 @@
|
|||||||
(push msg who)
|
(push msg who)
|
||||||
(fn [] (i64 (length msg)))))
|
(fn [] (i64 (length msg)))))
|
||||||
|
|
||||||
(defstruct Button [label string on-click (Option (Fn [] i64))])
|
(defstruct Button [label str on-click (Option (Fn [] i64))])
|
||||||
|
|
||||||
(defonce handler (Option (Fn [i64] i64)))
|
(defonce handler (Option (Fn [i64] i64)))
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
(push junk true))))
|
(push junk true))))
|
||||||
|
|
||||||
(defn main [] i32
|
(defn main [] i32
|
||||||
(let [ops (map-new string (Fn [i32] i32))
|
(let [ops (map-new str (Fn [i32] i32))
|
||||||
many (map-new i32 (Fn [i32] i32))
|
many (map-new i32 (Fn [i32] i32))
|
||||||
rows (map-new i32 dyn)]
|
rows (map-new i32 dyn)]
|
||||||
(put ops "one" (adder 1))
|
(put ops "one" (adder 1))
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
(defn show [x f64 p i32] ()
|
(defn show [x f64 p i32] ()
|
||||||
(let [v (format-f64 x p)]
|
(let [v (format-f64 x p)]
|
||||||
(println (string (slice v)))
|
(println (str (slice v)))
|
||||||
(free v)))
|
(free v)))
|
||||||
|
|
||||||
(defn main [] i32
|
(defn main [] i32
|
||||||
@ -95,6 +95,6 @@
|
|||||||
(let [f (format-f64 0.0166667 4)]
|
(let [f (format-f64 0.0166667 4)]
|
||||||
(append (addr b) (slice f))
|
(append (addr b) (slice f))
|
||||||
(free f))
|
(free f))
|
||||||
(println (string (slice b))) ; fps 59.9 / frame 0.0167
|
(println (str (slice b))) ; fps 59.9 / frame 0.0167
|
||||||
(free b))
|
(free b))
|
||||||
0)
|
0)
|
||||||
|
|||||||
@ -109,7 +109,7 @@
|
|||||||
(when (!= (.brush world) (.brush world-backup)) (set d (+ d 1)))
|
(when (!= (.brush world) (.brush world-backup)) (set d (+ d 1)))
|
||||||
d))
|
d))
|
||||||
|
|
||||||
(defn show [name string n i64] ()
|
(defn show [name str n i64] ()
|
||||||
(print name) (print " ") (print n) (println ""))
|
(print name) (print " ") (print n) (println ""))
|
||||||
|
|
||||||
(defn dump [] ()
|
(defn dump [] ()
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
;;;; 3 frees a view of an array, which no allocator handed out; 4 frees a
|
;;;; 3 frees a view of an array, which no allocator handed out; 4 frees a
|
||||||
;;;; Vec's storage through a let-bound view of it; 5 frees a formatted
|
;;;; Vec's storage through a let-bound view of it; 5 frees a formatted
|
||||||
;;;; number's text, which the temp allocator holds.
|
;;;; number's text, which the temp allocator holds.
|
||||||
(defn main [args [string]] i32
|
(defn main [args [str]] i32
|
||||||
(let [which (if (> (length args) 1) (bytes->i64 (bytes-view (at args 1))) 0)
|
(let [which (if (> (length args) 1) (bytes->i64 (bytes-view (at args 1))) 0)
|
||||||
a (arena-new 4096)]
|
a (arena-new 4096)]
|
||||||
(cond
|
(cond
|
||||||
@ -26,7 +26,7 @@
|
|||||||
(let [b (bytes "heap")
|
(let [b (bytes "heap")
|
||||||
c (bytes "arena" a)
|
c (bytes "arena" a)
|
||||||
d (clone (slice [1.5 2.5]) (heap-allocator))]
|
d (clone (slice [1.5 2.5]) (heap-allocator))]
|
||||||
(println (string b) (string c) (at d 1))
|
(println (str b) (str c) (at d 1))
|
||||||
(free b)
|
(free b)
|
||||||
(free c a)
|
(free c a)
|
||||||
(free d (heap-allocator))))
|
(free d (heap-allocator))))
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
;;;; position that takes i32 takes int, the cast head included, and nothing
|
;;;; position that takes i32 takes int, the cast head included, and nothing
|
||||||
;;;; downstream of the checker ever hears the word.
|
;;;; downstream of the checker ever hears the word.
|
||||||
;;;;
|
;;;;
|
||||||
;;;; The rest of the foreign spellings -- long, double, integer, str -- are
|
;;;; The rest of the foreign spellings -- long, double, integer, string -- are
|
||||||
;;;; still refusals that teach the Flan name, which a program cannot show
|
;;;; still refusals that teach the Flan name, which a program cannot show
|
||||||
;;;; because it would not compile; that half is in test_flan.ml.
|
;;;; because it would not compile; that half is in test_flan.ml.
|
||||||
|
|
||||||
@ -41,7 +41,7 @@
|
|||||||
;; Generic type arguments: the element type of a Vec and both halves of a
|
;; Generic type arguments: the element type of a Vec and both halves of a
|
||||||
;; Map, named with the alias.
|
;; Map, named with the alias.
|
||||||
(let [v (vec-new int)
|
(let [v (vec-new int)
|
||||||
m (map-new string int)]
|
m (map-new str int)]
|
||||||
(push v 10)
|
(push v 10)
|
||||||
(push v 20)
|
(push v 20)
|
||||||
(put m "k" 30)
|
(put m "k" 30)
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
;; its backslash still on it; that is the divergence between the tokenizer and
|
;; its backslash still on it; that is the divergence between the tokenizer and
|
||||||
;; string-of, and this is where it is visible.
|
;; string-of, and this is where it is visible.
|
||||||
|
|
||||||
(defn kind-letter [k i32] string
|
(defn kind-letter [k i32] str
|
||||||
(cond
|
(cond
|
||||||
(= k json/tok-eof) "."
|
(= k json/tok-eof) "."
|
||||||
(= k json/tok-error) "!"
|
(= k json/tok-error) "!"
|
||||||
@ -61,7 +61,7 @@
|
|||||||
(= k json/tok-comma) ","
|
(= k json/tok-comma) ","
|
||||||
:else "?"))
|
:else "?"))
|
||||||
|
|
||||||
(defn dump [src string] ()
|
(defn dump [src str] ()
|
||||||
(let [b (bytes-view src)
|
(let [b (bytes-view src)
|
||||||
c (json/cursor b)
|
c (json/cursor b)
|
||||||
t (json/next (addr c))]
|
t (json/next (addr c))]
|
||||||
@ -79,7 +79,7 @@
|
|||||||
;; The refusals. Asserted on the *reason* and not on the fact of failing: a
|
;; The refusals. Asserted on the *reason* and not on the fact of failing: a
|
||||||
;; tokenizer answering one generic error for all of these would pass a test
|
;; tokenizer answering one generic error for all of these would pass a test
|
||||||
;; that only checked that it stopped.
|
;; that only checked that it stopped.
|
||||||
(defn refusal [src string] ()
|
(defn refusal [src str] ()
|
||||||
(let [b (bytes-view src)
|
(let [b (bytes-view src)
|
||||||
c (json/cursor b)]
|
c (json/cursor b)]
|
||||||
(while (and (json/ok? (addr c))
|
(while (and (json/ok? (addr c))
|
||||||
@ -96,9 +96,9 @@
|
|||||||
(Bool [b bool])
|
(Bool [b bool])
|
||||||
(Int [n i64])
|
(Int [n i64])
|
||||||
(Float [x f64])
|
(Float [x f64])
|
||||||
(Text [s string])
|
(Text [s str])
|
||||||
(Array [items (Vec Value)])
|
(Array [items (Vec Value)])
|
||||||
(Object [entries (Map string Value)])])
|
(Object [entries (Map str Value)])])
|
||||||
|
|
||||||
;; One token in hand, and the cursor for whatever the token opens. An array and
|
;; One token in hand, and the cursor for whatever the token opens. An array and
|
||||||
;; an object recurse; everything else is a leaf.
|
;; an object recurse; everything else is a leaf.
|
||||||
@ -160,7 +160,7 @@
|
|||||||
;; same string-of the values use, so the map owns its keys and the source
|
;; same string-of the values use, so the map owns its keys and the source
|
||||||
;; buffer is not in the picture.
|
;; buffer is not in the picture.
|
||||||
(= (.kind t) json/tok-object-open)
|
(= (.kind t) json/tok-object-open)
|
||||||
(let [entries (map-new string Value)
|
(let [entries (map-new str Value)
|
||||||
k (json/next c)
|
k (json/next c)
|
||||||
more (and (json/ok? c) (!= (.kind k) json/tok-object-close))]
|
more (and (json/ok? c) (!= (.kind k) json/tok-object-close))]
|
||||||
(while more
|
(while more
|
||||||
@ -234,14 +234,14 @@
|
|||||||
(match (get entries "xs") (Some x) (sum-ints x) None (i64 0))
|
(match (get entries "xs") (Some x) (sum-ints x) None (i64 0))
|
||||||
_ (i64 0)))
|
_ (i64 0)))
|
||||||
|
|
||||||
(defn describe [v Value] string
|
(defn describe [v Value] str
|
||||||
(match v
|
(match v
|
||||||
Null "null" (Bool _b) "bool" (Int _n) "int" (Float _x) "float"
|
Null "null" (Bool _b) "bool" (Int _n) "int" (Float _x) "float"
|
||||||
(Text _s) "string" (Array _i) "array" (Object _e) "object"))
|
(Text _s) "string" (Array _i) "array" (Object _e) "object"))
|
||||||
|
|
||||||
;; The text at a top-level key, or a marker. Used after the source buffer has
|
;; The text at a top-level key, or a marker. Used after the source buffer has
|
||||||
;; been scribbled over, which is the whole reason it exists.
|
;; been scribbled over, which is the whole reason it exists.
|
||||||
(defn text-at [v Value key string] string
|
(defn text-at [v Value key str] str
|
||||||
(match v
|
(match v
|
||||||
(Object entries)
|
(Object entries)
|
||||||
(match (get entries key)
|
(match (get entries key)
|
||||||
@ -257,7 +257,7 @@
|
|||||||
;; A reader's own refusals, driven end to end: read the whole document and then
|
;; A reader's own refusals, driven end to end: read the whole document and then
|
||||||
;; report what the cursor says. The position matters as much as the message —
|
;; report what the cursor says. The position matters as much as the message —
|
||||||
;; a trailing comma reported at the opening brace would be useless.
|
;; a trailing comma reported at the opening brace would be useless.
|
||||||
(defn reject [src string] ()
|
(defn reject [src str] ()
|
||||||
(let [b (bytes-view src)
|
(let [b (bytes-view src)
|
||||||
c (json/cursor b)
|
c (json/cursor b)
|
||||||
t (json/next (addr c))]
|
t (json/next (addr c))]
|
||||||
|
|||||||
@ -55,7 +55,7 @@
|
|||||||
(defn inf-f32? [x f32] bool
|
(defn inf-f32? [x f32] bool
|
||||||
(and (= x (* x (f32 2.0))) (!= x (f32 0.0))))
|
(and (= x (* x (f32 2.0))) (!= x (f32 0.0))))
|
||||||
|
|
||||||
(defn say [name string ok bool] ()
|
(defn say [name str ok bool] ()
|
||||||
(print name)
|
(print name)
|
||||||
(print " ")
|
(print " ")
|
||||||
(println (if ok "ok" "WRONG")))
|
(println (if ok "ok" "WRONG")))
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
(defmacro thru [& body]
|
(defmacro thru [& body]
|
||||||
`(do ~@body))
|
`(do ~@body))
|
||||||
|
|
||||||
(defn g [s string] i32 0)
|
(defn g [s str] i32 0)
|
||||||
|
|
||||||
(defn main [] i32
|
(defn main [] i32
|
||||||
(thru
|
(thru
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
;;;; the move, which is the point: the test for the feature is the corpus that
|
;;;; the move, which is the point: the test for the feature is the corpus that
|
||||||
;;;; was written against the special form.
|
;;;; was written against the special form.
|
||||||
|
|
||||||
(defn classify [n i32] string
|
(defn classify [n i32] str
|
||||||
(let [out "even"]
|
(let [out "even"]
|
||||||
(unless (= 0 (% n 2))
|
(unless (= 0 (% n 2))
|
||||||
(set out "odd"))
|
(set out "odd"))
|
||||||
|
|||||||
@ -2,13 +2,13 @@
|
|||||||
;; Each element is hashed and compared by its own pair, so two keys built from
|
;; Each element is hashed and compared by its own pair, so two keys built from
|
||||||
;; different storage with the same bytes are the same key.
|
;; different storage with the same bytes are the same key.
|
||||||
|
|
||||||
(defstruct Tag [name string n i32])
|
(defstruct Tag [name str n i32])
|
||||||
|
|
||||||
(defn main [] i32
|
(defn main [] i32
|
||||||
(let [m (map-new [2 string] i32)
|
(let [m (map-new [2 str] i32)
|
||||||
a (the [2 string] ["ab" "cd"])
|
a (the [2 str] ["ab" "cd"])
|
||||||
b (the [2 string] [(slice "xab" 1) (slice "cdx" 0 2)])
|
b (the [2 str] [(slice "xab" 1) (slice "cdx" 0 2)])
|
||||||
c (the [2 string] ["ab" "ce"])]
|
c (the [2 str] ["ab" "ce"])]
|
||||||
(put m a 1)
|
(put m a 1)
|
||||||
(put m c 3)
|
(put m c 3)
|
||||||
(println (or-else (get m b) -1))
|
(println (or-else (get m b) -1))
|
||||||
|
|||||||
@ -64,7 +64,7 @@
|
|||||||
(set failures (+ failures 1))
|
(set failures (+ failures 1))
|
||||||
(set-alloc-budget tight (* 8 (alloc-budget tight)))
|
(set-alloc-budget tight (* 8 (alloc-budget tight)))
|
||||||
(invoke-restart 'retry))]
|
(invoke-restart 'retry))]
|
||||||
(let [m (map-new string i32 tight)]
|
(let [m (map-new str i32 tight)]
|
||||||
(reserve m 200)
|
(reserve m 200)
|
||||||
(println (length m)) ; 0
|
(println (length m)) ; 0
|
||||||
(put m "a" 1)
|
(put m "a" 1)
|
||||||
|
|||||||
@ -65,7 +65,7 @@
|
|||||||
(defstruct Point [x i32 y i32])
|
(defstruct Point [x i32 y i32])
|
||||||
|
|
||||||
(defn wider-entries [] ()
|
(defn wider-entries [] ()
|
||||||
(let [m (map-new string Point)]
|
(let [m (map-new str Point)]
|
||||||
(put m "a" (Point {.x 1 .y 2}))
|
(put m "a" (Point {.x 1 .y 2}))
|
||||||
(put m "bb" (Point {.x 3 .y 4}))
|
(put m "bb" (Point {.x 3 .y 4}))
|
||||||
(put m "ccc" (Point {.x 5 .y 6}))
|
(put m "ccc" (Point {.x 5 .y 6}))
|
||||||
|
|||||||
@ -28,8 +28,8 @@
|
|||||||
(free vs))
|
(free vs))
|
||||||
(free m))
|
(free m))
|
||||||
;; A string key, and a map that never allocated.
|
;; A string key, and a map that never allocated.
|
||||||
(let [names (map-new string i32)
|
(let [names (map-new str i32)
|
||||||
none (map-new string i32)]
|
none (map-new str i32)]
|
||||||
(put names "b" 2)
|
(put names "b" 2)
|
||||||
(put names "a" 1)
|
(put names "a" 1)
|
||||||
(let [ks (map-keys names)
|
(let [ks (map-keys names)
|
||||||
|
|||||||
@ -88,7 +88,7 @@
|
|||||||
(print (length g)) (println "") ; 399
|
(print (length g)) (println "") ; 399
|
||||||
(free g))
|
(free g))
|
||||||
|
|
||||||
(let [s (map-new string i32)]
|
(let [s (map-new str i32)]
|
||||||
(put s "alpha" 1)
|
(put s "alpha" 1)
|
||||||
(put s "beta" 2)
|
(put s "beta" 2)
|
||||||
(match (map-remove s "alpha")
|
(match (map-remove s "alpha")
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
;;;; version gets wrong, and the numbers differ per failure so a single wrong
|
;;;; version gets wrong, and the numbers differ per failure so a single wrong
|
||||||
;;;; answer names its own cause.
|
;;;; answer names its own cause.
|
||||||
(defstruct Cell [x i32 y i32])
|
(defstruct Cell [x i32 y i32])
|
||||||
(defstruct Named [tag string n i32])
|
(defstruct Named [tag str n i32])
|
||||||
(defenum Suit [hearts 0 spades 1 clubs 2])
|
(defenum Suit [hearts 0 spades 1 clubs 2])
|
||||||
|
|
||||||
;;;; (8) A map crosses a function boundary in both directions. Returning one
|
;;;; (8) A map crosses a function boundary in both directions. Returning one
|
||||||
@ -103,7 +103,7 @@
|
|||||||
|
|
||||||
;; (6) Upsert replaces and does not grow the length, and reserve means room
|
;; (6) Upsert replaces and does not grow the length, and reserve means room
|
||||||
;; for n *entries* — n still under the load factor — not n slots.
|
;; for n *entries* — n still under the load factor — not n slots.
|
||||||
(let [u (map-new string i32)]
|
(let [u (map-new str i32)]
|
||||||
(reserve u 100)
|
(reserve u 100)
|
||||||
(put u "k" 1)
|
(put u "k" 1)
|
||||||
(put u "k" 2)
|
(put u "k" 2)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user