nomen-lang 0.6.12 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/NOMEN_AGENTS.md +27 -13
  2. package/audit_runtime.c +2 -0
  3. package/core/System/Arena.nm +4 -4
  4. package/core/System/Array.nm +108 -78
  5. package/core/System/Atomic.nm +81 -0
  6. package/core/System/Awaitable.nm +12 -5
  7. package/core/System/BigInt.nm +1 -1
  8. package/core/System/Box.nm +32 -0
  9. package/core/System/Buffer.nm +47 -18
  10. package/core/System/Channel.nm +27 -11
  11. package/core/System/ClassBuffer.nm +24 -28
  12. package/core/System/Console.nm +4 -4
  13. package/core/System/Controls/Button.nm +8 -3
  14. package/core/System/Controls/CheckBox.nm +8 -3
  15. package/core/System/Controls/Container.nm +18 -11
  16. package/core/System/Controls/Layout.nm +1 -1
  17. package/core/System/Controls/Text.nm +9 -4
  18. package/core/System/Controls/TextBox.nm +8 -3
  19. package/core/System/Controls/Window.nm +10 -3
  20. package/core/System/Fiber.nm +6 -2
  21. package/core/System/Graph.nm +2 -2
  22. package/core/System/Init.nm +2 -2
  23. package/core/System/LinkedList.nm +2 -2
  24. package/core/System/List.nm +7 -7
  25. package/core/System/Map.nm +10 -7
  26. package/core/System/Math.nm +1 -1
  27. package/core/System/Mutex.nm +14 -2
  28. package/core/System/Random.nm +7 -1
  29. package/core/System/Result.nm +1 -1
  30. package/core/System/Sendable.nm +2 -2
  31. package/core/System/Set.nm +6 -6
  32. package/core/System/Spawnable.nm +9 -9
  33. package/core/System/Stream/Directory.nm +1 -2
  34. package/core/System/Stream/File.nm +8 -9
  35. package/core/System/Stream/Http.nm +2 -3
  36. package/core/System/Stream/Tcp.nm +13 -8
  37. package/core/System/String.nm +22 -12
  38. package/core/System/StringBuilder.nm +2 -2
  39. package/core/System/Task.nm +21 -29
  40. package/core/System/Test.nm +10 -4
  41. package/core/System/Text/CharIndex.nm +2 -3
  42. package/core/System/Text/Json.nm +8 -12
  43. package/core/System/Text/JsonTree.nm +4 -4
  44. package/core/System/Text/Regex.nm +7 -7
  45. package/core/System/Text/Utf8.nm +2 -3
  46. package/core/System/Thread.nm +9 -4
  47. package/core/System/Tree.nm +2 -2
  48. package/core/System/Viewable.nm +2 -2
  49. package/core/System/WeakHandle.nm +56 -0
  50. package/core/System/bool.nm +1 -1
  51. package/core/System/char.nm +1 -1
  52. package/core/System/float.nm +1 -1
  53. package/core/System/float32.nm +1 -1
  54. package/core/System/float64.nm +1 -1
  55. package/core/System/int.nm +1 -1
  56. package/core/System/int16.nm +1 -1
  57. package/core/System/int32.nm +1 -1
  58. package/core/System/int64.nm +1 -1
  59. package/core/System/int8.nm +1 -1
  60. package/core/System/ufloat.nm +1 -1
  61. package/core/System/ufloat32.nm +1 -1
  62. package/core/System/ufloat64.nm +1 -1
  63. package/core/System/uint.nm +1 -1
  64. package/core/System/uint16.nm +1 -1
  65. package/core/System/uint32.nm +1 -1
  66. package/core/System/uint64.nm +1 -1
  67. package/core/System/uint8.nm +1 -1
  68. package/core/docs/System/Result.md +2 -2
  69. package/dist/index.mjs +28088 -24186
  70. package/package.json +1 -1
  71. package/src/test.ts +26 -11
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * A graph of values connected by edges
8
8
  **/
