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
|
||||
(declare-c set-seed [seed u32] "set_seed")
|
||||
(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
|
||||
;; 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
|
||||
|
||||
** NEXT str and String
|
||||
Decided 2026-09-25: the typed read-only text is =str= (renamed from =string=); =String=
|
||||
is new, owned, growable, always valid UTF-8, through an allocator. The prelude's text
|
||||
Decided 2026-09-25: the typed read-only text is =str= (the rename from =string= is
|
||||
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
|
||||
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
|
||||
@ -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.
|
||||
|
||||
** 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
|
||||
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.
|
||||
|
||||
@ -118,7 +118,7 @@
|
||||
;; 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
|
||||
;; 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)
|
||||
(do (println "usage: calc-me \"1 + 2 * 3\"") 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 `declare-c` may return `string`. 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
|
||||
A `declare-c` may return `str`. The C wrapper answers the pointer and its length, and the generated Flan wrapper is
|
||||
`(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
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
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
|
||||
@ -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:
|
||||
`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-`.
|
||||
|
||||
### rlgl is its own package
|
||||
@ -1167,7 +1167,7 @@ i8..i64 / u8..u64 i8..i64 signedness lives in the ops
|
||||
f32 f64 float double
|
||||
bool i1
|
||||
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
|
||||
(Ptr T) ptr opaque pointers
|
||||
(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.
|
||||
|
||||
**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
|
||||
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,
|
||||
@ -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
|
||||
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.
|
||||
- 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
|
||||
@ -3564,7 +3564,7 @@ the payload at offset 8, and 40/8 for a struct holding one.
|
||||
[Empty
|
||||
(Dot [x f64 y f64])
|
||||
(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}) ; 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
|
||||
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
|
||||
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
|
||||
*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.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
`(string (slice v))` is the round trip, free precisely because the layouts are identical.
|
||||
have moved up into the code; `string-from-bytes` turned out to be the `str` builtin all along, and
|
||||
`(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*
|
||||
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
|
||||
|
||||
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
|
||||
(`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
|
||||
@ -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
|
||||
`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
|
||||
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
|
||||
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
|
||||
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
|
||||
`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.
|
||||
|
||||
**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:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
@ -7079,7 +7079,7 @@ expression the checker walks can live.
|
||||
### 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
|
||||
`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
|
||||
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
|
||||
@ -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.
|
||||
|
||||
**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.*
|
||||
|
||||
**`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
|
||||
one parameter on three functions.
|
||||
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
|
||||
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
|
||||
> `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;
|
||||
> `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
|
||||
> `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
|
||||
@ -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
|
||||
*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",
|
||||
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 "いろはに"
|
||||
b (bytes text)
|
||||
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))
|
||||
```
|
||||
|
||||
@ -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
|
||||
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
|
||||
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:
|
||||
|
||||
```
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
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
|
||||
`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)))`
|
||||
is the C's `char *ptr` and compiles to nothing: a `string` and a `[u8]` are the same two
|
||||
**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 `str` and a `[u8]` are the same two
|
||||
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
|
||||
@ -852,7 +852,7 @@ example.
|
||||
> 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
|
||||
`[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
|
||||
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.
|
||||
|
||||
**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
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -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:
|
||||
|
||||
```flan
|
||||
(declare-c watch-num-i64 [name string 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-i64 [name str x i64] i32 "flan_dev_watch_num_i64")
|
||||
(declare-c watch-num-f64 [name str x f64] i32 "flan_dev_watch_num_f64")
|
||||
|
||||
(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:
|
||||
|
||||
```flan
|
||||
(declare-c watch-i64 [name string x i64] i32 "flan_dev_watch_i64")
|
||||
(declare-c watch-f64 [name string x f64] i32 "flan_dev_watch_f64")
|
||||
(declare-c watch-str [name string s string] i32 "flan_dev_watch_str")
|
||||
(declare-c watch-i64 [name str x i64] i32 "flan_dev_watch_i64")
|
||||
(declare-c watch-f64 [name str x f64] i32 "flan_dev_watch_f64")
|
||||
(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
|
||||
|
||||
@ -717,7 +717,7 @@ visits the source of the one it lands on."
|
||||
|
||||
(defun flan-cnr-param-types (params)
|
||||
"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."
|
||||
(let ((form (and (stringp 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)
|
||||
;; The package half of a qualified name, as `flan-mode' draws it.
|
||||
("\\_<\\([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)
|
||||
("\\_<\\$[^][ \t\n(){},;\":]*" . font-lock-type-face)
|
||||
;; A character literal, `\c' or `\space'.
|
||||
|
||||
@ -175,15 +175,15 @@ face says.")
|
||||
;; containers and memory
|
||||
"length" "at" "slice" "slice-from" "addr" "deref"
|
||||
;; options, bytes, the host
|
||||
"Some" "bytes" "bytes-view" "string"
|
||||
"Some" "bytes" "bytes-view" "str"
|
||||
"bytes->f64" "bytes->i64" "f64->bytes" "i64->bytes"
|
||||
"write-stdout" "print" "println" "exit" "argv")
|
||||
"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
|
||||
builtins and not as keywords. `string' is in this list and in the type rule
|
||||
below and means a different thing in each: `(string b)' converts and a bare
|
||||
`string' names a type, which the rules tell apart by the paren.
|
||||
builtins and not as keywords. `str' is in this list and in the type rule
|
||||
below and means a different thing in each: `(str b)' converts and a bare
|
||||
`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
|
||||
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
|
||||
;; advertise a spelling the parser rejects, which is the same reason
|
||||
;; `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)
|
||||
;; A type variable, `$t', which is what a generic `defn' names its
|
||||
;; 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 "()")
|
||||
(:report "Try again with another path"
|
||||
:at "/src/files.flan:12:3" :arity 1
|
||||
:params "(string)")
|
||||
:params "(str)")
|
||||
(:report "" :at nil :arity 0 :params "()")))))
|
||||
(text (with-current-buffer buf (buffer-string))))
|
||||
(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"
|
||||
(string-match-p "again (/src/files.flan:12:3)" text))
|
||||
(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))
|
||||
(test-flan--check "one with no report and no source shows its name alone"
|
||||
(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.
|
||||
(test-flan--check "a restart's parameter types are read from their spelling"
|
||||
(equal (flan-cnr-param-types "(i64 (Option string))")
|
||||
'("i64" "(Option string)")))
|
||||
(equal (flan-cnr-param-types "(i64 (Option str))")
|
||||
'("i64" "(Option str)")))
|
||||
(let ((sent nil) (asked nil))
|
||||
(let ((flan-cnr-request-function
|
||||
(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.
|
||||
(let ((text (with-current-buffer
|
||||
(test-flan--cnr (list :condition "Missing" :restarts '("retry")
|
||||
:fields '(("path" "string" nil)
|
||||
:fields '(("path" "str" nil)
|
||||
("tried" "i32" "3"))
|
||||
:fields-why "the stop's value was not readable"))
|
||||
(buffer-string))))
|
||||
(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"
|
||||
(and (string-match-p "not read — the stop's value" text)
|
||||
(= 1 (seq-count
|
||||
@ -1696,7 +1696,7 @@ would be overwritten. Look again and re-do the edit")
|
||||
(let ((text (with-current-buffer
|
||||
(test-flan--cnr
|
||||
(list :condition "Missing" :restarts '("retry" "a" "retry")
|
||||
:fields '(("path" "string" nil))
|
||||
:fields '(("path" "str" nil))
|
||||
:stack (list (list :fn "f" :fetched t :locals nil))))
|
||||
(buffer-string))))
|
||||
(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"
|
||||
:restarts ("retry")))
|
||||
("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))
|
||||
(buffer-string))))
|
||||
(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)
|
||||
"sim/Missing"))
|
||||
(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
|
||||
;; daemon answers only the first — so the values fall back to the
|
||||
;; 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.
|
||||
:globals '(("grid" "[4 i32]" "[7 5 0 0]" (0 1))
|
||||
("pressure" "i64" "12" (0))
|
||||
("label" "string" "\"running\"" (1)))))
|
||||
("label" "str" "\"running\"" (1)))))
|
||||
(buf (test-flan--cnr state))
|
||||
(text (with-current-buffer buf (buffer-string))))
|
||||
(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
|
||||
(list :condition "Boom" :restarts '("retry")
|
||||
: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-skipped
|
||||
'(("0: sim/inner" "this frame's body was redefined since it was entered"))))
|
||||
|
||||
@ -111,13 +111,13 @@
|
||||
;; there.
|
||||
(test-flan-mode--check
|
||||
"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)
|
||||
n)")
|
||||
|
||||
(test-flan-mode--check
|
||||
"and a defn without one indents it the same"
|
||||
"(defn show-trim [s string] ()
|
||||
"(defn show-trim [s str] ()
|
||||
(print s)
|
||||
(println \"\"))")
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
(defconst gesture-log-size 20)
|
||||
(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,
|
||||
;; 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
|
||||
@ -103,7 +103,7 @@
|
||||
;; belongs under a :gesture-none guard. The C's switch over single members
|
||||
;; hides both; a range test cannot.
|
||||
|
||||
(defn gesture-name [g rl/Gesture] string
|
||||
(defn gesture-name [g rl/Gesture] str
|
||||
(cond
|
||||
(= g :gesture-none) "None"
|
||||
(= g :gesture-tap) "Tap"
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
(defconst max-gesture-strings 20)
|
||||
|
||||
(defonce gesture-log [max-gesture-strings string])
|
||||
(defonce gesture-log [max-gesture-strings str])
|
||||
(defonce gestures-count i32)
|
||||
(defonce current-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
|
||||
;; gesture logs the empty string, which draws nothing, which is what falling
|
||||
;; 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
|
||||
(= g :gesture-tap) "GESTURE TAP"
|
||||
(= g :gesture-double-tap) "GESTURE DOUBLETAP"
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
;; and a table of one-character strings; (string b) makes the
|
||||
;; number a string with no instructions, so it is one draw-text and
|
||||
;; 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
|
||||
rl/black))))
|
||||
|
||||
|
||||
@ -188,7 +188,7 @@
|
||||
;; Not in the C: which button the search picked, as a number, so the
|
||||
;; headless case and the window agree about the same thing.
|
||||
(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
|
||||
rl/lightgray))
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
;; 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
|
||||
;; 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)
|
||||
(let [x (+ 10 (rl/measure-text label 10))]
|
||||
(if (rl/window-state? flag)
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
;;
|
||||
;; 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.
|
||||
(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/measure-text s size))
|
||||
|
||||
@ -74,7 +74,7 @@
|
||||
;; the old note about i32's most negative value — it is widened to i64 before
|
||||
;; formatting, so there is no negation to wrap.
|
||||
(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
|
||||
;; wider than `width` is drawn in full rather than truncated, which is what
|
||||
|
||||
@ -135,7 +135,7 @@
|
||||
(let [b (bytes-view text)]
|
||||
(if (>= off (length b))
|
||||
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.
|
||||
;;
|
||||
|
||||
@ -122,7 +122,7 @@
|
||||
(i32 (.width text-box)) (i32 (.height text-box))
|
||||
(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)
|
||||
40 rl/maroon)
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
i 0]
|
||||
(while (< i length)
|
||||
(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
|
||||
;; stop; this walks on one byte at a time so the bad bytes get drawn.
|
||||
(when (= cp (i32 \?)) (set size 1))
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
;; the C — see the header comment.
|
||||
(let [b (bytes-view message)
|
||||
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 "HOLD [SPACE] to SPEED UP!" 239 300 20 rl/lightgray))))
|
||||
|
||||
@ -80,7 +80,7 @@
|
||||
(defconst proc-flip-vertical 7)
|
||||
(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.
|
||||
(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,
|
||||
strings as strings. [Shim] generates the C that flattens it and rewrites
|
||||
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. *)
|
||||
| DeclareC of fn * string
|
||||
|
||||
125
lib/check.ml
125
lib/check.ml
@ -570,7 +570,7 @@ let foreign_spelling = function
|
||||
| "byte" -> Some "u8"
|
||||
| "double" -> Some "f64"
|
||||
| "boolean" -> Some "bool"
|
||||
| "str" -> Some "string"
|
||||
| "string" -> Some "str"
|
||||
| _ -> None
|
||||
|
||||
(* 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 ->
|
||||
match n with
|
||||
| "bool" -> Types.Bool
|
||||
| "string" -> Types.String
|
||||
| "str" -> Types.String
|
||||
(* 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
|
||||
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
|
||||
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]
|
||||
...)] has no good reading: taken as written it is a parameter called [i64],
|
||||
which shadows nothing but confuses everything, and the likelier intent is a
|
||||
pair written backwards. Refusing here costs a rename in the one program that
|
||||
meant it and closes the one place where this rule could still hand somebody
|
||||
a signature they did not write. *)
|
||||
A name that *is* a type name pairs only when a type follows it: [[str str]]
|
||||
has one reading. [(defn f [i64 x] ...)] has two — a dyn parameter called
|
||||
[i64], or a pair written backwards — so it is refused rather than handed
|
||||
back as a signature nobody wrote. *)
|
||||
let is_type_name env n =
|
||||
Types.ikind_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.structs 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
|
||||
second parameter and needs no word about parameter vectors. *)
|
||||
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
|
||||
| Some m when fln ->
|
||||
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
|
||||
"a parameter's name was expected here, and this is a type. Parameters \
|
||||
are [name Type ...]"
|
||||
| Ast.Pname (n, loc) :: rest when is_type_name env n ->
|
||||
ignore rest;
|
||||
(* A parameter may share a type's name — [str] is a common name for text —
|
||||
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
|
||||
"%s names a type, so it cannot also be this parameter's name. Write \
|
||||
[name %s], or rename the parameter" n n
|
||||
"%s names a type, and no type follows this parameter called %s. Give \
|
||||
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. *)
|
||||
| Ast.Pname (n, _) :: Ast.Pname ("_", 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. *)
|
||||
|| n <> tyvar_bare n
|
||||
|| 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.datas n
|
||||
|| Hashtbl.mem ctx.env.unions n
|
||||
|| Hashtbl.mem ctx.env.enums 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
|
||||
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
|
||||
@ -10427,6 +10459,7 @@ and vec_new_elem ctx ~want loc args =
|
||||
(match want with
|
||||
| Some (Types.Vec t) -> t, args
|
||||
| _ ->
|
||||
shadowed_type_arg ctx loc "vec-new" args;
|
||||
fail loc
|
||||
"nothing here says what (vec-new) is a Vec of — write the element \
|
||||
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 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 —
|
||||
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. *)
|
||||
and map_new_types ctx ~want loc args =
|
||||
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
|
||||
| a :: _ when type_of_expr ~generic:(Hashtbl.mem ctx.env.gstructs) a <> None ->
|
||||
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)"
|
||||
| { Ast.e = Ast.Var k; _ } :: rest when is_type k && rest = [] ->
|
||||
fail loc
|
||||
@ -10517,9 +10550,10 @@ and map_new_types ctx ~want loc args =
|
||||
(match want with
|
||||
| Some (Types.Map (k, v)) -> k, v, args
|
||||
| _ ->
|
||||
shadowed_type_arg ctx loc "map-new" args;
|
||||
fail loc
|
||||
"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. *)
|
||||
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
|
||||
after fixing it. *)
|
||||
(match args with
|
||||
| [ _; { Ast.e = Ast.Var "string"; _ } ] | [ _ ] -> ()
|
||||
| [ _; { Ast.e = Ast.Var "str"; _ } ] | [ _ ] -> ()
|
||||
| [ _; t ] ->
|
||||
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 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
|
||||
depends on it. *)
|
||||
(match args with
|
||||
| [ _; { Ast.e = Ast.Var "string"; _ } ] ->
|
||||
| [ _; { Ast.e = Ast.Var "str"; _ } ] ->
|
||||
expect ctx loc ~want (as_string ())
|
||||
| _ ->
|
||||
(match want with
|
||||
@ -12096,7 +12130,7 @@ and named_call ?(qualified = false) ctx ~want loc name args =
|
||||
| _ -> expect ctx loc ~want (as_bytes ())))
|
||||
| _ ->
|
||||
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 ───────────────────
|
||||
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
|
||||
@ -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)
|
||||
| _ -> 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
|
||||
unlike the numeric casts, which go through [is_cast] and really do
|
||||
convert.
|
||||
@ -12680,7 +12714,7 @@ and named_call ?(qualified = false) ctx ~want loc name args =
|
||||
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
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.
|
||||
|
||||
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
|
||||
kept past the frame is cloned first. *)
|
||||
| "string" ->
|
||||
| "str" ->
|
||||
arity ctx loc name 1 args;
|
||||
prim Tast.StrOfBytes Types.String [ byte_slice ctx (List.hd args) ]
|
||||
| "bytes->f64" ->
|
||||
@ -13362,6 +13396,13 @@ and ordinary_call ctx ~want loc name args =
|
||||
not (List.mem m [ "true"; "false"; "nil"; "None";
|
||||
"context/allocator"; "context/temp" ])
|
||||
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
|
||||
| Some m when not (callable m) ->
|
||||
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 \
|
||||
class's name as class-of answers it. A typed value answers the kind it \
|
||||
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 \
|
||||
exists at run time — a reader building :texture-path out of a token's \
|
||||
text. A literal :foo is already one.");
|
||||
|
||||
(* 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; \
|
||||
(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 \
|
||||
read-only data.");
|
||||
("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.");
|
||||
|
||||
(* 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 \
|
||||
signals FileError under retry and use-value, and a failure to allocate \
|
||||
signals StorageExhausted.");
|
||||
("barf", "barf [string [const u8]] ()",
|
||||
("barf", "barf [str [const u8]] ()",
|
||||
"Writes a whole file. On the web target it signals FileError every \
|
||||
time, with the path — there is no conditional compilation, so the \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
use-value names a different source for the same destination, which is \
|
||||
the direction a handler can act on.");
|
||||
|
||||
(* 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, \
|
||||
a string, a Vec and a Map.");
|
||||
("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 \
|
||||
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.");
|
||||
("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 \
|
||||
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 \
|
||||
@ -14580,20 +14621,20 @@ let builtins : (string * string * string) list =
|
||||
written as a name rather than as a call.");
|
||||
|
||||
(* 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 \
|
||||
one named. It allocates like vec-new does — a failure signals \
|
||||
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, \
|
||||
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 \
|
||||
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 \
|
||||
copy.");
|
||||
("string", "string [[const u8]] string",
|
||||
"A byte slice seen as a string, and free at run time. It does not check \
|
||||
UTF-8, because `string` does not claim UTF-8 — valid-utf8? is an \
|
||||
("str", "str [[const u8]] str",
|
||||
"A byte slice seen as a str, and free at run time. It does not check \
|
||||
UTF-8, because `str` does not claim UTF-8 — valid-utf8? is an \
|
||||
ordinary function you call when you care.");
|
||||
("bytes->f64", "bytes->f64 [[const u8]] f64", "Parses a float out of the bytes.");
|
||||
("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.");
|
||||
("println", "println [T ...] ()",
|
||||
"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 \
|
||||
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 \
|
||||
@ -14623,7 +14664,7 @@ let builtins : (string * string * string) list =
|
||||
("exit", "exit [i32] never",
|
||||
"Ends the process with this status. It has no value, so nothing written \
|
||||
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
|
||||
signature is the [name type] shape [Dev.defs] gives a global, because
|
||||
@ -16507,7 +16548,7 @@ let check_main env decls =
|
||||
in
|
||||
if not ok_params then
|
||||
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 " ")
|
||||
(List.map (tyname at) params));
|
||||
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 is_const = strip_prefix "const " inner <> None in
|
||||
match bare inner with
|
||||
| "char" when is_const -> tname "string"
|
||||
| "char" when is_const -> tname "str"
|
||||
| "char" ->
|
||||
refuse
|
||||
"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
|
||||
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
|
||||
([LoadFileText] and [UnloadFileText]); copying it would leak the original
|
||||
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 is_const = strip_prefix "const " inner <> None in
|
||||
match bare inner with
|
||||
| "char" when is_const -> Some (tname "string")
|
||||
| "char" when is_const -> Some (tname "str")
|
||||
| "char" ->
|
||||
refuse
|
||||
"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
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
[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 *]
|
||||
and none of them is a scalar. *)
|
||||
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
|
||||
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
|
||||
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.
|
||||
[(Ptr u8)] over a [char *], and [(Ptr] anything[)] over a [void *], now
|
||||
agree; [(Ptr A)] over a [B *] does not.
|
||||
@ -1642,15 +1642,15 @@ let diff_bound ~env ~(bound : (Ast.fn * string) list) (d : dump) =
|
||||
| None ->
|
||||
(match (try Ok (ret_ty env c.cret) with Refused w -> Error w) with
|
||||
(* 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
|
||||
leave the library's buffer with no owner. *)
|
||||
| Error _ ->
|
||||
(match fn.Ast.ret with
|
||||
| Some { Ast.t = Ast.Tname "string"; _ } ->
|
||||
| Some { Ast.t = Ast.Tname "str"; _ } ->
|
||||
say
|
||||
(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 — \
|
||||
declare it (Ptr u8)"
|
||||
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
|
||||
capacity, so two members are the whole truth about a slice. *)
|
||||
| Types.String ->
|
||||
composite "string"
|
||||
composite "str"
|
||||
[ ("ptr", Types.Ptr (Types.Mut, (Types.Int Types.U8))); ("len", Types.Int Types.I64) ]
|
||||
| Types.Slice (_, e) ->
|
||||
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). *)
|
||||
| Tast.Bytes, [ x ] -> value f x
|
||||
(* (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.BytesToF64, [ x ] -> shim_in f "@flan_bytes_to_f64" "double" 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.
|
||||
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].
|
||||
- [[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
|
||||
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
|
||||
@ -47,11 +47,11 @@
|
||||
- [(Fn [..] R)] — a JS function. Function {e values} come along; they carry
|
||||
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
|
||||
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
|
||||
[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
|
||||
throughout ([rune-count], [valid-utf8?], [decode-rune] all take [[u8]]).
|
||||
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. *)
|
||||
| [ n; { v = Kw "parent"; _ }; p ] | [ n; { v = Kw "parent"; _ }; p; { v = Vec []; _ } ] ->
|
||||
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 }
|
||||
in
|
||||
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
|
||||
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
|
||||
(declare f [p string] ...) already means the symbol takes ptr+len and
|
||||
(declare-c f [p string] ...) means it takes a NUL-terminated char *. *)
|
||||
(declare f [p str] ...) already means the symbol takes ptr+len and
|
||||
(declare-c f [p str] ...) means it takes a NUL-terminated char *. *)
|
||||
let mkd fn csym =
|
||||
if String.equal which "declare-c" then Ast.DeclareC (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.
|
||||
;;
|
||||
;; (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
|
||||
;; 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
|
||||
;; established at the call, BoundsError's decision for BoundsError's reason:
|
||||
;; 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
|
||||
;; 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
|
||||
;; **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.
|
||||
(defstruct NullCall :parent Error [type string])
|
||||
(defstruct NullCall :parent Error [type str])
|
||||
|
||||
;; What a generic function signals when no method answers. `generic` is 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
|
||||
;; 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
|
||||
;; 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
|
||||
;; string, so the test below is arithmetic and the pointer is never dereferenced
|
||||
;; 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)
|
||||
p (getenv-raw name (addr n))]
|
||||
(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
|
||||
;; 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
|
||||
;; 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.
|
||||
;;
|
||||
;; 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
|
||||
;; 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.
|
||||
(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
|
||||
;; 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
|
||||
;; length is part of its type and there are no generics: write
|
||||
;; (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)]
|
||||
(when (bytes=? (bytes-view (.name (at files i))) (bytes-view name))
|
||||
(return (Some (.data (at files i))))))
|
||||
@ -2021,7 +2021,7 @@ let source = {flan|
|
||||
;; parent link, not class inheritance", decides on is the
|
||||
;; answer to that, and it is not built; when it is, these reasons can become
|
||||
;; 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-write i32 1)
|
||||
@ -2051,7 +2051,7 @@ let source = {flan|
|
||||
;; 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
|
||||
;; 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 —
|
||||
;; 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,
|
||||
;; deciding whether to write a default — and not as a guard in front of an
|
||||
;; operation that already reports its own failure properly.
|
||||
(defn file-exists? [path string] bool
|
||||
(defn file-exists? [path str] bool
|
||||
(let [n (i64 0)]
|
||||
(= (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
|
||||
;; restart on it. A caller that needs to tell "missing" from "denied" wants
|
||||
;; `slurp`, whose FileError carries the reason.
|
||||
(defn file-size [path string] (Option i64)
|
||||
(defn file-size [path str] (Option i64)
|
||||
(let [n (i64 0)]
|
||||
(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
|
||||
;; 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.
|
||||
(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")
|
||||
|
||||
(defn macro-slurp [path string] (Option [u8])
|
||||
(defn macro-slurp [path str] (Option [u8])
|
||||
(let [n (i64 0)
|
||||
p (macro-slurp-raw path (addr n))]
|
||||
(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
|
||||
;; contract with lib/expand.ml's marshaller and may not be reordered.
|
||||
(defdata Form
|
||||
[(Sym [s string])
|
||||
(Kw [s string])
|
||||
[(Sym [s str])
|
||||
(Kw [s str])
|
||||
(Int [i i64])
|
||||
(Float [x f64])
|
||||
(Str [s string])
|
||||
(Str [s str])
|
||||
(Byte [b i32])
|
||||
(List [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:
|
||||
;; 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)]
|
||||
(dotimes [i (length xs)]
|
||||
(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))]
|
||||
(dotimes [i (length d)]
|
||||
(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 ──────────────────────────
|
||||
;;
|
||||
@ -2443,7 +2443,7 @@ let source = {flan|
|
||||
(Form.List xs) xs
|
||||
_ (form-nil)))
|
||||
|
||||
(defn form-sym? [f Form name string] bool
|
||||
(defn form-sym? [f Form name str] bool
|
||||
(match f
|
||||
(Form.Sym s) (bytes=? (bytes-view s) (bytes-view name))
|
||||
_ 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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
by value and all, and the compiler is to produce whatever flattening makes
|
||||
it crossable. The two cannot be one form —
|
||||
[(declare start-raw [path string] i32 "flan_agent_start")] and
|
||||
[(declare-c init-window [w i32 h i32 title string] "InitWindow")] are the
|
||||
[(declare start-raw [path str] i32 "flan_agent_start")] and
|
||||
[(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.
|
||||
|
||||
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. \
|
||||
Pass (Ptr %s) and let the C side read it"
|
||||
what n n
|
||||
else if String.equal n "string" then
|
||||
else if String.equal n "str" then
|
||||
fail loc
|
||||
"%s is a string, and a string crosses only as a parameter or a \
|
||||
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 t' = unalias env t in
|
||||
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
|
||||
generator writes would have to spell the copy's type, and it builds its
|
||||
wrapper from struct names. *)
|
||||
@ -891,7 +891,7 @@ let flan_wrapper ?track (fn : Ast.fn) (s : shim) raw : Ast.decl_kind =
|
||||
out ],
|
||||
Some (ty loc (Ast.Tname n)) )
|
||||
| `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
|
||||
again. The length is bound before the pointer is, so its address
|
||||
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 };
|
||||
{ Ast.bname = ptr_tmp; bty = None;
|
||||
bval = call (args @ [ app "addr" [ v len_tmp ] ]); bloc = loc } ];
|
||||
( [ app "string"
|
||||
( [ app "str"
|
||||
[ app "bytes"
|
||||
[ app "string"
|
||||
[ app "str"
|
||||
[ app "slice-from" [ v ptr_tmp; v len_tmp ] ] ] ] ],
|
||||
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
|
||||
(match t'.Ast.t with
|
||||
| Ast.Tname "Unit" -> `Void
|
||||
| Ast.Tname "string" -> `Str
|
||||
| Ast.Tname "str" -> `Str
|
||||
| Ast.Tname n when Hashtbl.mem env.structs n ->
|
||||
ignore (cty env ~needed ~loc ~what t');
|
||||
`Struct (n, ctype_name n)
|
||||
|
||||
@ -36,7 +36,7 @@ type prim =
|
||||
calc-me's tokenizer and the prelude's printers each need. *)
|
||||
| Bytes | BytesToF64 | BytesToI64 | F64ToBytes | I64ToBytes
|
||||
(* (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
|
||||
(* 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
|
||||
|
||||
@ -44,7 +44,7 @@ type t =
|
||||
| Array of int64 * t (* [n T] inline, a value, copies *)
|
||||
| Map of t * t (* (Map K V) *)
|
||||
| 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
|
||||
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
|
||||
@ -145,7 +145,7 @@ let bits_f = function F32 -> 32 | F64 -> 64
|
||||
that already accepts [i32] accepts [int] without learning the word.
|
||||
|
||||
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.
|
||||
|
||||
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. *)
|
||||
let primitive_names =
|
||||
[ "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" ]
|
||||
|
||||
let ikind_name k =
|
||||
@ -272,7 +272,7 @@ and to_string = function
|
||||
| Int k -> ikind_name k
|
||||
| Float k -> fkind_name k
|
||||
| Bool -> "bool"
|
||||
| String -> "string"
|
||||
| String -> "str"
|
||||
| Unit -> "()"
|
||||
| Never -> "Never"
|
||||
| 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
|
||||
* 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)
|
||||
*
|
||||
@ -901,7 +901,7 @@ void flan_dev_watch_reset(void) {
|
||||
/* 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:
|
||||
*
|
||||
* (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))
|
||||
*
|
||||
|
||||
@ -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;
|
||||
} known[] = {
|
||||
{ "bool", ST_BOOL, 0, 0, 0 },
|
||||
{ "string", ST_TEXT, 0, 0, 0 },
|
||||
{ "str", ST_TEXT, 0, 0, 0 },
|
||||
{ "f32", ST_FLOAT, 24, 0, 0 },
|
||||
{ "f64", ST_FLOAT, 53, 0, 0 },
|
||||
{ "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
|
||||
* 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.
|
||||
*
|
||||
* 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,
|
||||
* 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
|
||||
* condition with its values: [message] for the runtime's own conditions,
|
||||
* 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 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) {
|
||||
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.
|
||||
*
|
||||
* 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. */
|
||||
|
||||
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
|
||||
* 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
|
||||
* (defstruct NullCall :parent Error [type string]). */
|
||||
* (defstruct NullCall :parent Error [type str]). */
|
||||
|
||||
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->epoch = (int64_t)a->epoch;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
```
|
||||
(defn load-texture [path string] (Handle Texture)
|
||||
(defn load-texture [path str] (Handle Texture)
|
||||
(if (file-exists? path)
|
||||
(rl/load-texture path)
|
||||
(restart-case
|
||||
|
||||
@ -53,7 +53,7 @@ it is usually written in — a `let` binding — has no type slot for it to take
|
||||
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
|
||||
;; 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))
|
||||
table (try (parse-toml text))
|
||||
port (try (ok-or (get table "port")
|
||||
@ -143,7 +143,7 @@
|
||||
|
||||
;; errdefer runs only on the Result failure path — NOT on a restart transfer
|
||||
;; (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)]
|
||||
(errdefer (free buf))
|
||||
(try (decode-png path buf))
|
||||
@ -155,13 +155,13 @@
|
||||
;; 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
|
||||
;; 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
|
||||
;; fall-through path of a restart-case in value position must still produce the
|
||||
;; type. `abort` has type Never, which unifies with (Handle Texture).
|
||||
;; 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)
|
||||
(rl/load-texture path)
|
||||
(restart-case
|
||||
@ -176,7 +176,7 @@
|
||||
;; 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
|
||||
;; goes on the condition or into a global.
|
||||
(defn load-level [path string] Level
|
||||
(defn load-level [path str] Level
|
||||
(handler-bind [(AssetMissing [c]
|
||||
(log "missing asset:" (.path c))
|
||||
(invoke-restart 'use-placeholder))]
|
||||
@ -195,7 +195,7 @@
|
||||
(skip-form [] (skip-to-next-delimiter p))))
|
||||
forms))
|
||||
|
||||
(defn collect-parse-errors [src string] (Result Ast)
|
||||
(defn collect-parse-errors [src str] (Result Ast)
|
||||
(let [errors (make-vec ParseError)]
|
||||
(handler-bind [(ParseError [c]
|
||||
(push errors c) ; value struct: copies out of
|
||||
@ -218,7 +218,7 @@
|
||||
|
||||
;; ── defer for explicit resources ──────────────────────────────────────
|
||||
;; 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)]
|
||||
(defer (close f))
|
||||
(write-bytes f (serialize w))))
|
||||
@ -235,7 +235,7 @@
|
||||
;; 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
|
||||
;; it out of preload.
|
||||
(defn ^:async preload [paths [string]] (Result ())
|
||||
(defn ^:async preload [paths [str]] (Result ())
|
||||
(for [p paths]
|
||||
(try (await (load-texture-async p))))
|
||||
(Ok unit))
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
(set ticks (+ ticks 1))
|
||||
ticks)
|
||||
|
||||
(defn main [args [string]] i32
|
||||
(defn main [args [str]] i32
|
||||
(if (< (length args) 2)
|
||||
(do (println "usage: agent-queue <socket>") 2)
|
||||
(do
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
(set ticks (+ ticks 1))
|
||||
ticks)
|
||||
|
||||
(defn main [args [string]] i32
|
||||
(defn main [args [str]] i32
|
||||
(if (< (length args) 2)
|
||||
(do (println "usage: agent <socket>") 2)
|
||||
(do
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
(defn show-fields [s [[const u8]]] ()
|
||||
(dotimes [i (length s)]
|
||||
(print (string (at s i)))
|
||||
(print (str (at s i)))
|
||||
(print " "))
|
||||
(println ""))
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
(let [f (split (bytes-view "delta,alpha,charlie,bravo") \,)]
|
||||
(sort-bytes (slice f))
|
||||
(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 f))
|
||||
0)
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
(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))
|
||||
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)]
|
||||
(cond
|
||||
|
||||
@ -19,9 +19,9 @@
|
||||
(defdata Value
|
||||
[(Nil [])
|
||||
(Int [n i64])
|
||||
(Text [s string])
|
||||
(Text [s str])
|
||||
(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
|
||||
;; 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
|
||||
;; deep before it reaches a leaf: Table -> Vec -> List -> Vec -> Int.
|
||||
(defn a-table [] Value
|
||||
(let [entries (map-new string Value)]
|
||||
(let [entries (map-new str Value)]
|
||||
(put entries "xs" (number-list 3))
|
||||
(put entries "ys" (number-list 5))
|
||||
(put entries "name" (Value.Text {.s "edn"}))
|
||||
|
||||
@ -61,7 +61,7 @@
|
||||
(defonce small f64 -1e300)
|
||||
(defonce uz u32)
|
||||
|
||||
(defn show [name string n i64] ()
|
||||
(defn show [name str n i64] ()
|
||||
(print name) (print " ") (print n) (println ""))
|
||||
|
||||
;;; 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 wide f32 1e30)
|
||||
|
||||
(defn main [args [string]] i32
|
||||
(defn main [args [str]] i32
|
||||
(let [n (i32 (bytes->i64 (bytes-view (at args 1))))
|
||||
;; 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
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
|
||||
;;; Two frames deep, with a defer on the way, so the transfer has something to
|
||||
;;; 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 ""))
|
||||
|
||||
(defn read-cell [i i32] i32
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
;;;; (that is a separate job) and lets LLVM fold the branch away here.
|
||||
(defonce arr [3 i32])
|
||||
|
||||
(defn main [args [string]] i32
|
||||
(defn main [args [str]] i32
|
||||
(let [n (i32 (bytes->i64 (bytes-view (at args 1))))
|
||||
s (bytes-view "hello")] ; len 5
|
||||
(cond
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
;;; one.
|
||||
;;; Both additions are qualified too, since + is shadowed below and this
|
||||
;;; 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)
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
(let [s "INSERTIONSORT"
|
||||
b (bytes s)]
|
||||
(set (at b 0) \Z)
|
||||
(println (string b)) ; ZNSERTIONSORT
|
||||
(println (str b)) ; ZNSERTIONSORT
|
||||
(println s) ; INSERTIONSORT
|
||||
;; The copy's block came from the context allocator, and free hands it
|
||||
;; back there — which is what keeps this program leak-free.
|
||||
@ -23,7 +23,7 @@
|
||||
;; at -O0 and silently do nothing at -O2.
|
||||
(let [b (bytes "hi")]
|
||||
(set (at b 0) \H)
|
||||
(println (string b)) ; Hi
|
||||
(println (str b)) ; Hi
|
||||
(free b))
|
||||
|
||||
;; 3. The view still costs nothing and reads the string's own storage.
|
||||
@ -36,7 +36,7 @@
|
||||
(set frame (arena-new 4096))
|
||||
(let [b (bytes "arena" frame)]
|
||||
(set (at b 4) \A)
|
||||
(println (string b))) ; arenA
|
||||
(println (str b))) ; arenA
|
||||
(free-all frame)
|
||||
(arena-destroy frame)
|
||||
|
||||
|
||||
@ -7,5 +7,5 @@
|
||||
(defn main [] i32
|
||||
(let [v (bytes-view "INSERTIONSORT")]
|
||||
(set (at v 0) \Z)
|
||||
(print (string v))
|
||||
(print (str v))
|
||||
0))
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
;; Brackets around the result so an empty trim is visible as [] rather than
|
||||
;; as nothing at all — the all-whitespace case is otherwise indistinguishable
|
||||
;; from a trim that printed the wrong slice of length zero.
|
||||
(defn show-trim [s string] ()
|
||||
(defn show-trim [s str] ()
|
||||
(print "[")
|
||||
(print (trim (bytes-view s)))
|
||||
(print "]"))
|
||||
|
||||
@ -16,12 +16,12 @@
|
||||
|
||||
;; Prints its tag and answers its value. Every operand below is one of these,
|
||||
;; 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))
|
||||
(print tag)
|
||||
v)
|
||||
|
||||
(defn markf [tag string v f64] f64
|
||||
(defn markf [tag str v f64] f64
|
||||
(print tag)
|
||||
v)
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
;;;; before 1100 two-byte characters, so a cut at a fixed byte count would
|
||||
;;;; land inside one.
|
||||
|
||||
(defstruct Wide :parent Error [code i32 why string])
|
||||
(defstruct Wide :parent Error [code i32 why str])
|
||||
(defstruct Longs :parent Error)
|
||||
|
||||
(defn main [] i32
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
(defstruct IoError :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)
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
(defstruct MyErr :parent Error [code i32])
|
||||
|
||||
(defn why [] string
|
||||
(defn why [] str
|
||||
(handler-case (do (error (MyErr {.code 3})) "")
|
||||
[(Error [e] (.message e))]))
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
(sort w)
|
||||
(println (total w) (total (slice w 1)))
|
||||
(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))
|
||||
(push names head)
|
||||
(push names tail)
|
||||
@ -51,15 +51,15 @@
|
||||
both [a b]]
|
||||
(println (widths (slice both)))
|
||||
(set (at a 0) \A)
|
||||
(println (string a)))
|
||||
(println (str a)))
|
||||
(let [f (split (bytes-view "b,a,c") \,)]
|
||||
(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 (call-rd rd) (call-bare rd) (call-mk mk))
|
||||
(let [b (bytes "q")]
|
||||
(println (peek (addr (at r 1))) (peek (addr (at "abc" 2)))
|
||||
(peek (addr (at b 0)))
|
||||
(string (slice-from (addr (at r 7)) 5))))
|
||||
(str (slice-from (addr (at r 7)) 5))))
|
||||
(free names))
|
||||
0)
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
;;;; destroyed arena's record. Allocating from the context must then trap,
|
||||
;;;; 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.
|
||||
(defn main [args [string]] i32
|
||||
(defn main [args [str]] i32
|
||||
(let [which (if (> (length args) 1) (bytes->i64 (bytes-view (at args 1))) 0)
|
||||
a (arena-new 4096)]
|
||||
(with-allocator a
|
||||
|
||||
@ -19,8 +19,8 @@
|
||||
(let [path (vec-new u8)]
|
||||
(append (addr path) (bytes-view "dir/"))
|
||||
(dotimes [i 300] (push path \x))
|
||||
(let [tail (cret/after-slash (string (slice path)))
|
||||
long-name (string (slice path 4))]
|
||||
(let [tail (cret/after-slash (str (slice path)))
|
||||
long-name (str (slice path 4))]
|
||||
(println (length tail))
|
||||
(println (= tail long-name))))
|
||||
(println (length (cret/nothing)))
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
[Empty
|
||||
(Dot [x f64 y f64])
|
||||
(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
|
||||
;; return type -- a value that cannot do that is not a value.
|
||||
@ -29,7 +29,7 @@
|
||||
;; alignment visible to something other than a slot.
|
||||
(defstruct Cell [id i32 s Shape])
|
||||
|
||||
(defn describe [s Shape] string
|
||||
(defn describe [s Shape] str
|
||||
(match s
|
||||
Empty "empty"
|
||||
(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
|
||||
;; held -- by a program that had said.
|
||||
(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.Empty)
|
||||
(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
|
||||
;;;; 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
|
||||
(let [bump (+ n 1)]
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
;;;; wrong, because it is the only one whose own alignment exceeds its first
|
||||
;;;; 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
|
||||
(let [bump (+ n 1)]
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
;;;; 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
|
||||
;;;; 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)
|
||||
a (arena-new 4096)]
|
||||
(cond
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
(set calls (+ calls 1))
|
||||
(Point {.x 3 .y 4}))
|
||||
|
||||
(defn show2 [label string a i32 b i32] ()
|
||||
(defn show2 [label str a i32 b i32] ()
|
||||
(print label)
|
||||
(print " ")
|
||||
(print a)
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
(defstruct Boom [why i32])
|
||||
|
||||
(defonce label string)
|
||||
(defonce label str)
|
||||
(defonce grid [4 i32])
|
||||
(defonce pressure i64)
|
||||
(defonce untouched i64 99)
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
(defstruct Point [x f32 y f32])
|
||||
(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})
|
||||
xs [10 20 30]
|
||||
flag (> n 0)
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
(defonce ticks i64)
|
||||
|
||||
(defn parity [n i64] string
|
||||
(defn parity [n i64] str
|
||||
(let [out "even"]
|
||||
(unless (= 0 (% n 2))
|
||||
(set out "odd"))
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
(defonce odd f64)
|
||||
(defonce yes bool)
|
||||
(defonce byte u8)
|
||||
(defonce text string)
|
||||
(defonce text str)
|
||||
(defonce colour Colour)
|
||||
(defonce stray Colour)
|
||||
(defonce some (Option Point))
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
(defn hold [] i32
|
||||
(set tv context/temp)
|
||||
(let [r (fetch)]
|
||||
(println (string (i64->bytes 31)))
|
||||
(println (str (i64->bytes 31)))
|
||||
r))
|
||||
|
||||
(defn main [] i32
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
(defn hold [] i32
|
||||
(set keep (vec-new u8 context/temp))
|
||||
(push keep (u8 5))
|
||||
(let [s (string (i64->bytes 4242))
|
||||
(let [s (str (i64->bytes 4242))
|
||||
r (fetch)]
|
||||
(println s)
|
||||
(println (length keep))
|
||||
|
||||
@ -10,13 +10,13 @@
|
||||
;;;; at frame rate and the editor reads memory.
|
||||
(import agent "vendor:agent")
|
||||
|
||||
(declare-c watch-i64 [name string x i64] i32 "flan_dev_watch_i64")
|
||||
(declare-c watch-f64 [name string x f64] i32 "flan_dev_watch_f64")
|
||||
(declare-c watch-str [name string s string] i32 "flan_dev_watch_str")
|
||||
(declare-c watch-i64 [name str x i64] i32 "flan_dev_watch_i64")
|
||||
(declare-c watch-f64 [name str x f64] i32 "flan_dev_watch_f64")
|
||||
(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
|
||||
;; 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".
|
||||
(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)
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
;;;; exists and (get s :pause) is a place, where a plain map's absent key is
|
||||
;;;; 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.
|
||||
(defclass node [owner state next (Option node) weight (Option f32)])
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
(defn pick [x dyn n i64] dyn x)
|
||||
(defn pick-t [t T n i64] dyn (.d t))
|
||||
|
||||
(defn show [label string v dyn] ()
|
||||
(defn show [label str v dyn] ()
|
||||
(churn)
|
||||
(println label (at v 0) (at v 1)))
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
(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)
|
||||
v (vec-new dyn)
|
||||
ar (arena-new 4096)]
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
;;
|
||||
;; 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")]
|
||||
(println (slice d))
|
||||
(println (slice d 1))
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
(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)
|
||||
s (state false 3 nil)]
|
||||
(println "before")
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
(let [n (the i32 7)
|
||||
f (the f32 1.5)
|
||||
b (the bool true)
|
||||
s (the string "typed")]
|
||||
s (the str "typed")]
|
||||
(println (type-of nil))
|
||||
(println (type-of true))
|
||||
(println (type-of 42))
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
;; carries that pair, because a refusal cannot run.
|
||||
(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))))]
|
||||
(cond
|
||||
(= n 0)
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
;; 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
|
||||
;; 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}}}")
|
||||
|
||||
(defn show-drift [a Allocator] ()
|
||||
@ -93,7 +93,7 @@
|
||||
;; 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
|
||||
;; be at least as honest.
|
||||
(defconst broken string "{:name \"orc\" :hp }")
|
||||
(defconst broken str "{:name \"orc\" :hp }")
|
||||
|
||||
(defn show-broken [a Allocator] ()
|
||||
(handler-bind
|
||||
|
||||
@ -54,12 +54,12 @@
|
||||
|
||||
;; The size of a set after the dedup, which is the whole of what the dedup can
|
||||
;; be asked for.
|
||||
(defn set-size [src string] ()
|
||||
(defn set-size [src str] ()
|
||||
(println (length (edn/read (bytes-view src)))))
|
||||
|
||||
;; 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.
|
||||
(defn malformed? [src string] bool
|
||||
(defn malformed? [src str] bool
|
||||
(let [c (edn/cursor (bytes-view src))
|
||||
t (edn/next (addr c))
|
||||
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
|
||||
;; alone.
|
||||
|
||||
(defn kind-letter [k i32] string
|
||||
(defn kind-letter [k i32] str
|
||||
(cond
|
||||
(= k edn/tok-eof) "."
|
||||
(= k edn/tok-error) "!"
|
||||
@ -40,7 +40,7 @@
|
||||
(= k edn/tok-set-open) "#"
|
||||
:else "?"))
|
||||
|
||||
(defn dump [src string] ()
|
||||
(defn dump [src str] ()
|
||||
(let [b (bytes-view src)
|
||||
c (edn/cursor b)
|
||||
t (edn/next (addr c))]
|
||||
@ -58,7 +58,7 @@
|
||||
;; 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
|
||||
;; pass a test that only checked that it failed.
|
||||
(defn refusal [src string] ()
|
||||
(defn refusal [src str] ()
|
||||
(let [b (bytes-view src)
|
||||
c (edn/cursor b)]
|
||||
(while (and (edn/ok? (addr c))
|
||||
@ -121,7 +121,7 @@
|
||||
(return e)))))
|
||||
e))
|
||||
|
||||
(defn show-enemy [src string] ()
|
||||
(defn show-enemy [src str] ()
|
||||
(let [b (bytes-view src)
|
||||
c (edn/cursor b)
|
||||
e (read-enemy (addr c))]
|
||||
|
||||
@ -20,13 +20,13 @@
|
||||
;; The default answer is a [u8]: bytes, because that is what an asset is.
|
||||
(let [a (embed "assets/a.txt")]
|
||||
(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
|
||||
;; text. With structural equality and nothing that converts one container
|
||||
;; into another -- implicit widening is numbers only -- one form that changes
|
||||
;; 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
|
||||
;; escape hex-escapes everything outside printable ASCII, so a PNG makes the
|
||||
@ -50,7 +50,7 @@
|
||||
;; there are no generics.
|
||||
(let [all (slice assets 0 (length assets))]
|
||||
(match (embed-find all "b.bin")
|
||||
(Some b) (println (string b)) ; BBB
|
||||
(Some b) (println (str b)) ; BBB
|
||||
None (println "missing"))
|
||||
(match (embed-find all "nope.txt")
|
||||
(Some _) (println "found")
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
;; An enum parameter driven by a loop variable, which is the shape this exists
|
||||
;; 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)]
|
||||
(cond (= k :lo) "lo"
|
||||
(= k :mid) "mid"
|
||||
|
||||
@ -10,13 +10,13 @@
|
||||
(defn double [x i32] i32 (* x 2))
|
||||
(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 hook (CFn [i32] i32))
|
||||
(defonce evaluated i32 0)
|
||||
(defonce caught i32 0)
|
||||
(defonce seen string "")
|
||||
(defonce seen str "")
|
||||
|
||||
(defn arg [x i32] i32
|
||||
(set evaluated (+ evaluated 1))
|
||||
@ -27,7 +27,7 @@
|
||||
(do (print (f (arg x))) (println ""))
|
||||
(continue [] (println "empty"))))
|
||||
|
||||
(defn main [args [string]] i32
|
||||
(defn main [args [str]] i32
|
||||
(set (at table 0) double)
|
||||
(set (at table 2) negate)
|
||||
(let [ops (Ops {.name "half-built"})]
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
(push msg who)
|
||||
(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)))
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
(push junk true))))
|
||||
|
||||
(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))
|
||||
rows (map-new i32 dyn)]
|
||||
(put ops "one" (adder 1))
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
(defn show [x f64 p i32] ()
|
||||
(let [v (format-f64 x p)]
|
||||
(println (string (slice v)))
|
||||
(println (str (slice v)))
|
||||
(free v)))
|
||||
|
||||
(defn main [] i32
|
||||
@ -95,6 +95,6 @@
|
||||
(let [f (format-f64 0.0166667 4)]
|
||||
(append (addr b) (slice 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))
|
||||
0)
|
||||
|
||||
@ -109,7 +109,7 @@
|
||||
(when (!= (.brush world) (.brush world-backup)) (set d (+ d 1)))
|
||||
d))
|
||||
|
||||
(defn show [name string n i64] ()
|
||||
(defn show [name str n i64] ()
|
||||
(print name) (print " ") (print n) (println ""))
|
||||
|
||||
(defn dump [] ()
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
;;;; 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
|
||||
;;;; 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)
|
||||
a (arena-new 4096)]
|
||||
(cond
|
||||
@ -26,7 +26,7 @@
|
||||
(let [b (bytes "heap")
|
||||
c (bytes "arena" a)
|
||||
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 c a)
|
||||
(free d (heap-allocator))))
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
;;;; position that takes i32 takes int, the cast head included, and nothing
|
||||
;;;; 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
|
||||
;;;; 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
|
||||
;; Map, named with the alias.
|
||||
(let [v (vec-new int)
|
||||
m (map-new string int)]
|
||||
m (map-new str int)]
|
||||
(push v 10)
|
||||
(push v 20)
|
||||
(put m "k" 30)
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
;; its backslash still on it; that is the divergence between the tokenizer and
|
||||
;; string-of, and this is where it is visible.
|
||||
|
||||
(defn kind-letter [k i32] string
|
||||
(defn kind-letter [k i32] str
|
||||
(cond
|
||||
(= k json/tok-eof) "."
|
||||
(= k json/tok-error) "!"
|
||||
@ -61,7 +61,7 @@
|
||||
(= k json/tok-comma) ","
|
||||
:else "?"))
|
||||
|
||||
(defn dump [src string] ()
|
||||
(defn dump [src str] ()
|
||||
(let [b (bytes-view src)
|
||||
c (json/cursor b)
|
||||
t (json/next (addr c))]
|
||||
@ -79,7 +79,7 @@
|
||||
;; 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
|
||||
;; that only checked that it stopped.
|
||||
(defn refusal [src string] ()
|
||||
(defn refusal [src str] ()
|
||||
(let [b (bytes-view src)
|
||||
c (json/cursor b)]
|
||||
(while (and (json/ok? (addr c))
|
||||
@ -96,9 +96,9 @@
|
||||
(Bool [b bool])
|
||||
(Int [n i64])
|
||||
(Float [x f64])
|
||||
(Text [s string])
|
||||
(Text [s str])
|
||||
(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
|
||||
;; 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
|
||||
;; buffer is not in the picture.
|
||||
(= (.kind t) json/tok-object-open)
|
||||
(let [entries (map-new string Value)
|
||||
(let [entries (map-new str Value)
|
||||
k (json/next c)
|
||||
more (and (json/ok? c) (!= (.kind k) json/tok-object-close))]
|
||||
(while more
|
||||
@ -234,14 +234,14 @@
|
||||
(match (get entries "xs") (Some x) (sum-ints x) None (i64 0))
|
||||
_ (i64 0)))
|
||||
|
||||
(defn describe [v Value] string
|
||||
(defn describe [v Value] str
|
||||
(match v
|
||||
Null "null" (Bool _b) "bool" (Int _n) "int" (Float _x) "float"
|
||||
(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
|
||||
;; 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
|
||||
(Object entries)
|
||||
(match (get entries key)
|
||||
@ -257,7 +257,7 @@
|
||||
;; 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 —
|
||||
;; a trailing comma reported at the opening brace would be useless.
|
||||
(defn reject [src string] ()
|
||||
(defn reject [src str] ()
|
||||
(let [b (bytes-view src)
|
||||
c (json/cursor b)
|
||||
t (json/next (addr c))]
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
(defn inf-f32? [x f32] bool
|
||||
(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 " ")
|
||||
(println (if ok "ok" "WRONG")))
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
(defmacro thru [& body]
|
||||
`(do ~@body))
|
||||
|
||||
(defn g [s string] i32 0)
|
||||
(defn g [s str] i32 0)
|
||||
|
||||
(defn main [] i32
|
||||
(thru
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
;;;; the move, which is the point: the test for the feature is the corpus that
|
||||
;;;; was written against the special form.
|
||||
|
||||
(defn classify [n i32] string
|
||||
(defn classify [n i32] str
|
||||
(let [out "even"]
|
||||
(unless (= 0 (% n 2))
|
||||
(set out "odd"))
|
||||
|
||||
@ -2,13 +2,13 @@
|
||||
;; 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.
|
||||
|
||||
(defstruct Tag [name string n i32])
|
||||
(defstruct Tag [name str n i32])
|
||||
|
||||
(defn main [] i32
|
||||
(let [m (map-new [2 string] i32)
|
||||
a (the [2 string] ["ab" "cd"])
|
||||
b (the [2 string] [(slice "xab" 1) (slice "cdx" 0 2)])
|
||||
c (the [2 string] ["ab" "ce"])]
|
||||
(let [m (map-new [2 str] i32)
|
||||
a (the [2 str] ["ab" "cd"])
|
||||
b (the [2 str] [(slice "xab" 1) (slice "cdx" 0 2)])
|
||||
c (the [2 str] ["ab" "ce"])]
|
||||
(put m a 1)
|
||||
(put m c 3)
|
||||
(println (or-else (get m b) -1))
|
||||
|
||||
@ -64,7 +64,7 @@
|
||||
(set failures (+ failures 1))
|
||||
(set-alloc-budget tight (* 8 (alloc-budget tight)))
|
||||
(invoke-restart 'retry))]
|
||||
(let [m (map-new string i32 tight)]
|
||||
(let [m (map-new str i32 tight)]
|
||||
(reserve m 200)
|
||||
(println (length m)) ; 0
|
||||
(put m "a" 1)
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
(defstruct Point [x i32 y i32])
|
||||
|
||||
(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 "bb" (Point {.x 3 .y 4}))
|
||||
(put m "ccc" (Point {.x 5 .y 6}))
|
||||
|
||||
@ -28,8 +28,8 @@
|
||||
(free vs))
|
||||
(free m))
|
||||
;; A string key, and a map that never allocated.
|
||||
(let [names (map-new string i32)
|
||||
none (map-new string i32)]
|
||||
(let [names (map-new str i32)
|
||||
none (map-new str i32)]
|
||||
(put names "b" 2)
|
||||
(put names "a" 1)
|
||||
(let [ks (map-keys names)
|
||||
|
||||
@ -88,7 +88,7 @@
|
||||
(print (length g)) (println "") ; 399
|
||||
(free g))
|
||||
|
||||
(let [s (map-new string i32)]
|
||||
(let [s (map-new str i32)]
|
||||
(put s "alpha" 1)
|
||||
(put s "beta" 2)
|
||||
(match (map-remove s "alpha")
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
;;;; version gets wrong, and the numbers differ per failure so a single wrong
|
||||
;;;; answer names its own cause.
|
||||
(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])
|
||||
|
||||
;;;; (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
|
||||
;; 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)
|
||||
(put u "k" 1)
|
||||
(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