nomen-lang 0.8.0 → 0.10.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 (90) hide show
  1. package/audit_runtime.c +12 -2
  2. package/core/System/Arena.nm +14 -5
  3. package/core/System/Array.nm +1 -1
  4. package/core/System/Atomic.nm +3 -3
  5. package/core/System/BigInt.nm +182 -23
  6. package/core/System/Buffer.nm +392 -33
  7. package/core/System/ClassBuffer.nm +145 -13
  8. package/core/System/Controls/Alert.nm +3 -3
  9. package/core/System/Controls/App.nm +17 -17
  10. package/core/System/Controls/Button.nm +2 -2
  11. package/core/System/Controls/CheckBox.nm +3 -3
  12. package/core/System/Controls/ColorPicker.nm +2 -2
  13. package/core/System/Controls/ComboBox.nm +2 -2
  14. package/core/System/Controls/Container.nm +39 -33
  15. package/core/System/Controls/DatePicker.nm +1 -1
  16. package/core/System/Controls/Form.nm +2 -2
  17. package/core/System/Controls/GroupBox.nm +2 -2
  18. package/core/System/Controls/ImageView.nm +2 -2
  19. package/core/System/Controls/Layout.nm +5 -5
  20. package/core/System/Controls/LevelIndicator.nm +2 -2
  21. package/core/System/Controls/ListView.nm +2 -2
  22. package/core/System/Controls/Menu.nm +2 -2
  23. package/core/System/Controls/NumberInput.nm +3 -3
  24. package/core/System/Controls/OtpInput.nm +2 -2
  25. package/core/System/Controls/OutlineView.nm +2 -2
  26. package/core/System/Controls/Pagination.nm +14 -14
  27. package/core/System/Controls/Popover.nm +2 -2
  28. package/core/System/Controls/Progress.nm +2 -2
  29. package/core/System/Controls/Radio.nm +3 -3
  30. package/core/System/Controls/Scrollable.nm +1 -1
  31. package/core/System/Controls/SearchField.nm +2 -2
  32. package/core/System/Controls/SecureField.nm +2 -2
  33. package/core/System/Controls/Segmented.nm +2 -2
  34. package/core/System/Controls/Select.nm +2 -2
  35. package/core/System/Controls/Separator.nm +2 -2
  36. package/core/System/Controls/Sheet.nm +2 -2
  37. package/core/System/Controls/Slider.nm +2 -2
  38. package/core/System/Controls/Spinner.nm +5 -5
  39. package/core/System/Controls/SplitView.nm +3 -3
  40. package/core/System/Controls/Stepper.nm +2 -2
  41. package/core/System/Controls/Switch.nm +2 -2
  42. package/core/System/Controls/Table.nm +2 -2
  43. package/core/System/Controls/Tabs.nm +2 -2
  44. package/core/System/Controls/Text.nm +2 -2
  45. package/core/System/Controls/TextBox.nm +3 -3
  46. package/core/System/Controls/TextView.nm +2 -2
  47. package/core/System/Controls/Toggle.nm +3 -3
  48. package/core/System/Controls/Toolbar.nm +2 -2
  49. package/core/System/Controls/Window.nm +12 -5
  50. package/core/System/Fiber.nm +16 -3
  51. package/core/System/Graph.nm +2 -2
  52. package/core/System/LinkedList.nm +13 -4
  53. package/core/System/List.nm +76 -17
  54. package/core/System/Map.nm +179 -21
  55. package/core/System/Mutex.nm +4 -4
  56. package/core/System/Random.nm +6 -7
  57. package/core/System/Set.nm +99 -23
  58. package/core/System/StableList.nm +371 -0
  59. package/core/System/Stream/Directory.nm +2 -2
  60. package/core/System/Stream/File.nm +18 -18
  61. package/core/System/Stream/Http.nm +5 -5
  62. package/core/System/Stream/Tcp.nm +5 -5
  63. package/core/System/String.nm +10 -5
  64. package/core/System/StringBuilder.nm +223 -12
  65. package/core/System/Task.nm +56 -64
  66. package/core/System/Test.nm +18 -18
  67. package/core/System/Text/CharIndex.nm +9 -9
  68. package/core/System/Text/Chars.nm +1 -1
  69. package/core/System/Text/Json.nm +72 -58
  70. package/core/System/Text/JsonTree.nm +126 -98
  71. package/core/System/Text/Regex.nm +43 -38
  72. package/core/System/Text/Utf8.nm +5 -5
  73. package/core/System/Thread.nm +26 -3
  74. package/core/System/Tree.nm +19 -3
  75. package/core/System/float.nm +36 -22
  76. package/core/System/int.nm +80 -28
  77. package/core/System/int16.nm +11 -0
  78. package/core/System/int32.nm +11 -0
  79. package/core/System/int64.nm +11 -0
  80. package/core/System/int8.nm +11 -0
  81. package/core/System/uint.nm +11 -0
  82. package/core/System/uint16.nm +11 -0
  83. package/core/System/uint32.nm +11 -0
  84. package/core/System/uint64.nm +11 -0
  85. package/core/System/uint8.nm +11 -0
  86. package/core/docs/System/StringBuilder.md +6 -0
  87. package/core/docs/System/Text/JsonTree.md +3 -2
  88. package/dist/index.mjs +37622 -30603
  89. package/package.json +1 -1
  90. package/src/bench_loop.nm +9 -9