9
- pub struct Graph<T>: Enumerable {
9
+ pub mv struct Graph<T>: Enumerable {
10
10
  var values = Buffer<T>()
11
11
  var head_edge = Buffer<int>()
12
12
  var edge_target = Buffer<int>()
@@ -14,7 +14,7 @@ pub struct Graph<T>: Enumerable {
14
14
  var node_count = 0
15
15
  var edge_count = 0
16
16
 
17
- pub func add_node = (ref self, move T value) {
17
+ pub func add_node = (ref self, mv T value) {
18
18
  var int idx = self.node_count
19
19
  self.values.grow(idx + 1)
20
20
  self.values.store(idx, value)
@@ -2,14 +2,14 @@
2
2
  * Program startup state — the argument count and argument list passed to `main`,
3
3
  * plus whether stdout is a terminal (for renderer selection).
4
4
  **/
5
- pub struct Init {
5
+ pub mv struct Init {
6
6
  var int argc
7
7
  var string[16] args
8
8
  var bool is_tty
9
9
  }
10
10
 
11
11
  // FFI: the C library's decimal-string parser (stdlib.h).
12
- extern func atoi = (string s, out int)
12
+ foreign func atoi = (string s, out int)
13
13
 
14
14
  /**
15
15
  * Parses a decimal string into an int
@@ -6,14 +6,14 @@
6
6
  /**
7
7
  * A doubly-linked list of values
8
8
  **/
9
- pub struct LinkedList<T>: Enumerable {
9
+ pub mv struct LinkedList<T>: Enumerable {
10
10
  var values = Buffer<T>()
11
11
  var nexts = Buffer<int>()
12
12
  var prevs = Buffer<int>()
13
13
  var int head = -1
14
14
  var count = 0
15
15
 
16
- pub func add = (ref self, move T value) {
16
+ pub func add = (ref self, mv T value) {
17
17
  var int idx = self.count
18
18
  self.values.grow(idx + 1)
19
19
  self.values.store(idx, value)
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * A growable, ordered list of values (`push`/`pop`/`at`)
3
3
  **/
4
- pub struct List<T>: Viewable {
4
+ pub mv struct List<T>: Viewable {
5
5
  var length = 0
6
6
  var items = Buffer<T>()
7
7
 
8
- pub func push = (ref self, move T value) {
8
+ pub func push = (ref self, mv T value) {
9
9
  if self.length >= self.items.cap {
10
10
  var new_cap = 4
11
11
  var int old_cap = self.items.cap
@@ -18,7 +18,7 @@ pub struct List<T>: Viewable {
18
18
  self.length += 1
19
19
  }
20
20
 
21
- pub func pop = (ref self, move out T) {
21
+ pub func pop = (ref self, mv out T) {
22
22
  if self.length <= 0 {
23
23
  return self.items.move(0)
24
24
  }
@@ -51,13 +51,13 @@ pub struct List<T>: Viewable {
51
51
  panic("index out of range")
52
52
  }
53
53
 
54
- // A non-owning `view T` over [start, end). Delegates to the backing Buffer's
54
+ // A non-mv `view T` over [start, end). Delegates to the backing Buffer's
55
55
  // #arch slice primitive — no #arch code here. Borrows from self.
56
56
  pub func slice = (self, int start: start >= 0, int end: end >= start, out view T) {
57
57
  return self.items.slice(start, end)
58
58
  }
59
59
 
60
- pub func set = (ref self, int i: i >= 0 && i < self.length, move T value) {
60
+ pub func set = (ref self, int i: i >= 0 && i < self.length, mv T value) {
61
61
  self.items.replace(i, value)
62
62
  }
63
63
 
@@ -65,7 +65,7 @@ pub struct List<T>: Viewable {
65
65
  // for indices that can't be proven at compile time (cross-module calls
66
66
  // can never discharge `set`'s parameter constraint) and out-of-range is
67
67
  // a bug, not a case.
68
- pub func set_or_panic = (ref self, int i, move T value) {
68
+ pub func set_or_panic = (ref self, int i, mv T value) {
69
69
  if i >= 0 && i < self.length {
70
70
  self.set(i, value)
71
71
  return
@@ -74,7 +74,7 @@ pub struct List<T>: Viewable {
74
74
  }
75
75
 
76
76
  // A deep copy: a fresh List<T> with an independent copy of every element.
77
- // For owning element types (strings, owning value structs) each slot in the
77
+ // For mv element types (strings, mv value structs) each slot in the
78
78
  // copy owns its own heap data (Buffer deep-copies on store), so the source
79
79
  // and the copy share nothing. Not available for class/trait element types
80
80
  // (the copy would share the stored instances — the checker rejects it).
@@ -8,7 +8,7 @@
8
8
  * it is correct for negative hashes too: two's-complement `&` already lands
9
9
  * in `[0, cap)`, which is why no negative adjustment is needed.
10
10
  **/
11
- pub struct Map<TK: Hashable + Equatable, TV> {
11
+ pub mv struct Map<TK: Hashable + Equatable, TV> {
12
12
  var length = 0
13
13
  var keys = Buffer<TK>()
14
14
  var values = Buffer<TV>()
@@ -17,6 +17,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
17
17
  // Variadic-tuple constructor: Map<string, int>(["a", 1], ["b", 2]) or
18
18
  // Map(["a", 1], ["b", 2]) (type args inferred from the first pair).
19
19
  // Zero pairs yields an empty Map, so this also covers Map<K, V>().
20
+ // The pair reads are temp-rooted (`pairs.at(i)` is a statement temp):
21
+ // the element transfer is absorbed by set's mv store (store_T
22
+ // deep-copies string-field elements), so no explicit mv is spelled.
20
23
  pub func #init = (self, ...[TK, TV] pairs) {
21
24
  var i = 0
22
25
  while i < pairs.length; i += 1 {
@@ -24,7 +27,7 @@ pub struct Map<TK: Hashable + Equatable, TV> {
24
27
  }
25
28
  }
26
29
 
27
- pub func set = (ref self, move TK key, move TV value) {
30
+ pub func set = (ref self, mv TK key, mv TV value) {
28
31
  var int cap = self.keys.cap
29
32
  if cap == 0 {
30
33
  // alloc_T: for Buffer<TK> it is T_SIZE-aware (string keys are
@@ -169,9 +172,9 @@ pub struct Map<TK: Hashable + Equatable, TV> {
169
172
  }
170
173
 
171
174
  func rehash = (ref self, int new_cap) {
172
- var Buffer<TK> old_keys = move self.keys swap Buffer<TK>()
173
- var Buffer<TV> old_values = move self.values swap Buffer<TV>()
174
- var Buffer<int> old_used = move self.used swap Buffer<int>()
175
+ var Buffer<TK> old_keys = mv self.keys swap Buffer<TK>()
176
+ var Buffer<TV> old_values = mv self.values swap Buffer<TV>()
177
+ var Buffer<int> old_used = mv self.used swap Buffer<int>()
175
178
  var int old_cap = old_keys.cap
176
179
 
177
180
  self.keys.alloc(new_cap)
@@ -187,13 +190,13 @@ pub struct Map<TK: Hashable + Equatable, TV> {
187
190
  // afterwards. load_T would leave the old slot referencing
188
191
  // the same class pointer — a double-free when old_keys is
189
192
  // destroyed. The results are bound to locals so an
190
- // owning-element copy (e.g. a `Buffer<string>` slot, which
193
+ // mv-element copy (e.g. a `Buffer<string>` slot, which
191
194
  // store_T strdup's) is freed here once the new buffer has
192
195
  // made its own copy — passing them inline would orphan the
193
196
  // move_T results.
194
197
  var TK k = old_keys.move(i)
195
198
  var TV v = old_values.move(i)
196
- self.set(move k, move v)
199
+ self.set(mv k, mv v)
197
200
  }
198
201
  }
199
202
  }
@@ -28,5 +28,5 @@ pub struct Math {
28
28
  }
29
29
 
30
30
  // libm natural logarithm — extern.
31
- extern func log = (float x, out float)
31
+ foreign func log = (float x, out float)
32
32
  }
@@ -10,16 +10,28 @@
10
10
  // observes the cancel flag at its next checkpoint after acquiring — so a
11
11
  // matching unlock is always sound.
12
12
 
13
+ // Mutex is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 3 — the shape
14
+ // menu): the single field is an opaque handle, so the value is movable and
15
+ // its `#destroy` closes what the handle names. Moving a Mutex transfers the
16
+ // handle; there is no aliasing copy to misuse. Sharing one across tasks
17
+ // rides the checked region borrows (`async { }`) — the lock/unlock methods
18
+ // take the receiver bare (struct receivers travel by address), so a locked
19
+ // section mutates the kernel object the handle names, never the binding.
20
+
13
21
  /**
14
22
  * A pthread-backed mutual-exclusion lock for protecting shared mutable state
15
23
  **/
16
- pub class Mutex: Sendable {
24
+ pub mv struct Mutex {
17
25
  pub var uint64 handle = 0
18
26
 
19
27
  pub func #init = (self) {
28
+ // The constructor's `self` is the INLINE instance (a local value in the
29
+ // C lowering — methods take the pointer form, the ctor does not), so the
30
+ // C body uses the `.` accessor; the aarch64 body writes through x19 =
31
+ // &instance as always.
20
32
  ```
21
33
  #arch: c
22
- self->handle = (unsigned long long)__nomen_mutex_create();
34
+ self.handle = (unsigned long long)__nomen_mutex_create();
23
35
  ```
24
36
  ```
25
37
  #arch: aarch64
@@ -15,10 +15,16 @@
15
15
  //
16
16
  import Time
17
17
 
18
+ // Random is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 3 — the shape
19
+ // menu): bindings mv instead of alias. The state is a bare uint64, so the
20
+ // value is freely movable (and trivially copyable in principle — `mv`
21
+ // is the uniform spelling for the launch/IO primitives; a `ref Random`
22
+ // parameter is the read-only borrow that keeps one stream per binding).
23
+
18
24
  /**
19
25
  * A fast splitmix64 pseudo-random number generator
20
26
  **/
21
- pub class Random {
27
+ pub mv struct Random {
22
28
  // The raw 64-bit generator state (seeded from the wall clock by the
23
29
  // no-arg constructor, or an explicit seed for reproducible sequences).
24
30
  pub var uint64 state = 0
@@ -1,4 +1,4 @@
1
- pub must_use enum Result<T, E> {
1
+ pub checked enum Result<T, E> {
2
2
  case ok(T value)
3
3
  case error(E error)
4
4
  }
@@ -1,9 +1,9 @@
1
- // Marker trait for types whose values are safe to move across task boundaries.
1
+ // Marker trait for types whose values are safe to mv across task boundaries.
2
2
  // See ASYNC.md for the design. Auto-derivable in a follow-up; for now, structs
3
3
  // opt in explicitly with `: Sendable`.
4
4
 
5
5
  /**
6
- * A marker trait for values that are safe to move across task boundaries
6
+ * A marker trait for values that are safe to mv across task boundaries
7
7
  **/
8
8
  pub trait Sendable {
9
9
  }
@@ -7,12 +7,12 @@
7
7
  * slot indexing is a mask (`hash & (cap - 1)`) — correct for negative hashes
8
8
  * too (two's-complement `&` already lands in `[0, cap)`).
9
9
  **/
10
- pub struct Set<T: Hashable + Equatable> {
10
+ pub mv struct Set<T: Hashable + Equatable> {
11
11
  var length = 0
12
12
  var slots = Buffer<T>()
13
13
  var used = Buffer<int>()
14
14
 
15
- pub func add = (ref self, move T value) {
15
+ pub func add = (ref self, mv T value) {
16
16
  var int cap = self.slots.cap
17
17
  if cap == 0 {
18
18
  cap = self.slots.alloc(8)
@@ -148,8 +148,8 @@ pub struct Set<T: Hashable + Equatable> {
148
148
  }
149
149
 
150
150
  func rehash = (ref self, int new_cap) {
151
- var Buffer<T> old_slots = move self.slots swap Buffer<T>()
152
- var Buffer<int> old_used = move self.used swap Buffer<int>()
151
+ var Buffer<T> old_slots = mv self.slots swap Buffer<T>()
152
+ var Buffer<int> old_used = mv self.used swap Buffer<int>()
153
153
  var int old_cap = old_slots.cap
154
154
 
155
155
  self.slots.alloc(new_cap)
@@ -163,12 +163,12 @@ pub struct Set<T: Hashable + Equatable> {
163
163
  // is owned by exactly one buffer (the new self) afterwards.
164
164
  // load_T would leave the old slot referencing the same class
165
165
  // pointer — a double-free when old_slots is destroyed. The
166
- // result is bound to a local so an owning-element copy (e.g. a
166
+ // result is bound to a local so a mv-element copy (e.g. a
167
167
  // `Buffer<string>` slot, which store_T strdup's) is freed here
168
168
  // once the new buffer has made its own copy — passing it inline
169
169
  // would orphan the move_T result.
170
170
  var T v = old_slots.move(i)
171
- self.add(move v)
171
+ self.add(mv v)
172
172
  }
173
173
  }
174
174
  }
@@ -1,18 +1,18 @@
1
1
  // Spawnable — the trait role of a deferred-work LAUNCHER (the C# shape;
2
- // see docs/ASYNC.md, "Design decisions"). A Spawnable class packs a deferred unit of work
3
- // (the construction special form) and its `start` submits it, yielding the
4
- // library-owned `Task<T>` handle — so the await half is guaranteed by the
5
- // return type and each type carries exactly one role: `Thread<T>`/`Fiber<T>`
6
- // are spawnable, `Task<T>` is awaitable. `Awaitable` stays non-generic (its
7
- // `wait` does not mention T); `Spawnable` is generic because `start`'s
8
- // return type does.
2
+ // see docs/ASYNC.md, "Design decisions"). A Spawnable type packs a deferred
3
+ // unit of work (the construction special form) and its `start` submits it,
4
+ // yielding the library-owned `Task<T>` handle — so the await half is
5
+ // guaranteed by the return type and each type carries exactly one role:
6
+ // `Thread<T>`/`Fiber<T>` are spawnable, `Task<T>` is awaitable.
7
+ // `Awaitable` stays non-generic (its `wait` does not mention T);
8
+ // `Spawnable` is generic because `start`'s return type does.
9
9
  //
10
10
  // `detach` is the daemon role: run the work unjoinable, statement only.
11
11
 
12
12
  /**
13
- * A class that can launch a deferred call and hand back its Task<T> handle
13
+ * A type that can launch a deferred call and hand back its Task<T> handle
14
14
  **/
15
15
  pub trait Spawnable<T> {
16
- func start = (ref self, move out Task<T>)
16
+ func start = (ref self, mv out Task<T>)
17
17
  func detach = (ref self)
18
18
  }
@@ -28,10 +28,9 @@ pub struct Directory {
28
28
  case err == 66 {
29
29
  return DirectoryError.not_empty
30
30
  }
31
- else {
31
+ } else {
32
32
  return DirectoryError.other
33
33
  }
34
- }
35
34
  }
36
35
 
37
36
  // (static) Create a directory at `path`; returns errno (0 on success).
@@ -56,10 +56,9 @@ pub struct File {
56
56
  case err == 17 {
57
57
  return FileError.already_exists
58
58
  }
59
- else {
59
+ } else {
60
60
  return FileError.other
61
61
  }
62
- }
63
62
  }
64
63
 
65
64
  // Open the file at `path` with a C mode string ("r", "w", "a", …).
@@ -157,9 +156,9 @@ pub struct File {
157
156
  }
158
157
 
159
158
  // Read every byte from the current position to EOF and return it. Sets
160
- // `eof` and `error`. Declared `move out string`: the raw body mallocs a
159
+ // `eof` and `error`. Declared `mv out string`: the raw body mallocs a
161
160
  // fresh buffer and hands ownership to the caller.
162
- func raw_read_all = (ref self, move out string) {
161
+ func raw_read_all = (ref self, mv out string) {
163
162
  ```
164
163
  #arch: c
165
164
  FILE *f = (FILE*)(unsigned long long)self->handle;
@@ -272,8 +271,8 @@ pub struct File {
272
271
 
273
272
  // Read up to the next '\n' (the newline is not included). Sets `eof`
274
273
  // when the end of the file is reached and `error` on failure. The raw
275
- // body mallocs a fresh buffer — `move out string` transfers it.
276
- func raw_read_line = (ref self, move out string) {
274
+ // body mallocs a fresh buffer — `mv out string` transfers it.
275
+ func raw_read_line = (ref self, mv out string) {
277
276
  ```
278
277
  #arch: c
279
278
  FILE *f = (FILE*)(unsigned long long)self->handle;
@@ -416,8 +415,8 @@ pub struct File {
416
415
 
417
416
  // Read up to `size` bytes from the current position. Sets `eof` if fewer
418
417
  // than `size` bytes remain and `error` on failure. The raw body mallocs a
419
- // fresh buffer — `move out string` transfers it.
420
- func raw_read_chunk = (ref self, int size, move out string) {
418
+ // fresh buffer — `mv out string` transfers it.
419
+ func raw_read_chunk = (ref self, int size, mv out string) {
421
420
  ```
422
421
  #arch: c
423
422
  FILE *f = (FILE*)(unsigned long long)self->handle;
@@ -590,7 +589,7 @@ pub struct File {
590
589
 
591
590
  // (static) Write `data` to `path` (replacing any existing contents) in
592
591
  // one open/write/close. A write failure is reported as `.error`, not
593
- // silently swallowed (the `must_use` Result discard check forces this to
592
+ // silently swallowed (the `checked` Result discard check forces this to
594
593
  // be deliberate).
595
594
  pub func write_all = (string path, string data, out Result<bool, FileError>) {
596
595
  var Result<bool, FileError> result = .error(FileError.other)
@@ -48,10 +48,9 @@ pub struct Http {
48
48
  case err == 3 {
49
49
  return HttpError.connect
50
50
  }
51
- else {
51
+ } else {
52
52
  return HttpError.other
53
53
  }
54
- }
55
54
  }
56
55
 
57
56
  // Shared socket round-trip used by get/post. `method` is the request
@@ -59,7 +58,7 @@ pub struct Http {
59
58
  // (sends `body` and the Content-* headers). Sets self->status (0 on
60
59
  // failure) and self->error, and returns the response body (empty string
61
60
  // on failure).
62
- func raw_exchange = (ref self, string method, string url, string body, move out string) {
61
+ func raw_exchange = (ref self, string method, string url, string body, mv out string) {
63
62
  // Parse the URL: [http://]host[:port][/path]
64
63
  var host_start = 0
65
64
  if url.starts_with("http://") {
@@ -23,10 +23,15 @@
23
23
  // linked companion on aarch64) — OS socket/DNS interop, where hand-written
24
24
  // per-target assembly is not practical.
25
25
 
26
+ // Tcp is an OWNING STRUCT (STRUCT_PLAN_3 Phase R, tranche 3 — the shape
27
+ // menu): the fields are the fd and an error code — the fd is the handle, so
28
+ // the value is movable and `#destroy` closes it. A moved Tcp transfers the
29
+ // socket; there is no aliasing copy to double-close.
30
+
26
31
  /**
27
32
  * A non-blocking TCP socket whose waits park the calling fiber
28
33
  **/
29
- pub class Tcp: Sendable {
34
+ pub mv struct Tcp {
30
35
  // The underlying file descriptor, -1 when closed/failed.
31
36
  pub var int fd = -1
32
37
  // 0 = ok; 1 = DNS, 2 = socket, 3 = connect, 4 = listen, 5 = closed.
@@ -64,7 +69,7 @@ pub class Tcp: Sendable {
64
69
  // ---- listening ----
65
70
 
66
71
  // Create a listening socket bound to `port` on all interfaces.
67
- pub func listen = (int port, int backlog, move out Tcp) {
72
+ pub func listen = (int port, int backlog, mv out Tcp) {
68
73
  var int handle = Tcp.listen_fd(port, backlog)
69
74
  var t = Tcp(handle)
70
75
  if handle < 0 {
@@ -76,7 +81,7 @@ pub class Tcp: Sendable {
76
81
  // Accept the next connection, parking the fiber while the backlog is
77
82
  // empty. The returned socket is -1 if the listener was cancelled or
78
83
  // failed.
79
- pub func accept = (ref self, move out Tcp) {
84
+ pub func accept = (ref self, mv out Tcp) {
80
85
  var int handle = Tcp.accept_fd(self.fd)
81
86
  var t = Tcp(handle)
82
87
  if handle < 0 {
@@ -88,7 +93,7 @@ pub class Tcp: Sendable {
88
93
  // ---- connecting ----
89
94
 
90
95
  // Connect to `host`:`port`. Check `fd >= 0` (or `error == 0`) for success.
91
- pub func connect = (string host, int port, move out Tcp) {
96
+ pub func connect = (string host, int port, mv out Tcp) {
92
97
  var int handle = Tcp.socket_fd()
93
98
  if handle < 0 {
94
99
  var bad = Tcp(-1)
@@ -115,12 +120,12 @@ pub class Tcp: Sendable {
115
120
 
116
121
  // Receive up to `max` bytes. Parks the fiber until data arrives; returns
117
122
  // the empty string at end-of-stream, on error, or when cancelled.
118
- pub func recv = (ref self, int max, move out string) {
123
+ pub func recv = (ref self, int max, mv out string) {
119
124
  return Tcp.recv_some(self.fd, max)
120
125
  }
121
126
 
122
127
  // Receive until the peer closes (how Connection: close HTTP works).
123
- pub func recv_all = (ref self, move out string) {
128
+ pub func recv_all = (ref self, mv out string) {
124
129
  return Tcp.recv_until_close(self.fd)
125
130
  }
126
131
 
@@ -326,7 +331,7 @@ pub class Tcp: Sendable {
326
331
  ```
327
332
  }
328
333
 
329
- func recv_some = (int handle, int max, move out string) {
334
+ func recv_some = (int handle, int max, mv out string) {
330
335
  ```
331
336
  #arch: c
332
337
  long cap = max > 0 ? max : 1;
@@ -375,7 +380,7 @@ pub class Tcp: Sendable {
375
380
  ```
376
381
  }
377
382
 
378
- func recv_until_close = (int handle, move out string) {
383
+ func recv_until_close = (int handle, mv out string) {
379
384
  ```
380
385
  #arch: c
381
386
  long cap = 4096, len = 0;
@@ -1,7 +1,7 @@
1
1
  // FFI: the C library's heap-copy entry point (string.h). The adapter
2
2
  // marshals the fat string to the thin char* the C ABI expects; the string
3
3
  // result is re-wrapped with its length.
4
- extern func strdup = (string s, move out string)
4
+ foreign func strdup = (string s, mv out string)
5
5
 
6
6
  // Raw memory externs — the allocation primitives every `unsafe` Nomen body
7
7
  // across core (Buffer, StringBuilder, Array, ...) is built on. This file is
@@ -9,17 +9,20 @@ extern func strdup = (string s, move out string)
9
9
  // every core file regardless of pull order. Free externs emit under an
10
10
  // `extern_<name>` label that wraps the identically-named C symbol, so these
11
11
  // can never collide with it (docs/CORE_RAW.md roadmap items 1+2).
12
- extern func calloc = (int count, int size, out uint64)
13
- extern func malloc = (int bytes, out uint64)
14
- extern func realloc = (uint64 address, int bytes, out uint64)
15
- extern func free = (uint64 address)
16
- extern func memcpy = (uint64 dst, uint64 src, int bytes, out uint64)
17
- extern func memset = (uint64 dst, int value, int bytes, out uint64)
12
+ foreign func calloc = (int count, int size, out uint64)
13
+ foreign func malloc = (int bytes, out uint64)
14
+ foreign func realloc = (uint64 address, int bytes, out uint64)
15
+ foreign func free = (uint64 address)
16
+ foreign func memcpy = (uint64 dst, uint64 src, int bytes, out uint64)
17
+ foreign func memset = (uint64 dst, int value, int bytes, out uint64)
18
18
 
19
19
  /**
20
- * A UTF-8 text string — a heap-owned, length-tracked sequence of bytes
20
+ * A UTF-8 text string — a heap-owned, length-tracked sequence of bytes.
21
+ * STRUCT_PLAN_3 D3: `string` is OWNING — the fat (ptr, len) pair owns its
22
+ * bytes, so bindings mv unless a copy is spelled (`.copy()`); `view string`
23
+ * is the cheap read-only passing form.
21
24
  **/
22
- pub struct string: Stringable, Hashable, Equatable {
25
+ pub mv struct string: Stringable, Hashable, Equatable {
23
26
  pub func hash = (self, out uint) {
24
27
  // djb2 over exactly self.length bytes — matches the byte count of
25
28
  // owned strings and literals (views hash the viewed bytes only).
@@ -31,12 +34,19 @@ pub struct string: Stringable, Hashable, Equatable {
31
34
  return h
32
35
  }
33
36
 
34
- // Returns an OWNED byte-exact copy of self (`move out string`). Fresh
37
+ // The uniform mv-type verb: a fresh, owned byte-exact copy of self.
38
+ // The deep-copy spelling the binding/assignment copy errors name — same
39
+ // allocation contract as to_string (fresh buffer, never an alias).
40
+ pub func copy = (self, mv out string) {
41
+ return self.to_string()
42
+ }
43
+
44
+ // Returns an OWNED byte-exact copy of self (`mv out string`). Fresh
35
45
  // allocation, never an alias of self's storage — the result can outlive
36
46
  // the receiver (e.g. escape a match branch that reclaims the scrutinee
37
47
  // temp). Copies by tracked length, so embedded NULs survive (an extern
38
48
  // strdup boundary would re-synthesize length via strlen and truncate).
39
- pub func to_string = (self, move out string) {
49
+ pub func to_string = (self, mv out string) {
40
50
  ```
41
51
  #arch: c
42
52
  // Fat-string ABI: copy self.len bytes; no strlen anywhere.
@@ -90,7 +100,7 @@ pub struct string: Stringable, Hashable, Equatable {
90
100
  panic("index out of range")
91
101
  }
92
102
 
93
- // A non-owning slice [start, end) into self's buffer. Returns a `view
103
+ // A non-mv slice [start, end) into self's buffer. Returns a `view
94
104
  // string` (ptr, len) that borrows from self: it may not outlive self's
95
105
  // scope and is invalidated if self is reassigned. Use .to_string() to
96
106
  // materialize an owned copy.
@@ -178,9 +178,9 @@ pub struct StringBuilder {
178
178
  // measure-and-restart shape: record `length()`, append a section, then
179
179
  // `take_since(mark)` to measure it and re-emit decorated. `mark` clamps
180
180
  // to [0, len]; the returned string is always an independent allocation.
181
- // (`move out string` — the raw body mallocs the result, so the caller
181
+ // (`mv out string` — the raw body mallocs the result, so the caller
182
182
  // owns it by signature, like `Console.read_line`.)
183
- pub func take_since = (ref self, int mark, move out string) {
183
+ pub func take_since = (ref self, int mark, mv out string) {
184
184
  ```
185
185
  #arch: c
186
186
  int start = mark;