package/audit_runtime.c CHANGED
@@ -51,13 +51,20 @@ typedef struct {
51
51
  unsigned long pad; // keeps the payload 16-byte aligned
52
52
  } nomen_audit_header;
53
53
 
54
+ // True when the NOMEN_AUDIT_TRACE env var is on. The getenv is not cached —
55
+ // the trace is a developer diagnostic, and alloc/free volumes under it are
56
+ // already dominated by the fprintf.
57
+ static int audit_trace(void) {
58
+ return getenv("NOMEN_AUDIT_TRACE") != 0;
59
+ }
60
+
54
61
  static void *audit_alloc(unsigned long size) {
55
62
  nomen_audit_header *header = (nomen_audit_header *)malloc(size + sizeof(nomen_audit_header));
56
63
  if (!header) return 0;
57
64
  header->magic = NOMEN_AUDIT_MAGIC;
58
65
  header->size = size;
59
66
  header->state = NOMEN_AUDIT_LIVE;
60
- if (getenv("NOMEN_AUDIT_TRACE")) fprintf(stderr, "ALLOC %lu\n", (unsigned long)size);
67
+ if (audit_trace()) fprintf(stderr, "ALLOC %p %lu\n", (void *)(header + 1), (unsigned long)size);
61
68
  __atomic_add_fetch(&nomen_malloc_count, 1, __ATOMIC_SEQ_CST);
62
69
  return (void *)(header + 1);
63
70
  }
@@ -74,7 +81,7 @@ static nomen_audit_header *audit_header(void *ptr) {
74
81
  // Retire a block: poison the header first so a second free of the same pointer
75
82
  // is recognized as stale, then hand the memory back and drop the count.
76
83
  static void audit_release(nomen_audit_header *header) {
77
- if (getenv("NOMEN_AUDIT_TRACE")) fprintf(stderr, "FREE %lu\n", (unsigned long)header->size);
84
+ if (audit_trace()) fprintf(stderr, "FREE %p %lu\n", (void *)(header + 1), (unsigned long)header->size);
78
85
  header->magic = 0;
79
86
  header->state = NOMEN_AUDIT_DEAD;
80
87
  __atomic_sub_fetch(&nomen_malloc_count, 1, __ATOMIC_SEQ_CST);
@@ -157,6 +164,9 @@ void nomen_free_wrap(void *ptr) {
157
164
  // of passing it on, and leave the count alone: an unmatched free is not
158
165
  // evidence that a live block was reclaimed.
159
166
  if (!header || header->state != NOMEN_AUDIT_LIVE) {
167
+ if (audit_trace())
168
+ fprintf(stderr, "STALE-FREE %p (%s)\n", ptr,
169
+ header ? "already freed" : "not an audit allocation");
160
170
  audit_record_stale();
161
171
  audit_report_stale(0);
162
172
  return;
@@ -51,7 +51,7 @@ pub mv struct Arena<T> {
51
51
  /**
52
52
  * A fresh arena with no slots.
53
53
  **/
54
- pub func #init = (ref self) {
54
+ pub func #init = (ref self { free_indices, generations, values }) {
55
55
  self.values = Buffer<T>()
56
56
  self.generations = Buffer<int>()
57
57
  self.free_indices = Buffer<int>()
@@ -63,7 +63,7 @@ pub mv struct Arena<T> {
63
63
  * Store `value` in a slot (reusing a freed slot when one is available) and
64
64
  * return a handle to it.
65
65
  **/
66
- pub func alloc = (ref self, mv T value, out ArenaRef<T>) {
66
+ pub func alloc = (ref self { generations, values }, mv T value, out ArenaRef<T>) {
67
67
  var int index = -1
68
68
  if self.free_count > 0 {
69
69
  // Reuse a freed slot. Its generation was already bumped by `free`,
@@ -77,7 +77,16 @@ pub mv struct Arena<T> {
77
77
  self.generations.store_int(index, 0)
78
78
  }
79
79
  self.values.grow(index + 1)
80
- self.values.store(index, value)
80
+ // The value arrives owned (`mv T value`): move a value-struct element
81
+ // that OWNS resources into the fresh slot (the caller's storage
82
+ // zeroes, no deep copy). A non-owning value struct is a legal bare
83
+ // argument, so it keeps the copying store; strings keep the
84
+ // deep-copying store too (their pair arrives by value).
85
+ if T_TAKES_OWNERSHIP {
86
+ self.values.store_take(index, value)
87
+ } else {
88
+ self.values.store(index, value)
89
+ }
81
90
  var handle = ArenaRef<T>()
82
91
  handle.index = index
83
92
  handle.generation = self.generations.load_int(index)
@@ -88,7 +97,7 @@ pub mv struct Arena<T> {
88
97
  * Relinquish the slot `handle` points at (its value is reclaimed), bumping the
89
98
  * generation so every outstanding handle to that slot becomes stale.
90
99
  **/
91
- pub func free = (ref self, ArenaRef<T> handle) {
100
+ pub func free = (ref self { free_indices, generations, values }, ArenaRef<T> handle) {
92
101
  if !self.is_valid(handle) {
93
102
  panic("arena: free of a stale handle")
94
103
  }
@@ -140,7 +149,7 @@ pub mv struct Arena<T> {
140
149
  /**
141
150
  * Replace the value `handle` names (same slot, same handle).
142
151
  **/
143
- pub func set = (ref self, ArenaRef<T> handle, mv T value) {
152
+ pub func set = (ref self { values }, ArenaRef<T> handle, mv T value) {
144
153
  if !self.is_valid(handle) {
145
154
  panic("arena: set through a stale handle")
146
155
  }
@@ -50,7 +50,7 @@ pub struct Array<T>: Viewable {
50
50
  // to express: T_NEEDS_STRDUP is a per-instantiation constant the
51
51
  // monomorphizer substitutes (true for string, false otherwise) and folds,
52
52
  // so each mono body keeps only its arm.
53
- pub func set = (ref self, int index: index >= 0 && index < self.length, T value) {
53
+ pub func set = (ref self {}, int index: index >= 0 && index < self.length, T value) {
54
54
  unsafe {
55
55
  if T_NEEDS_STRDUP {
56
56
  // T is string: a fat value whose backing bytes must be
@@ -41,7 +41,7 @@ pub struct Atomic<T> {
41
41
  ```
42
42
  }
43
43
 
44
- pub func store = (ref self, T v) {
44
+ pub func store = (ref self {}, T v) {
45
45
  ```
46
46
  #arch: c
47
47
  __atomic_store_n(&self->word, v, __ATOMIC_SEQ_CST);
@@ -54,7 +54,7 @@ pub struct Atomic<T> {
54
54
  }
55
55
 
56
56
  // Adds v and returns the PREVIOUS value (fetch-and-add).
57
- pub func fetch_add = (ref self, T v, out T) {
57
+ pub func fetch_add = (ref self {}, T v, out T) {
58
58
  ```
59
59
  #arch: c
60
60
  return __atomic_fetch_add(&self->word, v, __ATOMIC_SEQ_CST);
@@ -67,7 +67,7 @@ pub struct Atomic<T> {
67
67
  }
68
68
 
69
69
  // Replaces the value and returns the PREVIOUS one.
70
- pub func swap = (ref self, T v, out T) {
70
+ pub func swap = (ref self {}, T v, out T) {
71
71
  ```
72
72
  #arch: c
73
73
  return __atomic_exchange_n(&self->word, v, __ATOMIC_SEQ_CST);
@@ -1,25 +1,69 @@
1
1
  /**
2
- * An arbitrary-precision integer
2
+ * An arbitrary-precision integer (sign-magnitude)
3
+ *
4
+ * The sign is a real three-state machine — `zero / positive / negative`,
5
+ * canonical: `sign == 0` exactly when the magnitude is zero. Every producer
6
+ * that writes limbs (the constructors, add/sub/mul/div, copy) maintains it;
7
+ * `cmp` consumes it. Limbs always hold the absolute value.
3
8
  **/
4
9
  pub mv struct BigInt {
5
10
  var sign = 0
6
11
  var len = 0
7
12
  var digits = Buffer<int>()
8
13
 
9
- pub func #init = (ref self) {
14
+ pub func #init = (ref self {}) {
10
15
  }
11
16
 
12
- pub func #init = (ref self, int val) {
13
- self.sign = 1
17
+ pub func #init = (ref self { digits }, int val) {
14
18
  var int v = val
15
19
  if v < 0 {
16
- self.sign = -1
17
20
  v = 0 - v
18
21
  }
19
22
  self.digits.grow_int(4)
20
23
  self.digits.zero_int(self.digits.cap)
21
24
  self.digits.store_int(0, v)
22
25
  self.len = 1
26
+ if val == 0 {
27
+ self.sign = 0
28
+ } else {
29
+ if val < 0 {
30
+ self.sign = -1
31
+ } else {
32
+ self.sign = 1
33
+ }
34
+ }
35
+ }
36
+
37
+ // The canonical sign: 0 for a zero magnitude, ±1 otherwise — derived
38
+ // from the magnitude so a stale stored sign can never leak into a
39
+ // comparison or a producer.
40
+ func eff_sign = (self, out int) {
41
+ if self.len == 1 && self.get(0) == 0 {
42
+ return 0
43
+ }
44
+ if self.sign < 0 {
45
+ return -1
46
+ }
47
+ return 1
48
+ }
49
+
50
+ // Reset to the canonical zero (len 1, limb 0, sign 0).
51
+ func set_zero = (ref self { digits }) {
52
+ self.ensure(1)
53
+ self.set(0, 0)
54
+ self.len = 1
55
+ self.sign = 0
56
+ }
57
+
58
+ // Store a producer's computed sign, canonicalized against the final
59
+ // magnitude: a zero result is sign 0 no matter what the sign arithmetic
60
+ // produced (0 * -1 == 0, an equal-magnitude subtraction, a zero quotient).
61
+ func finish_sign = (ref self {}, int s) {
62
+ if self.len == 1 && self.get(0) == 0 {
63
+ self.sign = 0
64
+ return
65
+ }
66
+ self.sign = s
23
67
  }
24
68
 
25
69
  // Per-limb get/set stay raw: they are `inline` and splice into the limb
@@ -36,7 +80,7 @@ pub mv struct BigInt {
36
80
  }
37
81
  }
38
82
 
39
- inline func set = (ref self, int i, uint64 val) {
83
+ inline func set = (ref self {}, int i, uint64 val) {
40
84
  unsafe {
41
85
  var ptr uint64 limbs = self.digits.data as ptr uint64
42
86
  limbs[i] = val
@@ -65,22 +109,22 @@ pub mv struct BigInt {
65
109
  }
66
110
  }
67
111
 
68
- inline func set_at = (ref self, uint64 ptr, int i, uint64 val) {
112
+ inline func set_at = (ref self {}, uint64 ptr, int i, uint64 val) {
69
113
  unsafe {
70
114
  var ptr uint64 limbs = ptr as ptr uint64
71
115
  limbs[i] = val
72
116
  }
73
117
  }
74
118
 
75
- func ensure = (ref self, int needed) {
119
+ func ensure = (ref self { digits }, int needed) {
76
120
  self.digits.grow_int(needed)
77
121
  }
78
122
 
79
- func clear = (ref self, int len) {
123
+ func clear = (ref self { digits }, int len) {
80
124
  self.digits.zero_int(len)
81
125
  }
82
126
 
83
- func copy_range_from = (ref self, BigInt src, int start, int count) {
127
+ func copy_range_from = (ref self { digits }, BigInt src, int start, int count) {
84
128
  self.ensure(count)
85
129
  var i = 0
86
130
  while i < count; i += 1 {
@@ -95,7 +139,7 @@ pub mv struct BigInt {
95
139
  }
96
140
  }
97
141
 
98
- func add_at = (ref self, BigInt other, int shift) {
142
+ func add_at = (ref self { digits }, BigInt other, int shift) {
99
143
  self.ensure(other.len + shift + 1)
100
144
  var carry = 0
101
145
  var i = 0
@@ -126,7 +170,7 @@ pub mv struct BigInt {
126
170
  }
127
171
  }
128
172
 
129
- func sub_at = (ref self, BigInt other, int shift) {
173
+ func sub_at = (ref self {}, BigInt other, int shift) {
130
174
  var borrow = 0
131
175
  var i = 0
132
176
  while i < other.len; i += 1 {
@@ -212,7 +256,31 @@ pub mv struct BigInt {
212
256
  ```
213
257
  }
214
258
 
259
+ // Sign-aware compare: the signs decide first (canonical zero sorts
260
+ // before every nonzero), and same-sign operands compare by magnitude
261
+ // with the result flipped for negatives.
215
262
  pub func cmp = (self, BigInt other, out int) {
263
+ const int sself = self.eff_sign()
264
+ const int sother = other.eff_sign()
265
+ if sself != sother {
266
+ if sself > sother {
267
+ return 1
268
+ }
269
+ return -1
270
+ }
271
+ if sself == 0 {
272
+ return 0
273
+ }
274
+ var int mag = self.mag_cmp(other)
275
+ if sself < 0 {
276
+ mag = 0 - mag
277
+ }
278
+ return mag
279
+ }
280
+
281
+ // Magnitude compare (ignores sign): 1 when |self| > |other|, -1 when
282
+ // less, 0 when the limbs are equal.
283
+ func mag_cmp = (self, BigInt other, out int) {
216
284
  if self.len != other.len {
217
285
  if self.len > other.len {
218
286
  return 1
@@ -235,7 +303,65 @@ pub mv struct BigInt {
235
303
  return 0
236
304
  }
237
305
 
238
- pub func add_to = (ref self, BigInt a, BigInt b) {
306
+ // The signed sum (and, with flip_b, difference): self = a + b, or
307
+ // a - b when flip_b. Same-sign operands magnitude-add; opposite-sign
308
+ // operands subtract the smaller magnitude from the larger and take the
309
+ // larger's sign; a zero operand degenerates to a copy. This is the one
310
+ // place the sign machine meets the limb machines — every rule is here,
311
+ // not duplicated at call sites.
312
+ func signed_add = (ref self { digits }, BigInt a, BigInt b, bool flip_b) {
313
+ var int sa = a.eff_sign()
314
+ var int sb = b.eff_sign()
315
+ if flip_b {
316
+ sb = 0 - sb
317
+ }
318
+ // A zero operand: the result is the other operand (flipped for a
319
+ // subtracted zero is still zero — -0 is canonical 0).
320
+ if sb == 0 {
321
+ if sa == 0 {
322
+ self.set_zero()
323
+ return
324
+ }
325
+ self.copy_from(a)
326
+ self.sign = sa
327
+ return
328
+ }
329
+ if sa == 0 {
330
+ self.copy_from(b)
331
+ self.sign = sb
332
+ return
333
+ }
334
+ if sa == sb {
335
+ self.mag_add_to(a, b)
336
+ self.sign = sa
337
+ return
338
+ }
339
+ var int mag = a.mag_cmp(b)
340
+ if mag == 0 {
341
+ self.set_zero()
342
+ return
343
+ }
344
+ if mag > 0 {
345
+ self.mag_sub_to(a, b)
346
+ self.sign = sa
347
+ return
348
+ }
349
+ self.mag_sub_to(b, a)
350
+ self.sign = sb
351
+ }
352
+
353
+ // self = a + b (signed).
354
+ pub func add_to = (ref self { digits }, BigInt a, BigInt b) {
355
+ self.signed_add(a, b, false)
356
+ }
357
+
358
+ // self = a - b (signed; truncating like the limb primitive it wraps).
359
+ pub func sub_to = (ref self { digits }, BigInt a, BigInt b) {
360
+ self.signed_add(a, b, true)
361
+ }
362
+
363
+ // Magnitude add: |self| = |a| + |b| (sign untouched — signed_add owns it).
364
+ func mag_add_to = (ref self { digits }, BigInt a, BigInt b) {
239
365
  if a.len == 1 && b.len == 1 {
240
366
  var uint64 a_val = a.get(0)
241
367
  var uint64 b_val = b.get(0)
@@ -297,7 +423,9 @@ pub mv struct BigInt {
297
423
  }
298
424
  }
299
425
 
300
- pub func sub_to = (ref self, BigInt a, BigInt b) {
426
+ // Magnitude subtract: |self| = |a| - |b|; callers guarantee |a| >= |b|
427
+ // (signed_add orders the operands). Sign untouched.
428
+ func mag_sub_to = (ref self { digits }, BigInt a, BigInt b) {
301
429
  if a.len == 1 && b.len == 1 {
302
430
  self.ensure(1)
303
431
  self.set(0, a.get(0) - b.get(0))
@@ -342,7 +470,10 @@ pub mv struct BigInt {
342
470
  }
343
471
  }
344
472
 
345
- pub func mul_to = (ref self, BigInt a, BigInt b, ref BigInt scratch) {
473
+ pub func mul_to = (ref self { digits }, BigInt a, BigInt b, ref BigInt scratch { digits }) {
474
+ // The product's sign, computed before anything can alias-mutate the
475
+ // operands (self may alias a or b).
476
+ const int mul_sign = a.eff_sign() * b.eff_sign()
346
477
  if a.len == 1 || b.len == 1 {
347
478
  var uint64 sv
348
479
  var int other_len
@@ -406,6 +537,7 @@ pub mv struct BigInt {
406
537
  if self.len == 0 {
407
538
  self.len = 1
408
539
  }
540
+ self.finish_sign(mul_sign)
409
541
  return
410
542
  }
411
543
 
@@ -458,6 +590,7 @@ pub mv struct BigInt {
458
590
  }
459
591
  }
460
592
  self.len = last_nonzero
593
+ self.finish_sign(mul_sign)
461
594
  return
462
595
  }
463
596
 
@@ -530,11 +663,18 @@ pub mv struct BigInt {
530
663
  }
531
664
  self.len = self.len - 1
532
665
  }
666
+ self.finish_sign(mul_sign)
533
667
  }
534
668
 
535
669
  // self = quotient, a = dividend, b = divisor, remainder = remainder
536
670
  // Uses remainder's internal buffer as working space
537
- pub func div_to = (ref self, BigInt a, BigInt b, ref BigInt remainder) {
671
+ //
672
+ // Truncating division (C semantics): the quotient takes the product of
673
+ // the operands' signs, the remainder takes the dividend's, and both are
674
+ // canonicalized (a zero quotient/remainder is sign 0).
675
+ pub func div_to = (ref self { digits }, BigInt a, BigInt b, ref BigInt remainder { digits }) {
676
+ const int q_sign = a.eff_sign() * b.eff_sign()
677
+ const int r_sign = a.eff_sign()
538
678
  if b.len == 1 {
539
679
  const uint64 divisor = b.get(0)
540
680
  self.ensure(a.len)
@@ -580,9 +720,11 @@ pub mv struct BigInt {
580
720
  if self.len == 0 {
581
721
  self.len = 1
582
722
  }
723
+ self.finish_sign(q_sign)
583
724
  remainder.len = 1
584
725
  remainder.ensure(1)
585
726
  remainder.set(0, rem)
727
+ remainder.finish_sign(r_sign)
586
728
  return
587
729
  }
588
730
 
@@ -596,6 +738,7 @@ pub mv struct BigInt {
596
738
  self.ensure(1)
597
739
  self.set(0, 0)
598
740
  self.len = 1
741
+ self.sign = 0
599
742
  remainder.ensure(a.len)
600
743
  remainder.clear(remainder.digits.cap)
601
744
  var ci = 0
@@ -603,6 +746,7 @@ pub mv struct BigInt {
603
746
  remainder.set(ci, a.get(ci))
604
747
  }
605
748
  remainder.len = a.len
749
+ remainder.finish_sign(r_sign)
606
750
  return
607
751
  }
608
752
 
@@ -800,6 +944,7 @@ pub mv struct BigInt {
800
944
  }
801
945
  self.len -= 1
802
946
  }
947
+ self.finish_sign(q_sign)
803
948
 
804
949
  // Extract remainder from working dividend (normalized at wd_off..wd_off+n-1)
805
950
  // Shift right by 'shift' to un-normalize
@@ -826,6 +971,7 @@ pub mv struct BigInt {
826
971
  }
827
972
  remainder.len = remainder.len - 1
828
973
  }
974
+ remainder.finish_sign(r_sign)
829
975
  }
830
976
 
831
977
  pub func to_digit = (self, out int) {
@@ -835,32 +981,45 @@ pub mv struct BigInt {
835
981
  return -1
836
982
  }
837
983
 
838
- pub func copy_from = (ref self, BigInt other) {
984
+ pub func copy_from = (ref self { digits }, BigInt other) {
839
985
  self.ensure(other.len)
840
986
  self.len = other.len
841
- self.sign = other.sign
842
987
  var i = 0
843
988
  while i < other.len; i += 1 {
844
989
  self.set(i, other.get(i))
845
990
  }
991
+ // The copied value's canonical sign — 0 for a copied zero, ±1 from
992
+ // the source otherwise (never the raw stored field).
993
+ self.sign = other.eff_sign()
846
994
  }
847
995
 
848
- pub func set_int = (ref self, int val) {
849
- self.sign = 1
996
+ pub func set_int = (ref self { digits }, int val) {
850
997
  var int v = val
851
998
  if v < 0 {
852
- self.sign = -1
853
999
  v = 0 - v
854
1000
  }
855
1001
  self.ensure(1)
856
1002
  self.digits.store_int(0, v)
857
1003
  self.len = 1
1004
+ if val == 0 {
1005
+ self.sign = 0
1006
+ } else {
1007
+ if val < 0 {
1008
+ self.sign = -1
1009
+ } else {
1010
+ self.sign = 1
1011
+ }
1012
+ }
858
1013
  }
859
1014
 
860
- pub func set_u64 = (ref self, uint64 val) {
861
- self.sign = 1
1015
+ pub func set_u64 = (ref self { digits }, uint64 val) {
862
1016
  self.ensure(1)
863
1017
  self.set(0, val)
864
1018
  self.len = 1
1019
+ if val == 0 {
1020
+ self.sign = 0
1021
+ } else {
1022
+ self.sign = 1
1023
+ }
865
1024
  }
866
1025
  }